Skip to content

Commit 5e5c380

Browse files
committed
Use std::expected instead of asserts
1 parent d0cde69 commit 5e5c380

File tree

4 files changed

+149
-84
lines changed

4 files changed

+149
-84
lines changed

ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include "RimEclipseStatisticsCaseEvaluator.h"
2222

23+
#include "RiaLogging.h"
24+
2325
#include "RigCaseCellResultsData.h"
2426
#include "RigEclipseCaseData.h"
2527
#include "RigEclipseResultInfo.h"
@@ -262,13 +264,20 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList<ResSpec>
262264
pValPoss.push_back( m_statisticsConfig.m_pMinPos );
263265
pValPoss.push_back( m_statisticsConfig.m_pMidPos );
264266
pValPoss.push_back( m_statisticsConfig.m_pMaxPos );
265-
std::vector<double> pVals =
267+
auto pVals =
266268
RigStatisticsMath::calculateNearestRankPercentiles( values,
267269
pValPoss,
268270
RigStatisticsMath::PercentileStyle::SWITCHED );
269-
statParams[PMIN] = pVals[0];
270-
statParams[PMID] = pVals[1];
271-
statParams[PMAX] = pVals[2];
271+
if ( pVals.has_value() )
272+
{
273+
statParams[PMIN] = ( *pVals )[0];
274+
statParams[PMID] = ( *pVals )[1];
275+
statParams[PMAX] = ( *pVals )[2];
276+
}
277+
else
278+
{
279+
RiaLogging::warning( QString::fromStdString( pVals.error() ) );
280+
}
272281
}
273282
else if ( m_statisticsConfig.m_pValMethod == RimEclipseStatisticsCase::PercentileCalcType::HISTOGRAM_ESTIMATED )
274283
{
@@ -285,17 +294,24 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults( const QList<ResSpec>
285294
else if ( m_statisticsConfig.m_pValMethod ==
286295
RimEclipseStatisticsCase::PercentileCalcType::INTERPOLATED_OBSERVATION )
287296
{
288-
std::vector<double> pValPoss;
289-
pValPoss.push_back( m_statisticsConfig.m_pMinPos );
290-
pValPoss.push_back( m_statisticsConfig.m_pMidPos );
291-
pValPoss.push_back( m_statisticsConfig.m_pMaxPos );
292-
std::vector<double> pVals =
297+
std::vector<double> percentiles;
298+
percentiles.push_back( m_statisticsConfig.m_pMinPos );
299+
percentiles.push_back( m_statisticsConfig.m_pMidPos );
300+
percentiles.push_back( m_statisticsConfig.m_pMaxPos );
301+
auto resultValues =
293302
RigStatisticsMath::calculateInterpolatedPercentiles( values,
294-
pValPoss,
303+
percentiles,
295304
RigStatisticsMath::PercentileStyle::SWITCHED );
296-
statParams[PMIN] = pVals[0];
297-
statParams[PMID] = pVals[1];
298-
statParams[PMAX] = pVals[2];
305+
if ( resultValues.has_value() )
306+
{
307+
statParams[PMIN] = ( *resultValues )[0];
308+
statParams[PMID] = ( *resultValues )[1];
309+
statParams[PMAX] = ( *resultValues )[2];
310+
}
311+
else
312+
{
313+
RiaLogging::warning( QString::fromStdString( resultValues.error() ) );
314+
}
299315
}
300316
else
301317
{

ApplicationLibCode/ResultStatisticsCache/RigStatisticsMath.cpp

Lines changed: 99 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <algorithm>
2424
#include <cassert>
2525
#include <cmath>
26+
#include <expected>
2627
#include <numeric>
2728

2829
namespace
@@ -148,13 +149,13 @@ void RigStatisticsMath::calculateStatisticsCurves( const std::vector<double>& va
148149

149150
// Use the vector-based implementation
150151
std::vector<double> percentiles = { 0.1, 0.5, 0.9 };
151-
std::vector<double> results = calculatePercentiles( values, percentiles, percentileStyle );
152+
auto results = calculatePercentiles( values, percentiles, percentileStyle );
152153

153-
if ( results.size() == 3 )
154+
if ( results.has_value() && results->size() == 3 )
154155
{
155-
*p10 = results[0];
156-
*p50 = results[1];
157-
*p90 = results[2];
156+
*p10 = ( *results )[0];
157+
*p50 = ( *results )[1];
158+
*p90 = ( *results )[2];
158159
}
159160
else
160161
{
@@ -198,14 +199,24 @@ void RigStatisticsMath::calculateStatisticsCurves( const std::vector<double>& va
198199
/// https://en.wikipedia.org/wiki/Percentile
199200
/// https://en.wikipedia.org/wiki/Percentile#Third_variant,_C_=_0
200201
//--------------------------------------------------------------------------------------------------
201-
std::vector<double> RigStatisticsMath::calculatePercentiles( const std::vector<double>& values,
202-
const std::vector<double>& quantiles,
203-
PercentileStyle percentileStyle )
202+
std::expected<std::vector<double>, std::string> RigStatisticsMath::calculatePercentiles( const std::vector<double>& values,
203+
const std::vector<double>& quantiles,
204+
PercentileStyle percentileStyle )
204205
{
205-
CVF_ASSERT( areValidQuantiles( quantiles ) && "Quantiles must be in range [0-1]" );
206+
if ( !areValidQuantiles( quantiles ) )
207+
{
208+
return std::unexpected( "Quantiles must be in range [0-1]" );
209+
}
206210

207-
std::vector<double> resultValues;
208-
if ( values.empty() || quantiles.empty() ) return resultValues;
211+
if ( values.empty() )
212+
{
213+
return std::unexpected( "Input values are empty" );
214+
}
215+
216+
if ( quantiles.empty() )
217+
{
218+
return std::unexpected( "Quantiles are empty" );
219+
}
209220

210221
std::vector<double> sortedValues = values;
211222

@@ -214,11 +225,15 @@ std::vector<double> RigStatisticsMath::calculatePercentiles( const std::vector<d
214225
[]( double x ) { return !RiaStatisticsTools::isValidNumber( x ); } ),
215226
sortedValues.end() );
216227

217-
if ( sortedValues.empty() ) return resultValues;
228+
if ( sortedValues.empty() )
229+
{
230+
return std::unexpected( "No valid values in input" );
231+
}
218232

219233
std::sort( sortedValues.begin(), sortedValues.end() );
220234

221-
int valueCount = (int)sortedValues.size();
235+
int valueCount = (int)sortedValues.size();
236+
std::vector<double> resultValues;
222237
resultValues.reserve( quantiles.size() );
223238

224239
for ( size_t i = 0; i < quantiles.size(); ++i )
@@ -273,11 +288,25 @@ std::vector<double> RigStatisticsMath::calculatePercentiles( const std::vector<d
273288
/// https://en.wikipedia.org/wiki/Percentile#First_variant,_C_=_1/2
274289
//--------------------------------------------------------------------------------------------------
275290

276-
std::vector<double> RigStatisticsMath::calculateNearestRankPercentiles( const std::vector<double>& inputValues,
277-
const std::vector<double>& percentiles,
278-
RigStatisticsMath::PercentileStyle percentileStyle )
291+
std::expected<std::vector<double>, std::string>
292+
RigStatisticsMath::calculateNearestRankPercentiles( const std::vector<double>& inputValues,
293+
const std::vector<double>& percentiles,
294+
RigStatisticsMath::PercentileStyle percentileStyle )
279295
{
280-
CVF_ASSERT( areValidPercentiles( percentiles ) && "Percentiles must be in range [0-100]" );
296+
if ( !areValidPercentiles( percentiles ) )
297+
{
298+
return std::unexpected( "Percentiles must be in range [0-100]" );
299+
}
300+
301+
if ( inputValues.empty() )
302+
{
303+
return std::unexpected( "Input values are empty" );
304+
}
305+
306+
if ( percentiles.empty() )
307+
{
308+
return std::unexpected( "Percentiles are empty" );
309+
}
281310

282311
std::vector<double> sortedValues;
283312
sortedValues.reserve( inputValues.size() );
@@ -290,27 +319,29 @@ std::vector<double> RigStatisticsMath::calculateNearestRankPercentiles( const st
290319
}
291320
}
292321

322+
if ( sortedValues.empty() )
323+
{
324+
return std::unexpected( "No valid values in input" );
325+
}
326+
293327
std::sort( sortedValues.begin(), sortedValues.end() );
294328

295329
std::vector<double> resultValues( percentiles.size(), HUGE_VAL );
296-
if ( !sortedValues.empty() )
330+
for ( size_t i = 0; i < percentiles.size(); ++i )
297331
{
298-
for ( size_t i = 0; i < percentiles.size(); ++i )
299-
{
300-
double quantile = cvf::Math::abs( percentiles[i] ) / 100;
301-
if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
332+
double quantile = cvf::Math::abs( percentiles[i] ) / 100;
333+
if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
302334

303-
size_t index = static_cast<size_t>( sortedValues.size() * quantile );
335+
size_t index = static_cast<size_t>( sortedValues.size() * quantile );
304336

305-
if ( index >= sortedValues.size() ) index = sortedValues.size() - 1;
337+
if ( index >= sortedValues.size() ) index = sortedValues.size() - 1;
306338

307-
auto value = sortedValues[index];
308-
resultValues[i] = value;
309-
}
339+
auto value = sortedValues[index];
340+
resultValues[i] = value;
310341
}
311342

312343
return resultValues;
313-
};
344+
}
314345

315346
//--------------------------------------------------------------------------------------------------
316347
/// Calculate the percentiles of /a inputValues at the pValPosition percentages by interpolating input values.
@@ -331,11 +362,25 @@ std::vector<double> RigStatisticsMath::calculateNearestRankPercentiles( const st
331362
/// https://en.wikipedia.org/wiki/Percentile#The_linear_interpolation_between_closest_ranks_method
332363
/// https://en.wikipedia.org/wiki/Percentile#Second_variant,_C_=_1
333364
//--------------------------------------------------------------------------------------------------
334-
std::vector<double> RigStatisticsMath::calculateInterpolatedPercentiles( const std::vector<double>& inputValues,
335-
const std::vector<double>& percentiles,
336-
RigStatisticsMath::PercentileStyle percentileStyle )
365+
std::expected<std::vector<double>, std::string>
366+
RigStatisticsMath::calculateInterpolatedPercentiles( const std::vector<double>& inputValues,
367+
const std::vector<double>& percentiles,
368+
RigStatisticsMath::PercentileStyle percentileStyle )
337369
{
338-
CVF_ASSERT( areValidPercentiles( percentiles ) && "Percentiles must be in range [0-100]" );
370+
if ( !areValidPercentiles( percentiles ) )
371+
{
372+
return std::unexpected( "Percentiles must be in range [0-100]" );
373+
}
374+
375+
if ( inputValues.empty() )
376+
{
377+
return std::unexpected( "Input values are empty" );
378+
}
379+
380+
if ( percentiles.empty() )
381+
{
382+
return std::unexpected( "Percentiles are empty" );
383+
}
339384

340385
std::vector<double> sortedValues;
341386
sortedValues.reserve( inputValues.size() );
@@ -348,36 +393,38 @@ std::vector<double> RigStatisticsMath::calculateInterpolatedPercentiles( const s
348393
}
349394
}
350395

396+
if ( sortedValues.empty() )
397+
{
398+
return std::unexpected( "No valid values in input" );
399+
}
400+
351401
std::sort( sortedValues.begin(), sortedValues.end() );
352402

353403
std::vector<double> resultValues( percentiles.size(), HUGE_VAL );
354-
if ( !sortedValues.empty() )
404+
for ( size_t i = 0; i < percentiles.size(); ++i )
355405
{
356-
for ( size_t i = 0; i < percentiles.size(); ++i )
357-
{
358-
double value = HUGE_VAL;
406+
double value = HUGE_VAL;
359407

360-
double quantile = cvf::Math::abs( percentiles[i] ) / 100.0;
361-
if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
408+
double quantile = cvf::Math::abs( percentiles[i] ) / 100.0;
409+
if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
362410

363-
double doubleIndex = ( sortedValues.size() - 1 ) * quantile;
411+
double doubleIndex = ( sortedValues.size() - 1 ) * quantile;
364412

365-
size_t lowerValueIndex = static_cast<size_t>( floor( doubleIndex ) );
366-
size_t upperValueIndex = lowerValueIndex + 1;
413+
size_t lowerValueIndex = static_cast<size_t>( floor( doubleIndex ) );
414+
size_t upperValueIndex = lowerValueIndex + 1;
367415

368-
double upperValueWeight = doubleIndex - lowerValueIndex;
369-
assert( upperValueWeight < 1.0 );
416+
double upperValueWeight = doubleIndex - lowerValueIndex;
417+
assert( upperValueWeight < 1.0 );
370418

371-
if ( upperValueIndex < sortedValues.size() )
372-
{
373-
value = ( 1.0 - upperValueWeight ) * sortedValues[lowerValueIndex] + upperValueWeight * sortedValues[upperValueIndex];
374-
}
375-
else
376-
{
377-
value = sortedValues[lowerValueIndex];
378-
}
379-
resultValues[i] = value;
419+
if ( upperValueIndex < sortedValues.size() )
420+
{
421+
value = ( 1.0 - upperValueWeight ) * sortedValues[lowerValueIndex] + upperValueWeight * sortedValues[upperValueIndex];
422+
}
423+
else
424+
{
425+
value = sortedValues[lowerValueIndex];
380426
}
427+
resultValues[i] = value;
381428
}
382429

383430
return resultValues;

ApplicationLibCode/ResultStatisticsCache/RigStatisticsMath.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
#include <cmath>
2323
#include <cstddef>
24+
#include <expected>
2425
#include <set>
26+
#include <string>
2527
#include <vector>
2628

2729
class RigStatisticsMath
@@ -42,16 +44,16 @@ class RigStatisticsMath
4244
double* p90,
4345
double* mean,
4446
PercentileStyle percentileStyle );
45-
static std::vector<double>
47+
static std::expected<std::vector<double>, std::string>
4648
calculatePercentiles( const std::vector<double>& values, const std::vector<double>& quantiles, PercentileStyle percentileStyle );
4749

48-
static std::vector<double> calculateNearestRankPercentiles( const std::vector<double>& inputValues,
49-
const std::vector<double>& percentiles,
50-
PercentileStyle percentileStyle );
50+
static std::expected<std::vector<double>, std::string> calculateNearestRankPercentiles( const std::vector<double>& inputValues,
51+
const std::vector<double>& percentiles,
52+
PercentileStyle percentileStyle );
5153

52-
static std::vector<double> calculateInterpolatedPercentiles( const std::vector<double>& inputValues,
53-
const std::vector<double>& percentiles,
54-
PercentileStyle percentileStyle );
54+
static std::expected<std::vector<double>, std::string> calculateInterpolatedPercentiles( const std::vector<double>& inputValues,
55+
const std::vector<double>& percentiles,
56+
PercentileStyle percentileStyle );
5557
};
5658

5759
//==================================================================================================

ApplicationLibCode/UnitTests/RigStatisticsMath-Test.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,13 @@ TEST( RigStatisticsMath, RankPercentiles )
9090
pValPos.push_back( 40 );
9191
pValPos.push_back( 50 );
9292
pValPos.push_back( 90 );
93-
std::vector<double> pVals =
94-
RigStatisticsMath::calculateNearestRankPercentiles( values, pValPos, RigStatisticsMath::PercentileStyle::REGULAR );
93+
auto pVals = RigStatisticsMath::calculateNearestRankPercentiles( values, pValPos, RigStatisticsMath::PercentileStyle::REGULAR );
9594

96-
EXPECT_DOUBLE_EQ( -76092.8157632591000, pVals[0] );
97-
EXPECT_DOUBLE_EQ( 2788.2723335651900, pVals[1] );
98-
EXPECT_DOUBLE_EQ( 6391.979999097290, pVals[2] );
99-
EXPECT_DOUBLE_EQ( 96161.7546348456000, pVals[3] );
95+
ASSERT_TRUE( pVals.has_value() );
96+
EXPECT_DOUBLE_EQ( -76092.8157632591000, ( *pVals )[0] );
97+
EXPECT_DOUBLE_EQ( 2788.2723335651900, ( *pVals )[1] );
98+
EXPECT_DOUBLE_EQ( 6391.979999097290, ( *pVals )[2] );
99+
EXPECT_DOUBLE_EQ( 96161.7546348456000, ( *pVals )[3] );
100100
}
101101

102102
//--------------------------------------------------------------------------------------------------
@@ -169,13 +169,13 @@ TEST( RigStatisticsMath, InterpolatedPercentiles )
169169
pValPos.push_back( 40 );
170170
pValPos.push_back( 50 );
171171
pValPos.push_back( 90 );
172-
std::vector<double> pVals =
173-
RigStatisticsMath::calculateInterpolatedPercentiles( values, pValPos, RigStatisticsMath::PercentileStyle::REGULAR );
172+
auto pVals = RigStatisticsMath::calculateInterpolatedPercentiles( values, pValPos, RigStatisticsMath::PercentileStyle::REGULAR );
174173

175-
EXPECT_DOUBLE_EQ( -72278.340409937548, pVals[0] );
176-
EXPECT_DOUBLE_EQ( -2265.6006907818496, pVals[1] );
177-
EXPECT_DOUBLE_EQ( 6391.9799990972897, pVals[2] );
178-
EXPECT_DOUBLE_EQ( 93073.49128098879, pVals[3] );
174+
ASSERT_TRUE( pVals.has_value() );
175+
EXPECT_DOUBLE_EQ( -72278.340409937548, ( *pVals )[0] );
176+
EXPECT_DOUBLE_EQ( -2265.6006907818496, ( *pVals )[1] );
177+
EXPECT_DOUBLE_EQ( 6391.9799990972897, ( *pVals )[2] );
178+
EXPECT_DOUBLE_EQ( 93073.49128098879, ( *pVals )[3] );
179179
}
180180

181181
//--------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)