#5706 Make Analysis plot filtering start working

This commit is contained in:
Jacob Støren
2020-03-24 16:29:38 +01:00
parent f18fa26e32
commit 94fadb7540
4 changed files with 754 additions and 172 deletions

View File

@@ -308,9 +308,8 @@ void RimAnalysisPlot::maxMinValueFromAddress( const RifEclipseSummaryAddress&
double* minVal,
double* maxVal )
{
std::vector<time_t> selectedTimesteps;
double min = std::numeric_limits<double>::infinity();
double max = useAbsValue ? 0.0 : -std::numeric_limits<double>::infinity();
double min = std::numeric_limits<double>::infinity();
double max = useAbsValue ? 0.0 : -std::numeric_limits<double>::infinity();
std::function<double( double, double )> minOrAbsMin;
std::function<double( double, double )> maxOrAbsMax;
@@ -326,6 +325,7 @@ void RimAnalysisPlot::maxMinValueFromAddress( const RifEclipseSummaryAddress&
maxOrAbsMax = []( double v1, double v2 ) { return std::max( v1, v2 ); };
}
std::vector<time_t> selectedTimesteps;
if ( timeStepSourceType == RimPlotDataFilterItem::SELECT_TIMESTEPS )
{
for ( const QDateTime& dateTime : timeRangeOrSelection )
@@ -335,10 +335,7 @@ void RimAnalysisPlot::maxMinValueFromAddress( const RifEclipseSummaryAddress&
}
else if ( timeStepSourceType == RimPlotDataFilterItem::PLOT_SOURCE_TIMESTEPS )
{
for ( const QDateTime& dateTime : m_selectedTimeSteps.v() )
{
selectedTimesteps.push_back( dateTime.toTime_t() );
}
selectedTimesteps = selectedTimeSteps();
}
std::set<RimSummaryCase*> allSumCases = allSourceCases();
@@ -355,7 +352,7 @@ void RimAnalysisPlot::maxMinValueFromAddress( const RifEclipseSummaryAddress&
const std::vector<time_t>& timesteps = reader->timeSteps( address );
if ( timesteps.size() )
if ( timesteps.size() && values.size() )
{
if ( timeStepSourceType == RimPlotDataFilterItem::LAST_TIMESTEP )
{
@@ -409,21 +406,10 @@ void RimAnalysisPlot::maxMinValueFromAddress( const RifEclipseSummaryAddress&
}
else if ( selectedTimesteps.size() )
{
std::vector<int> selectedTimestepIndices;
std::vector<size_t> selectedTimestepIndices =
RimAnalysisPlot::findTimestepIndices( selectedTimesteps, timesteps );
for ( time_t tt : selectedTimesteps )
{
for ( int timestepIdx = 0; static_cast<unsigned>( timestepIdx ) < timesteps.size(); ++timestepIdx )
{
if ( timesteps[timestepIdx] == tt )
{
selectedTimestepIndices.push_back( timestepIdx );
break;
}
}
}
for ( int tsIdx : selectedTimestepIndices )
for ( size_t tsIdx : selectedTimestepIndices )
{
min = minOrAbsMin( min, values[tsIdx] );
max = maxOrAbsMax( max, values[tsIdx] );
@@ -442,6 +428,21 @@ void RimAnalysisPlot::maxMinValueFromAddress( const RifEclipseSummaryAddress&
//--------------------------------------------------------------------------------------------------
void RimAnalysisPlot::onFiltersChanged()
{
this->loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<time_t> RimAnalysisPlot::selectedTimeSteps()
{
std::vector<time_t> selectedTimeTTimeSteps;
for ( const QDateTime& dateTime : m_selectedTimeSteps.v() )
{
selectedTimeTTimeSteps.push_back( dateTime.toTime_t() );
}
return selectedTimeTTimeSteps;
}
//--------------------------------------------------------------------------------------------------
@@ -461,7 +462,7 @@ void RimAnalysisPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
dlg.enableMultiSelect( true );
dlg.enableIndividualEnsembleCaseSelection( true );
dlg.setCurveSelection( this->curveDefinitions() );
dlg.setCurveSelection( this->curveDefinitionsWithCollapsedEnsembleCurves() );
dlg.setCaseAndAddress( nullptr, RifEclipseSummaryAddress() );
if ( dlg.exec() == QDialog::Accepted )
@@ -595,8 +596,8 @@ QList<caf::PdmOptionItemInfo> RimAnalysisPlot::calculateValueOptions( const caf:
if ( !m_analyserOfSelectedCurveDefs )
{
m_analyserOfSelectedCurveDefs =
std::unique_ptr<RimCurveDefinitionAnalyser>( new RimCurveDefinitionAnalyser( this->curveDefinitions() ) );
m_analyserOfSelectedCurveDefs = std::unique_ptr<RimCurveDefinitionAnalyser>(
new RimCurveDefinitionAnalyser( this->curveDefinitionsWithCollapsedEnsembleCurves() ) );
}
if ( fieldNeedingOptions == &m_addTimestepUiField )
@@ -729,8 +730,8 @@ void RimAnalysisPlot::onLoadDataAndUpdate()
{
updateMdiWindowVisibility();
m_analyserOfSelectedCurveDefs =
std::unique_ptr<RimCurveDefinitionAnalyser>( new RimCurveDefinitionAnalyser( this->curveDefinitions() ) );
m_analyserOfSelectedCurveDefs = std::unique_ptr<RimCurveDefinitionAnalyser>(
new RimCurveDefinitionAnalyser( this->curveDefinitionsWithCollapsedEnsembleCurves() ) );
if ( m_plotWidget )
{
@@ -884,7 +885,7 @@ void RimAnalysisPlot::updateAxes()
std::set<QString> timeHistoryQuantities;
RimSummaryPlotAxisFormatter calc( valAxisProperties, {}, curveDefinitions(), {}, {} );
RimSummaryPlotAxisFormatter calc( valAxisProperties, {}, curveDefinitionsWithCollapsedEnsembleCurves(), {}, {} );
calc.applyAxisPropertiesToPlot( m_plotWidget );
}
else
@@ -1004,6 +1005,430 @@ QString assignGroupingText( RimAnalysisPlot::SortGroupType sortGroup,
return groupingText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<size_t> RimAnalysisPlot::findTimestepIndices( std::vector<time_t> selectedTimesteps,
const std::vector<time_t>& timesteps )
{
std::vector<size_t> selectedTimestepIndices;
for ( time_t tt : selectedTimesteps )
{
for ( size_t timestepIdx = 0; timestepIdx < timesteps.size(); ++timestepIdx )
{
if ( timesteps[timestepIdx] == tt )
{
selectedTimestepIndices.push_back( timestepIdx );
break;
}
}
}
return selectedTimestepIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaSummaryCurveDefinition> RimAnalysisPlot::filteredCurveDefs()
{
std::vector<RiaSummaryCurveDefinition> dataDefinitions = curveDefinitionsWitExpandedEnsembleCurves();
// Split out the filter targets
std::set<RimSummaryCase*> filteredSumCases;
std::set<RifEclipseSummaryAddress> filteredSummaryItems; // Stores only the unique summary items
for ( const auto& curveDef : dataDefinitions )
{
filteredSumCases.insert( curveDef.summaryCase() );
RifEclipseSummaryAddress address = curveDef.summaryAddress();
address.setQuantityName( "" ); // Quantity name set to "" in order to store only unique summary items
filteredSummaryItems.insert( address );
}
std::vector<RimPlotDataFilterItem*> filters = m_plotDataFilterCollection->filters();
for ( RimPlotDataFilterItem* filter : filters )
{
applyFilter( filter, &filteredSumCases, &filteredSummaryItems );
}
// Remove all
std::vector<RiaSummaryCurveDefinition> filteredDataDefinitions;
for ( const RiaSummaryCurveDefinition& curveDefCandidate : dataDefinitions )
{
RimSummaryCase* sumCase = curveDefCandidate.summaryCase();
RifEclipseSummaryAddress addr = curveDefCandidate.summaryAddress();
addr.setQuantityName( "" );
if ( filteredSumCases.count( sumCase ) && filteredSummaryItems.count( addr ) )
{
filteredDataDefinitions.push_back( curveDefCandidate );
}
}
return filteredDataDefinitions;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimAnalysisPlot::applyFilter( const RimPlotDataFilterItem* filter,
std::set<RimSummaryCase*>* filteredSumCases,
std::set<RifEclipseSummaryAddress>* filteredSummaryItems )
{
const std::vector<RiaSummaryCurveDefinition> curveDefsToFilter;
if ( !filter->isActive() ) return;
std::vector<RiaSummaryCurveDefinition> filteredCurveDefs;
std::set<RimSummaryCase*> casesToKeep;
std::set<RifEclipseSummaryAddress> sumItemsToKeep;
std::map<RimSummaryCase*, double> casesToKeepWithValue;
std::map<RifEclipseSummaryAddress, double> sumItemsToKeepWithValue;
if ( filter->filterTarget() == RimPlotDataFilterItem::ENSEMBLE_CASE )
{
sumItemsToKeep = ( *filteredSummaryItems ); // Not filtering items
EnsembleParameter eParam = this->ensembleParameter( filter->ensembleParameterName() );
std::set<RimSummaryCase*> casesToRemove;
for ( auto sumCase : ( *filteredSumCases ) )
{
if ( !eParam.isValid() ) continue;
if ( !sumCase->caseRealizationParameters() ) continue;
RigCaseRealizationParameters::Value crpValue =
sumCase->caseRealizationParameters()->parameterValue( filter->ensembleParameterName() );
if ( eParam.isNumeric() && crpValue.isNumeric() )
{
double value = crpValue.numericValue();
if ( filter->filterOperation() == RimPlotDataFilterItem::RANGE )
{
std::pair<double, double> minMax = filter->filterRangeMinMax();
if ( filter->useAbsoluteValues() ) value = fabs( value );
if ( minMax.first < value && value < minMax.second )
{
casesToKeep.insert( sumCase );
}
}
else if ( filter->filterOperation() == RimPlotDataFilterItem::TOP_N ||
filter->filterOperation() == RimPlotDataFilterItem::BOTTOM_N )
{
if ( filter->useAbsoluteValues() ) value = fabs( value );
bool useLargest = filter->filterOperation() == RimPlotDataFilterItem::TOP_N;
auto itIsInsertedPair = casesToKeepWithValue.insert( {sumCase, value} );
if ( !itIsInsertedPair.second ) // Already exists in map
{
double& insertedValue = itIsInsertedPair.first->second;
if ( ( useLargest && ( insertedValue < value ) ) || ( !useLargest && ( value < insertedValue ) ) )
{
insertedValue = value;
}
}
}
}
else if ( eParam.isText() && crpValue.isText() )
{
const auto& filterCategories = filter->selectedEnsembleParameterCategories();
if ( crpValue.isText() &&
std::count( filterCategories.begin(), filterCategories.end(), crpValue.textValue() ) == 0 )
{
casesToKeep.insert( sumCase );
}
}
}
}
else
{
std::vector<time_t> selectedTimesteps;
if ( filter->consideredTimeStepsType() == RimPlotDataFilterItem::SELECT_TIMESTEPS )
{
selectedTimesteps = filter->explicitlySelectedTimeSteps();
}
else if ( filter->consideredTimeStepsType() == RimPlotDataFilterItem::PLOT_SOURCE_TIMESTEPS )
{
selectedTimesteps = this->selectedTimeSteps();
}
std::function<void( double )> storeResultCoreLambda;
RimSummaryCase* sumCaseInEvaluation = nullptr;
// clang-format off
std::function<void( RifEclipseSummaryAddress )> evaluateFilterForAllCases =
[&]( RifEclipseSummaryAddress addrToFilterValue ) // clang-format on
{
for ( auto sumCase : *filteredSumCases )
{
sumCaseInEvaluation = sumCase;
RifSummaryReaderInterface* reader = sumCase->summaryReader();
if ( !reader ) continue;
if ( reader->hasAddress( addrToFilterValue ) )
{
std::vector<double> values;
reader->values( addrToFilterValue, &values );
const std::vector<time_t>& timesteps = reader->timeSteps( addrToFilterValue );
if ( filter->consideredTimeStepsType() == RimPlotDataFilterItem::ALL_TIMESTEPS )
{
for ( int tIdx = 0; tIdx < timesteps.size(); ++tIdx )
{
double value = values[tIdx];
storeResultCoreLambda( value );
}
}
else if ( timesteps.size() )
{
std::vector<size_t> selectedTimestepIndices;
if ( filter->consideredTimeStepsType() == RimPlotDataFilterItem::FIRST_TIMESTEP )
{
selectedTimestepIndices.push_back( 0 );
}
else if ( filter->consideredTimeStepsType() == RimPlotDataFilterItem::LAST_TIMESTEP )
{
size_t timeStepIdx = timesteps.size() - 1;
selectedTimestepIndices.push_back( timeStepIdx );
}
else if ( selectedTimesteps.size() )
{
selectedTimestepIndices = RimAnalysisPlot::findTimestepIndices( selectedTimesteps, timesteps );
}
else if ( filter->consideredTimeStepsType() == RimPlotDataFilterItem::LAST_TIMESTEP_WITH_HISTORY )
{
RifEclipseSummaryAddress historyAddr = addrToFilterValue;
if ( !historyAddr.isHistoryQuantity() )
historyAddr.setQuantityName( addrToFilterValue.quantityName() + "H" );
const std::vector<time_t>& historyTimesteps = reader->timeSteps( historyAddr );
if ( historyTimesteps.size() )
{
selectedTimestepIndices =
RimAnalysisPlot::findTimestepIndices( {historyTimesteps.back()}, timesteps );
}
}
else if ( filter->consideredTimeStepsType() == RimPlotDataFilterItem::SELECT_TIMESTEP_RANGE )
{
std::pair<time_t, time_t> timeMinMax = filter->timeRangeMinMax();
for ( size_t tIdx = 0; tIdx < timesteps.size(); ++tIdx )
{
time_t dateTime = timesteps[tIdx];
if ( timeMinMax.first <= dateTime && dateTime <= timeMinMax.second )
{
selectedTimestepIndices.push_back( tIdx );
}
}
}
for ( size_t timeStepIdx : selectedTimestepIndices )
{
double value = values[timeStepIdx];
storeResultCoreLambda( value );
}
}
}
}
};
if ( filter->filterTarget() == RimPlotDataFilterItem::SUMMARY_CASE )
{
sumItemsToKeep = ( *filteredSummaryItems ); // Not filtering items
RifEclipseSummaryAddress addrToFilterValue = filter->summaryAddress();
if ( filter->filterOperation() == RimPlotDataFilterItem::RANGE )
{
std::pair<double, double> minMax = filter->filterRangeMinMax();
// clang-format off
storeResultCoreLambda = [&]( double value ) // clang-format on
{
if ( filter->useAbsoluteValues() ) value = fabs( value );
if ( minMax.first <= value && value <= minMax.second )
{
casesToKeep.insert( sumCaseInEvaluation );
}
};
}
else if ( filter->filterOperation() == RimPlotDataFilterItem::TOP_N ||
filter->filterOperation() == RimPlotDataFilterItem::BOTTOM_N )
{
// clang-format off
storeResultCoreLambda = [&]( double value ) // clang-format on
{
if ( filter->useAbsoluteValues() ) value = fabs( value );
bool useLargest = filter->filterOperation() == RimPlotDataFilterItem::TOP_N;
auto itIsInsertedPair = casesToKeepWithValue.insert( {sumCaseInEvaluation, value} );
if ( !itIsInsertedPair.second ) // Already exists in map
{
double& insertedValue = itIsInsertedPair.first->second;
if ( ( useLargest && ( insertedValue < value ) ) || ( !useLargest && ( value < insertedValue ) ) )
{
insertedValue = value;
}
}
};
}
evaluateFilterForAllCases( addrToFilterValue );
}
else if ( filter->filterTarget() == RimPlotDataFilterItem::SUMMARY_ITEM )
{
casesToKeep = ( *filteredSumCases ); // Not filtering cases
std::string quantityName;
{
RifEclipseSummaryAddress addrToFilterValue = filter->summaryAddress();
quantityName = addrToFilterValue.quantityName();
}
for ( auto sumItem : *filteredSummaryItems )
{
RifEclipseSummaryAddress addrToFilterValue = sumItem;
addrToFilterValue.setQuantityName( quantityName );
if ( filter->filterOperation() == RimPlotDataFilterItem::RANGE )
{
std::pair<double, double> minMax = filter->filterRangeMinMax();
// clang-format off
storeResultCoreLambda = [&]( double value ) // clang-format on
{
if ( filter->useAbsoluteValues() ) value = fabs( value );
if ( minMax.first <= value && value <= minMax.second )
{
sumItemsToKeep.insert( sumItem );
}
};
}
else if ( filter->filterOperation() == RimPlotDataFilterItem::TOP_N ||
filter->filterOperation() == RimPlotDataFilterItem::BOTTOM_N )
{
// clang-format off
storeResultCoreLambda = [&]( double value ) // clang-format on
{
if ( filter->useAbsoluteValues() ) value = fabs( value );
bool useLargest = filter->filterOperation() == RimPlotDataFilterItem::TOP_N;
auto itIsInsertedPair = sumItemsToKeepWithValue.insert( {sumItem, value} );
if ( !itIsInsertedPair.second ) // Already exists in map
{
double& insertedValue = itIsInsertedPair.first->second;
if ( ( useLargest && ( insertedValue < value ) ) ||
( !useLargest && ( value < insertedValue ) ) )
{
insertedValue = value;
}
}
};
}
evaluateFilterForAllCases( addrToFilterValue );
}
}
}
// Handle top/bottom n filter
if ( filter->filterOperation() == RimPlotDataFilterItem::TOP_N ||
filter->filterOperation() == RimPlotDataFilterItem::BOTTOM_N )
{
if ( filter->filterTarget() == RimPlotDataFilterItem::SUMMARY_ITEM )
{
std::multimap<double, RifEclipseSummaryAddress> valueSortedSumItems;
for ( const auto& itemValPair : sumItemsToKeepWithValue )
{
valueSortedSumItems.insert( {itemValPair.second, itemValPair.first} );
}
if ( filter->filterOperation() == RimPlotDataFilterItem::TOP_N )
{
size_t count = 0;
for ( auto it = valueSortedSumItems.rbegin();
count < filter->topBottomN() && it != valueSortedSumItems.rend();
++it )
{
sumItemsToKeep.insert( it->second );
++count;
}
}
else if ( filter->filterOperation() == RimPlotDataFilterItem::BOTTOM_N )
{
size_t count = 0;
for ( auto it = valueSortedSumItems.begin();
count < filter->topBottomN() && it != valueSortedSumItems.end();
++it )
{
sumItemsToKeep.insert( it->second );
++count;
}
}
}
else
{
std::multimap<double, RimSummaryCase*> valueSortedSumCases;
for ( const auto& caseValPair : casesToKeepWithValue )
{
valueSortedSumCases.insert( {caseValPair.second, caseValPair.first} );
}
if ( filter->filterOperation() == RimPlotDataFilterItem::TOP_N )
{
size_t count = 0;
for ( auto it = valueSortedSumCases.rbegin();
count < filter->topBottomN() && it != valueSortedSumCases.rend();
++it )
{
casesToKeep.insert( it->second );
++count;
}
}
else if ( filter->filterOperation() == RimPlotDataFilterItem::BOTTOM_N )
{
size_t count = 0;
for ( auto it = valueSortedSumCases.begin();
count < filter->topBottomN() && it != valueSortedSumCases.end();
++it )
{
casesToKeep.insert( it->second );
++count;
}
}
}
}
( *filteredSumCases ) = casesToKeep;
( *filteredSummaryItems ) = sumItemsToKeep;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1019,147 +1444,121 @@ void RimAnalysisPlot::addDataToChartBuilder( RiuGroupedBarChartBuilder& chartBui
if ( m_referenceCase ) referenceCaseReader = m_referenceCase->summaryReader();
for ( const RimAnalysisPlotDataEntry* dataEntry : m_analysisPlotDataSelection )
// Unpack ensemble curves and make one curve definition for each individual curve.
// Store both ensemble and summary case in the definition
std::vector<RiaSummaryCurveDefinition> barDataDefinitions = filteredCurveDefs();
for ( const RiaSummaryCurveDefinition& curveDef : barDataDefinitions )
{
RiaSummaryCurveDefinition orgBarDataEntry = dataEntry->curveDefinition();
RifSummaryReaderInterface* reader = curveDef.summaryCase()->summaryReader();
// Unpack ensemble curves and make one curve definition for each individual curve.
// Store both ensemble and summary case in the definition
if ( !reader ) continue;
std::vector<RiaSummaryCurveDefinition> barDataDefinitions;
// Todo:
// If curveDef.summaryCase() is a RimGridSummaryCase and we are using summary item as legend and the summary
// items are wells, then:
/// use color from eclCase->defaultWellColor( wellName );
if ( orgBarDataEntry.isEnsembleCurve() )
std::vector<time_t> timeStepStorage;
const std::vector<time_t>* timeStepsPtr = &timeStepStorage;
std::vector<double> values;
if ( referenceCaseReader )
{
std::vector<RimSummaryCase*> sumCases = orgBarDataEntry.ensemble()->allSummaryCases();
for ( auto sumCase : sumCases )
{
barDataDefinitions.push_back(
RiaSummaryCurveDefinition( sumCase, orgBarDataEntry.summaryAddress(), orgBarDataEntry.ensemble() ) );
}
std::pair<std::vector<time_t>, std::vector<double>> timeAndValues =
RimDerivedSummaryCase::calculateDerivedValues( reader,
referenceCaseReader,
DerivedSummaryOperator::DERIVED_OPERATOR_SUB,
curveDef.summaryAddress() );
timeStepStorage.swap( timeAndValues.first );
values.swap( timeAndValues.second );
}
else
{
if ( orgBarDataEntry.summaryCase() && orgBarDataEntry.summaryCase()->ensemble() )
timeStepsPtr = &( reader->timeSteps( curveDef.summaryAddress() ) );
reader->values( curveDef.summaryAddress(), &values );
}
const std::vector<time_t>& timesteps = *timeStepsPtr;
if ( !( timesteps.size() && values.size() ) ) continue;
// Find selected timestep indices
std::vector<int> selectedTimestepIndices;
for ( time_t tt : selectedTimesteps )
{
for ( int timestepIdx = 0; static_cast<unsigned>( timestepIdx ) < timesteps.size(); ++timestepIdx )
{
barDataDefinitions.push_back( RiaSummaryCurveDefinition( orgBarDataEntry.summaryCase(),
orgBarDataEntry.summaryAddress(),
orgBarDataEntry.summaryCase()->ensemble() ) );
}
else
{
barDataDefinitions.push_back( orgBarDataEntry );
if ( timesteps[timestepIdx] == tt )
{
selectedTimestepIndices.push_back( timestepIdx );
break;
}
}
}
for ( const RiaSummaryCurveDefinition& curveDef : barDataDefinitions )
for ( int timestepIdx : selectedTimestepIndices )
{
RifSummaryReaderInterface* reader = curveDef.summaryCase()->summaryReader();
double sortValue = std::numeric_limits<double>::infinity();
if ( !reader ) continue;
QDateTime dateTime = RiaQDateTimeTools::fromTime_t( timesteps[timestepIdx] );
QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates( {dateTime} );
// Todo:
// If curveDef.summaryCase() is a RimGridSummaryCase and we are using summary item as legend and the summary
// items are wells, then:
/// use color from eclCase->defaultWellColor( wellName );
QString timestepString = dateTime.toString( formatString );
std::vector<time_t> timeStepStorage;
const std::vector<time_t>* timeStepsPtr = &timeStepStorage;
std::vector<double> values;
QString majorText = assignGroupingText( m_majorGroupType(), curveDef, timestepString );
QString medText = assignGroupingText( m_mediumGroupType(), curveDef, timestepString );
QString minText = assignGroupingText( m_minorGroupType(), curveDef, timestepString );
QString legendText = assignGroupingText( m_sortGroupForLegend(), curveDef, timestepString );
if ( referenceCaseReader )
double value = values[timestepIdx];
switch ( m_valueSortOperation() )
{
std::pair<std::vector<time_t>, std::vector<double>> timeAndValues =
RimDerivedSummaryCase::calculateDerivedValues( reader,
referenceCaseReader,
DerivedSummaryOperator::DERIVED_OPERATOR_SUB,
curveDef.summaryAddress() );
timeStepStorage.swap( timeAndValues.first );
values.swap( timeAndValues.second );
}
else
{
timeStepsPtr = &( reader->timeSteps( curveDef.summaryAddress() ) );
reader->values( curveDef.summaryAddress(), &values );
case VALUE:
sortValue = value;
break;
case ABS_VALUE:
sortValue = fabs( value );
break;
}
const std::vector<time_t>& timesteps = *timeStepsPtr;
QString barText;
QString separator = " ";
// Find selected timestep indices
std::vector<int> selectedTimestepIndices;
for ( time_t tt : selectedTimesteps )
if ( m_useBarText() )
{
for ( int timestepIdx = 0; static_cast<unsigned>( timestepIdx ) < timesteps.size(); ++timestepIdx )
if ( m_useQuantityInBarText )
{
if ( timesteps[timestepIdx] == tt )
{
selectedTimestepIndices.push_back( timestepIdx );
break;
}
barText += QString::fromStdString( curveDef.summaryAddress().quantityName() ) + separator;
}
if ( m_useSummaryItemInBarText )
{
barText += QString::fromStdString( curveDef.summaryAddress().itemUiText() ) + separator;
}
if ( m_useCaseInBarText && curveDef.summaryCase() )
{
barText += curveDef.summaryCase()->displayCaseName() + separator;
}
if ( m_useEnsembleInBarText && curveDef.ensemble() )
{
barText += curveDef.ensemble()->name() + separator;
}
if ( m_useTimeStepInBarText )
{
barText += timestepString + separator;
}
}
for ( int timestepIdx : selectedTimestepIndices )
{
double sortValue = std::numeric_limits<double>::infinity();
QDateTime dateTime = RiaQDateTimeTools::fromTime_t( timesteps[timestepIdx] );
QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates( {dateTime} );
QString timestepString = dateTime.toString( formatString );
QString majorText = assignGroupingText( m_majorGroupType(), curveDef, timestepString );
QString medText = assignGroupingText( m_mediumGroupType(), curveDef, timestepString );
QString minText = assignGroupingText( m_minorGroupType(), curveDef, timestepString );
QString legendText = assignGroupingText( m_sortGroupForLegend(), curveDef, timestepString );
double value = values[timestepIdx];
switch ( m_valueSortOperation() )
{
case VALUE:
sortValue = value;
break;
case ABS_VALUE:
sortValue = fabs( value );
break;
}
QString barText;
QString separator = " ";
if ( m_useBarText() )
{
if ( m_useQuantityInBarText )
{
barText += QString::fromStdString( curveDef.summaryAddress().quantityName() ) + separator;
}
if ( m_useSummaryItemInBarText )
{
barText += QString::fromStdString( curveDef.summaryAddress().itemUiText() ) + separator;
}
if ( m_useCaseInBarText && curveDef.summaryCase() )
{
barText += curveDef.summaryCase()->displayCaseName() + separator;
}
if ( m_useEnsembleInBarText && curveDef.ensemble() )
{
barText += curveDef.ensemble()->name() + separator;
}
if ( m_useTimeStepInBarText )
{
barText += timestepString + separator;
}
}
chartBuilder.addBarEntry( majorText, medText, minText, sortValue, legendText, barText, value );
}
chartBuilder.addBarEntry( majorText, medText, minText, sortValue, legendText, barText, value );
}
}
}
@@ -1236,8 +1635,8 @@ RimCurveDefinitionAnalyser* RimAnalysisPlot::getOrCreateSelectedCurveDefAnalyser
{
if ( !m_analyserOfSelectedCurveDefs )
{
m_analyserOfSelectedCurveDefs =
std::unique_ptr<RimCurveDefinitionAnalyser>( new RimCurveDefinitionAnalyser( this->curveDefinitions() ) );
m_analyserOfSelectedCurveDefs = std::unique_ptr<RimCurveDefinitionAnalyser>(
new RimCurveDefinitionAnalyser( this->curveDefinitionsWithCollapsedEnsembleCurves() ) );
}
return m_analyserOfSelectedCurveDefs.get();
@@ -1246,7 +1645,7 @@ RimCurveDefinitionAnalyser* RimAnalysisPlot::getOrCreateSelectedCurveDefAnalyser
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaSummaryCurveDefinition> RimAnalysisPlot::curveDefinitions() const
std::vector<RiaSummaryCurveDefinition> RimAnalysisPlot::curveDefinitionsWithCollapsedEnsembleCurves() const
{
std::vector<RiaSummaryCurveDefinition> curveDefs;
for ( auto dataEntry : m_analysisPlotDataSelection )
@@ -1257,6 +1656,47 @@ std::vector<RiaSummaryCurveDefinition> RimAnalysisPlot::curveDefinitions() const
return curveDefs;
}
//--------------------------------------------------------------------------------------------------
/// The curve definitions returned contain both the case AND the ensemble from which it has been spawned
//--------------------------------------------------------------------------------------------------
std::vector<RiaSummaryCurveDefinition> RimAnalysisPlot::curveDefinitionsWitExpandedEnsembleCurves()
{
std::vector<RiaSummaryCurveDefinition> barDataDefinitions;
for ( const RimAnalysisPlotDataEntry* dataEntry : m_analysisPlotDataSelection )
{
RiaSummaryCurveDefinition orgBarDataEntry = dataEntry->curveDefinition();
// Unpack ensemble curves and make one curve definition for each individual curve.
// Store both ensemble and summary case in the definition
if ( orgBarDataEntry.isEnsembleCurve() )
{
std::vector<RimSummaryCase*> sumCases = orgBarDataEntry.ensemble()->allSummaryCases();
for ( auto sumCase : sumCases )
{
barDataDefinitions.push_back(
RiaSummaryCurveDefinition( sumCase, orgBarDataEntry.summaryAddress(), orgBarDataEntry.ensemble() ) );
}
}
else
{
if ( orgBarDataEntry.summaryCase() && orgBarDataEntry.summaryCase()->ensemble() )
{
barDataDefinitions.push_back( RiaSummaryCurveDefinition( orgBarDataEntry.summaryCase(),
orgBarDataEntry.summaryAddress(),
orgBarDataEntry.summaryCase()->ensemble() ) );
}
else
{
barDataDefinitions.push_back( orgBarDataEntry );
}
}
}
return barDataDefinitions;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -66,6 +66,8 @@ public:
void onFiltersChanged();
std::vector<time_t> selectedTimeSteps();
public: // Internal. Public needed for AppEnum setup
enum BarOrientation
{
@@ -149,8 +151,17 @@ private:
void addDataToChartBuilder( RiuGroupedBarChartBuilder& chartBuilder );
void updatePlotTitle();
RimCurveDefinitionAnalyser* getOrCreateSelectedCurveDefAnalyser();
std::vector<RiaSummaryCurveDefinition> curveDefinitions() const;
RimCurveDefinitionAnalyser* getOrCreateSelectedCurveDefAnalyser();
std::vector<RiaSummaryCurveDefinition> curveDefinitionsWithCollapsedEnsembleCurves() const;
std::vector<RiaSummaryCurveDefinition> curveDefinitionsWitExpandedEnsembleCurves();
std::vector<RiaSummaryCurveDefinition> filteredCurveDefs();
void applyFilter( const RimPlotDataFilterItem* filter,
std::set<RimSummaryCase*>* filteredSumCases,
std::set<RifEclipseSummaryAddress>* filteredSummaryItems );
static std::vector<size_t> findTimestepIndices( std::vector<time_t> selectedTimesteps,
const std::vector<time_t>& timesteps );
std::set<RimPlotAxisPropertiesInterface*> allPlotAxes() const;
void buildTestPlot( RiuGroupedBarChartBuilder& chartBuilder );

View File

@@ -21,6 +21,9 @@
#include "RimSummaryAddress.h"
#include "RimSummaryCaseCollection.h"
#include "RifSummaryReaderInterface.h"
#include "RimSummaryCase.h"
#include "cafPdmUiActionPushButtonEditor.h"
#include "cafPdmUiDoubleSliderEditor.h"
#include "cafPdmUiLineEditor.h"
@@ -44,7 +47,7 @@ void caf::AppEnum<RimPlotDataFilterItem::FilterOperation>::setUp()
{
addItem( RimPlotDataFilterItem::RANGE, "RANGE", "Range" );
addItem( RimPlotDataFilterItem::TOP_N, "TOP_N", "Top N" );
addItem( RimPlotDataFilterItem::MIN_N, "MIN_N", "Min N" );
addItem( RimPlotDataFilterItem::BOTTOM_N, "BOTTOM_N", "Bottom N" );
setDefault( RimPlotDataFilterItem::RANGE );
}
@@ -83,6 +86,7 @@ RimPlotDataFilterItem::RimPlotDataFilterItem()
CAF_PDM_InitFieldNoDefault( &m_filterAddress, "FilterAddressField", "Filter Address", "", "", "" );
m_filterAddress.uiCapability()->setUiTreeHidden( true );
m_filterAddress = new RimSummaryAddress();
CAF_PDM_InitField( &m_filterEnsembleParameter, "QuantityText", QString( "" ), "Quantity", "", "", "" );
@@ -95,7 +99,7 @@ RimPlotDataFilterItem::RimPlotDataFilterItem()
CAF_PDM_InitFieldNoDefault( &m_filterOperation, "FilterOperation", "Operation", "", "", "" );
CAF_PDM_InitField( &m_useAbsoluteValue, "UseAbsoluteValue", true, "Use Abs(value)", "", "", "" );
CAF_PDM_InitField( &m_minTopN, "MinTopN", 20, "N", "", "", "" );
CAF_PDM_InitField( &m_topBottomN, "MinTopN", 20, "N", "", "", "" );
CAF_PDM_InitField( &m_max, "Max", 0.0, "Max", "", "", "" );
m_max.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_min, "Min", 0.0, "Min", "", "", "" );
@@ -120,6 +124,95 @@ RimPlotDataFilterItem::~RimPlotDataFilterItem()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RimPlotDataFilterItem::summaryAddress() const
{
CVF_ASSERT( m_filterTarget() == SUMMARY_CASE || m_filterTarget() == SUMMARY_ITEM );
return m_filterAddress->address();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimPlotDataFilterItem::ensembleParameterName() const
{
CVF_ASSERT( m_filterTarget() == ENSEMBLE_CASE );
return m_filterEnsembleParameter();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<double, double> RimPlotDataFilterItem::filterRangeMinMax() const
{
CVF_ASSERT( m_filterOperation() == RANGE );
return std::make_pair( m_min(), m_max() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimPlotDataFilterItem::topBottomN() const
{
CVF_ASSERT( m_filterOperation() != RANGE );
return m_topBottomN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QString> RimPlotDataFilterItem::selectedEnsembleParameterCategories() const
{
CVF_ASSERT( m_filterTarget() == ENSEMBLE_CASE );
return m_ensembleParameterValueCategories;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPlotDataFilterItem::TimeStepSourceType RimPlotDataFilterItem::consideredTimeStepsType() const
{
CVF_ASSERT( m_filterTarget() != ENSEMBLE_CASE );
return m_consideredTimestepsType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<time_t, time_t> RimPlotDataFilterItem::timeRangeMinMax() const
{
CVF_ASSERT( m_consideredTimestepsType() == RANGE );
if ( m_explicitlySelectedTimeSteps().size() >= 2 )
{
time_t minTime = m_explicitlySelectedTimeSteps().front().toTime_t();
time_t maxTime = m_explicitlySelectedTimeSteps().back().toTime_t();
return std::make_pair( minTime, maxTime );
}
return std::make_pair( time_t( 0 ), time_t( 0 ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<time_t> RimPlotDataFilterItem::explicitlySelectedTimeSteps() const
{
CVF_ASSERT( m_consideredTimestepsType == RimPlotDataFilterItem::SELECT_TIMESTEPS );
std::vector<time_t> selectedTimesteps;
{
for ( const QDateTime& dateTime : m_explicitlySelectedTimeSteps() )
{
selectedTimesteps.push_back( dateTime.toTime_t() );
}
}
return selectedTimesteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -135,8 +228,9 @@ void RimPlotDataFilterItem::fieldChangedByUi( const caf::PdmFieldHandle* changed
this->updateMaxMinAndDefaultValues( true );
parentPlot->onFiltersChanged();
}
else if ( changedField == &m_filterAddress )
else if ( changedField == &m_filterQuantityUiField )
{
m_filterAddress->setAddress( m_filterQuantityUiField );
this->updateMaxMinAndDefaultValues( true );
parentPlot->onFiltersChanged();
}
@@ -232,6 +326,11 @@ caf::PdmFieldHandle* RimPlotDataFilterItem::objectToggleField()
//--------------------------------------------------------------------------------------------------
void RimPlotDataFilterItem::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
if ( m_filterAddress )
{
m_filterQuantityUiField = m_filterAddress->address();
}
updateMaxMinAndDefaultValues( false );
uiOrdering.add( &m_filterTarget, {true, 4, 1} );
@@ -265,9 +364,9 @@ void RimPlotDataFilterItem::defineUiOrdering( QString uiConfigName, caf::PdmUiOr
uiOrdering.add( &m_max, {true, 4, 1} );
uiOrdering.add( &m_min, {true, 4, 1} );
}
else if ( m_filterOperation == TOP_N || m_filterOperation == MIN_N )
else if ( m_filterOperation == TOP_N || m_filterOperation == BOTTOM_N )
{
uiOrdering.add( &m_minTopN, {true, 4, 1} );
uiOrdering.add( &m_topBottomN, {true, 4, 1} );
}
}
@@ -325,8 +424,19 @@ void RimPlotDataFilterItem::updateMaxMinAndDefaultValues( bool forceDefault )
EnsembleParameter eParam = selectedEnsembleParameter();
if ( eParam.isValid() && eParam.isNumeric() )
{
if ( RiaCurveDataTools::isValidValue( eParam.minValue, false ) ) m_lowerLimit = eParam.minValue;
if ( RiaCurveDataTools::isValidValue( eParam.maxValue, false ) ) m_upperLimit = eParam.maxValue;
if ( RiaCurveDataTools::isValidValue( eParam.minValue, false ) )
{
m_lowerLimit = eParam.minValue;
if ( m_useAbsoluteValue ) m_lowerLimit = fabs( eParam.minValue );
}
if ( RiaCurveDataTools::isValidValue( eParam.maxValue, false ) )
{
m_upperLimit = eParam.maxValue;
if ( m_useAbsoluteValue ) m_upperLimit = fabs( eParam.maxValue );
}
// Make sure max is > min after doing abs
if ( m_upperLimit < m_lowerLimit ) std::swap( m_upperLimit, m_lowerLimit );
}
}
else

View File

@@ -28,6 +28,8 @@
#include "RimSummaryCaseCollection.h"
#include "RiaSummaryCurveDefinition.h"
#include <QDateTime>
class RiuSummaryQwtPlot;
@@ -64,6 +66,41 @@ public:
SELECT_TIMESTEP_RANGE
};
// Filter target
enum FilterTarget
{
SUMMARY_ITEM,
SUMMARY_CASE,
ENSEMBLE_CASE
};
enum FilterOperation
{
TOP_N,
BOTTOM_N,
RANGE
};
std::vector<RiaSummaryCurveDefinition> applyFilter( const std::vector<RiaSummaryCurveDefinition>& curveDefsToFilter );
bool isActive() const { return m_isActive(); }
FilterTarget filterTarget() const { return m_filterTarget(); }
RifEclipseSummaryAddress summaryAddress() const;
QString ensembleParameterName() const;
FilterOperation filterOperation() const { return m_filterOperation(); }
bool useAbsoluteValues() const { return m_useAbsoluteValue(); }
std::pair<double, double> filterRangeMinMax() const;
int topBottomN() const;
std::vector<QString> selectedEnsembleParameterCategories() const;
TimeStepSourceType consideredTimeStepsType() const;
std::pair<time_t, time_t> timeRangeMinMax() const;
std::vector<time_t> explicitlySelectedTimeSteps() const;
private:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
@@ -80,14 +117,6 @@ private:
caf::PdmField<bool> m_isActive;
// Filter target
enum FilterTarget
{
SUMMARY_ITEM,
SUMMARY_CASE,
ENSEMBLE_CASE
};
friend caf::AppEnum<FilterTarget>;
caf::PdmField<caf::AppEnum<FilterTarget>> m_filterTarget;
// Quantity
@@ -100,17 +129,9 @@ private:
// Operation and parameters
enum FilterOperation
{
TOP_N,
MIN_N,
RANGE
};
friend caf::AppEnum<FilterOperation>;
caf::PdmField<caf::AppEnum<FilterOperation>> m_filterOperation;
caf::PdmField<bool> m_useAbsoluteValue;
caf::PdmField<int> m_minTopN;
caf::PdmField<int> m_topBottomN;
caf::PdmField<double> m_max;
caf::PdmField<double> m_min;