From 39fc9d5c36e845b2e8dc7b1b8ee17f7f4d9eb2bc Mon Sep 17 00:00:00 2001
From: Magne Sjaastad
Date: Tue, 7 Nov 2023 19:23:12 +0100
Subject: [PATCH] Add support for grid calculations as data source for
statistics
- add data source selection, either Case Property or Grid Calculation
- add Time Step Selection, can be used for both dynamic case properties and Grid Calculations
- optionally release grid calculation data when statistics is computed
- recursive grid calculations is supported
---
.../Commands/RicCreateTemporaryLgrFeature.cpp | 6 +-
.../RimEclipseStatisticsCase.cpp | 372 +++++++++++++-----
.../RimEclipseStatisticsCase.h | 31 +-
.../RimEclipseStatisticsCaseEvaluator.cpp | 58 +--
.../RimEclipseStatisticsCaseEvaluator.h | 10 +-
.../ProjectDataModel/RimGridCalculation.cpp | 276 +++++++------
.../ProjectDataModel/RimGridCalculation.h | 2 +
.../RimGridCalculationCollection.cpp | 59 +++
.../RimGridCalculationCollection.h | 4 +
.../RimIdenticalGridCaseGroup.cpp | 1 +
.../RigCaseCellResultsData.cpp | 25 +-
.../RigCaseCellResultsData.h | 3 +-
12 files changed, 565 insertions(+), 282 deletions(-)
diff --git a/ApplicationLibCode/Commands/RicCreateTemporaryLgrFeature.cpp b/ApplicationLibCode/Commands/RicCreateTemporaryLgrFeature.cpp
index d845392420..27d9a7cfa5 100644
--- a/ApplicationLibCode/Commands/RicCreateTemporaryLgrFeature.cpp
+++ b/ApplicationLibCode/Commands/RicCreateTemporaryLgrFeature.cpp
@@ -285,16 +285,18 @@ void RicCreateTemporaryLgrFeature::deleteAllCachedData( RimEclipseCase* eclipseC
{
if ( eclipseCase )
{
+ std::vector categoriesToExclude = { RiaDefines::ResultCatType::GENERATED };
+
RigCaseCellResultsData* cellResultsDataMatrix = eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
if ( cellResultsDataMatrix )
{
- cellResultsDataMatrix->freeAllocatedResultsData();
+ cellResultsDataMatrix->freeAllocatedResultsData( categoriesToExclude, std::nullopt );
}
RigCaseCellResultsData* cellResultsDataFracture = eclipseCase->results( RiaDefines::PorosityModelType::FRACTURE_MODEL );
if ( cellResultsDataFracture )
{
- cellResultsDataFracture->freeAllocatedResultsData();
+ cellResultsDataFracture->freeAllocatedResultsData( categoriesToExclude, std::nullopt );
}
RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.cpp b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.cpp
index c6dc5071db..4b21ae13a0 100644
--- a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.cpp
+++ b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.cpp
@@ -34,8 +34,10 @@
#include "RimEclipseCellColors.h"
#include "RimEclipseStatisticsCaseEvaluator.h"
#include "RimEclipseView.h"
+#include "RimGridCalculationCollection.h"
#include "RimIdenticalGridCaseGroup.h"
#include "RimIntersectionCollection.h"
+#include "RimProject.h"
#include "RimReservoirCellResultsStorage.h"
#include "RimSimWellInViewCollection.h"
@@ -44,6 +46,7 @@
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmUiPushButtonEditor.h"
#include "cafPdmUiTextEditor.h"
+#include "cafPdmUiTreeSelectionEditor.h"
#include "cafProgressInfo.h"
namespace caf
@@ -51,10 +54,19 @@ namespace caf
template <>
void caf::AppEnum::setUp()
{
- addItem( RimEclipseStatisticsCase::NEAREST_OBSERVATION, "NearestObservationPercentile", "Nearest Observation" );
- addItem( RimEclipseStatisticsCase::HISTOGRAM_ESTIMATED, "HistogramEstimatedPercentile", "Histogram based estimate" );
- addItem( RimEclipseStatisticsCase::INTERPOLATED_OBSERVATION, "InterpolatedObservationPercentile", "Interpolated Observation" );
- setDefault( RimEclipseStatisticsCase::INTERPOLATED_OBSERVATION );
+ addItem( RimEclipseStatisticsCase::PercentileCalcType::NEAREST_OBSERVATION, "NearestObservationPercentile", "Nearest Observation" );
+ addItem( RimEclipseStatisticsCase::PercentileCalcType::HISTOGRAM_ESTIMATED, "HistogramEstimatedPercentile", "Histogram based estimate" );
+ addItem( RimEclipseStatisticsCase::PercentileCalcType::INTERPOLATED_OBSERVATION,
+ "InterpolatedObservationPercentile",
+ "Interpolated Observation" );
+ setDefault( RimEclipseStatisticsCase::PercentileCalcType::INTERPOLATED_OBSERVATION );
+}
+template <>
+void caf::AppEnum::setUp()
+{
+ addItem( RimEclipseStatisticsCase::DataSourceType::GRID_CALCULATION, "GridCalculation", "Grid Calculation" );
+ addItem( RimEclipseStatisticsCase::DataSourceType::CASE_PROPERTY, "CaseProperty", "Case Property" );
+ setDefault( RimEclipseStatisticsCase::DataSourceType::CASE_PROPERTY );
}
} // namespace caf
@@ -78,6 +90,14 @@ RimEclipseStatisticsCase::RimEclipseStatisticsCase()
m_selectionSummary.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
m_selectionSummary.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
+ CAF_PDM_InitFieldNoDefault( &m_dataSourceForStatistics, "DataSourceForStatistics", "Data Source" );
+
+ CAF_PDM_InitFieldNoDefault( &m_gridCalculation, "GridCalculation", "Grid Calculation" );
+ CAF_PDM_InitField( &m_clearGridCalculationMemory, "ClearGridCalculationMemory", true, "Clear Grid Calculation Memory" );
+
+ CAF_PDM_InitScriptableFieldNoDefault( &m_selectedTimeSteps, "SelectedTimeSteps", "Time Step Selection" );
+ m_selectedTimeSteps.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
+
CAF_PDM_InitScriptableFieldNoDefault( &m_resultType, "ResultType", "Result Type" );
m_resultType.xmlCapability()->setIOWritable( false );
CAF_PDM_InitScriptableFieldNoDefault( &m_porosityModel, "PorosityModel", "Porosity Model" );
@@ -120,6 +140,8 @@ RimEclipseStatisticsCase::RimEclipseStatisticsCase()
m_flipXAxis.uiCapability()->setUiHidden( true );
m_flipYAxis.uiCapability()->setUiHidden( true );
m_activeFormationNames.uiCapability()->setUiHidden( true );
+
+ m_displayNameOption = RimCaseDisplayNameTools::DisplayName::CUSTOM;
}
//--------------------------------------------------------------------------------------------------
@@ -174,6 +196,8 @@ bool RimEclipseStatisticsCase::openEclipseGridFile()
m_populateSelectionAfterLoadingGrid = false;
}
+ initializeSelectedTimeSteps();
+
return true;
}
@@ -240,6 +264,26 @@ void RimEclipseStatisticsCase::setSourceProperties( RiaDefines::ResultCatType pr
}
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+void RimEclipseStatisticsCase::selectAllTimeSteps()
+{
+ RimIdenticalGridCaseGroup* idgcg = caseGroup();
+ if ( idgcg && idgcg->mainCase() )
+ {
+ int timeStepCount = idgcg->mainCase()->timeStepStrings().size();
+
+ if ( timeStepCount > 0 )
+ {
+ std::vector allTimeSteps;
+ allTimeSteps.resize( timeStepCount );
+ std::iota( allTimeSteps.begin(), allTimeSteps.end(), 0 );
+ m_selectedTimeSteps = allTimeSteps;
+ }
+ }
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -256,15 +300,32 @@ void RimEclipseStatisticsCase::computeStatistics()
std::vector sourceCases = getSourceCases();
+ if ( m_dataSourceForStatistics() == DataSourceType::GRID_CALCULATION && m_gridCalculation() )
+ {
+ auto proj = RimProject::current();
+ auto calcColl = proj->gridCalculationCollection();
+
+ auto dependentCalculations = calcColl->dependentCalculations( m_gridCalculation() );
+ if ( dependentCalculations.empty() )
+ {
+ // No calculations found, usually triggered by a circular dependency of calculations. Error message displayed by
+ // dependentCalculations().
+ return;
+ }
+
+ std::vector timeStepIndices( m_selectedTimeSteps().begin(), m_selectedTimeSteps().end() );
+
+ for ( auto calc : dependentCalculations )
+ {
+ calc->calculateForCases( sourceCases, timeStepIndices );
+ }
+ }
+
if ( sourceCases.empty() || !sourceCases.at( 0 )->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) )
{
return;
}
- // The first source has been read completely from disk, and contains grid and meta data
- // Use this information for all cases in the case group
- size_t timeStepCount = sourceCases.at( 0 )->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->maxTimeStepCount();
-
RimStatisticsConfig statisticsConfig;
statisticsConfig.m_calculatePercentiles = m_calculatePercentiles();
@@ -273,11 +334,7 @@ void RimEclipseStatisticsCase::computeStatistics()
statisticsConfig.m_pMinPos = m_lowPercentile();
statisticsConfig.m_pValMethod = m_percentileCalculationType();
- std::vector timeStepIndices;
- for ( size_t i = 0; i < timeStepCount; i++ )
- {
- timeStepIndices.push_back( i );
- }
+ auto timeStepIndices = m_selectedTimeSteps();
// If no dynamic data is present, we might end up with no time steps. Make sure we have at least one.
if ( timeStepIndices.empty() )
@@ -289,63 +346,79 @@ void RimEclipseStatisticsCase::computeStatistics()
QList resultSpecification;
- for ( size_t pIdx = 0; pIdx < m_selectedDynamicProperties().size(); ++pIdx )
+ if ( m_dataSourceForStatistics() == DataSourceType::CASE_PROPERTY )
{
- resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
- RiaDefines::ResultCatType::DYNAMIC_NATIVE,
- m_selectedDynamicProperties()[pIdx] ) );
- }
+ for ( size_t pIdx = 0; pIdx < m_selectedDynamicProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
+ RiaDefines::ResultCatType::DYNAMIC_NATIVE,
+ m_selectedDynamicProperties()[pIdx] ) );
+ }
- for ( size_t pIdx = 0; pIdx < m_selectedStaticProperties().size(); ++pIdx )
- {
- resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
- RiaDefines::ResultCatType::STATIC_NATIVE,
- m_selectedStaticProperties()[pIdx] ) );
- }
+ for ( size_t pIdx = 0; pIdx < m_selectedStaticProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
+ RiaDefines::ResultCatType::STATIC_NATIVE,
+ m_selectedStaticProperties()[pIdx] ) );
+ }
- for ( size_t pIdx = 0; pIdx < m_selectedGeneratedProperties().size(); ++pIdx )
+ for ( size_t pIdx = 0; pIdx < m_selectedGeneratedProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
+ RiaDefines::ResultCatType::GENERATED,
+ m_selectedGeneratedProperties()[pIdx] ) );
+ }
+
+ for ( size_t pIdx = 0; pIdx < m_selectedInputProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
+ RiaDefines::ResultCatType::INPUT_PROPERTY,
+ m_selectedInputProperties()[pIdx] ) );
+ }
+
+ for ( size_t pIdx = 0; pIdx < m_selectedFractureDynamicProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
+ RiaDefines::ResultCatType::DYNAMIC_NATIVE,
+ m_selectedFractureDynamicProperties()[pIdx] ) );
+ }
+
+ for ( size_t pIdx = 0; pIdx < m_selectedFractureStaticProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
+ RiaDefines::ResultCatType::STATIC_NATIVE,
+ m_selectedFractureStaticProperties()[pIdx] ) );
+ }
+
+ for ( size_t pIdx = 0; pIdx < m_selectedFractureGeneratedProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
+ RiaDefines::ResultCatType::GENERATED,
+ m_selectedFractureGeneratedProperties()[pIdx] ) );
+ }
+
+ for ( size_t pIdx = 0; pIdx < m_selectedFractureInputProperties().size(); ++pIdx )
+ {
+ resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
+ RiaDefines::ResultCatType::INPUT_PROPERTY,
+ m_selectedFractureInputProperties()[pIdx] ) );
+ }
+ }
+ else if ( m_dataSourceForStatistics() == DataSourceType::GRID_CALCULATION && m_gridCalculation() )
{
+ auto calculationName = m_gridCalculation->shortName();
+
resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
RiaDefines::ResultCatType::GENERATED,
- m_selectedGeneratedProperties()[pIdx] ) );
+ calculationName ) );
}
- for ( size_t pIdx = 0; pIdx < m_selectedInputProperties().size(); ++pIdx )
- {
- resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::MATRIX_MODEL,
- RiaDefines::ResultCatType::INPUT_PROPERTY,
- m_selectedInputProperties()[pIdx] ) );
- }
-
- for ( size_t pIdx = 0; pIdx < m_selectedFractureDynamicProperties().size(); ++pIdx )
- {
- resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
- RiaDefines::ResultCatType::DYNAMIC_NATIVE,
- m_selectedFractureDynamicProperties()[pIdx] ) );
- }
-
- for ( size_t pIdx = 0; pIdx < m_selectedFractureStaticProperties().size(); ++pIdx )
- {
- resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
- RiaDefines::ResultCatType::STATIC_NATIVE,
- m_selectedFractureStaticProperties()[pIdx] ) );
- }
-
- for ( size_t pIdx = 0; pIdx < m_selectedFractureGeneratedProperties().size(); ++pIdx )
- {
- resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
- RiaDefines::ResultCatType::GENERATED,
- m_selectedFractureGeneratedProperties()[pIdx] ) );
- }
-
- for ( size_t pIdx = 0; pIdx < m_selectedFractureInputProperties().size(); ++pIdx )
- {
- resultSpecification.append( RimEclipseStatisticsCaseEvaluator::ResSpec( RiaDefines::PorosityModelType::FRACTURE_MODEL,
- RiaDefines::ResultCatType::INPUT_PROPERTY,
- m_selectedFractureInputProperties()[pIdx] ) );
- }
-
- RimEclipseStatisticsCaseEvaluator stat( sourceCases, timeStepIndices, statisticsConfig, resultCase, gridCaseGroup );
+ RimEclipseStatisticsCaseEvaluator stat( sourceCases,
+ timeStepIndices,
+ statisticsConfig,
+ resultCase,
+ gridCaseGroup,
+ m_clearGridCalculationMemory() );
if ( m_useZeroAsInactiveCellValue )
{
@@ -419,37 +492,63 @@ void RimEclipseStatisticsCase::defineUiOrdering( QString uiConfigName, caf::PdmU
uiOrdering.add( &m_calculateEditCommand );
- caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Summary of Calculation Setup" );
- group->add( &m_useZeroAsInactiveCellValue );
- m_useZeroAsInactiveCellValue.uiCapability()->setUiHidden( hasComputedStatistics() );
- group->add( &m_selectionSummary );
+ {
+ caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Summary of Calculation Setup" );
+ group->add( &m_useZeroAsInactiveCellValue );
+ m_useZeroAsInactiveCellValue.uiCapability()->setUiHidden( hasComputedStatistics() );
+ group->add( &m_selectionSummary );
+ }
- group = uiOrdering.addNewGroup( "Properties to consider" );
- group->setUiHidden( hasComputedStatistics() );
- group->add( &m_resultType );
- group->add( &m_porosityModel );
- group->add( &m_selectedDynamicProperties );
- group->add( &m_selectedStaticProperties );
- group->add( &m_selectedGeneratedProperties );
- group->add( &m_selectedInputProperties );
- group->add( &m_selectedFractureDynamicProperties );
- group->add( &m_selectedFractureStaticProperties );
- group->add( &m_selectedFractureGeneratedProperties );
- group->add( &m_selectedFractureInputProperties );
+ {
+ auto group = uiOrdering.addNewGroup( "Properties to consider" );
+ group->setUiHidden( hasComputedStatistics() );
+ group->add( &m_dataSourceForStatistics );
- group = uiOrdering.addNewGroup( "Percentile setup" );
- group->setUiHidden( hasComputedStatistics() );
- group->add( &m_calculatePercentiles );
- group->add( &m_percentileCalculationType );
- group->add( &m_lowPercentile );
- group->add( &m_midPercentile );
- group->add( &m_highPercentile );
+ if ( m_dataSourceForStatistics() == DataSourceType::GRID_CALCULATION )
+ {
+ group->add( &m_gridCalculation );
+ group->add( &m_clearGridCalculationMemory );
+ }
+ else
+ {
+ group->add( &m_resultType );
+ group->add( &m_porosityModel );
+ group->add( &m_selectedDynamicProperties );
+ group->add( &m_selectedStaticProperties );
+ group->add( &m_selectedGeneratedProperties );
+ group->add( &m_selectedInputProperties );
+ group->add( &m_selectedFractureDynamicProperties );
+ group->add( &m_selectedFractureStaticProperties );
+ group->add( &m_selectedFractureGeneratedProperties );
+ group->add( &m_selectedFractureInputProperties );
+ }
+ }
- group = uiOrdering.addNewGroup( "Case Options" );
- group->add( &m_wellDataSourceCase );
- group->add( &m_activeFormationNames );
- group->add( &m_flipXAxis );
- group->add( &m_flipYAxis );
+ {
+ auto group = uiOrdering.addNewGroup( "Time Step Selection" );
+ group->setCollapsedByDefault();
+ group->add( &m_selectedTimeSteps );
+ }
+
+ {
+ auto group = uiOrdering.addNewGroup( "Percentile setup" );
+ group->setUiHidden( hasComputedStatistics() );
+ group->add( &m_calculatePercentiles );
+ group->add( &m_percentileCalculationType );
+ group->add( &m_lowPercentile );
+ group->add( &m_midPercentile );
+ group->add( &m_highPercentile );
+ }
+
+ {
+ auto group = uiOrdering.addNewGroup( "Case Options" );
+ group->add( &m_wellDataSourceCase );
+ group->add( &m_activeFormationNames );
+ group->add( &m_flipXAxis );
+ group->add( &m_flipYAxis );
+ }
+
+ uiOrdering.skipRemainingFields();
}
QList toOptionList( const QStringList& varList )
@@ -468,16 +567,63 @@ QList toOptionList( const QStringList& varList )
//--------------------------------------------------------------------------------------------------
QList RimEclipseStatisticsCase::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
- QList options;
-
RimIdenticalGridCaseGroup* idgcg = caseGroup();
if ( !( caseGroup() && caseGroup()->mainCase() && caseGroup()->mainCase()->eclipseCaseData() ) )
{
+ return {};
+ }
+
+ if ( &m_dataSourceForStatistics == fieldNeedingOptions )
+ {
+ QList options;
+
+ {
+ caf::IconProvider iconProvider( ":/Case48x48.png" );
+ options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( DataSourceType::CASE_PROPERTY ),
+ DataSourceType::CASE_PROPERTY,
+ false,
+ iconProvider ) );
+ }
+ {
+ caf::IconProvider iconProvider( ":/Calculator.svg" );
+ options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( DataSourceType::GRID_CALCULATION ),
+ DataSourceType::GRID_CALCULATION,
+ false,
+ iconProvider ) );
+ }
+
+ return options;
+ }
+
+ if ( &m_gridCalculation == fieldNeedingOptions )
+ {
+ QList options;
+
+ for ( auto calc : RimProject::current()->gridCalculationCollection()->calculations() )
+ {
+ options.push_back( caf::PdmOptionItemInfo( calc->shortName(), calc ) );
+ }
+
return options;
}
RigEclipseCaseData* caseData = idgcg->mainCase()->eclipseCaseData();
+ if ( &m_selectedTimeSteps == fieldNeedingOptions )
+ {
+ QList options;
+
+ const auto timeStepStrings = idgcg->mainCase()->timeStepStrings();
+
+ int index = 0;
+ for ( const auto& text : timeStepStrings )
+ {
+ options.push_back( caf::PdmOptionItemInfo( text, index++ ) );
+ }
+
+ return options;
+ }
+
if ( &m_selectedDynamicProperties == fieldNeedingOptions )
{
QStringList varList =
@@ -540,9 +686,7 @@ QList RimEclipseStatisticsCase::calculateValueOptions( c
return toOptionList( sourceCaseNames );
}
- if ( options.empty() ) options = RimEclipseCase::calculateValueOptions( fieldNeedingOptions );
-
- return options;
+ return RimEclipseCase::calculateValueOptions( fieldNeedingOptions );
}
//--------------------------------------------------------------------------------------------------
@@ -662,15 +806,26 @@ void RimEclipseStatisticsCase::updateSelectionSummaryLabel()
}
html += "
";
- addPropertySetToHtmlText( html, "Dynamic properties", m_selectedDynamicProperties() );
- addPropertySetToHtmlText( html, "Static properties", m_selectedStaticProperties() );
- addPropertySetToHtmlText( html, "Generated properties", m_selectedGeneratedProperties() );
- addPropertySetToHtmlText( html, "Input properties", m_selectedInputProperties() );
+ if ( m_dataSourceForStatistics() == DataSourceType::CASE_PROPERTY )
+ {
+ addPropertySetToHtmlText( html, "Dynamic properties", m_selectedDynamicProperties() );
+ addPropertySetToHtmlText( html, "Static properties", m_selectedStaticProperties() );
+ addPropertySetToHtmlText( html, "Generated properties", m_selectedGeneratedProperties() );
+ addPropertySetToHtmlText( html, "Input properties", m_selectedInputProperties() );
- addPropertySetToHtmlText( html, "Dynamic properties, fracture model", m_selectedFractureDynamicProperties() );
- addPropertySetToHtmlText( html, "Static properties, fracture model", m_selectedFractureStaticProperties() );
- addPropertySetToHtmlText( html, "Generated properties, fracture model", m_selectedFractureGeneratedProperties() );
- addPropertySetToHtmlText( html, "Input properties, fracture model", m_selectedFractureInputProperties() );
+ addPropertySetToHtmlText( html, "Dynamic properties, fracture model", m_selectedFractureDynamicProperties() );
+ addPropertySetToHtmlText( html, "Static properties, fracture model", m_selectedFractureStaticProperties() );
+ addPropertySetToHtmlText( html, "Generated properties, fracture model", m_selectedFractureGeneratedProperties() );
+ addPropertySetToHtmlText( html, "Input properties, fracture model", m_selectedFractureInputProperties() );
+ }
+
+ if ( m_dataSourceForStatistics() == DataSourceType::GRID_CALCULATION && m_gridCalculation() )
+ {
+ html += "Grid calculation:
";
+ html += "";
+ html += m_gridCalculation()->shortName();
+ html += "
";
+ }
m_selectionSummary = html;
}
@@ -699,6 +854,17 @@ void RimEclipseStatisticsCase::defineEditorAttribute( const caf::PdmFieldHandle*
}
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+void RimEclipseStatisticsCase::initializeSelectedTimeSteps()
+{
+ if ( RimProject::current()->isProjectFileVersionEqualOrOlderThan( "2023.10.0" ) )
+ {
+ selectAllTimeSteps();
+ }
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.h b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.h
index 1bade5cb64..91eba7bb7d 100644
--- a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.h
+++ b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCase.h
@@ -35,6 +35,7 @@ class RigSimWellData;
class RimEclipseResultDefinition;
class RimEclipseStatisticsCaseCollection;
class RimIdenticalGridCaseGroup;
+class RimGridCalculation;
//==================================================================================================
//
@@ -45,6 +46,20 @@ class RimEclipseStatisticsCase : public RimEclipseCase
{
CAF_PDM_HEADER_INIT;
+public:
+ enum class PercentileCalcType
+ {
+ NEAREST_OBSERVATION,
+ HISTOGRAM_ESTIMATED,
+ INTERPOLATED_OBSERVATION
+ };
+
+ enum class DataSourceType
+ {
+ GRID_CALCULATION,
+ CASE_PROPERTY
+ };
+
public:
RimEclipseStatisticsCase();
~RimEclipseStatisticsCase() override;
@@ -63,18 +78,12 @@ public:
RimCaseCollection* parentStatisticsCaseCollection() const;
- enum PercentileCalcType
- {
- NEAREST_OBSERVATION,
- HISTOGRAM_ESTIMATED,
- INTERPOLATED_OBSERVATION
- };
-
caf::PdmField m_calculateEditCommand;
void populateResultSelectionAfterLoadingGrid();
void setSourceProperties( RiaDefines::ResultCatType propertyType, const std::vector& propertyNames );
+ void selectAllTimeSteps();
private:
void scheduleACTIVEGeometryRegenOnReservoirViews();
@@ -95,8 +104,16 @@ private:
void loadSimulationWellDataFromSourceCase();
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
+ void initializeSelectedTimeSteps();
private:
+ caf::PdmField> m_dataSourceForStatistics;
+
+ caf::PdmPtrField m_gridCalculation;
+ caf::PdmField m_clearGridCalculationMemory;
+
+ caf::PdmField> m_selectedTimeSteps;
+
caf::PdmField> m_resultType;
caf::PdmField> m_porosityModel;
diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp
index 2801701125..dbc20ecfcd 100644
--- a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp
+++ b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp
@@ -116,23 +116,23 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
for ( size_t timeIndicesIdx = 0; timeIndicesIdx < m_timeStepIndices.size(); timeIndicesIdx++ )
{
- size_t timeStepIdx = m_timeStepIndices[timeIndicesIdx];
+ auto timeStepIdx = m_timeStepIndices[timeIndicesIdx];
for ( size_t gridIdx = 0; gridIdx < m_destinationCase->gridCount(); gridIdx++ )
{
RigGridBase* grid = m_destinationCase->grid( gridIdx );
- for ( int resSpecIdx = 0; resSpecIdx < resultSpecification.size(); resSpecIdx++ )
+ for ( const auto& resSpec : resultSpecification )
{
- RiaDefines::PorosityModelType poroModel = resultSpecification[resSpecIdx].m_poroModel;
- RiaDefines::ResultCatType resultType = resultSpecification[resSpecIdx].m_resType;
- QString resultName = resultSpecification[resSpecIdx].m_resVarName;
+ RiaDefines::PorosityModelType poroModel = resSpec.m_poroModel;
+ RiaDefines::ResultCatType resultType = resSpec.m_resType;
+ QString resultName = resSpec.m_resVarName;
size_t activeCellCount = m_destinationCase->activeCellInfo( poroModel )->reservoirActiveCellCount();
if ( activeCellCount == 0 ) continue;
- size_t dataAccessTimeStepIndex = timeStepIdx;
+ auto dataAccessTimeStepIndex = static_cast( timeStepIdx );
// Always evaluate statistics once, and always use time step index zero
if ( resultType == RiaDefines::ResultCatType::STATIC_NATIVE )
@@ -145,10 +145,8 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
// Build data access objects for source scalar results
cvf::Collection sourceDataAccessList;
- for ( size_t caseIdx = 0; caseIdx < m_sourceCases.size(); caseIdx++ )
+ for ( RimEclipseCase* sourceCase : m_sourceCases )
{
- RimEclipseCase* sourceCase = m_sourceCases.at( caseIdx );
-
// Trigger loading of dataset
// NB! Many other functions are based on loading of all time steps at the same time
// Use this concept carefully
@@ -184,21 +182,21 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
statisticalResultNames[PMID] = createResultNamePVal( resultName, m_statisticsConfig.m_pMidPos );
statisticalResultNames[PMAX] = createResultNamePVal( resultName, m_statisticsConfig.m_pMaxPos );
- for ( size_t stIdx = 0; stIdx < statisticalResultNames.size(); ++stIdx )
+ for ( const auto& statisticalResultName : statisticalResultNames )
{
cvf::ref resultModifier =
RigResultModifierFactory::createResultModifier( m_destinationCase,
grid->gridIndex(),
poroModel,
dataAccessTimeStepIndex,
- RigEclipseResultAddress( resultType, statisticalResultNames[stIdx] ) );
+ RigEclipseResultAddress( resultType, statisticalResultName ) );
destinationDataAccessList.push_back( resultModifier.p() );
}
std::vector statParams( STAT_PARAM_COUNT, HUGE_VAL );
std::vector values( sourceDataAccessList.size(), HUGE_VAL );
- int cellCount = static_cast( grid->cellCount() );
+ auto cellCount = static_cast( grid->cellCount() );
// Loop over the cells in the grid, get the case values, and calculate the cell statistics
#pragma omp parallel for schedule( dynamic ) firstprivate( statParams, values )
@@ -245,7 +243,7 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
// Calculate percentiles
if ( m_statisticsConfig.m_calculatePercentiles )
{
- if ( m_statisticsConfig.m_pValMethod == RimEclipseStatisticsCase::NEAREST_OBSERVATION )
+ if ( m_statisticsConfig.m_pValMethod == RimEclipseStatisticsCase::PercentileCalcType::NEAREST_OBSERVATION )
{
std::vector pValPoss;
pValPoss.push_back( m_statisticsConfig.m_pMinPos );
@@ -259,7 +257,7 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
statParams[PMID] = pVals[1];
statParams[PMAX] = pVals[2];
}
- else if ( m_statisticsConfig.m_pValMethod == RimEclipseStatisticsCase::HISTOGRAM_ESTIMATED )
+ else if ( m_statisticsConfig.m_pValMethod == RimEclipseStatisticsCase::PercentileCalcType::HISTOGRAM_ESTIMATED )
{
std::vector histogram;
RigHistogramCalculator histCalc( statParams[MIN], statParams[MAX], 100, &histogram );
@@ -271,7 +269,8 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
statParams[PMAX] = histCalc.calculatePercentil( m_statisticsConfig.m_pMaxPos / 100.0,
RigStatisticsMath::PercentileStyle::SWITCHED );
}
- else if ( m_statisticsConfig.m_pValMethod == RimEclipseStatisticsCase::INTERPOLATED_OBSERVATION )
+ else if ( m_statisticsConfig.m_pValMethod ==
+ RimEclipseStatisticsCase::PercentileCalcType::INTERPOLATED_OBSERVATION )
{
std::vector pValPoss;
pValPoss.push_back( m_statisticsConfig.m_pMinPos );
@@ -310,14 +309,15 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
// Microsoft note: On Windows, the maximum number of files open at the same time is 512
// http://msdn.microsoft.com/en-us/library/kdfaxaay%28vs.71%29.aspx
- for ( size_t caseIdx = 0; caseIdx < m_sourceCases.size(); caseIdx++ )
- {
- RimEclipseCase* eclipseCase = m_sourceCases.at( caseIdx );
+ std::vector categoriesToExclude;
+ if ( !m_clearGridCalculationMemory ) categoriesToExclude.push_back( RiaDefines::ResultCatType::GENERATED );
+ for ( RimEclipseCase* eclipseCase : m_sourceCases )
+ {
if ( eclipseCase->reservoirViews.empty() )
{
- eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->freeAllocatedResultsData();
- eclipseCase->results( RiaDefines::PorosityModelType::FRACTURE_MODEL )->freeAllocatedResultsData();
+ eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->freeAllocatedResultsData( categoriesToExclude, timeStepIdx );
+ eclipseCase->results( RiaDefines::PorosityModelType::FRACTURE_MODEL )->freeAllocatedResultsData( categoriesToExclude, timeStepIdx );
}
}
@@ -330,11 +330,11 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList
//--------------------------------------------------------------------------------------------------
void RimEclipseStatisticsCaseEvaluator::addNamedResults( const QList& resultSpecification )
{
- for ( int i = 0; i < resultSpecification.size(); i++ )
+ for ( const auto& resSpec : resultSpecification )
{
- RiaDefines::PorosityModelType poroModel = resultSpecification[i].m_poroModel;
- RiaDefines::ResultCatType resultType = resultSpecification[i].m_resType;
- QString resultName = resultSpecification[i].m_resVarName;
+ RiaDefines::PorosityModelType poroModel = resSpec.m_poroModel;
+ RiaDefines::ResultCatType resultType = resSpec.m_resType;
+ QString resultName = resSpec.m_resVarName;
size_t activeCellCount = m_destinationCase->activeCellInfo( poroModel )->reservoirActiveCellCount();
if ( activeCellCount == 0 ) continue;
@@ -361,9 +361,9 @@ void RimEclipseStatisticsCaseEvaluator::addNamedResults( const QList& r
statisticalResultNames.push_back( createResultNamePVal( resultName, m_statisticsConfig.m_pMaxPos ) );
}
- for ( size_t j = 0; j < statisticalResultNames.size(); ++j )
+ for ( const auto& statisticalResultName : statisticalResultNames )
{
- addNamedResult( destCellResultsData, resultType, statisticalResultNames[j], activeCellCount );
+ addNamedResult( destCellResultsData, resultType, statisticalResultName, activeCellCount );
}
}
}
@@ -372,10 +372,11 @@ void RimEclipseStatisticsCaseEvaluator::addNamedResults( const QList& r
///
//--------------------------------------------------------------------------------------------------
RimEclipseStatisticsCaseEvaluator::RimEclipseStatisticsCaseEvaluator( const std::vector& sourceCases,
- const std::vector& timeStepIndices,
+ const std::vector& timeStepIndices,
const RimStatisticsConfig& statisticsConfig,
RigEclipseCaseData* destinationCase,
- RimIdenticalGridCaseGroup* identicalGridCaseGroup )
+ RimIdenticalGridCaseGroup* identicalGridCaseGroup,
+ bool clearGridCalculationMemory )
: m_sourceCases( sourceCases )
, m_statisticsConfig( statisticsConfig )
, m_destinationCase( destinationCase )
@@ -383,6 +384,7 @@ RimEclipseStatisticsCaseEvaluator::RimEclipseStatisticsCaseEvaluator( const std:
, m_timeStepIndices( timeStepIndices )
, m_identicalGridCaseGroup( identicalGridCaseGroup )
, m_useZeroAsInactiveCellValue( false )
+ , m_clearGridCalculationMemory( clearGridCalculationMemory )
{
if ( !sourceCases.empty() )
{
diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h
index 7b086d9bd9..c92798276e 100644
--- a/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h
+++ b/ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h
@@ -38,7 +38,7 @@ public:
, m_pMinPos( 10.0 )
, m_pMidPos( 50.0 )
, m_pMaxPos( 90.0 )
- , m_pValMethod( RimEclipseStatisticsCase::INTERPOLATED_OBSERVATION )
+ , m_pValMethod( RimEclipseStatisticsCase::PercentileCalcType::INTERPOLATED_OBSERVATION )
{
}
@@ -54,10 +54,11 @@ class RimEclipseStatisticsCaseEvaluator
{
public:
RimEclipseStatisticsCaseEvaluator( const std::vector& sourceCases,
- const std::vector& timeStepIndices,
+ const std::vector& timeStepIndices,
const RimStatisticsConfig& statisticsConfig,
RigEclipseCaseData* destinationCase,
- RimIdenticalGridCaseGroup* identicalGridCaseGroup );
+ RimIdenticalGridCaseGroup* identicalGridCaseGroup,
+ bool clearGridCalculationMemory );
struct ResSpec
{
@@ -105,11 +106,12 @@ private:
private:
std::vector m_sourceCases;
- std::vector m_timeStepIndices;
+ std::vector m_timeStepIndices;
size_t m_reservoirCellCount;
RimStatisticsConfig m_statisticsConfig;
RigEclipseCaseData* m_destinationCase;
RimIdenticalGridCaseGroup* m_identicalGridCaseGroup;
bool m_useZeroAsInactiveCellValue;
+ bool m_clearGridCalculationMemory;
};
diff --git a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp
index fefeec8f7e..6540fb534e 100644
--- a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp
+++ b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp
@@ -44,6 +44,8 @@
#include "expressionparser/ExpressionParser.h"
+#include "cafProgressInfo.h"
+
#include
CAF_PDM_SOURCE_INIT( RimGridCalculation, "RimGridCalculation" );
@@ -109,137 +111,9 @@ RimGridCalculationVariable* RimGridCalculation::createVariable()
//--------------------------------------------------------------------------------------------------
bool RimGridCalculation::calculate()
{
- QString leftHandSideVariableName = RimGridCalculation::findLeftHandSide( m_expression );
+ auto timeSteps = std::nullopt;
- if ( !m_destinationCase )
- {
- RiaLogging::errorInMessageBox( nullptr,
- "Grid Property Calculator",
- QString( "No destination case found for calculation : %1" ).arg( leftHandSideVariableName ) );
-
- return false;
- }
-
- auto [isOk, errorMessage] = validateVariables();
- if ( !isOk )
- {
- RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", errorMessage );
- return false;
- }
-
- for ( auto variableCase : inputCases() )
- {
- if ( !m_destinationCase->isGridSizeEqualTo( variableCase ) )
- {
- QString msg = "Detected IJK mismatch between input cases and destination case. All grid "
- "cases must have identical IJK sizes.";
- RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", msg );
- return false;
- }
- }
-
- const bool isMultipleCasesPresent = outputEclipseCases().size() > 1;
-
- if ( isMultipleCasesPresent )
- {
- QString txt = "Starting calculation " + description() + " for " + QString::number( outputEclipseCases().size() ) + " cases.";
- RiaLogging::info( txt );
- }
-
- bool anyErrorsDetected = false;
- for ( RimEclipseCase* outputEclipseCase : outputEclipseCases() )
- {
- if ( !outputEclipseCase )
- {
- RiaLogging::errorInMessageBox( nullptr,
- "Grid Property Calculator",
- QString( "No case found for calculation : %1" ).arg( leftHandSideVariableName ) );
- anyErrorsDetected = true;
- continue;
- }
-
- auto porosityModel = RiaDefines::PorosityModelType::MATRIX_MODEL;
-
- RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::GENERATED, leftHandSideVariableName );
-
- if ( !outputEclipseCase->results( porosityModel )->ensureKnownResultLoaded( resAddr ) )
- {
- bool needsToBeStored = false;
- outputEclipseCase->results( porosityModel )->createResultEntry( resAddr, needsToBeStored );
- }
-
- outputEclipseCase->results( porosityModel )->clearScalarResult( resAddr );
-
- // If an input grid is present, max time step count is zero. Make sure the time step count for the calculation is
- // always 1 or more.
- const size_t timeStepCount = std::max( size_t( 1 ), outputEclipseCase->results( porosityModel )->maxTimeStepCount() );
-
- std::vector>* scalarResultFrames =
- outputEclipseCase->results( porosityModel )->modifiableCellScalarResultTimesteps( resAddr );
- scalarResultFrames->resize( timeStepCount );
-
- for ( size_t tsId = 0; tsId < timeStepCount; tsId++ )
- {
- std::vector> values;
- for ( size_t i = 0; i < m_variables.size(); i++ )
- {
- RimGridCalculationVariable* v = dynamic_cast( m_variables[i] );
- CAF_ASSERT( v != nullptr );
- values.push_back( getInputVectorForVariable( v, tsId, porosityModel, outputEclipseCase ) );
- }
-
- ExpressionParser parser;
- for ( size_t i = 0; i < m_variables.size(); i++ )
- {
- RimGridCalculationVariable* v = dynamic_cast( m_variables[i] );
- CAF_ASSERT( v != nullptr );
- parser.assignVector( v->name(), values[i] );
- }
-
- std::vector resultValues;
- resultValues.resize( values[0].size() );
- parser.assignVector( leftHandSideVariableName, resultValues );
-
- QString errorText;
- bool evaluatedOk = parser.expandIfStatementsAndEvaluate( m_expression, &errorText );
-
- if ( evaluatedOk )
- {
- if ( m_cellFilterView() )
- {
- filterResults( m_cellFilterView(), values, m_defaultValueType(), m_defaultValue(), resultValues, porosityModel, outputEclipseCase );
- }
-
- scalarResultFrames->at( tsId ) = resultValues;
-
- m_isDirty = false;
- }
- else
- {
- QString s = "The following error message was received from the parser library : \n\n";
- s += errorText;
-
- RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", s );
- return false;
- }
-
- outputEclipseCase->updateResultAddressCollection();
- }
-
- if ( isMultipleCasesPresent )
- {
- QString txt = " " + outputEclipseCase->caseUserDescription();
- RiaLogging::info( txt );
- }
- }
-
- if ( isMultipleCasesPresent )
- {
- QString txt = "Completed calculation " + description() + " for " + QString::number( outputEclipseCases().size() ) + " cases";
- RiaLogging::info( txt );
- }
-
- return !anyErrorsDetected;
+ return calculateForCases( outputEclipseCases(), timeSteps );
}
//--------------------------------------------------------------------------------------------------
@@ -639,6 +513,148 @@ void RimGridCalculation::removeDependentObjects()
}
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RimGridCalculation::calculateForCases( const std::vector& calculationCases, std::optional> timeSteps )
+{
+ if ( calculationCases.empty() ) return true;
+
+ QString leftHandSideVariableName = RimGridCalculation::findLeftHandSide( m_expression );
+
+ auto [isOk, errorMessage] = validateVariables();
+ if ( !isOk )
+ {
+ RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", errorMessage );
+ return false;
+ }
+
+ for ( auto calculationCase : calculationCases )
+ {
+ for ( auto inputCase : inputCases() )
+ {
+ if ( !calculationCase->isGridSizeEqualTo( inputCase ) )
+ {
+ QString msg = "Detected IJK mismatch between input cases and destination case. All grid "
+ "cases must have identical IJK sizes.";
+ RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", msg );
+ return false;
+ }
+ }
+ }
+
+ const bool isMultipleCasesPresent = calculationCases.size() > 1;
+
+ if ( isMultipleCasesPresent )
+ {
+ QString txt = "Starting calculation " + description() + " for " + QString::number( calculationCases.size() ) + " cases.";
+ RiaLogging::info( txt );
+ }
+
+ caf::ProgressInfo progressInfo( calculationCases.size(), "Processing Grid Calculations" );
+ size_t progressIndex = 0;
+
+ bool anyErrorsDetected = false;
+ for ( RimEclipseCase* calculationCase : calculationCases )
+ {
+ if ( !calculationCase )
+ {
+ RiaLogging::errorInMessageBox( nullptr,
+ "Grid Property Calculator",
+ QString( "No case found for calculation : %1" ).arg( leftHandSideVariableName ) );
+ anyErrorsDetected = true;
+ continue;
+ }
+
+ auto porosityModel = RiaDefines::PorosityModelType::MATRIX_MODEL;
+
+ RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::GENERATED, leftHandSideVariableName );
+
+ if ( !calculationCase->results( porosityModel )->ensureKnownResultLoaded( resAddr ) )
+ {
+ bool needsToBeStored = false;
+ calculationCase->results( porosityModel )->createResultEntry( resAddr, needsToBeStored );
+ }
+
+ calculationCase->results( porosityModel )->clearScalarResult( resAddr );
+
+ // If an input grid is present, max time step count is zero. Make sure the time step count for the calculation is
+ // always 1 or more.
+ const size_t timeStepCount = std::max( size_t( 1 ), calculationCase->results( porosityModel )->maxTimeStepCount() );
+
+ std::vector>* scalarResultFrames =
+ calculationCase->results( porosityModel )->modifiableCellScalarResultTimesteps( resAddr );
+ scalarResultFrames->resize( timeStepCount );
+
+ for ( size_t tsId = 0; tsId < timeStepCount; tsId++ )
+ {
+ // Skip time steps that are not in the list of time steps to calculate
+ if ( timeSteps && std::find( timeSteps->begin(), timeSteps->end(), tsId ) == timeSteps->end() ) continue;
+
+ std::vector> values;
+ for ( size_t i = 0; i < m_variables.size(); i++ )
+ {
+ RimGridCalculationVariable* v = dynamic_cast( m_variables[i] );
+ CAF_ASSERT( v != nullptr );
+ values.push_back( getInputVectorForVariable( v, tsId, porosityModel, calculationCase ) );
+ }
+
+ ExpressionParser parser;
+ for ( size_t i = 0; i < m_variables.size(); i++ )
+ {
+ RimGridCalculationVariable* v = dynamic_cast( m_variables[i] );
+ CAF_ASSERT( v != nullptr );
+ parser.assignVector( v->name(), values[i] );
+ }
+
+ std::vector resultValues;
+ resultValues.resize( values[0].size() );
+ parser.assignVector( leftHandSideVariableName, resultValues );
+
+ QString errorText;
+ bool evaluatedOk = parser.expandIfStatementsAndEvaluate( m_expression, &errorText );
+
+ if ( evaluatedOk )
+ {
+ if ( m_cellFilterView() )
+ {
+ filterResults( m_cellFilterView(), values, m_defaultValueType(), m_defaultValue(), resultValues, porosityModel, calculationCase );
+ }
+
+ scalarResultFrames->at( tsId ) = resultValues;
+
+ m_isDirty = false;
+ }
+ else
+ {
+ QString s = "The following error message was received from the parser library : \n\n";
+ s += errorText;
+
+ RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", s );
+ return false;
+ }
+
+ calculationCase->updateResultAddressCollection();
+ }
+
+ if ( isMultipleCasesPresent )
+ {
+ QString txt = " " + calculationCase->caseUserDescription();
+ RiaLogging::info( txt );
+ }
+
+ progressInfo.setProgress( progressIndex++ );
+ }
+
+ if ( isMultipleCasesPresent )
+ {
+ QString txt = "Completed calculation " + description() + " for " + QString::number( outputEclipseCases().size() ) + " cases";
+ RiaLogging::info( txt );
+ }
+
+ return !anyErrorsDetected;
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
diff --git a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h
index 9091ec359b..719b72d6fc 100644
--- a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h
+++ b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h
@@ -49,11 +49,13 @@ public:
bool preCalculate() const override;
bool calculate() override;
+
void updateDependentObjects() override;
void removeDependentObjects() override;
std::vector outputEclipseCases() const;
RigEclipseResultAddress outputAddress() const;
+ bool calculateForCases( const std::vector& calculationCases, std::optional> timeSteps );
std::vector inputCases() const;
diff --git a/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp b/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp
index e5f78b91c7..3a85a89e6d 100644
--- a/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp
+++ b/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp
@@ -94,6 +94,22 @@ std::vector RimGridCalculationCollection::sortedGridCalcula
return sortedCalculations;
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+std::vector RimGridCalculationCollection::dependentCalculations( RimGridCalculation* sourceCalculation ) const
+{
+ // Find all dependent grid calculations recursively. The ordering of calculations is least dependent first.
+
+ std::vector calculations;
+
+ if ( !dependentCalculationsRecursively( sourceCalculation, calculations ) ) return {};
+
+ std::reverse( calculations.begin(), calculations.end() );
+
+ return calculations;
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -102,6 +118,49 @@ void RimGridCalculationCollection::rebuildCaseMetaData()
ensureValidCalculationIds();
}
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+RimGridCalculation* RimGridCalculationCollection::findCalculation( const QString& calculationName ) const
+{
+ for ( auto userCalculation : calculations() )
+ {
+ auto gridCalculation = dynamic_cast( userCalculation );
+ if ( gridCalculation && gridCalculation->shortName() == calculationName ) return gridCalculation;
+ }
+
+ return nullptr;
+}
+
+//--------------------------------------------------------------------------------------------------
+///
+//--------------------------------------------------------------------------------------------------
+bool RimGridCalculationCollection::dependentCalculationsRecursively( RimGridCalculation* sourceCalculation,
+ std::vector& calculations ) const
+{
+ if ( std::find( calculations.begin(), calculations.end(), sourceCalculation ) != calculations.end() )
+ {
+ RiaLogging::error( "Detected circular dependency for " + sourceCalculation->description() );
+ return false;
+ }
+
+ calculations.push_back( sourceCalculation );
+
+ for ( auto v : sourceCalculation->allVariables() )
+ {
+ auto gridVariable = dynamic_cast( v );
+ if ( gridVariable->resultCategoryType() == RiaDefines::ResultCatType::GENERATED )
+ {
+ if ( auto other = findCalculation( gridVariable->resultVariable() ) )
+ {
+ if ( !dependentCalculationsRecursively( other, calculations ) ) return false;
+ }
+ }
+ }
+
+ return true;
+}
+
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
diff --git a/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.h b/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.h
index 03a767837a..bc57397e43 100644
--- a/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.h
+++ b/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.h
@@ -36,7 +36,11 @@ public:
RimGridCalculation* createCalculation() const override;
std::vector sortedGridCalculations() const;
+ std::vector dependentCalculations( RimGridCalculation* sourceCalculation ) const;
private:
+ RimGridCalculation* findCalculation( const QString& calculationName ) const;
+ bool dependentCalculationsRecursively( RimGridCalculation* sourceCalculation, std::vector& calculations ) const;
+
void initAfterRead() override;
};
diff --git a/ApplicationLibCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp b/ApplicationLibCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp
index 1f9065017e..6d95200da1 100644
--- a/ApplicationLibCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp
+++ b/ApplicationLibCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp
@@ -433,6 +433,7 @@ RimEclipseStatisticsCase* RimIdenticalGridCaseGroup::createStatisticsCase( bool
newStatisticsCase->openEclipseGridFile();
newStatisticsCase->eclipseCaseData()->computeActiveCellBoundingBoxes();
+ newStatisticsCase->selectAllTimeSteps();
return newStatisticsCase;
}
diff --git a/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp
index 94c44903c9..7db146a91d 100644
--- a/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp
+++ b/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp
@@ -699,23 +699,34 @@ void RigCaseCellResultsData::clearAllResults()
/// Removes all the actual numbers put into this object, and frees up the memory.
/// Does not touch the metadata in any way
//--------------------------------------------------------------------------------------------------
-void RigCaseCellResultsData::freeAllocatedResultsData()
+void RigCaseCellResultsData::freeAllocatedResultsData( std::vector categoriesToExclude,
+ std::optional timeStepIndexToRelease )
{
for ( size_t resultIdx = 0; resultIdx < m_cellScalarResults.size(); ++resultIdx )
{
- if ( resultIdx < m_resultInfos.size() &&
- m_resultInfos[resultIdx].eclipseResultAddress().resultCatType() == RiaDefines::ResultCatType::GENERATED )
+ if ( resultIdx < m_resultInfos.size() )
{
- // Not possible to recreate generated results, keep them
- continue;
+ auto resultCategory = m_resultInfos[resultIdx].eclipseResultAddress().resultCatType();
+ if ( std::find( categoriesToExclude.begin(), categoriesToExclude.end(), resultCategory ) != categoriesToExclude.end() )
+ {
+ // Keep generated results for these categories
+ continue;
+ }
}
- for ( auto& tsIdx : m_cellScalarResults[resultIdx] )
+ for ( size_t index = 0; index < m_cellScalarResults[resultIdx].size(); index++ )
{
+ if ( timeStepIndexToRelease && index != *timeStepIndexToRelease )
+ {
+ // Keep generated results for these time steps
+ continue;
+ }
+
+ auto& dataForTimeStep = m_cellScalarResults[resultIdx][index];
// Using swap with an empty vector as that is the safest way to really get rid of the allocated data in a
// vector
std::vector empty;
- tsIdx.swap( empty );
+ dataForTimeStep.swap( empty );
}
}
}
diff --git a/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.h b/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.h
index c6ac4577c9..4165204a09 100644
--- a/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.h
+++ b/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.h
@@ -29,6 +29,7 @@
#include
#include