From be65d2ea3b03d606218c45230866a2c311dc4527 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 30 Jan 2024 15:10:26 +0100 Subject: [PATCH 1/4] Display decline curve data in text dialog --- .../Summary/RimSummaryDeclineCurve.cpp | 142 ++++++++++++++++++ .../Summary/RimSummaryDeclineCurve.h | 10 ++ 2 files changed, 152 insertions(+) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp index 4576cac93d..f74386fe97 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp @@ -22,14 +22,18 @@ #include "RiaSummaryTools.h" #include "RiaTimeTTools.h" +#include "RifSummaryReaderInterface.h" + #include "RigDeclineCurveCalculator.h" +#include "RimSummaryCase.h" #include "RimSummaryPlot.h" #include "RimTimeAxisAnnotation.h" #include "cafPdmUiDoubleSliderEditor.h" #include "cafPdmUiLineEditor.h" #include "cafPdmUiSliderEditor.h" +#include "cafPdmUiTextEditor.h" #include @@ -68,6 +72,9 @@ RimSummaryDeclineCurve::RimSummaryDeclineCurve() m_maxTimeSliderPosition.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_showTimeSelectionInPlot, "ShowTimeSelectionInPlot", true, "Show In Plot" ); + + CAF_PDM_InitField( &m_expressionText, "ExpressionText", QString(), "Expression" ); + m_expressionText.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() ); } //-------------------------------------------------------------------------------------------------- @@ -305,6 +312,129 @@ std::pair RimSummaryDeclineCurve::selectedTimeStepRange() const return { selectedMin, selectedMax }; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryDeclineCurve::updateExpressionText() +{ + auto [minTimeStep, maxTimeStep] = selectedTimeStepRange(); + + auto a = curveParameters( RimSummaryCurve::valuesY(), + RimSummaryCurve::timeStepsY(), + minTimeStep, + maxTimeStep, + RiaSummaryTools::hasAccumulatedData( summaryAddressY() ) ); + + QString text; + + for ( auto [key, value] : a ) + { + text += QString( "%1 - %2\n" ).arg( QString::fromStdString( key ) ).arg( value ); + } + + m_expressionText = text; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map RimSummaryDeclineCurve::curveParameters( const std::vector& values, + const std::vector& timeSteps, + time_t minTimeStep, + time_t maxTimeStep, + bool isAccumulatedResult ) const +{ + if ( values.empty() || timeSteps.empty() ) return {}; + + // Use only the values inside the range specified + auto [timeStepsInRange, valuesInRange] = getInRangeValues( timeSteps, values, minTimeStep, maxTimeStep ); + + if ( timeStepsInRange.empty() || valuesInRange.empty() ) return {}; + + auto [initialProductionRate, initialDeclineRate] = + computeInitialProductionAndDeclineRate( valuesInRange, timeStepsInRange, isAccumulatedResult ); + if ( std::isinf( initialProductionRate ) || std::isnan( initialProductionRate ) || std::isinf( initialDeclineRate ) || + std::isnan( initialDeclineRate ) ) + { + return {}; + } + + std::map parameters; + parameters["InitialProductionRate"] = initialProductionRate; + parameters["InitialDeclineRate"] = initialDeclineRate; + parameters["BFactor"] = m_hyperbolicDeclineConstant; + + auto timeToExtractValues = timeStepsInRange.back(); + + auto computeValue = []( const RifSummaryReaderInterface* reader, + const RifEclipseSummaryAddress& curveAddress, + time_t timeToExtractValues, + const std::string& vectorPostFix ) -> std::pair + { + auto invalidReturnValue = std::make_pair( "", 0.0 ); + + if ( !reader ) return invalidReturnValue; + + auto vectorName = curveAddress.vectorName(); + if ( !vectorName.empty() ) + { + auto otherVectorName = vectorName.substr( 0, 1 ) + vectorPostFix; + auto otherAdr = curveAddress; + otherAdr.setVectorName( otherVectorName ); + + if ( reader->hasAddress( otherAdr ) ) + { + auto timeSteps = reader->timeSteps( otherAdr ); + + size_t stepIndex = std::numeric_limits::max(); + for ( size_t i = 0; i < timeSteps.size(); ++i ) + { + if ( timeSteps[i] == timeToExtractValues ) + { + stepIndex = i; + break; + } + } + + if ( stepIndex != std::numeric_limits::max() ) + { + auto [isOk, values] = reader->values( otherAdr ); + if ( isOk ) + { + if ( stepIndex < values.size() ) + { + return { otherVectorName, values[stepIndex] }; + } + } + } + } + } + + return invalidReturnValue; + }; + + if ( summaryCaseY() ) + { + RifSummaryReaderInterface* reader = summaryCaseY()->summaryReader(); + + auto adr = summaryAddressY(); + + auto [liquidVectorName, liquidRateValue] = computeValue( reader, adr, timeToExtractValues, "LPR" ); + if ( !liquidVectorName.empty() ) + { + parameters["LiquidRate (" + liquidVectorName + ")"] = liquidRateValue; + } + + auto [gorVectorName, gorValue] = computeValue( reader, adr, timeToExtractValues, "GOR" ); + if ( !gorVectorName.empty() ) + { + parameters["Gas-Oil-Ratio (" + gorVectorName + ")"] = gorValue; + } + } + + return parameters; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -357,6 +487,8 @@ void RimSummaryDeclineCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiO declineCurveGroup->add( &m_hyperbolicDeclineConstant ); } + declineCurveGroup->add( &m_expressionText ); + caf::PdmUiGroup* timeSelectionGroup = uiOrdering.addNewGroup( "Time Selection" ); timeSelectionGroup->add( &m_minTimeSliderPosition ); timeSelectionGroup->add( &m_maxTimeSliderPosition ); @@ -469,6 +601,16 @@ void RimSummaryDeclineCurve::updateTimeAnnotations() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryDeclineCurve::onLoadDataAndUpdate( bool updateParentPlot ) +{ + RimSummaryCurve::onLoadDataAndUpdate( updateParentPlot ); + + updateExpressionText(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h index 35e2b6aa38..649142caef 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h @@ -58,6 +58,7 @@ class RimSummaryDeclineCurve : public RimSummaryCurve protected: void updateTimeAnnotations() override; + void onLoadDataAndUpdate( bool updateParentPlot ) override; private: QString createCurveAutoName() override; @@ -94,11 +95,20 @@ class RimSummaryDeclineCurve : public RimSummaryCurve std::pair fullTimeStepRange() const; std::pair selectedTimeStepRange() const; + void updateExpressionText(); + std::map curveParameters( const std::vector& values, + const std::vector& timeSteps, + time_t minTimeStep, + time_t maxTimeStep, + bool isAccumulatedResult ) const; + private: caf::PdmField> m_declineCurveType; caf::PdmField m_predictionYears; caf::PdmField m_hyperbolicDeclineConstant; + caf::PdmField m_expressionText; + // Time step range defined in the range [0..100] as time_t can hold values that do not fit into int used by QSpinBox caf::PdmField m_minTimeSliderPosition; caf::PdmField m_maxTimeSliderPosition; From 6fc3581514fbaaca909253c77df6772748edcd3d Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 30 Jan 2024 15:40:52 +0100 Subject: [PATCH 2/4] Create htmlTable from cell texts --- .../Application/Tools/RiaTextStringTools.cpp | 24 +++++++++++++++++++ .../Application/Tools/RiaTextStringTools.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/ApplicationLibCode/Application/Tools/RiaTextStringTools.cpp b/ApplicationLibCode/Application/Tools/RiaTextStringTools.cpp index 7822d9e770..c6eff64415 100644 --- a/ApplicationLibCode/Application/Tools/RiaTextStringTools.cpp +++ b/ApplicationLibCode/Application/Tools/RiaTextStringTools.cpp @@ -158,6 +158,30 @@ QString RiaTextStringTools::replaceTemplateTextWithValues( const QString& templa return resolvedText; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaTextStringTools::createHtmlTable( const std::vector>& tableCellContent ) +{ + QString htmlTable; + + htmlTable += "\n"; + + for ( const auto& row : tableCellContent ) + { + htmlTable += "\n"; + for ( const auto& cell : row ) + { + htmlTable += "\n"; + } + htmlTable += "\n"; + } + + htmlTable += "
" + cell + "
\n"; + + return htmlTable; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Application/Tools/RiaTextStringTools.h b/ApplicationLibCode/Application/Tools/RiaTextStringTools.h index a3b726273a..5fb182dd95 100644 --- a/ApplicationLibCode/Application/Tools/RiaTextStringTools.h +++ b/ApplicationLibCode/Application/Tools/RiaTextStringTools.h @@ -39,6 +39,8 @@ QStringList splitSkipEmptyParts( const QString& text, const QRegExp& regExp ); QString replaceTemplateTextWithValues( const QString& templateText, const std::map& valueMap ); +QString createHtmlTable( const std::vector>& tableCellContent ); + } // namespace RiaTextStringTools //-------------------------------------------------------------------------------------------------- From feafb89d642f8aa7b52c4aa55a4ab5c9566d5215 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 30 Jan 2024 15:42:01 +0100 Subject: [PATCH 3/4] Show values as text --- .../Summary/RimSummaryDeclineCurve.cpp | 54 ++++++++++++------- .../Summary/RimSummaryDeclineCurve.h | 12 ++--- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp index f74386fe97..a39dd19ce1 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp @@ -20,6 +20,7 @@ #include "RiaQDateTimeTools.h" #include "RiaSummaryTools.h" +#include "RiaTextStringTools.h" #include "RiaTimeTTools.h" #include "RifSummaryReaderInterface.h" @@ -319,30 +320,35 @@ void RimSummaryDeclineCurve::updateExpressionText() { auto [minTimeStep, maxTimeStep] = selectedTimeStepRange(); - auto a = curveParameters( RimSummaryCurve::valuesY(), - RimSummaryCurve::timeStepsY(), - minTimeStep, - maxTimeStep, - RiaSummaryTools::hasAccumulatedData( summaryAddressY() ) ); + auto parameters = curveParameters( RimSummaryCurve::valuesY(), + RimSummaryCurve::timeStepsY(), + minTimeStep, + maxTimeStep, + RiaSummaryTools::hasAccumulatedData( summaryAddressY() ) ); - QString text; + std::vector> text; - for ( auto [key, value] : a ) + for ( auto [key, value] : parameters ) { - text += QString( "%1 - %2\n" ).arg( QString::fromStdString( key ) ).arg( value ); + auto keyString = QString::fromStdString( key ); + auto valueString = QString::number( value ); + + text.push_back( { keyString, valueString } ); } - m_expressionText = text; + QString htmlTable = RiaTextStringTools::createHtmlTable( text ); + + m_expressionText = htmlTable; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::map RimSummaryDeclineCurve::curveParameters( const std::vector& values, - const std::vector& timeSteps, - time_t minTimeStep, - time_t maxTimeStep, - bool isAccumulatedResult ) const +std::vector> RimSummaryDeclineCurve::curveParameters( const std::vector& values, + const std::vector& timeSteps, + time_t minTimeStep, + time_t maxTimeStep, + bool isAccumulatedResult ) const { if ( values.empty() || timeSteps.empty() ) return {}; @@ -359,10 +365,10 @@ std::map RimSummaryDeclineCurve::curveParameters( const std return {}; } - std::map parameters; - parameters["InitialProductionRate"] = initialProductionRate; - parameters["InitialDeclineRate"] = initialDeclineRate; - parameters["BFactor"] = m_hyperbolicDeclineConstant; + std::vector> parameters; + parameters.push_back( { "InitialProductionRate", initialProductionRate } ); + parameters.push_back( { "InitialDeclineRate", initialDeclineRate } ); + parameters.push_back( { "BFactor", m_hyperbolicDeclineConstant } ); auto timeToExtractValues = timeStepsInRange.back(); @@ -422,13 +428,13 @@ std::map RimSummaryDeclineCurve::curveParameters( const std auto [liquidVectorName, liquidRateValue] = computeValue( reader, adr, timeToExtractValues, "LPR" ); if ( !liquidVectorName.empty() ) { - parameters["LiquidRate (" + liquidVectorName + ")"] = liquidRateValue; + parameters.push_back( { "LiquidRate (" + liquidVectorName + ")", liquidRateValue } ); } auto [gorVectorName, gorValue] = computeValue( reader, adr, timeToExtractValues, "GOR" ); if ( !gorVectorName.empty() ) { - parameters["Gas-Oil-Ratio (" + gorVectorName + ")"] = gorValue; + parameters.push_back( { "Gas-Oil-Ratio (" + gorVectorName + ")", gorValue } ); } } @@ -557,6 +563,14 @@ void RimSummaryDeclineCurve::defineEditorAttribute( const caf::PdmFieldHandle* f myAttr->m_showSpinBox = false; } } + + if ( field == &m_expressionText ) + { + if ( auto* attr = dynamic_cast( attribute ) ) + { + attr->textMode = caf::PdmUiTextEditorAttribute::HTML; + } + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h index 649142caef..625e16972d 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h @@ -95,12 +95,12 @@ class RimSummaryDeclineCurve : public RimSummaryCurve std::pair fullTimeStepRange() const; std::pair selectedTimeStepRange() const; - void updateExpressionText(); - std::map curveParameters( const std::vector& values, - const std::vector& timeSteps, - time_t minTimeStep, - time_t maxTimeStep, - bool isAccumulatedResult ) const; + void updateExpressionText(); + std::vector> curveParameters( const std::vector& values, + const std::vector& timeSteps, + time_t minTimeStep, + time_t maxTimeStep, + bool isAccumulatedResult ) const; private: caf::PdmField> m_declineCurveType; From c2150d040fec712fa1bfceb2732c47c2e2f34ab3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 30 Jan 2024 15:59:18 +0100 Subject: [PATCH 4/4] Include units --- .../Summary/RimSummaryDeclineCurve.cpp | 35 ++++++++++--------- .../Summary/RimSummaryDeclineCurve.h | 12 +++---- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp index a39dd19ce1..4e91367d28 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.cpp @@ -328,12 +328,13 @@ void RimSummaryDeclineCurve::updateExpressionText() std::vector> text; - for ( auto [key, value] : parameters ) + for ( auto [key, unit, value] : parameters ) { auto keyString = QString::fromStdString( key ); + auto unitString = QString::fromStdString( unit ); auto valueString = QString::number( value ); - text.push_back( { keyString, valueString } ); + text.push_back( { keyString, unitString, valueString } ); } QString htmlTable = RiaTextStringTools::createHtmlTable( text ); @@ -344,11 +345,11 @@ void RimSummaryDeclineCurve::updateExpressionText() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector> RimSummaryDeclineCurve::curveParameters( const std::vector& values, - const std::vector& timeSteps, - time_t minTimeStep, - time_t maxTimeStep, - bool isAccumulatedResult ) const +std::vector> RimSummaryDeclineCurve::curveParameters( const std::vector& values, + const std::vector& timeSteps, + time_t minTimeStep, + time_t maxTimeStep, + bool isAccumulatedResult ) const { if ( values.empty() || timeSteps.empty() ) return {}; @@ -357,18 +358,20 @@ std::vector> RimSummaryDeclineCurve::curveParamet if ( timeStepsInRange.empty() || valuesInRange.empty() ) return {}; - auto [initialProductionRate, initialDeclineRate] = + auto [initialProductionRate, initialDeclineRatePerSecond] = computeInitialProductionAndDeclineRate( valuesInRange, timeStepsInRange, isAccumulatedResult ); - if ( std::isinf( initialProductionRate ) || std::isnan( initialProductionRate ) || std::isinf( initialDeclineRate ) || - std::isnan( initialDeclineRate ) ) + if ( std::isinf( initialProductionRate ) || std::isnan( initialProductionRate ) || std::isinf( initialDeclineRatePerSecond ) || + std::isnan( initialDeclineRatePerSecond ) ) { return {}; } - std::vector> parameters; - parameters.push_back( { "InitialProductionRate", initialProductionRate } ); - parameters.push_back( { "InitialDeclineRate", initialDeclineRate } ); - parameters.push_back( { "BFactor", m_hyperbolicDeclineConstant } ); + auto initialDeclineRatePerYear = initialDeclineRatePerSecond * 60 * 24 * 365; + + std::vector> parameters; + parameters.push_back( { "Initial Production Rate", "SM3/STREAM DAY", initialProductionRate } ); + parameters.push_back( { "Initial Decline Rate", "FRACTION 1/YEAR", initialDeclineRatePerYear } ); + parameters.push_back( { "B Factor", "UNITLESS", m_hyperbolicDeclineConstant } ); auto timeToExtractValues = timeStepsInRange.back(); @@ -428,13 +431,13 @@ std::vector> RimSummaryDeclineCurve::curveParamet auto [liquidVectorName, liquidRateValue] = computeValue( reader, adr, timeToExtractValues, "LPR" ); if ( !liquidVectorName.empty() ) { - parameters.push_back( { "LiquidRate (" + liquidVectorName + ")", liquidRateValue } ); + parameters.push_back( { "LiquidRate (" + liquidVectorName + ")", "SM3/STREAM DAY", liquidRateValue } ); } auto [gorVectorName, gorValue] = computeValue( reader, adr, timeToExtractValues, "GOR" ); if ( !gorVectorName.empty() ) { - parameters.push_back( { "Gas-Oil-Ratio (" + gorVectorName + ")", gorValue } ); + parameters.push_back( { "Gas-Oil-Ratio (" + gorVectorName + ")", "SM3/SM3", gorValue } ); } } diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h index 625e16972d..ab9ded4154 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryDeclineCurve.h @@ -95,12 +95,12 @@ class RimSummaryDeclineCurve : public RimSummaryCurve std::pair fullTimeStepRange() const; std::pair selectedTimeStepRange() const; - void updateExpressionText(); - std::vector> curveParameters( const std::vector& values, - const std::vector& timeSteps, - time_t minTimeStep, - time_t maxTimeStep, - bool isAccumulatedResult ) const; + void updateExpressionText(); + std::vector> curveParameters( const std::vector& values, + const std::vector& timeSteps, + time_t minTimeStep, + time_t maxTimeStep, + bool isAccumulatedResult ) const; private: caf::PdmField> m_declineCurveType;