Summary Calculation: add import and export to toml

This commit is contained in:
Kristian Bendiksen 2023-12-01 11:24:58 +01:00 committed by Magne Sjaastad
parent 232706a4e9
commit ca87cee79b
25 changed files with 866 additions and 73 deletions

View File

@ -230,6 +230,9 @@ RiaPreferences::RiaPreferences()
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_useQtChartsPlotByDefault );
CAF_PDM_InitFieldNoDefault( &m_gridCalculationExpressionFolder, "gridCalculationExpressionFolder", "Grid Calculation Expression Folder" );
CAF_PDM_InitFieldNoDefault( &m_summaryCalculationExpressionFolder,
"summaryCalculationExpressionFolder",
"Summary Calculation Expression Folder" );
CAF_PDM_InitField( &m_surfaceImportResamplingDistance,
"SurfaceImportResamplingDistance",
@ -294,7 +297,7 @@ void RiaPreferences::defineEditorAttribute( const caf::PdmFieldHandle* field, QS
myAttr->m_selectDirectory = true;
myAttr->m_appendUiSelectedFolderToText = true;
}
else if ( field == &m_gridCalculationExpressionFolder )
else if ( field == &m_gridCalculationExpressionFolder || field == &m_summaryCalculationExpressionFolder )
{
myAttr->m_selectDirectory = true;
}
@ -457,6 +460,7 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering&
caf::PdmUiGroup* otherGroup = uiOrdering.addNewGroup( "Other" );
otherGroup->add( &m_gridCalculationExpressionFolder );
otherGroup->add( &m_summaryCalculationExpressionFolder );
}
else if ( RiaApplication::enableDevelopmentFeatures() && uiConfigName == RiaPreferences::tabNameSystem() )
{
@ -855,6 +859,14 @@ QString RiaPreferences::gridCalculationExpressionFolder() const
return m_gridCalculationExpressionFolder().path();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaPreferences::summaryCalculationExpressionFolder() const
{
return m_summaryCalculationExpressionFolder().path();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -103,6 +103,7 @@ public:
static QString defaultMultiLateralWellNamePattern();
QString gridCalculationExpressionFolder() const;
QString summaryCalculationExpressionFolder() const;
// 3D view
RiaDefines::MeshModeType defaultMeshModeType() const;
@ -196,6 +197,7 @@ private:
caf::PdmField<bool> m_useQtChartsPlotByDefault;
caf::PdmField<caf::FilePath> m_gridCalculationExpressionFolder;
caf::PdmField<caf::FilePath> m_summaryCalculationExpressionFolder;
// Script paths
caf::PdmField<QString> m_octaveExecutable;

View File

@ -91,6 +91,8 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicCopyGridStatisticsToClipboardFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicExportGridCalculationExpressionsFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicImportGridCalculationExpressionsFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicExportSummaryCalculationExpressionsFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCalculationExpressionsFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -185,6 +187,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicCopyGridStatisticsToClipboardFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicExportGridCalculationExpressionsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportGridCalculationExpressionsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicExportSummaryCalculationExpressionsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCalculationExpressionsFeature.cpp
)
if(RESINSIGHT_USE_QT_CHARTS)

View File

@ -0,0 +1,120 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023 Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicExportSummaryCalculationExpressionsFeature.h"
#include "RiaGuiApplication.h"
#include "RiaLogging.h"
#include "RiaPreferences.h"
#include "RifSummaryCalculation.h"
#include "RifSummaryCalculationExporter.h"
#include "RimProject.h"
#include "RimSummaryAddress.h"
#include "RimSummaryCalculationCollection.h"
#include "RimSummaryCalculationVariable.h"
#include "RiuFileDialogTools.h"
#include "RiuPlotMainWindow.h"
#include <QAction>
#include <QFile>
#include <QFileInfo>
CAF_CMD_SOURCE_INIT( RicExportSummaryCalculationExpressionsFeature, "RicExportSummaryCalculationExpressionsFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicExportSummaryCalculationExpressionsFeature::summaryCalculationExpressionId()
{
return "SUMMARY_CALCULATION_EXPRESSION";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicExportSummaryCalculationExpressionsFeature::onActionTriggered( bool isChecked )
{
auto proj = RimProject::current();
auto calcColl = proj->calculationCollection();
if ( calcColl->calculations().empty() ) return;
QString fallbackPath = RiaPreferences::current()->summaryCalculationExpressionFolder();
auto app = RiaGuiApplication::instance();
QString startPath =
app->lastUsedDialogDirectoryWithFallback( RicExportSummaryCalculationExpressionsFeature::summaryCalculationExpressionId(),
fallbackPath );
QString fileName = RiuFileDialogTools::getSaveFileName( nullptr,
"Select File for Summary Calculation Expression Export",
startPath,
"Toml File(*.toml);;All files(*.*)" );
if ( fileName.isEmpty() ) return;
auto fi = QFileInfo( fileName );
if ( fi.suffix().isEmpty() )
{
fileName += ".toml";
}
QString absPath = fi.absolutePath();
app->setLastUsedDialogDirectory( RicExportSummaryCalculationExpressionsFeature::summaryCalculationExpressionId(), absPath );
std::vector<RifSummaryCalculation> calculations;
for ( auto calculation : calcColl->calculations() )
{
if ( auto summaryCalculation = dynamic_cast<RimSummaryCalculation*>( calculation ) )
{
RifSummaryCalculation calc;
calc.expression = calculation->expression().toStdString();
calc.unit = calculation->unitName().toStdString();
calc.distributeToAllCases = summaryCalculation->isDistributeToAllCases();
calc.distributeToOther = summaryCalculation->isDistributeToOtherItems();
for ( auto variable : calculation->allVariables() )
{
if ( auto gridVariable = dynamic_cast<RimSummaryCalculationVariable*>( variable ) )
{
RifSummaryCalculationVariable var;
var.address = gridVariable->summaryAddress()->address().toEclipseTextAddress();
var.name = gridVariable->name().toStdString();
calc.variables.push_back( var );
}
}
calculations.push_back( calc );
}
}
auto [isOk, errorMessage] = RifSummaryCalculationExporter::writeToFile( calculations, fileName.toStdString() );
if ( !isOk )
{
RiaLogging::errorInMessageBox( RiuPlotMainWindow::instance(), "Summary Calculation Export Error", QString::fromStdString( errorMessage ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicExportSummaryCalculationExpressionsFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Export Summary Calculation Expressions" );
actionToSetup->setIcon( QIcon( ":/Calculator.svg" ) );
}

View File

@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023 Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicExportSummaryCalculationExpressionsFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
static QString summaryCalculationExpressionId();
private:
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};

View File

@ -33,12 +33,6 @@ CAF_PDM_SOURCE_INIT( RicGridCalculatorUi, "RicGridCalculator" );
RicGridCalculatorUi::RicGridCalculatorUi()
{
CAF_PDM_InitObject( "RicGridCalculator" );
CAF_PDM_InitFieldNoDefault( &m_importCalculations, "ImportCalculations", "Import Calculations" );
RicUserDefinedCalculatorUi::assignPushButtonEditor( &m_importCalculations );
CAF_PDM_InitFieldNoDefault( &m_exportCalculations, "ExportCalculations", "Export Calculations" );
RicUserDefinedCalculatorUi::assignPushButtonEditor( &m_exportCalculations );
}
//--------------------------------------------------------------------------------------------------
@ -64,65 +58,6 @@ void RicGridCalculatorUi::notifyCalculatedNameChanged( int id, const QString& ne
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicGridCalculatorUi::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
RicUserDefinedCalculatorUi::defineUiOrdering( uiConfigName, uiOrdering );
caf::PdmUiGroup* group = uiOrdering.findGroup( calculationsGroupName() );
if ( group )
{
group->add( &m_importCalculations );
group->appendToRow( &m_exportCalculations );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicGridCalculatorUi::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
RicUserDefinedCalculatorUi::fieldChangedByUi( changedField, oldValue, newValue );
if ( changedField == &m_importCalculations )
{
if ( auto feature = caf::CmdFeatureManager::instance()->getCommandFeature( "RicImportGridCalculationExpressionsFeature" ) )
{
feature->action()->trigger();
}
m_importCalculations = false;
}
else if ( changedField == &m_exportCalculations )
{
if ( auto feature = caf::CmdFeatureManager::instance()->getCommandFeature( "RicExportGridCalculationExpressionsFeature" ) )
{
feature->action()->trigger();
}
m_exportCalculations = false;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicGridCalculatorUi::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
RicUserDefinedCalculatorUi::defineEditorAttribute( field, uiConfigName, attribute );
if ( &m_importCalculations == field )
{
RicUserDefinedCalculatorUi::assignPushButtonEditorText( attribute, "Import Calculations" );
}
else if ( &m_exportCalculations == field )
{
RicUserDefinedCalculatorUi::assignPushButtonEditorText( attribute, "Export Calculations" );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -130,3 +65,25 @@ RimUserDefinedCalculationCollection* RicGridCalculatorUi::calculationCollection(
{
return RimProject::current()->gridCalculationCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicGridCalculatorUi::exportCalculations()
{
if ( auto feature = caf::CmdFeatureManager::instance()->getCommandFeature( "RicExportGridCalculationExpressionsFeature" ) )
{
feature->action()->trigger();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicGridCalculatorUi::importCalculations()
{
if ( auto feature = caf::CmdFeatureManager::instance()->getCommandFeature( "RicImportGridCalculationExpressionsFeature" ) )
{
feature->action()->trigger();
}
}

View File

@ -38,11 +38,6 @@ public:
void notifyCalculatedNameChanged( int id, const QString& newName ) const override;
protected:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
private:
caf::PdmField<bool> m_exportCalculations;
caf::PdmField<bool> m_importCalculations;
void exportCalculations() override;
void importCalculations() override;
};

View File

@ -0,0 +1,116 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023 Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicImportSummaryCalculationExpressionsFeature.h"
#include "RicExportSummaryCalculationExpressionsFeature.h"
#include "RiaGuiApplication.h"
#include "RiaLogging.h"
#include "RiaPreferences.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimSummaryAddress.h"
#include "RimSummaryCalculationCollection.h"
#include "RimSummaryCalculationVariable.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseMainCollection.h"
#include "RiuFileDialogTools.h"
#include "RiuPlotMainWindow.h"
#include "RifSummaryCalculationImporter.h"
#include <QAction>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
CAF_CMD_SOURCE_INIT( RicImportSummaryCalculationExpressionsFeature, "RicImportSummaryCalculationExpressionsFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicImportSummaryCalculationExpressionsFeature::onActionTriggered( bool isChecked )
{
auto app = RiaGuiApplication::instance();
QString defaultDir =
app->lastUsedDialogDirectoryWithFallback( RicExportSummaryCalculationExpressionsFeature::summaryCalculationExpressionId(),
RiaPreferences::current()->summaryCalculationExpressionFolder() );
QString fileName =
RiuFileDialogTools::getOpenFileName( nullptr, "Import Summary Calculation Expressions", defaultDir, "Toml File(*.toml);;All files(*.*)" );
if ( fileName.isEmpty() ) return;
auto [calculations, errorMessage] = RifSummaryCalculationImporter::readFromFile( fileName.toStdString() );
if ( !errorMessage.empty() )
{
RiaLogging::errorInMessageBox( RiuPlotMainWindow::instance(), "Summary Calculation Import Error", QString::fromStdString( errorMessage ) );
return;
}
auto proj = RimProject::current();
auto calcColl = proj->calculationCollection();
RimSummaryCaseMainCollection* sumCaseColl = proj->activeOilField() ? proj->activeOilField()->summaryCaseMainCollection() : nullptr;
RimSummaryCase* firstCase = nullptr;
if ( sumCaseColl && !sumCaseColl->allSummaryCases().empty() )
{
firstCase = sumCaseColl->allSummaryCases().front();
}
for ( auto calc : calculations )
{
bool addDefaultExpression = false;
auto summaryCalculation = dynamic_cast<RimSummaryCalculation*>( calcColl->addCalculation( addDefaultExpression ) );
if ( summaryCalculation )
{
summaryCalculation->setExpression( QString::fromStdString( calc.expression ) );
summaryCalculation->setDescription( QString::fromStdString( calc.expression ) );
summaryCalculation->setUnit( QString::fromStdString( calc.unit ) );
summaryCalculation->setDistributeToAllCases( calc.distributeToAllCases );
summaryCalculation->setDistributeToOtherItems( calc.distributeToOther );
for ( auto var : calc.variables )
{
auto variable =
dynamic_cast<RimSummaryCalculationVariable*>( summaryCalculation->addVariable( QString::fromStdString( var.name ) ) );
RifEclipseSummaryAddress address = RifEclipseSummaryAddress::fromEclipseTextAddress( var.address );
RimSummaryAddress summaryAddress;
summaryAddress.setAddress( address );
if ( firstCase ) summaryAddress.setCaseId( firstCase->caseId() );
variable->setSummaryAddress( summaryAddress );
variable->setName( QString::fromStdString( var.name ) );
}
}
}
QString absPath = QFileInfo( fileName ).absolutePath();
app->setLastUsedDialogDirectory( RicExportSummaryCalculationExpressionsFeature::summaryCalculationExpressionId(), absPath );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicImportSummaryCalculationExpressionsFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Import Grid Calculation Expressions" );
actionToSetup->setIcon( QIcon( ":/Calculator.svg" ) );
}

View File

@ -0,0 +1,33 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023 Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicImportSummaryCalculationExpressionsFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
private:
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};

View File

@ -45,6 +45,12 @@ RicUserDefinedCalculatorUi::RicUserDefinedCalculatorUi()
CAF_PDM_InitFieldNoDefault( &m_deleteCalculation, "DeleteCalculation", "Delete Calculation" );
RicUserDefinedCalculatorUi::assignPushButtonEditor( &m_deleteCalculation );
CAF_PDM_InitFieldNoDefault( &m_importCalculations, "ImportCalculations", "Import Calculations" );
RicUserDefinedCalculatorUi::assignPushButtonEditor( &m_importCalculations );
CAF_PDM_InitFieldNoDefault( &m_exportCalculations, "ExportCalculations", "Export Calculations" );
RicUserDefinedCalculatorUi::assignPushButtonEditor( &m_exportCalculations );
m_calcContextMenuMgr = std::make_unique<RiuCalculationsContextMenuManager>();
}
@ -122,6 +128,16 @@ void RicUserDefinedCalculatorUi::fieldChangedByUi( const caf::PdmFieldHandle* ch
{
connectSignals( m_currentCalculation() );
}
else if ( changedField == &m_importCalculations )
{
importCalculations();
m_importCalculations = false;
}
else if ( changedField == &m_exportCalculations )
{
exportCalculations();
m_exportCalculations = false;
}
}
//--------------------------------------------------------------------------------------------------
@ -148,6 +164,13 @@ void RicUserDefinedCalculatorUi::defineUiOrdering( QString uiConfigName, caf::Pd
m_currentCalculation->uiOrdering( uiConfigName, *group );
}
}
caf::PdmUiGroup* group = uiOrdering.findGroup( calculationsGroupName() );
if ( group )
{
group->add( &m_importCalculations );
group->appendToRow( &m_exportCalculations );
}
}
//--------------------------------------------------------------------------------------------------
@ -240,6 +263,14 @@ void RicUserDefinedCalculatorUi::defineEditorAttribute( const caf::PdmFieldHandl
{
RicUserDefinedCalculatorUi::assignPushButtonEditorText( attribute, "Delete Calculation" );
}
else if ( &m_importCalculations == field )
{
RicUserDefinedCalculatorUi::assignPushButtonEditorText( attribute, "Import Calculations" );
}
else if ( &m_exportCalculations == field )
{
RicUserDefinedCalculatorUi::assignPushButtonEditorText( attribute, "Export Calculations" );
}
}
//--------------------------------------------------------------------------------------------------

View File

@ -57,6 +57,9 @@ protected:
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void onEditorWidgetsCreated() override;
virtual void exportCalculations() = 0;
virtual void importCalculations() = 0;
// TODO : Move to a common caf helper class
static void assignPushButtonEditor( caf::PdmFieldHandle* fieldHandle );
static void assignPushButtonEditorText( caf::PdmUiEditorAttribute* attribute, const QString& text );
@ -70,6 +73,8 @@ private:
caf::PdmField<bool> m_newCalculation;
caf::PdmField<bool> m_deleteCalculation;
caf::PdmField<bool> m_exportCalculations;
caf::PdmField<bool> m_importCalculations;
std::unique_ptr<RiuCalculationsContextMenuManager> m_calcContextMenuMgr;
};

View File

@ -25,6 +25,9 @@
#include "RimUserDefinedCalculation.h"
#include "RimUserDefinedCalculationCollection.h"
#include "cafCmdFeature.h"
#include "cafCmdFeatureManager.h"
CAF_PDM_SOURCE_INIT( RicSummaryCurveCalculatorUi, "RicSummaryCurveCalculator" );
//--------------------------------------------------------------------------------------------------
@ -66,3 +69,25 @@ RimUserDefinedCalculationCollection* RicSummaryCurveCalculatorUi::calculationCol
{
return RimProject::current()->calculationCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryCurveCalculatorUi::exportCalculations()
{
if ( auto feature = caf::CmdFeatureManager::instance()->getCommandFeature( "RicExportSummaryCalculationExpressionsFeature" ) )
{
feature->action()->trigger();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryCurveCalculatorUi::importCalculations()
{
if ( auto feature = caf::CmdFeatureManager::instance()->getCommandFeature( "RicImportSummaryCalculationExpressionsFeature" ) )
{
feature->action()->trigger();
}
}

View File

@ -36,4 +36,8 @@ public:
QString calulationGroupName() const override;
RimUserDefinedCalculationCollection* calculationCollection() const override;
void notifyCalculatedNameChanged( int id, const QString& newName ) const override;
protected:
void exportCalculations() override;
void importCalculations() override;
};

View File

@ -92,6 +92,9 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RifGridCalculation.h
${CMAKE_CURRENT_LIST_DIR}/RifGridCalculationImporter.h
${CMAKE_CURRENT_LIST_DIR}/RifGridCalculationExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculation.h
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationImporter.h
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationExporter.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -184,6 +187,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RifEclipseSummaryAddressDefines.cpp
${CMAKE_CURRENT_LIST_DIR}/RifGridCalculationImporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifGridCalculationExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationImporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationExporter.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@ -727,6 +727,18 @@ std::string RifEclipseSummaryAddress::itemUiText() const
return text;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifEclipseSummaryAddress::toEclipseTextAddress() const
{
std::string noVectorName = itemUiText();
if ( noVectorName.empty() )
return m_vectorName;
else
return m_vectorName + ":" + noVectorName;
}
//--------------------------------------------------------------------------------------------------
/// Returns the stringified address component requested
//--------------------------------------------------------------------------------------------------

View File

@ -120,6 +120,8 @@ public:
std::string ensembleStatisticsVectorName() const;
std::string toEclipseTextAddress() const;
// Derived properties
std::string uiText() const;

View File

@ -0,0 +1,40 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
#include <vector>
//==================================================================================================
//
//==================================================================================================
struct RifSummaryCalculationVariable
{
std::string name;
std::string address;
};
struct RifSummaryCalculation
{
std::string expression;
std::string unit;
bool distributeToAllCases;
bool distributeToOther;
std::vector<RifSummaryCalculationVariable> variables;
};

View File

@ -0,0 +1,72 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifSummaryCalculationExporter.h"
#include <fstream>
#include <tomlplusplus/toml.hpp>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<bool, std::string> RifSummaryCalculationExporter::writeToFile( const std::vector<RifSummaryCalculation>& calculations,
const std::string& filePath )
{
std::ofstream stream( filePath );
if ( !stream.good() ) return { false, "Unable to open file: " + filePath };
return writeToStream( calculations, stream );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<bool, std::string> RifSummaryCalculationExporter::writeToStream( const std::vector<RifSummaryCalculation>& calculations,
std::ostream& stream )
{
auto calculationsVector = toml::array();
for ( auto calculation : calculations )
{
auto variablesVector = toml::array{};
for ( auto variable : calculation.variables )
{
variablesVector.push_back( toml::table{
{ "name", variable.name },
{ "address", variable.address },
} );
}
calculationsVector.push_back( toml::table{
{ "expression", calculation.expression },
{ "unit", calculation.unit },
{ "distribute-to-other-items", calculation.distributeToOther },
{ "distribute-to-all-cases", calculation.distributeToAllCases },
{ "variables", variablesVector },
} );
}
auto tbl = toml::table{
{ "summary-calculation", calculationsVector },
};
stream << tbl;
return { stream.good(), "" };
}

View File

@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifSummaryCalculation.h"
#include <string>
#include <vector>
//==================================================================================================
//
//==================================================================================================
class RifSummaryCalculationExporter
{
public:
static std::pair<bool, std::string> writeToFile( const std::vector<RifSummaryCalculation>& calculations, const std::string& filePath );
static std::pair<bool, std::string> writeToStream( const std::vector<RifSummaryCalculation>& calculations, std::ostream& stream );
};

View File

@ -0,0 +1,98 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifSummaryCalculationImporter.h"
#include <fstream>
#include <tomlplusplus/toml.hpp>
#include <utility>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<std::vector<RifSummaryCalculation>, std::string> RifSummaryCalculationImporter::readFromFile( const std::string& filePath )
{
std::ifstream stream( filePath );
if ( !stream.good() ) return { {}, "Unable to open file: " + filePath };
return readFromStream( stream );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<std::vector<RifSummaryCalculation>, std::string> RifSummaryCalculationImporter::readFromStream( std::istream& stream )
{
try
{
toml::table tbl = toml::parse( stream );
auto calculationsVector = tbl["summary-calculation"];
std::vector<RifSummaryCalculation> calculations;
if ( toml::array* arr = calculationsVector.as_array() )
{
for ( auto&& a : *arr )
{
RifSummaryCalculation calculation;
if ( toml::table* calc = a.as_table() )
{
calculation.expression = calc->at_path( "expression" ).value_or<std::string>( "" );
if ( calculation.expression.empty() ) throw std::runtime_error( "Missing expression." );
calculation.distributeToOther = calc->at_path( "distribute-to-other-items" ).value_or<bool>( true );
calculation.distributeToAllCases = calc->at_path( "distribute-to-all-cases" ).value_or<bool>( true );
calculation.unit = calc->at_path( "unit" ).value_or<std::string>( "" );
if ( toml::array* vars = calc->at_path( "variables" ).as_array() )
{
std::vector<RifSummaryCalculationVariable> variables;
for ( auto&& v : *vars )
{
if ( toml::table* var = v.as_table() )
{
RifSummaryCalculationVariable variable;
variable.name = var->at_path( "name" ).value_or<std::string>( "" );
variable.address = var->at_path( "address" ).value_or<std::string>( "" );
if ( variable.name.empty() || variable.address.empty() )
throw std::runtime_error( "Incomplete variable: Missing either name or address." );
variables.push_back( variable );
}
}
calculation.variables = variables;
}
calculations.push_back( calculation );
}
}
}
if ( calculations.empty() )
{
return { calculations, "No calculations imported." };
}
return { calculations, "" };
}
catch ( const std::runtime_error& error )
{
return { {}, error.what() };
}
}

View File

@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifSummaryCalculation.h"
#include <string>
#include <vector>
//==================================================================================================
//
//==================================================================================================
class RifSummaryCalculationImporter
{
public:
static std::pair<std::vector<RifSummaryCalculation>, std::string> readFromFile( const std::string& filePath );
static std::pair<std::vector<RifSummaryCalculation>, std::string> readFromStream( std::istream& stream );
};

View File

@ -699,3 +699,35 @@ QString RimSummaryCalculation::buildCalculationName() const
return name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCalculation::setDistributeToOtherItems( bool enable )
{
m_distributeToOtherItems = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCalculation::setDistributeToAllCases( bool enable )
{
m_distributeToAllCases = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryCalculation::isDistributeToOtherItems() const
{
return m_distributeToOtherItems();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryCalculation::isDistributeToAllCases() const
{
return m_distributeToAllCases();
}

View File

@ -66,6 +66,12 @@ public:
QString buildCalculationName() const override;
void setDistributeToOtherItems( bool enable );
void setDistributeToAllCases( bool enable );
bool isDistributeToOtherItems() const;
bool isDistributeToAllCases() const;
protected:
RimSummaryCalculationVariable* createVariable() override;

View File

@ -99,6 +99,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/opm-import-well-data-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifInpExportTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifGridCalculationIO-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationIO-Test.cpp
)
if(RESINSIGHT_ENABLE_GRPC)

View File

@ -0,0 +1,118 @@
#include "gtest/gtest.h"
#include "RiaTestDataDirectory.h"
#include "RifSummaryCalculation.h"
#include "RifSummaryCalculationExporter.h"
#include "RifSummaryCalculationImporter.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RifSummaryCalculationIO, importAndExport )
{
RifSummaryCalculation calc1;
calc1.expression = "answer = a + b";
calc1.unit = "meter";
calc1.distributeToAllCases = true;
calc1.distributeToOther = false;
RifSummaryCalculationVariable variable1;
variable1.name = "a";
variable1.address = "FOPT";
RifSummaryCalculationVariable variable2;
variable2.name = "b";
variable2.address = "FGPT";
calc1.variables = { variable1, variable2 };
RifSummaryCalculation calc2;
calc2.expression = "answer = x + y";
calc2.unit = "";
calc2.distributeToAllCases = false;
calc2.distributeToOther = true;
RifSummaryCalculationVariable variable3;
variable3.name = "x";
variable3.address = "WOPT";
RifSummaryCalculationVariable variable4;
variable4.name = "y";
variable4.address = "WOPR";
calc2.variables = { variable3, variable4 };
std::vector<RifSummaryCalculation> calculations = { calc1, calc2 };
std::stringstream stream;
auto [isOk, errorMessage] = RifSummaryCalculationExporter::writeToStream( calculations, stream );
EXPECT_TRUE( isOk );
EXPECT_TRUE( errorMessage.empty() );
auto [importedCalculations, importErrorMessage] = RifSummaryCalculationImporter::readFromStream( stream );
ASSERT_EQ( calculations.size(), importedCalculations.size() );
for ( size_t c = 0; c < calculations.size(); c++ )
{
ASSERT_EQ( calculations[c].expression, importedCalculations[c].expression );
ASSERT_EQ( calculations[c].unit, importedCalculations[c].unit );
ASSERT_TRUE( calculations[c].distributeToOther == importedCalculations[c].distributeToOther );
ASSERT_TRUE( calculations[c].distributeToAllCases == importedCalculations[c].distributeToAllCases );
ASSERT_EQ( calculations[c].variables.size(), importedCalculations[c].variables.size() );
for ( size_t v = 0; v < calculations[c].variables.size(); v++ )
{
ASSERT_EQ( calculations[c].variables[v].name, importedCalculations[c].variables[v].name );
ASSERT_EQ( calculations[c].variables[v].address, importedCalculations[c].variables[v].address );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RifSummaryCalculationIO, importEmptyStream )
{
std::stringstream stream;
auto [calculations, errorMessage] = RifSummaryCalculationImporter::readFromStream( stream );
ASSERT_EQ( 0u, calculations.size() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RifSummaryCalculationIO, importNotToml )
{
std::stringstream stream;
stream << "this is not valid toml";
auto [calculations, errorMessage] = RifSummaryCalculationImporter::readFromStream( stream );
ASSERT_EQ( 0u, calculations.size() );
ASSERT_FALSE( errorMessage.empty() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RifSummaryCalculationIO, importWrongToml )
{
std::stringstream stream;
stream << "[library]\n"
<< "book = \"book name\"\n"
<< "authors = [\"Author Name\"]\n"
<< "isbn = \"1234567\"\n";
auto [calculations, errorMessage] = RifSummaryCalculationImporter::readFromStream( stream );
ASSERT_EQ( 0u, calculations.size() );
ASSERT_FALSE( errorMessage.empty() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RifSummaryCalculationIO, importMissingDescriptionToml )
{
std::stringstream stream;
stream << "[[grid-calculation]]\n"
<< "description = 'MY_ASNWER ( NORNE_ATW2013_RFTPLT_V2 : PRESSURE, NORNE_ATW2013_RFTPLT_V2 : PORO )'\n"
<< "unit = ''\n";
auto [calculations, errorMessage] = RifSummaryCalculationImporter::readFromStream( stream );
ASSERT_EQ( 0u, calculations.size() );
ASSERT_FALSE( errorMessage.empty() );
}