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
This commit is contained in:
Magne Sjaastad 2023-11-07 19:23:12 +01:00
parent 92d1bd9386
commit 39fc9d5c36
12 changed files with 565 additions and 282 deletions

View File

@ -285,16 +285,18 @@ void RicCreateTemporaryLgrFeature::deleteAllCachedData( RimEclipseCase* eclipseC
{
if ( eclipseCase )
{
std::vector<RiaDefines::ResultCatType> 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();

View File

@ -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<RimEclipseStatisticsCase::PercentileCalcType>::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<RimEclipseStatisticsCase::DataSourceType>::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<int> allTimeSteps;
allTimeSteps.resize( timeStepCount );
std::iota( allTimeSteps.begin(), allTimeSteps.end(), 0 );
m_selectedTimeSteps = allTimeSteps;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -256,15 +300,32 @@ void RimEclipseStatisticsCase::computeStatistics()
std::vector<RimEclipseCase*> 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<size_t> 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<size_t> 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<RimEclipseStatisticsCaseEvaluator::ResSpec> 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<caf::PdmOptionItemInfo> toOptionList( const QStringList& varList )
@ -468,16 +567,63 @@ QList<caf::PdmOptionItemInfo> toOptionList( const QStringList& varList )
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimEclipseStatisticsCase::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
RimIdenticalGridCaseGroup* idgcg = caseGroup();
if ( !( caseGroup() && caseGroup()->mainCase() && caseGroup()->mainCase()->eclipseCaseData() ) )
{
return {};
}
if ( &m_dataSourceForStatistics == fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
{
caf::IconProvider iconProvider( ":/Case48x48.png" );
options.push_back( caf::PdmOptionItemInfo( caf::AppEnum<DataSourceType>::uiText( DataSourceType::CASE_PROPERTY ),
DataSourceType::CASE_PROPERTY,
false,
iconProvider ) );
}
{
caf::IconProvider iconProvider( ":/Calculator.svg" );
options.push_back( caf::PdmOptionItemInfo( caf::AppEnum<DataSourceType>::uiText( DataSourceType::GRID_CALCULATION ),
DataSourceType::GRID_CALCULATION,
false,
iconProvider ) );
}
return options;
}
if ( &m_gridCalculation == fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> 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<caf::PdmOptionItemInfo> 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<caf::PdmOptionItemInfo> 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 += "</p>";
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 += "<p><b>Grid calculation:</b></p>";
html += "<p class=indent>";
html += m_gridCalculation()->shortName();
html += "</p>";
}
m_selectionSummary = html;
}
@ -699,6 +854,17 @@ void RimEclipseStatisticsCase::defineEditorAttribute( const caf::PdmFieldHandle*
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseStatisticsCase::initializeSelectedTimeSteps()
{
if ( RimProject::current()->isProjectFileVersionEqualOrOlderThan( "2023.10.0" ) )
{
selectAllTimeSteps();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -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<bool> m_calculateEditCommand;
void populateResultSelectionAfterLoadingGrid();
void setSourceProperties( RiaDefines::ResultCatType propertyType, const std::vector<QString>& 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<caf::AppEnum<DataSourceType>> m_dataSourceForStatistics;
caf::PdmPtrField<RimGridCalculation*> m_gridCalculation;
caf::PdmField<bool> m_clearGridCalculationMemory;
caf::PdmField<std::vector<int>> m_selectedTimeSteps;
caf::PdmField<caf::AppEnum<RiaDefines::ResultCatType>> m_resultType;
caf::PdmField<caf::AppEnum<RiaDefines::PorosityModelType>> m_porosityModel;

View File

@ -116,23 +116,23 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList<ResSpec>
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<size_t>( 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<ResSpec>
// Build data access objects for source scalar results
cvf::Collection<RigResultAccessor> 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<ResSpec>
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<RigResultModifier> resultModifier =
RigResultModifierFactory::createResultModifier( m_destinationCase,
grid->gridIndex(),
poroModel,
dataAccessTimeStepIndex,
RigEclipseResultAddress( resultType, statisticalResultNames[stIdx] ) );
RigEclipseResultAddress( resultType, statisticalResultName ) );
destinationDataAccessList.push_back( resultModifier.p() );
}
std::vector<double> statParams( STAT_PARAM_COUNT, HUGE_VAL );
std::vector<double> values( sourceDataAccessList.size(), HUGE_VAL );
int cellCount = static_cast<int>( grid->cellCount() );
auto cellCount = static_cast<int>( 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<ResSpec>
// 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<double> pValPoss;
pValPoss.push_back( m_statisticsConfig.m_pMinPos );
@ -259,7 +257,7 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList<ResSpec>
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<size_t> histogram;
RigHistogramCalculator histCalc( statParams[MIN], statParams[MAX], 100, &histogram );
@ -271,7 +269,8 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList<ResSpec>
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<double> pValPoss;
pValPoss.push_back( m_statisticsConfig.m_pMinPos );
@ -310,14 +309,15 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList<ResSpec>
// 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<RiaDefines::ResultCatType> 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<ResSpec>
//--------------------------------------------------------------------------------------------------
void RimEclipseStatisticsCaseEvaluator::addNamedResults( const QList<ResSpec>& 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<ResSpec>& 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<ResSpec>& r
///
//--------------------------------------------------------------------------------------------------
RimEclipseStatisticsCaseEvaluator::RimEclipseStatisticsCaseEvaluator( const std::vector<RimEclipseCase*>& sourceCases,
const std::vector<size_t>& timeStepIndices,
const std::vector<int>& 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() )
{

View File

@ -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<RimEclipseCase*>& sourceCases,
const std::vector<size_t>& timeStepIndices,
const std::vector<int>& timeStepIndices,
const RimStatisticsConfig& statisticsConfig,
RigEclipseCaseData* destinationCase,
RimIdenticalGridCaseGroup* identicalGridCaseGroup );
RimIdenticalGridCaseGroup* identicalGridCaseGroup,
bool clearGridCalculationMemory );
struct ResSpec
{
@ -105,11 +106,12 @@ private:
private:
std::vector<RimEclipseCase*> m_sourceCases;
std::vector<size_t> m_timeStepIndices;
std::vector<int> m_timeStepIndices;
size_t m_reservoirCellCount;
RimStatisticsConfig m_statisticsConfig;
RigEclipseCaseData* m_destinationCase;
RimIdenticalGridCaseGroup* m_identicalGridCaseGroup;
bool m_useZeroAsInactiveCellValue;
bool m_clearGridCalculationMemory;
};

View File

@ -44,6 +44,8 @@
#include "expressionparser/ExpressionParser.h"
#include "cafProgressInfo.h"
#include <QMessageBox>
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<std::vector<double>>* scalarResultFrames =
outputEclipseCase->results( porosityModel )->modifiableCellScalarResultTimesteps( resAddr );
scalarResultFrames->resize( timeStepCount );
for ( size_t tsId = 0; tsId < timeStepCount; tsId++ )
{
std::vector<std::vector<double>> values;
for ( size_t i = 0; i < m_variables.size(); i++ )
{
RimGridCalculationVariable* v = dynamic_cast<RimGridCalculationVariable*>( 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<RimGridCalculationVariable*>( m_variables[i] );
CAF_ASSERT( v != nullptr );
parser.assignVector( v->name(), values[i] );
}
std::vector<double> 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<RimEclipseCase*>& calculationCases, std::optional<std::vector<size_t>> 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<std::vector<double>>* 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<std::vector<double>> values;
for ( size_t i = 0; i < m_variables.size(); i++ )
{
RimGridCalculationVariable* v = dynamic_cast<RimGridCalculationVariable*>( 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<RimGridCalculationVariable*>( m_variables[i] );
CAF_ASSERT( v != nullptr );
parser.assignVector( v->name(), values[i] );
}
std::vector<double> 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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -49,11 +49,13 @@ public:
bool preCalculate() const override;
bool calculate() override;
void updateDependentObjects() override;
void removeDependentObjects() override;
std::vector<RimEclipseCase*> outputEclipseCases() const;
RigEclipseResultAddress outputAddress() const;
bool calculateForCases( const std::vector<RimEclipseCase*>& calculationCases, std::optional<std::vector<size_t>> timeSteps );
std::vector<RimEclipseCase*> inputCases() const;

View File

@ -94,6 +94,22 @@ std::vector<RimGridCalculation*> RimGridCalculationCollection::sortedGridCalcula
return sortedCalculations;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimGridCalculation*> RimGridCalculationCollection::dependentCalculations( RimGridCalculation* sourceCalculation ) const
{
// Find all dependent grid calculations recursively. The ordering of calculations is least dependent first.
std::vector<RimGridCalculation*> 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<RimGridCalculation*>( userCalculation );
if ( gridCalculation && gridCalculation->shortName() == calculationName ) return gridCalculation;
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGridCalculationCollection::dependentCalculationsRecursively( RimGridCalculation* sourceCalculation,
std::vector<RimGridCalculation*>& 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<RimGridCalculationVariable*>( v );
if ( gridVariable->resultCategoryType() == RiaDefines::ResultCatType::GENERATED )
{
if ( auto other = findCalculation( gridVariable->resultVariable() ) )
{
if ( !dependentCalculationsRecursively( other, calculations ) ) return false;
}
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -36,7 +36,11 @@ public:
RimGridCalculation* createCalculation() const override;
std::vector<RimGridCalculation*> sortedGridCalculations() const;
std::vector<RimGridCalculation*> dependentCalculations( RimGridCalculation* sourceCalculation ) const;
private:
RimGridCalculation* findCalculation( const QString& calculationName ) const;
bool dependentCalculationsRecursively( RimGridCalculation* sourceCalculation, std::vector<RimGridCalculation*>& calculations ) const;
void initAfterRead() override;
};

View File

@ -433,6 +433,7 @@ RimEclipseStatisticsCase* RimIdenticalGridCaseGroup::createStatisticsCase( bool
newStatisticsCase->openEclipseGridFile();
newStatisticsCase->eclipseCaseData()->computeActiveCellBoundingBoxes();
newStatisticsCase->selectAllTimeSteps();
return newStatisticsCase;
}

View File

@ -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<RiaDefines::ResultCatType> categoriesToExclude,
std::optional<size_t> 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<double> empty;
tsIdx.swap( empty );
dataForTimeStep.swap( empty );
}
}
}

View File

@ -29,6 +29,7 @@
#include <cmath>
#include <map>
#include <optional>
#include <vector>
class RifReaderInterface;
@ -116,7 +117,7 @@ public:
void clearScalarResult( RiaDefines::ResultCatType type, const QString& resultName );
void clearScalarResult( const RigEclipseResultAddress& resultAddress );
void clearAllResults();
void freeAllocatedResultsData();
void freeAllocatedResultsData( std::vector<RiaDefines::ResultCatType> categoriesToExclude, std::optional<size_t> timeStepIndexToRelease );
void eraseAllSourSimData();
void setRemovedTagOnGeneratedResult( const RigEclipseResultAddress& resultAddress );