diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.cpp index c22d411ca2..87ce44ac2f 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.cpp @@ -21,7 +21,10 @@ #include "cafPdmUiLineEditor.h" #include "cafPdmUiTextEditor.h" +#include "ExponentialRegression.hpp" #include "LinearRegression.hpp" +#include "LogarithmicRegression.hpp" +#include "LogisticRegression.hpp" #include "PolynominalRegression.hpp" #include "PowerFitRegression.hpp" @@ -38,6 +41,9 @@ void caf::AppEnum::setUp() addItem( RimSummaryRegressionAnalysisCurve::RegressionType::LINEAR, "LINEAR", "Linear" ); addItem( RimSummaryRegressionAnalysisCurve::RegressionType::POLYNOMINAL, "POLYNOMINAL", "Polynominal" ); addItem( RimSummaryRegressionAnalysisCurve::RegressionType::POWER_FIT, "POWER_FIT", "Power Fit" ); + addItem( RimSummaryRegressionAnalysisCurve::RegressionType::EXPONENTIAL, "EXPONENTIAL", "Exponential" ); + addItem( RimSummaryRegressionAnalysisCurve::RegressionType::LOGARITHMIC, "LOGARITHMIC", "Logarithmic" ); + addItem( RimSummaryRegressionAnalysisCurve::RegressionType::LOGISTIC, "LOGISTIC", "Logistic" ); setDefault( RimSummaryRegressionAnalysisCurve::RegressionType::LINEAR ); } }; // namespace caf @@ -132,6 +138,31 @@ std::tuple, std::vector, QString> return doubleVector; }; + auto convertToTimeT = []( const std::vector& timeSteps ) + { + std::vector tVector( timeSteps.size() ); + std::transform( timeSteps.begin(), + timeSteps.end(), + tVector.begin(), + []( const auto& timeVal ) { return static_cast( timeVal ); } ); + return tVector; + }; + + auto filterValues = []( const std::vector& timeSteps, const std::vector& values ) + { + std::vector filteredTimeSteps; + std::vector filteredValues; + for ( size_t i = 0; i < timeSteps.size(); i++ ) + { + if ( timeSteps[i] > 0.0 && values[i] > 0.0 ) + { + filteredTimeSteps.push_back( timeSteps[i] ); + filteredValues.push_back( values[i] ); + } + } + return std::make_pair( filteredTimeSteps, filteredValues ); + }; + std::vector timeStepsD = convertToDouble( timeSteps ); if ( m_regressionType == RegressionType::LINEAR ) @@ -150,25 +181,34 @@ std::tuple, std::vector, QString> } else if ( m_regressionType == RegressionType::POWER_FIT ) { - auto filterValues = []( const std::vector& timeSteps, const std::vector& values ) - { - std::vector filteredTimeSteps; - std::vector filteredValues; - for ( size_t i = 0; i < timeSteps.size(); i++ ) - { - if ( timeSteps[i] > 0.0 && values[i] > 0.0 ) - { - filteredTimeSteps.push_back( timeSteps[i] ); - filteredValues.push_back( values[i] ); - } - } - return std::make_pair( filteredTimeSteps, filteredValues ); - }; auto [filteredTimeSteps, filteredValues] = filterValues( timeStepsD, values ); regression::PowerFitRegression powerFitRegression; powerFitRegression.fit( filteredTimeSteps, filteredValues ); - std::vector predictedValues = powerFitRegression.predict( timeStepsD ); - return { timeSteps, predictedValues, generateRegressionText( powerFitRegression ) }; + std::vector predictedValues = powerFitRegression.predict( filteredTimeSteps ); + return { convertToTimeT( filteredTimeSteps ), predictedValues, generateRegressionText( powerFitRegression ) }; + } + else if ( m_regressionType == RegressionType::EXPONENTIAL ) + { + auto [filteredTimeSteps, filteredValues] = filterValues( timeStepsD, values ); + regression::ExponentialRegression exponentialRegression; + exponentialRegression.fit( filteredTimeSteps, filteredValues ); + std::vector predictedValues = exponentialRegression.predict( filteredTimeSteps ); + return { convertToTimeT( filteredTimeSteps ), predictedValues, generateRegressionText( exponentialRegression ) }; + } + else if ( m_regressionType == RegressionType::LOGARITHMIC ) + { + auto [filteredTimeSteps, filteredValues] = filterValues( timeStepsD, values ); + regression::LogarithmicRegression logarithmicRegression; + logarithmicRegression.fit( filteredTimeSteps, filteredValues ); + std::vector predictedValues = logarithmicRegression.predict( filteredTimeSteps ); + return { convertToTimeT( filteredTimeSteps ), predictedValues, generateRegressionText( logarithmicRegression ) }; + } + else if ( m_regressionType == RegressionType::LOGISTIC ) + { + regression::LogisticRegression logisticRegression; + logisticRegression.fit( timeStepsD, values ); + std::vector predictedValues = logisticRegression.predict( timeStepsD ); + return { timeSteps, predictedValues, generateRegressionText( logisticRegression ) }; } return { timeSteps, values, "" }; @@ -315,3 +355,30 @@ QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regress return QString( "y = %1 + x%2" ).arg( formatDouble( reg.scale() ) ).arg( formatDouble( reg.exponent() ) ) + QString( "
R2 = %1" ).arg( reg.r2() ); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::ExponentialRegression& reg ) +{ + return QString( "y = %1 * e%2x" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) + + QString( "
R2 = %1" ).arg( reg.r2() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LogarithmicRegression& reg ) +{ + return QString( "y = %1 + %2 * ln(x)" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) + + QString( "
R2 = %1" ).arg( reg.r2() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LogisticRegression& reg ) +{ + // TODO: Display more parameters here. + return ""; +} diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.h index c4bae4d5c1..75f08a52c7 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryRegressionAnalysisCurve.h @@ -30,7 +30,10 @@ namespace regression { +class ExponentialRegression; class LinearRegression; +class LogarithmicRegression; +class LogisticRegression; class PolynominalRegression; class PowerFitRegression; } // namespace regression @@ -48,7 +51,10 @@ public: { LINEAR, POLYNOMINAL, - POWER_FIT + POWER_FIT, + EXPONENTIAL, + LOGARITHMIC, + LOGISTIC }; RimSummaryRegressionAnalysisCurve(); @@ -79,6 +85,9 @@ private: static QString generateRegressionText( const regression::LinearRegression& reg ); static QString generateRegressionText( const regression::PolynominalRegression& reg ); static QString generateRegressionText( const regression::PowerFitRegression& reg ); + static QString generateRegressionText( const regression::LogarithmicRegression& reg ); + static QString generateRegressionText( const regression::ExponentialRegression& reg ); + static QString generateRegressionText( const regression::LogisticRegression& reg ); static QString formatDouble( double v ); diff --git a/ThirdParty/regression-analysis b/ThirdParty/regression-analysis index 8cb0644ae6..34bfe0f1ea 160000 --- a/ThirdParty/regression-analysis +++ b/ThirdParty/regression-analysis @@ -1 +1 @@ -Subproject commit 8cb0644ae6983f4b69568164a595e2b287bc04ee +Subproject commit 34bfe0f1eab0c8946ae5b988a39f7a2884508851