2017-10-12 00:30:37 -05:00
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
2017-10-23 07:27:04 -05:00
# include "RimSummaryCalculation.h"
2017-10-12 00:30:37 -05:00
2017-10-13 05:22:35 -05:00
# include "expressionparser/ExpressionParser.h"
2017-10-16 15:04:00 -05:00
# include "RiaSummaryCurveDefinition.h"
2017-10-20 03:20:53 -05:00
# include "RiaSummaryTools.h"
2017-10-16 15:04:00 -05:00
2017-10-20 03:20:53 -05:00
# include "RimProject.h"
2017-10-23 07:42:38 -05:00
# include "RimSummaryCalculationCollection.h"
# include "RimSummaryCalculationVariable.h"
2017-10-16 15:04:00 -05:00
# include "RimSummaryCurve.h"
2017-10-20 03:20:53 -05:00
# include "RimSummaryPlot.h"
# include "RimSummaryPlotCollection.h"
2017-10-12 00:30:37 -05:00
2017-10-13 05:22:35 -05:00
# include "cafPdmUiTextEditor.h"
2017-10-23 06:31:57 -05:00
# include <QMessageBox>
2017-10-13 07:39:30 -05:00
# include <algorithm>
2017-10-13 05:22:35 -05:00
2017-10-23 07:42:38 -05:00
CAF_PDM_SOURCE_INIT ( RimSummaryCalculation , " RimSummaryCalculation " ) ;
2017-10-12 00:30:37 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
RimSummaryCalculation : : RimSummaryCalculation ( )
2017-10-12 00:30:37 -05:00
{
2017-10-23 07:42:38 -05:00
CAF_PDM_InitObject ( " RimSummaryCalculation " , " :/octave.png " , " Calculation " , " " ) ;
2017-10-12 00:30:37 -05:00
2017-10-13 05:22:35 -05:00
CAF_PDM_InitFieldNoDefault ( & m_description , " Description " , " Description " , " " , " " , " " ) ;
m_description . uiCapability ( ) - > setUiReadOnly ( true ) ;
2017-10-24 02:57:32 -05:00
CAF_PDM_InitField ( & m_expression , " Expression " , QString ( " variableName := a " ) , " Expression " , " " , " " , " " ) ;
2017-10-13 05:22:35 -05:00
m_expression . uiCapability ( ) - > setUiEditorTypeName ( caf : : PdmUiTextEditor : : uiEditorTypeName ( ) ) ;
CAF_PDM_InitFieldNoDefault ( & m_variables , " Variables " , " Variables " , " " , " " , " " ) ;
2017-10-12 00:30:37 -05:00
CAF_PDM_InitFieldNoDefault ( & m_calculatedValues , " CalculatedValues " , " Calculated Values " , " " , " " , " " ) ;
2017-10-18 01:20:21 -05:00
CAF_PDM_InitFieldNoDefault ( & m_timesteps , " TimeSteps " , " Time Steps " , " " , " " , " " ) ;
2017-10-12 00:30:37 -05:00
}
2017-10-13 05:22:35 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
void RimSummaryCalculation : : setDescription ( const QString & description )
2017-10-13 05:22:35 -05:00
{
m_description = description ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
QString RimSummaryCalculation : : description ( ) const
2017-10-13 05:22:35 -05:00
{
return m_description ;
}
2017-10-12 00:30:37 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
caf : : PdmChildArrayFieldHandle * RimSummaryCalculation : : variables ( )
2017-10-12 00:30:37 -05:00
{
return & m_variables ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-24 02:57:32 -05:00
RimSummaryCalculationVariable * RimSummaryCalculation : : addVariable ( const QString & name )
2017-10-12 00:30:37 -05:00
{
2017-10-23 07:42:38 -05:00
RimSummaryCalculationVariable * v = new RimSummaryCalculationVariable ;
2017-10-24 02:57:32 -05:00
v - > setName ( name ) ;
2017-10-12 00:30:37 -05:00
m_variables . push_back ( v ) ;
return v ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:42:38 -05:00
void RimSummaryCalculation : : deleteVariable ( RimSummaryCalculationVariable * calcVariable )
2017-10-12 00:30:37 -05:00
{
m_variables . removeChildObject ( calcVariable ) ;
delete calcVariable ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
const std : : vector < double > & RimSummaryCalculation : : values ( ) const
2017-10-12 00:30:37 -05:00
{
return m_calculatedValues ( ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
const std : : vector < time_t > & RimSummaryCalculation : : timeSteps ( ) const
2017-10-18 01:20:21 -05:00
{
return m_timesteps ( ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
caf : : PdmFieldHandle * RimSummaryCalculation : : userDescriptionField ( )
2017-10-13 05:22:35 -05:00
{
return & m_description ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
bool RimSummaryCalculation : : parseExpression ( )
2017-10-13 05:22:35 -05:00
{
2017-10-23 07:27:04 -05:00
QString leftHandSideVariableName = RimSummaryCalculation : : findLeftHandSide ( m_expression ) ;
2017-10-23 06:31:57 -05:00
if ( leftHandSideVariableName . isEmpty ( ) )
{
QMessageBox : : warning ( nullptr , " Expression Parser " , " Failed to detect left hand side of equation " ) ;
return false ;
}
2017-10-13 05:22:35 -05:00
std : : vector < QString > variableNames = ExpressionParser : : detectReferencedVariables ( m_expression ) ;
2017-10-23 06:45:29 -05:00
if ( variableNames . size ( ) < 1 )
{
QMessageBox : : warning ( nullptr , " Expression Parser " , " Failed to detect any variable names " ) ;
return false ;
}
2017-10-13 05:22:35 -05:00
// Remove variables not present in expression
{
2017-10-23 07:42:38 -05:00
std : : vector < RimSummaryCalculationVariable * > toBeDeleted ;
for ( RimSummaryCalculationVariable * v : m_variables )
2017-10-13 05:22:35 -05:00
{
if ( std : : find ( variableNames . begin ( ) , variableNames . end ( ) , v - > name ( ) ) = = variableNames . end ( ) )
{
toBeDeleted . push_back ( v ) ;
}
if ( leftHandSideVariableName = = v - > name ( ) )
{
toBeDeleted . push_back ( v ) ;
}
}
2017-10-23 07:42:38 -05:00
for ( RimSummaryCalculationVariable * v : toBeDeleted )
2017-10-13 05:22:35 -05:00
{
deleteVariable ( v ) ;
}
}
for ( auto variableName : variableNames )
{
if ( leftHandSideVariableName ! = variableName )
{
if ( ! findByName ( variableName ) )
{
2017-10-24 02:57:32 -05:00
this - > addVariable ( variableName ) ;
2017-10-13 05:22:35 -05:00
}
}
}
2017-10-20 03:20:53 -05:00
m_description = buildCalculationName ( ) ;
2017-10-13 07:33:26 -05:00
2017-10-13 05:22:35 -05:00
return true ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
bool RimSummaryCalculation : : calculate ( )
2017-10-12 00:30:37 -05:00
{
2017-10-23 07:27:04 -05:00
QString leftHandSideVariableName = RimSummaryCalculation : : findLeftHandSide ( m_expression ) ;
2017-10-13 05:22:35 -05:00
ExpressionParser parser ;
2017-10-16 15:04:00 -05:00
std : : vector < std : : vector < double > > variableValues ;
variableValues . resize ( m_variables . size ( ) ) ;
2017-10-18 04:18:43 -05:00
std : : vector < time_t > sourceTimeSteps ;
2017-10-13 05:22:35 -05:00
size_t itemCount = 0 ;
2017-10-16 15:04:00 -05:00
for ( size_t i = 0 ; i < m_variables . size ( ) ; i + + )
2017-10-13 05:22:35 -05:00
{
2017-10-23 07:42:38 -05:00
RimSummaryCalculationVariable * v = m_variables [ i ] ;
2017-10-16 15:04:00 -05:00
if ( ! v - > summaryCase ( ) )
{
2017-10-23 06:45:29 -05:00
QMessageBox : : warning ( nullptr , " Expression Parser " , QString ( " No summary case defined for variable : %1 " ) . arg ( v - > name ( ) ) ) ;
2017-10-16 15:04:00 -05:00
return false ;
}
if ( ! v - > summaryAddress ( ) )
{
2017-10-23 06:45:29 -05:00
QMessageBox : : warning ( nullptr , " Expression Parser " , QString ( " No summary address defined for variable : %1 " ) . arg ( v - > name ( ) ) ) ;
2017-10-16 15:04:00 -05:00
return false ;
}
RimSummaryAddress * sumAdr = v - > summaryAddress ( ) ;
RiaSummaryCurveDefinition curveDef ( v - > summaryCase ( ) , v - > summaryAddress ( ) - > address ( ) ) ;
std : : vector < double > & curveValues = variableValues [ i ] ;
RiaSummaryCurveDefinition : : resultValues ( curveDef , & curveValues ) ;
2017-10-18 04:18:43 -05:00
if ( sourceTimeSteps . size ( ) = = 0 )
{
sourceTimeSteps = RiaSummaryCurveDefinition : : timeSteps ( curveDef ) ;
}
2017-10-16 15:04:00 -05:00
if ( itemCount = = 0 )
{
itemCount = curveValues . size ( ) ;
}
else
{
if ( itemCount ! = curveValues . size ( ) )
{
2017-10-23 06:45:29 -05:00
QMessageBox : : warning ( nullptr , " Expression Parser " , QString ( " Detected varying number of time steps in input vectors. Only vectors with identical number of time steps is supported. " ) ) ;
2017-10-16 15:04:00 -05:00
return false ;
}
}
parser . assignVector ( v - > name ( ) , curveValues ) ;
2017-10-13 05:22:35 -05:00
}
if ( itemCount = = 0 )
{
2017-10-23 06:45:29 -05:00
QMessageBox : : warning ( nullptr , " Expression Parser " , QString ( " Detected zero time steps in input vectors, which is not supported. " ) ) ;
2017-10-13 05:22:35 -05:00
return false ;
}
m_calculatedValues . v ( ) . resize ( itemCount ) ;
parser . assignVector ( leftHandSideVariableName , m_calculatedValues . v ( ) ) ;
QString errorText ;
bool evaluatedOk = parser . evaluate ( m_expression , & errorText ) ;
if ( evaluatedOk )
{
2017-10-18 04:18:43 -05:00
// Copy time vector from source
m_timesteps = sourceTimeSteps ;
2017-10-13 05:22:35 -05:00
}
else
{
2017-10-23 06:45:29 -05:00
QString s = " The following error message was received from the parser library : \n \n " ;
s + = errorText ;
QMessageBox : : warning ( nullptr , " Expression Parser " , s ) ;
2017-10-13 05:22:35 -05:00
}
return evaluatedOk ;
}
//--------------------------------------------------------------------------------------------------
/// Find the last assignment using := and interpret the text before the := as LHS
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
QString RimSummaryCalculation : : findLeftHandSide ( const QString & expresion )
2017-10-13 05:22:35 -05:00
{
2017-10-23 06:11:38 -05:00
int index = expresion . lastIndexOf ( " := " ) ;
2017-10-13 05:22:35 -05:00
if ( index > 0 )
{
2017-10-23 06:11:38 -05:00
QString s = expresion . left ( index ) . simplified ( ) ;
QStringList words = s . split ( " " ) ;
if ( words . size ( ) > 0 )
{
return words . back ( ) ;
}
2017-10-13 05:22:35 -05:00
}
return " " ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:42:38 -05:00
RimSummaryCalculationVariable * RimSummaryCalculation : : findByName ( const QString & name ) const
2017-10-13 05:22:35 -05:00
{
2017-10-23 07:42:38 -05:00
for ( RimSummaryCalculationVariable * v : m_variables )
2017-10-13 05:22:35 -05:00
{
if ( v - > name ( ) = = name )
{
return v ;
}
}
return nullptr ;
2017-10-12 00:30:37 -05:00
}
2017-10-13 07:33:26 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
QString RimSummaryCalculation : : buildCalculationName ( ) const
2017-10-13 07:33:26 -05:00
{
QString name = " Default Calculation Name " ;
2017-10-23 07:27:04 -05:00
QString lhs = RimSummaryCalculation : : findLeftHandSide ( m_expression ) ;
2017-10-13 07:33:26 -05:00
if ( ! lhs . isEmpty ( ) )
{
name = lhs ;
name + = " ( " ;
2017-10-23 07:42:38 -05:00
for ( RimSummaryCalculationVariable * v : m_variables )
2017-10-13 07:33:26 -05:00
{
name + = v - > summaryAddressDisplayString ( ) ;
if ( v ! = m_variables [ m_variables . size ( ) - 1 ] )
{
name + = " , " ;
}
}
name + = " ) " ;
}
return name ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-23 07:27:04 -05:00
void RimSummaryCalculation : : updateDependentCurvesAndPlots ( )
2017-10-13 07:33:26 -05:00
{
2017-10-23 07:42:38 -05:00
RimSummaryCalculationCollection * calcColl = nullptr ;
2017-10-20 03:20:53 -05:00
this - > firstAncestorOrThisOfTypeAsserted ( calcColl ) ;
calcColl - > rebuildCaseMetaData ( ) ;
RimSummaryPlotCollection * summaryPlotCollection = RiaSummaryTools : : summaryPlotCollection ( ) ;
for ( RimSummaryPlot * sumPlot : summaryPlotCollection - > summaryPlots ( ) )
{
bool plotContainsCalculatedCurves = false ;
for ( RimSummaryCurve * sumCurve : sumPlot - > summaryCurves ( ) )
{
if ( sumCurve - > summaryAddress ( ) . category ( ) = = RifEclipseSummaryAddress : : SUMMARY_CALCULATED )
{
sumCurve - > updateConnectedEditors ( ) ;
plotContainsCalculatedCurves = true ;
}
}
if ( plotContainsCalculatedCurves )
{
sumPlot - > loadDataAndUpdate ( ) ;
}
}
2017-10-13 07:33:26 -05:00
}