#1977 Curve Calculator : Trigger parsing and evaluation of expression

This commit is contained in:
Magne Sjaastad 2017-10-13 12:22:35 +02:00
parent a3cd62d315
commit 9d0e59c60f
7 changed files with 246 additions and 12 deletions

View File

@ -24,9 +24,9 @@
#include "RimCalculationCollection.h"
#include "RimProject.h"
#include "cafPdmUiTreeSelectionEditor.h"
#include "cafPdmUiListEditor.h"
#include "cafPdmUiPushButtonEditor.h"
#include "cafPdmUiTreeSelectionEditor.h"
CAF_PDM_SOURCE_INIT(RicSummaryCurveCalculator, "RicSummaryCurveCalculator");
@ -49,6 +49,12 @@ RicSummaryCurveCalculator::RicSummaryCurveCalculator()
CAF_PDM_InitFieldNoDefault(&m_deleteCalculation, "DeleteCalculation", "Delete Calculation", "", "", "");
RicSummaryCurveCalculator::assignPushButtonEditor(&m_deleteCalculation);
CAF_PDM_InitFieldNoDefault(&m_parseExpression, "ParseExpression", "Parse", "", "", "");
RicSummaryCurveCalculator::assignPushButtonEditor(&m_parseExpression);
CAF_PDM_InitFieldNoDefault(&m_calculateExpression, "CalculateExpression", "Calculate", "", "", "");
RicSummaryCurveCalculator::assignPushButtonEditor(&m_calculateExpression);
CAF_PDM_InitFieldNoDefault(&m_newVariable, "NewVariable", "New Variable", "", "", "");
RicSummaryCurveCalculator::assignPushButtonEditor(&m_newVariable);
@ -106,6 +112,26 @@ void RicSummaryCurveCalculator::fieldChangedByUi(const caf::PdmFieldHandle* chan
this->updateConnectedEditors();
}
}
else if (changedField == &m_parseExpression)
{
m_parseExpression = false;
if (m_currentCalculation())
{
m_currentCalculation()->parseExpression();
this->updateConnectedEditors();
}
}
else if (changedField == &m_calculateExpression)
{
m_calculateExpression = false;
if (m_currentCalculation())
{
m_currentCalculation()->calculate();
}
}
else if (changedField == &m_newVariable)
{
m_newVariable = false;
@ -142,6 +168,9 @@ void RicSummaryCurveCalculator::defineUiOrdering(QString uiConfigName, caf::PdmU
m_currentCalculation->uiOrdering(uiConfigName, *group);
}
group->add(&m_parseExpression);
group->add(&m_calculateExpression);
group->add(&m_newVariable);
group->add(&m_deleteVariable);
}
@ -157,7 +186,7 @@ QList<caf::PdmOptionItemInfo> RicSummaryCurveCalculator::calculateValueOptions(c
{
for (auto c : calculationCollection()->calculations())
{
options.push_back(caf::PdmOptionItemInfo(c->name(), c));
options.push_back(caf::PdmOptionItemInfo(c->description(), c));
}
}
@ -223,4 +252,12 @@ void RicSummaryCurveCalculator::defineEditorAttribute(const caf::PdmFieldHandle*
{
RicSummaryCurveCalculator::assignPushButtonEditorText(attribute, "Delete Variable");
}
else if (&m_parseExpression == field)
{
RicSummaryCurveCalculator::assignPushButtonEditorText(attribute, "Parse Expression");
}
else if (&m_calculateExpression == field)
{
RicSummaryCurveCalculator::assignPushButtonEditorText(attribute, "Calculate");
}
}

View File

@ -64,4 +64,7 @@ private:
caf::PdmField<bool> m_newVariable;
caf::PdmField<bool> m_deleteVariable;
caf::PdmField<bool> m_parseExpression;
caf::PdmField<bool> m_calculateExpression;
};

View File

