mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Add realization filtering based on text string
Add unit tests and support min max range specifications. Example string "-5, 5, 8-10, 12-"
This commit is contained in:
parent
691b73d7f4
commit
785871cae3
@ -157,3 +157,11 @@ QString RiaDefines::summaryCalculated()
|
||||
{
|
||||
return "Calculated";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaDefines::summaryRealizationNumber()
|
||||
{
|
||||
return "RI:REALIZATION_NUM";
|
||||
}
|
||||
|
@ -52,4 +52,6 @@ QString summaryLgrWell();
|
||||
QString summaryLgrBlock();
|
||||
QString summaryCalculated();
|
||||
|
||||
QString summaryRealizationNumber();
|
||||
|
||||
}; // namespace RiaDefines
|
||||
|
@ -17,9 +17,12 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RiaStdStringTools.h"
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "fast_float/include/fast_float/fast_float.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <charconv>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
@ -301,3 +304,118 @@ std::string RiaStdStringTools::removeHtmlTags( const std::string& s )
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<int> RiaStdStringTools::valuesFromRangeSelection( const std::string& s )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::set<int> result;
|
||||
std::istringstream stringStream( s );
|
||||
std::string token;
|
||||
|
||||
while ( std::getline( stringStream, token, ',' ) )
|
||||
{
|
||||
token = RiaStdStringTools::trimString( token );
|
||||
|
||||
std::istringstream tokenStream( token );
|
||||
int startIndex, endIndex;
|
||||
char dash;
|
||||
|
||||
if ( tokenStream >> startIndex )
|
||||
{
|
||||
if ( tokenStream >> dash && dash == '-' && tokenStream >> endIndex )
|
||||
{
|
||||
if ( startIndex > endIndex )
|
||||
{
|
||||
// If start is greater than end, swap them
|
||||
std::swap( startIndex, endIndex );
|
||||
}
|
||||
|
||||
for ( int i = startIndex; i <= endIndex; ++i )
|
||||
{
|
||||
result.insert( i );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.insert( startIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
QString str = QString( "Failed to convert text string \" %1 \" to list of integers : " ).arg( QString::fromStdString( s ) ) +
|
||||
QString::fromStdString( e.what() );
|
||||
RiaLogging::error( str );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
QString str =
|
||||
QString( "Failed to convert text string \" %1 \" to list of integers : Caught unknown exception" ).arg( QString::fromStdString( s ) );
|
||||
RiaLogging::error( str );
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<int> RiaStdStringTools::valuesFromRangeSelection( const std::string& s, int minVal, int maxVal )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::set<int> result;
|
||||
std::stringstream stringStream( s );
|
||||
std::string token;
|
||||
|
||||
while ( std::getline( stringStream, token, ',' ) )
|
||||
{
|
||||
token = RiaStdStringTools::trimString( token );
|
||||
|
||||
// Check for range
|
||||
size_t dashPos = token.find( '-' );
|
||||
if ( dashPos != std::string::npos )
|
||||
{
|
||||
int startIndex = ( dashPos == 0 ) ? minVal : std::stoi( token.substr( 0, dashPos ) );
|
||||
int endIndex = ( dashPos == token.size() - 1 ) ? maxVal : std::stoi( token.substr( dashPos + 1 ) );
|
||||
if ( startIndex > endIndex )
|
||||
{
|
||||
// If start is greater than end, swap them
|
||||
std::swap( startIndex, endIndex );
|
||||
}
|
||||
for ( int i = startIndex; i <= endIndex; ++i )
|
||||
{
|
||||
result.insert( i );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for individual numbers
|
||||
result.insert( std::stoi( token ) );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
QString str = QString( "Failed to convert text string \" %1 \" to list of integers : " ).arg( QString::fromStdString( s ) ) +
|
||||
QString::fromStdString( e.what() );
|
||||
RiaLogging::error( str );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
QString str =
|
||||
QString( "Failed to convert text string \" %1 \" to list of integers : Caught unknown exception" ).arg( QString::fromStdString( s ) );
|
||||
RiaLogging::error( str );
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -60,6 +61,13 @@ public:
|
||||
|
||||
static std::string removeHtmlTags( const std::string& s );
|
||||
|
||||
// Convert the string "1,2,5-8,10" to {1, 2, 5, 6, 7, 8, 10}
|
||||
static std::set<int> valuesFromRangeSelection( const std::string& s );
|
||||
|
||||
// Convert the range string with support for open ended expressions. minimum and maximum value will be used to limit the ranges.
|
||||
// The input "-3,5-8,10-", min:1, max:12 will produce {1, 2, 3, 5, 6, 7, 8, 10, 11, 12}
|
||||
static std::set<int> valuesFromRangeSelection( const std::string& s, int minimumValue, int maximumValue );
|
||||
|
||||
private:
|
||||
template <class Container>
|
||||
static void splitByDelimiter( const std::string& str, Container& cont, char delimiter = ' ' );
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "RimEnsembleCurveFilter.h"
|
||||
|
||||
#include "RiaCurveDataTools.h"
|
||||
#include "RiaStdStringTools.h"
|
||||
#include "RiaSummaryCurveDefinition.h"
|
||||
|
||||
#include "RimCustomObjectiveFunction.h"
|
||||
@ -106,6 +107,8 @@ RimEnsembleCurveFilter::RimEnsembleCurveFilter()
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_categories, "Categories", "Categories" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_realizationFilter, "RealizationFilter", "Realization Filter" );
|
||||
|
||||
setDeletable( true );
|
||||
}
|
||||
|
||||
@ -185,6 +188,11 @@ QString RimEnsembleCurveFilter::description() const
|
||||
QString descriptor;
|
||||
if ( m_filterMode() == FilterMode::BY_ENSEMBLE_PARAMETER )
|
||||
{
|
||||
if ( m_ensembleParameterName() == RiaDefines::summaryRealizationNumber() )
|
||||
{
|
||||
return "Realizations : " + m_realizationFilter;
|
||||
}
|
||||
|
||||
descriptor = QString( "%0" ).arg( m_ensembleParameterName() );
|
||||
}
|
||||
else if ( m_filterMode() == FilterMode::BY_OBJECTIVE_FUNCTION )
|
||||
@ -357,7 +365,8 @@ void RimEnsembleCurveFilter::fieldChangedByUi( const caf::PdmFieldHandle* change
|
||||
}
|
||||
updateMaxMinAndDefaultValues( true );
|
||||
}
|
||||
else if ( changedField == &m_active || changedField == &m_minValue || changedField == &m_maxValue || changedField == &m_categories )
|
||||
else if ( changedField == &m_active || changedField == &m_minValue || changedField == &m_maxValue || changedField == &m_categories ||
|
||||
changedField == &m_realizationFilter )
|
||||
{
|
||||
if ( curveSet )
|
||||
{
|
||||
@ -458,7 +467,11 @@ void RimEnsembleCurveFilter::defineUiOrdering( QString uiConfigName, caf::PdmUiO
|
||||
uiOrdering.add( &m_customObjectiveFunction );
|
||||
}
|
||||
|
||||
if ( eParam.isNumeric() )
|
||||
if ( m_ensembleParameterName() == RiaDefines::summaryRealizationNumber() )
|
||||
{
|
||||
uiOrdering.add( &m_realizationFilter );
|
||||
}
|
||||
else if ( eParam.isNumeric() )
|
||||
{
|
||||
uiOrdering.add( &m_minValue );
|
||||
uiOrdering.add( &m_maxValue );
|
||||
@ -506,6 +519,19 @@ std::vector<RimSummaryCase*> RimEnsembleCurveFilter::applyFilter( const std::vec
|
||||
auto ensemble = curveSet ? curveSet->summaryCaseCollection() : nullptr;
|
||||
if ( !ensemble || !isActive() ) return allSumCases;
|
||||
|
||||
bool useIntegerSelection = false;
|
||||
std::set<int> integerSelection;
|
||||
|
||||
if ( m_ensembleParameterName() == RiaDefines::summaryRealizationNumber() )
|
||||
{
|
||||
auto eParam = selectedEnsembleParameter();
|
||||
int minValue = eParam.minValue;
|
||||
int maxValue = eParam.maxValue;
|
||||
|
||||
integerSelection = RiaStdStringTools::valuesFromRangeSelection( m_realizationFilter().toStdString(), minValue, maxValue );
|
||||
useIntegerSelection = true;
|
||||
}
|
||||
|
||||
std::set<RimSummaryCase*> casesToRemove;
|
||||
for ( const auto& sumCase : allSumCases )
|
||||
{
|
||||
@ -517,7 +543,16 @@ std::vector<RimSummaryCase*> RimEnsembleCurveFilter::applyFilter( const std::vec
|
||||
|
||||
auto crpValue = sumCase->caseRealizationParameters()->parameterValue( m_ensembleParameterName() );
|
||||
|
||||
if ( eParam.isNumeric() )
|
||||
if ( useIntegerSelection )
|
||||
{
|
||||
int integerValue = crpValue.numericValue();
|
||||
|
||||
if ( !integerSelection.contains( integerValue ) )
|
||||
{
|
||||
casesToRemove.insert( sumCase );
|
||||
}
|
||||
}
|
||||
else if ( eParam.isNumeric() )
|
||||
{
|
||||
if ( !crpValue.isNumeric() || crpValue.numericValue() < m_minValue() || crpValue.numericValue() > m_maxValue() )
|
||||
{
|
||||
@ -653,6 +688,19 @@ void RimEnsembleCurveFilter::updateMaxMinAndDefaultValues( bool forceDefault )
|
||||
|
||||
m_minValue.uiCapability()->setUiName( QString( "Min (%1)" ).arg( m_lowerLimit ) );
|
||||
m_maxValue.uiCapability()->setUiName( QString( "Max (%1)" ).arg( m_upperLimit ) );
|
||||
|
||||
if ( m_ensembleParameterName() == RiaDefines::summaryRealizationNumber() )
|
||||
{
|
||||
int lower = eParam.minValue;
|
||||
int upper = eParam.maxValue;
|
||||
|
||||
m_realizationFilter.uiCapability()->setUiName( QString( "Integer Selection\n[%1..%2]" ).arg( lower ).arg( upper ) );
|
||||
|
||||
if ( m_realizationFilter().isEmpty() )
|
||||
{
|
||||
m_realizationFilter = QString( "%1-%2" ).arg( lower ).arg( upper );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( m_filterMode() == FilterMode::BY_OBJECTIVE_FUNCTION )
|
||||
|
@ -105,6 +105,8 @@ private:
|
||||
caf::PdmField<double> m_maxValue;
|
||||
caf::PdmField<std::vector<QString>> m_categories;
|
||||
|
||||
caf::PdmField<QString> m_realizationFilter;
|
||||
|
||||
double m_lowerLimit;
|
||||
double m_upperLimit;
|
||||
};
|
||||
|
@ -82,7 +82,7 @@ void addCaseRealizationParametersIfFound( RimSummaryCase& sumCase, const QString
|
||||
|
||||
int realizationNumber = RifCaseRealizationParametersFileLocator::realizationNumber( modelFolderOrFile );
|
||||
parameters->setRealizationNumber( realizationNumber );
|
||||
parameters->addParameter( "RI:REALIZATION_NUM", realizationNumber );
|
||||
parameters->addParameter( RiaDefines::summaryRealizationNumber(), realizationNumber );
|
||||
|
||||
sumCase.setCaseRealizationParameters( parameters );
|
||||
}
|
||||
|
@ -202,3 +202,58 @@ TEST( RiaStdStringToolsTest, DISABLED_PerformanceConversion )
|
||||
std::cout << "std::from_chars " << std::setw( 9 ) << diff.count() << " s\n";
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RiaStdStringToolsTest, ValuesFromRangeSelection )
|
||||
{
|
||||
std::string testString = "1,2,5-10,15";
|
||||
std::set<int> expectedValues = { 1, 2, 5, 6, 7, 8, 9, 10, 15 };
|
||||
|
||||
auto actualValues = RiaStdStringTools::valuesFromRangeSelection( testString );
|
||||
|
||||
ASSERT_EQ( expectedValues, actualValues );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RiaStdStringToolsTest, ValuesFromRangeSelectionMinMax )
|
||||
{
|
||||
std::string testString = "-3, 5, 6-8, 10, 15-";
|
||||
int minimumValue = 1;
|
||||
int maximumValue = 20;
|
||||
std::set<int> expectedValues = { 1, 2, 3, 5, 6, 7, 8, 10, 15, 16, 17, 18, 19, 20 };
|
||||
|
||||
auto actualValues = RiaStdStringTools::valuesFromRangeSelection( testString, minimumValue, maximumValue );
|
||||
|
||||
ASSERT_EQ( expectedValues, actualValues );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RiaStdStringToolsTest, TestInvalidRangeStrings )
|
||||
{
|
||||
int minimumValue = 1;
|
||||
int maximumValue = 20;
|
||||
|
||||
{
|
||||
// Handle blank space and inverted from/to
|
||||
std::string testString = "5, -3, 9-8";
|
||||
std::set<int> expectedValues = { 1, 2, 3, 5, 8, 9 };
|
||||
auto actualValues = RiaStdStringTools::valuesFromRangeSelection( testString, minimumValue, maximumValue );
|
||||
|
||||
ASSERT_EQ( expectedValues, actualValues );
|
||||
}
|
||||
|
||||
{
|
||||
// If the range is invalid, the result should be an empty set
|
||||
std::string testString = "5, a";
|
||||
std::set<int> expectedValues = {};
|
||||
auto actualValues = RiaStdStringTools::valuesFromRangeSelection( testString, minimumValue, maximumValue );
|
||||
|
||||
ASSERT_EQ( expectedValues, actualValues );
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user