From 7eb3e98bb2435f08abe4b59b6a0c887f1a445c26 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 7 Nov 2023 14:04:53 +0100 Subject: [PATCH] Optionally apply a grid calculation on all grids --- .../Commands/RicUserDefinedCalculatorUi.cpp | 5 + .../ProjectDataModel/RimGridCalculation.cpp | 268 ++++++++++++------ .../ProjectDataModel/RimGridCalculation.h | 10 +- .../RimGridCalculationCollection.cpp | 8 +- .../ProjectDataModel/RimResultSelectionUi.cpp | 3 +- .../RimUserDefinedCalculation.cpp | 8 + .../RimUserDefinedCalculation.h | 1 + .../RigCaseCellResultsData.cpp | 7 +- 8 files changed, 214 insertions(+), 96 deletions(-) diff --git a/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp b/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp index 16197bc80a..b15a97de31 100644 --- a/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp +++ b/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp @@ -205,6 +205,11 @@ bool RicUserDefinedCalculatorUi::calculate() const notifyCalculatedNameChanged( m_currentCalculation()->id(), currentCurveName ); } + if ( !m_currentCalculation()->preCalculate() ) + { + return false; + } + if ( !m_currentCalculation()->calculate() ) { return false; diff --git a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp index 330a94c65e..fefeec8f7e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.cpp @@ -19,12 +19,15 @@ #include "RimGridCalculation.h" #include "RiaDefines.h" +#include "RiaGuiApplication.h" #include "RiaLogging.h" #include "RiaPorosityModel.h" #include "RigActiveCellInfo.h" #include "RimEclipseCase.h" +#include "RimEclipseCaseTools.h" #include "RimEclipseCellColors.h" +#include "RimEclipseStatisticsCase.h" #include "RimEclipseView.h" #include "RimGridCalculationVariable.h" #include "RimProject.h" @@ -41,6 +44,8 @@ #include "expressionparser/ExpressionParser.h" +#include + CAF_PDM_SOURCE_INIT( RimGridCalculation, "RimGridCalculation" ); namespace caf @@ -65,9 +70,28 @@ RimGridCalculation::RimGridCalculation() CAF_PDM_InitFieldNoDefault( &m_defaultValueType, "DefaultValueType", "Non-visible Cell Value" ); CAF_PDM_InitField( &m_defaultValue, "DefaultValue", 0.0, "Custom Value" ); CAF_PDM_InitFieldNoDefault( &m_destinationCase, "DestinationCase", "Destination Case" ); + CAF_PDM_InitField( &m_allCases, "AllDestinationCase", false, "Apply to All Cases" ); CAF_PDM_InitField( &m_defaultPropertyVariableIndex, "DefaultPropertyVariableName", 0, "Property Variable Name" ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCalculation::preCalculate() const +{ + if ( RiaGuiApplication::isRunning() && m_allCases() ) + { + auto reply = QMessageBox::question( nullptr, + QString( "Grid Property Calculator" ), + QString( "Calculation will be executed on all grid model cases. Do you want to continue? " ), + QMessageBox::Yes | QMessageBox::No ); + + if ( reply == QMessageBox::No ) return false; + } + + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -87,12 +111,12 @@ bool RimGridCalculation::calculate() { QString leftHandSideVariableName = RimGridCalculation::findLeftHandSide( m_expression ); - RimEclipseCase* eclipseCase = outputEclipseCase(); - if ( !eclipseCase ) + if ( !m_destinationCase ) { RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", - QString( "No case found for calculation : %1" ).arg( leftHandSideVariableName ) ); + QString( "No destination case found for calculation : %1" ).arg( leftHandSideVariableName ) ); + return false; } @@ -105,7 +129,7 @@ bool RimGridCalculation::calculate() for ( auto variableCase : inputCases() ) { - if ( !eclipseCase->isGridSizeEqualTo( variableCase ) ) + if ( !m_destinationCase->isGridSizeEqualTo( variableCase ) ) { QString msg = "Detected IJK mismatch between input cases and destination case. All grid " "cases must have identical IJK sizes."; @@ -114,83 +138,127 @@ bool RimGridCalculation::calculate() } } - auto porosityModel = RiaDefines::PorosityModelType::MATRIX_MODEL; - - RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::GENERATED, leftHandSideVariableName ); + const bool isMultipleCasesPresent = outputEclipseCases().size() > 1; - if ( !eclipseCase->results( porosityModel )->ensureKnownResultLoaded( resAddr ) ) + if ( isMultipleCasesPresent ) { - bool needsToBeStored = false; - eclipseCase->results( porosityModel )->createResultEntry( resAddr, needsToBeStored ); + QString txt = "Starting calculation " + description() + " for " + QString::number( outputEclipseCases().size() ) + " cases."; + RiaLogging::info( txt ); } - eclipseCase->results( porosityModel )->clearScalarResult( resAddr ); - - // If an input grid is present, max time step count is zero. Make sure the time step count for the calculation is - // always 1 or more. - const size_t timeStepCount = std::max( size_t( 1 ), eclipseCase->results( porosityModel )->maxTimeStepCount() ); - - std::vector>* scalarResultFrames = - eclipseCase->results( porosityModel )->modifiableCellScalarResultTimesteps( resAddr ); - scalarResultFrames->resize( timeStepCount ); - - for ( size_t tsId = 0; tsId < timeStepCount; tsId++ ) + bool anyErrorsDetected = false; + for ( RimEclipseCase* outputEclipseCase : outputEclipseCases() ) { - std::vector> values; - for ( size_t i = 0; i < m_variables.size(); i++ ) + if ( !outputEclipseCase ) { - RimGridCalculationVariable* v = dynamic_cast( m_variables[i] ); - CAF_ASSERT( v != nullptr ); - values.push_back( getInputVectorForVariable( v, tsId, porosityModel, outputEclipseCase() ) ); + RiaLogging::errorInMessageBox( nullptr, + "Grid Property Calculator", + QString( "No case found for calculation : %1" ).arg( leftHandSideVariableName ) ); + anyErrorsDetected = true; + continue; } - ExpressionParser parser; - for ( size_t i = 0; i < m_variables.size(); i++ ) + auto porosityModel = RiaDefines::PorosityModelType::MATRIX_MODEL; + + RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::GENERATED, leftHandSideVariableName ); + + if ( !outputEclipseCase->results( porosityModel )->ensureKnownResultLoaded( resAddr ) ) { - RimGridCalculationVariable* v = dynamic_cast( m_variables[i] ); - CAF_ASSERT( v != nullptr ); - parser.assignVector( v->name(), values[i] ); + bool needsToBeStored = false; + outputEclipseCase->results( porosityModel )->createResultEntry( resAddr, needsToBeStored ); } - std::vector resultValues; - resultValues.resize( values[0].size() ); - parser.assignVector( leftHandSideVariableName, resultValues ); + outputEclipseCase->results( porosityModel )->clearScalarResult( resAddr ); - QString errorText; - bool evaluatedOk = parser.expandIfStatementsAndEvaluate( m_expression, &errorText ); + // If an input grid is present, max time step count is zero. Make sure the time step count for the calculation is + // always 1 or more. + const size_t timeStepCount = std::max( size_t( 1 ), outputEclipseCase->results( porosityModel )->maxTimeStepCount() ); - if ( evaluatedOk ) + std::vector>* scalarResultFrames = + outputEclipseCase->results( porosityModel )->modifiableCellScalarResultTimesteps( resAddr ); + scalarResultFrames->resize( timeStepCount ); + + for ( size_t tsId = 0; tsId < timeStepCount; tsId++ ) { - if ( m_cellFilterView() ) + std::vector> values; + for ( size_t i = 0; i < m_variables.size(); i++ ) + { + RimGridCalculationVariable* v = dynamic_cast( m_variables[i] ); + CAF_ASSERT( v != nullptr ); + values.push_back( getInputVectorForVariable( v, tsId, porosityModel, outputEclipseCase ) ); + } + + ExpressionParser parser; + for ( size_t i = 0; i < m_variables.size(); i++ ) { - filterResults( m_cellFilterView(), values, m_defaultValueType(), m_defaultValue(), resultValues, porosityModel, outputEclipseCase() ); + RimGridCalculationVariable* v = dynamic_cast( m_variables[i] ); + CAF_ASSERT( v != nullptr ); + parser.assignVector( v->name(), values[i] ); } - scalarResultFrames->at( tsId ) = resultValues; + std::vector resultValues; + resultValues.resize( values[0].size() ); + parser.assignVector( leftHandSideVariableName, resultValues ); + + QString errorText; + bool evaluatedOk = parser.expandIfStatementsAndEvaluate( m_expression, &errorText ); - m_isDirty = false; + if ( evaluatedOk ) + { + if ( m_cellFilterView() ) + { + filterResults( m_cellFilterView(), values, m_defaultValueType(), m_defaultValue(), resultValues, porosityModel, outputEclipseCase ); + } + + scalarResultFrames->at( tsId ) = resultValues; + + m_isDirty = false; + } + else + { + QString s = "The following error message was received from the parser library : \n\n"; + s += errorText; + + RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", s ); + return false; + } + + outputEclipseCase->updateResultAddressCollection(); } - else - { - QString s = "The following error message was received from the parser library : \n\n"; - s += errorText; - RiaLogging::errorInMessageBox( nullptr, "Grid Property Calculator", s ); - return false; + if ( isMultipleCasesPresent ) + { + QString txt = " " + outputEclipseCase->caseUserDescription(); + RiaLogging::info( txt ); } } - eclipseCase->updateResultAddressCollection(); + if ( isMultipleCasesPresent ) + { + QString txt = "Completed calculation " + description() + " for " + QString::number( outputEclipseCases().size() ) + " cases"; + RiaLogging::info( txt ); + } - return true; + return !anyErrorsDetected; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimEclipseCase* RimGridCalculation::outputEclipseCase() const +std::vector RimGridCalculation::outputEclipseCases() const { - return m_destinationCase; + if ( m_allCases ) + { + // Find all Eclipse cases suitable for grid calculations. This includes all single grid cases and source cases in a grid case group. + // Exclude the statistics cases, as it is not possible to use them in a grid calculations. + // + // Note that data read from file can be released from memory when statistics for a time step is calculated. See + // RimEclipseStatisticsCaseEvaluator::evaluateForResults() + + return RimEclipseCaseTools::allEclipseGridCases(); + } + + return { m_destinationCase }; } //-------------------------------------------------------------------------------------------------- @@ -230,6 +298,13 @@ void RimGridCalculation::defineUiOrdering( QString uiConfigName, caf::PdmUiOrder uiOrdering.add( &m_destinationCase ); + uiOrdering.add( &m_allCases ); + if ( !allSourceCasesAreEqualToDestinationCase() ) + { + m_allCases = false; + } + m_allCases.uiCapability()->setUiReadOnly( !allSourceCasesAreEqualToDestinationCase() ); + caf::PdmUiGroup* filterGroup = uiOrdering.addNewGroup( "Cell Filter" ); filterGroup->setCollapsedByDefault(); filterGroup->add( &m_cellFilterView ); @@ -278,27 +353,19 @@ QList RimGridCalculation::calculateValueOptions( const c } else if ( fieldNeedingOptions == &m_destinationCase ) { - if ( inputCases().empty() ) + RimEclipseCase* firstInputCase = nullptr; + + if ( !inputCases().empty() ) { - RimTools::eclipseCaseOptionItems( &options ); + firstInputCase = inputCases()[0]; } - else - { - RimEclipseCase* firstInputCase = inputCases()[0]; - RimProject* proj = RimProject::current(); - if ( proj ) - { - std::vector cases = proj->allGridCases(); - for ( RimCase* c : cases ) - { - auto* eclipseCase = dynamic_cast( c ); - if ( !eclipseCase ) continue; - if ( !firstInputCase->isGridSizeEqualTo( eclipseCase ) ) continue; + for ( auto eclipseCase : RimEclipseCaseTools::allEclipseGridCases() ) + { + if ( !eclipseCase ) continue; + if ( firstInputCase && !firstInputCase->isGridSizeEqualTo( eclipseCase ) ) continue; - options.push_back( caf::PdmOptionItemInfo( c->caseUserDescription(), c, false, c->uiIconProvider() ) ); - } - } + options.push_back( caf::PdmOptionItemInfo( eclipseCase->caseUserDescription(), eclipseCase, false, eclipseCase->uiIconProvider() ) ); } options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) ); @@ -350,6 +417,25 @@ void RimGridCalculation::onVariableUpdated( const SignalEmitter* emitter ) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCalculation::allSourceCasesAreEqualToDestinationCase() const +{ + if ( m_destinationCase() == nullptr ) return false; + + for ( const auto& variable : m_variables ) + { + auto gridVar = dynamic_cast( variable.p() ); + if ( gridVar ) + { + if ( gridVar->eclipseCase() != m_destinationCase() ) return false; + } + } + + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -368,6 +454,11 @@ std::vector RimGridCalculation::getInputVectorForVariable( RimGridCalcul RiaDefines::PorosityModelType porosityModel, RimEclipseCase* outputEclipseCase ) const { + if ( !outputEclipseCase ) return {}; + + const RigMainGrid* mainGrid = outputEclipseCase->mainGrid(); + if ( !mainGrid ) return {}; + int timeStep = v->timeStep(); auto resultCategoryType = v->resultCategoryType(); @@ -388,10 +479,13 @@ std::vector RimGridCalculation::getInputVectorForVariable( RimGridCalcul RigEclipseResultAddress resAddr( resultCategoryType, v->resultVariable() ); - auto mainGrid = v->eclipseCase()->mainGrid(); + auto eclipseCaseData = outputEclipseCase->eclipseCaseData(); + auto rigCaseCellResultsData = eclipseCaseData->results( porosityModel ); + if ( !rigCaseCellResultsData->ensureKnownResultLoaded( resAddr ) ) return {}; + size_t maxGridCount = mainGrid->gridCount(); - auto activeCellInfo = outputEclipseCase->eclipseCaseData()->activeCellInfo( porosityModel ); + auto activeCellInfo = eclipseCaseData->activeCellInfo( porosityModel ); size_t cellCount = activeCellInfo->reservoirActiveCellCount(); std::vector inputValues( cellCount ); @@ -400,7 +494,7 @@ std::vector RimGridCalculation::getInputVectorForVariable( RimGridCalcul auto grid = mainGrid->gridByIndex( gridIdx ); cvf::ref sourceResultAccessor = - RigResultAccessorFactory::createFromResultAddress( v->eclipseCase()->eclipseCaseData(), gridIdx, porosityModel, timeStepToUse, resAddr ); + RigResultAccessorFactory::createFromResultAddress( eclipseCaseData, gridIdx, porosityModel, timeStepToUse, resAddr ); #pragma omp parallel for for ( int localGridCellIdx = 0; localGridCellIdx < static_cast( grid->cellCount() ); localGridCellIdx++ ) @@ -503,10 +597,12 @@ void RimGridCalculation::filterResults( RimGridView* //-------------------------------------------------------------------------------------------------- void RimGridCalculation::updateDependentObjects() { - RimEclipseCase* eclipseCase = outputEclipseCase(); - if ( eclipseCase ) + for ( RimEclipseCase* eclipseCase : outputEclipseCases() ) { - RimReloadCaseTools::updateAll3dViews( eclipseCase ); + if ( eclipseCase ) + { + RimReloadCaseTools::updateAll3dViews( eclipseCase ); + } } } @@ -521,23 +617,25 @@ void RimGridCalculation::removeDependentObjects() RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::GENERATED, leftHandSideVariableName ); - RimEclipseCase* eclipseCase = outputEclipseCase(); - if ( eclipseCase ) + for ( RimEclipseCase* eclipseCase : outputEclipseCases() ) { - // Select "None" result if the result that is being removed were displayed in a view. - for ( auto v : eclipseCase->reservoirViews() ) + if ( eclipseCase ) { - if ( v->cellResult()->resultType() == resAddr.resultCatType() && v->cellResult()->resultVariable() == resAddr.resultName() ) + // Select "None" result if the result that is being removed were displayed in a view. + for ( auto v : eclipseCase->reservoirViews() ) { - v->cellResult()->setResultType( RiaDefines::ResultCatType::GENERATED ); - v->cellResult()->setResultVariable( "None" ); + if ( v->cellResult()->resultType() == resAddr.resultCatType() && v->cellResult()->resultVariable() == resAddr.resultName() ) + { + v->cellResult()->setResultType( RiaDefines::ResultCatType::GENERATED ); + v->cellResult()->setResultVariable( "None" ); + } } - } - eclipseCase->results( porosityModel )->clearScalarResult( resAddr ); - eclipseCase->results( porosityModel )->setRemovedTagOnGeneratedResult( resAddr ); + eclipseCase->results( porosityModel )->clearScalarResult( resAddr ); + eclipseCase->results( porosityModel )->setRemovedTagOnGeneratedResult( resAddr ); - RimReloadCaseTools::updateAll3dViews( eclipseCase ); + RimReloadCaseTools::updateAll3dViews( eclipseCase ); + } } } diff --git a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h index 87cfb999bb..9091ec359b 100644 --- a/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h +++ b/ApplicationLibCode/ProjectDataModel/RimGridCalculation.h @@ -47,12 +47,13 @@ class RimGridCalculation : public RimUserDefinedCalculation RimGridCalculation(); + bool preCalculate() const override; bool calculate() override; void updateDependentObjects() override; void removeDependentObjects() override; - RimEclipseCase* outputEclipseCase() const; - RigEclipseResultAddress outputAddress() const; + std::vector outputEclipseCases() const; + RigEclipseResultAddress outputAddress() const; std::vector inputCases() const; @@ -96,11 +97,14 @@ class RimGridCalculation : public RimUserDefinedCalculation private: void onVariableUpdated( const SignalEmitter* emitter ); + bool allSourceCasesAreEqualToDestinationCase() const; private: caf::PdmPtrField m_cellFilterView; caf::PdmField> m_defaultValueType; caf::PdmField m_defaultValue; caf::PdmPtrField m_destinationCase; - caf::PdmField m_defaultPropertyVariableIndex; + caf::PdmField m_allCases; + + caf::PdmField m_defaultPropertyVariableIndex; }; diff --git a/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp b/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp index 7a1367ac39..e5f78b91c7 100644 --- a/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimGridCalculationCollection.cpp @@ -57,14 +57,14 @@ std::vector RimGridCalculationCollection::sortedGridCalcula // Check if source calculation is depending on other. Will check one level dependency. auto isSourceDependingOnOther = []( const RimGridCalculation* source, const RimGridCalculation* other ) -> bool { - auto outputCase = source->outputEclipseCase(); - auto outputAdr = source->outputAddress(); + auto outputCases = source->outputEclipseCases(); + auto outputAdr = source->outputAddress(); for ( auto v : other->allVariables() ) { auto gridVariable = dynamic_cast( v ); - if ( gridVariable->eclipseCase() == outputCase && outputAdr.resultCatType() == gridVariable->resultCategoryType() && - outputAdr.resultName() == gridVariable->resultVariable() ) + if ( std::find( outputCases.begin(), outputCases.end(), gridVariable->eclipseCase() ) != outputCases.end() && + outputAdr.resultCatType() == gridVariable->resultCategoryType() && outputAdr.resultName() == gridVariable->resultVariable() ) { return true; } diff --git a/ApplicationLibCode/ProjectDataModel/RimResultSelectionUi.cpp b/ApplicationLibCode/ProjectDataModel/RimResultSelectionUi.cpp index 4723e67886..76edca567e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimResultSelectionUi.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimResultSelectionUi.cpp @@ -110,8 +110,7 @@ QList RimResultSelectionUi::calculateValueOptions( const if ( fieldNeedingOptions == &m_eclipseCase ) { - auto cases = RimEclipseCaseTools::eclipseCases(); - for ( auto* c : cases ) + for ( auto* c : RimEclipseCaseTools::allEclipseGridCases() ) { options.push_back( caf::PdmOptionItemInfo( c->caseUserDescription(), c, false, c->uiIconProvider() ) ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.cpp b/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.cpp index 3cd0259d85..a52cc6a314 100644 --- a/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.cpp @@ -244,6 +244,14 @@ bool RimUserDefinedCalculation::parseExpression() return true; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimUserDefinedCalculation::preCalculate() const +{ + return true; +} + //-------------------------------------------------------------------------------------------------- /// Find the last assignment using := and interpret the text before the := as LHS //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.h b/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.h index 253de806be..01716fd337 100644 --- a/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.h +++ b/ApplicationLibCode/ProjectDataModel/RimUserDefinedCalculation.h @@ -56,6 +56,7 @@ class RimUserDefinedCalculation : public caf::PdmObject QString unitName() const; bool parseExpression(); + virtual bool preCalculate() const; virtual bool calculate() = 0; virtual void updateDependentObjects() = 0; virtual void removeDependentObjects() = 0; diff --git a/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp index c4b771c438..94c44903c9 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -2626,8 +2626,11 @@ void RigCaseCellResultsData::computeCompletionTypeForTimeStep( size_t timeStep ) { for ( auto userCalculation : RimProject::current()->gridCalculationCollection()->calculations() ) { - auto gridCalculation = dynamic_cast( userCalculation ); - if ( gridCalculation && gridCalculation->outputEclipseCase() != eclipseCase ) continue; + if ( auto gridCalculation = dynamic_cast( userCalculation ) ) + { + auto outputCases = gridCalculation->outputEclipseCases(); + if ( std::find( outputCases.begin(), outputCases.end(), eclipseCase ) == outputCases.end() ) continue; + } QString generatedPropertyName = RimUserDefinedCalculation::findLeftHandSide( userCalculation->expression() ); if ( generatedPropertyName == propertyName )