@ -18,8 +18,16 @@
#include "RimCalculation.h"
#include "expressionparser/ExpressionParser.h"
#include "RiaLogging.h"
#include "RimCalculationVariable.h"
#include "cafPdmUiTextEditor.h"
#include <numeric>
CAF_PDM_SOURCE_INIT(RimCalculation, "RimCalculation");
//--------------------------------------------------------------------------------------------------
@ -29,11 +37,32 @@ RimCalculation::RimCalculation()
{
CAF_PDM_InitObject("RimCalculation", ":/octave.png", "Calculation", "");
CAF_PDM_InitFieldNoDefault(&m_expression, "Expression", "Expression", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_variables, "Variables", "Variables", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_description, "Description", "Description", "", "", "");
m_description.uiCapability()->setUiReadOnly(true);
CAF_PDM_InitFieldNoDefault(&m_expression, "Expression", "Expression", "", "", "");
m_expression.uiCapability()->setUiEditorTypeName(caf::PdmUiTextEditor::uiEditorTypeName());
CAF_PDM_InitFieldNoDefault(&m_variables, "Variables", "Variables", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_calculatedValues, "CalculatedValues", "Calculated Values", "", "", "");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCalculation::setDescription(const QString& description)
{
m_description = description;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimCalculation::description() const
{
return m_description;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -74,7 +103,143 @@ const std::vector<double>& RimCalculation::values() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCalculation::setCalculatedValues(const std::vector<double>& values)
caf::PdmFieldHandle* RimCalculation::userDescriptionField()
{
m_calculatedValues = values;
return &m_description;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimCalculation::parseExpression()
{
QString leftHandSideVariableName = RimCalculation::findLeftHandSide(m_expression);
if (leftHandSideVariableName.isEmpty()) return false;
std::vector<QString> variableNames = ExpressionParser::detectReferencedVariables(m_expression);
// Remove variables not present in expression
{
std::vector<RimCalculationVariable*> toBeDeleted;
for (RimCalculationVariable* v : m_variables)
{
if (std::find(variableNames.begin(), variableNames.end(), v->name()) == variableNames.end())
{
toBeDeleted.push_back(v);
}
if (leftHandSideVariableName == v->name())
{
toBeDeleted.push_back(v);
}
}
for (RimCalculationVariable* v : toBeDeleted)
{
deleteVariable(v);
}
}
for (auto variableName : variableNames)
{
if (leftHandSideVariableName != variableName)
{
if (!findByName(variableName))
{
auto v = this->addVariable();
v->setName(variableName);
}
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimCalculation::calculate()
{
if (!parseExpression()) return false;
QString leftHandSideVariableName = RimCalculation::findLeftHandSide(m_expression);
ExpressionParser parser;
std::vector<double> a(10);
std::iota(a.begin(), a.end(), 0);
size_t itemCount = 0;
for (RimCalculationVariable* v : m_variables)
{
itemCount = a.size();
parser.assignVector(v->name(), a);
}
if (itemCount == 0)
{
RiaLogging::error("Not able to evaluate expression with no data.");
return false;
}
m_calculatedValues.v().resize(itemCount);
parser.assignVector(leftHandSideVariableName, m_calculatedValues.v());
QString errorText;
bool evaluatedOk = parser.evaluate(m_expression, &errorText);
if (evaluatedOk)
{
QString txt;
for (auto v : m_calculatedValues())
{
txt += QString::number(v);
txt += " ";
}
RiaLogging::info(txt);
}
else
{
RiaLogging::error(errorText);
}
return evaluatedOk;
}
//--------------------------------------------------------------------------------------------------
/// Find the last assignment using := and interpret the text before the := as LHS
//--------------------------------------------------------------------------------------------------
QString RimCalculation::findLeftHandSide(const QString& expresion)
{
QString exprWithSpace = expresion;
exprWithSpace.replace("\n", " ");
QStringList words = exprWithSpace.split(" ", QString::SkipEmptyParts);
int index = words.lastIndexOf(":=");
if (index > 0)
{
return words[index - 1];
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCalculationVariable* RimCalculation::findByName(const QString& name) const
{
for (RimCalculationVariable* v : m_variables)
{
if (v->name() == name)
{
return v;
}
}
return nullptr;
}

View File

@ -18,9 +18,9 @@
#pragma once
#include "RimNamedObject.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmObject.h"
#include "cafPdmField.h"
class RimCalculationVariable;
@ -28,21 +28,33 @@ class RimCalculationVariable;
///
///
//==================================================================================================
class RimCalculation : public RimNamedObject
class RimCalculation : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimCalculation();
void setDescription(const QString& description);
QString description() const;
caf::PdmChildArrayFieldHandle* variables();
RimCalculationVariable* addVariable();
void deleteVariable(RimCalculationVariable* calcVariable);
const std::vector<double>& values() const;
void setCalculatedValues(const std::vector<double>& values);
bool parseExpression();
bool calculate();
virtual caf::PdmFieldHandle* userDescriptionField() override;
private:
static QString findLeftHandSide(const QString& expresion);
RimCalculationVariable* findByName(const QString& name) const;
private:
caf::PdmField<QString> m_description;
caf::PdmField<QString> m_expression;
caf::PdmChildArrayField<RimCalculationVariable*> m_variables;

View File

@ -42,7 +42,7 @@ RimCalculationCollection::RimCalculationCollection()
RimCalculation* RimCalculationCollection::addCalculation()
{
RimCalculation* calculation = new RimCalculation;
calculation->setName(QString("Calculation %1").arg(m_calcuations.size()));
calculation->setDescription(QString("Calculation %1").arg(m_calcuations.size()));
m_calcuations.push_back(calculation);

View File

@ -54,6 +54,22 @@ RimCalculationVariable::RimCalculationVariable()
m_summaryAddress = new RimSummaryAddress;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimCalculationVariable::name() const
{
return m_name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCalculationVariable::setName(const QString& name)
{
m_name = name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -40,7 +40,8 @@ class RimCalculationVariable : public caf::PdmObject
public:
RimCalculationVariable();
QString name() const;
void setName(const QString& name);
private:
QString summaryAddressDisplayString() const;