mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
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:
parent
92d1bd9386
commit
39fc9d5c36
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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() )
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -433,6 +433,7 @@ RimEclipseStatisticsCase* RimIdenticalGridCaseGroup::createStatisticsCase( bool
|
||||
|
||||
newStatisticsCase->openEclipseGridFile();
|
||||
newStatisticsCase->eclipseCaseData()->computeActiveCellBoundingBoxes();
|
||||
newStatisticsCase->selectAllTimeSteps();
|
||||
|
||||
return newStatisticsCase;
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user