From ca87cee79ba881a21d3421b47f7ae3cd07c615be Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Fri, 1 Dec 2023 11:24:58 +0100 Subject: [PATCH] Summary Calculation: add import and export to toml --- .../Application/RiaPreferences.cpp | 14 +- .../Application/RiaPreferences.h | 2 + .../Commands/CMakeLists_files.cmake | 4 + ...rtSummaryCalculationExpressionsFeature.cpp | 120 ++++++++++++++++++ ...portSummaryCalculationExpressionsFeature.h | 35 +++++ .../Commands/RicGridCalculatorUi.cpp | 87 ++++--------- .../Commands/RicGridCalculatorUi.h | 9 +- ...rtSummaryCalculationExpressionsFeature.cpp | 116 +++++++++++++++++ ...portSummaryCalculationExpressionsFeature.h | 33 +++++ .../Commands/RicUserDefinedCalculatorUi.cpp | 31 +++++ .../Commands/RicUserDefinedCalculatorUi.h | 5 + .../RicSummaryCurveCalculatorUi.cpp | 25 ++++ .../RicSummaryCurveCalculatorUi.h | 4 + .../FileInterface/CMakeLists_files.cmake | 5 + .../RifEclipseSummaryAddress.cpp | 12 ++ .../FileInterface/RifEclipseSummaryAddress.h | 2 + .../FileInterface/RifSummaryCalculation.h | 40 ++++++ .../RifSummaryCalculationExporter.cpp | 72 +++++++++++ .../RifSummaryCalculationExporter.h | 34 +++++ .../RifSummaryCalculationImporter.cpp | 98 ++++++++++++++ .../RifSummaryCalculationImporter.h | 34 +++++ .../RimSummaryCalculation.cpp | 32 +++++ .../ProjectDataModel/RimSummaryCalculation.h | 6 + .../UnitTests/CMakeLists_files.cmake | 1 + .../RifSummaryCalculationIO-Test.cpp | 118 +++++++++++++++++ 25 files changed, 866 insertions(+), 73 deletions(-) create mode 100644 ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.cpp create mode 100644 ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.h create mode 100644 ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.cpp create mode 100644 ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.h create mode 100644 ApplicationLibCode/FileInterface/RifSummaryCalculation.h create mode 100644 ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.cpp create mode 100644 ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.h create mode 100644 ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.cpp create mode 100644 ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.h create mode 100644 ApplicationLibCode/UnitTests/RifSummaryCalculationIO-Test.cpp diff --git a/ApplicationLibCode/Application/RiaPreferences.cpp b/ApplicationLibCode/Application/RiaPreferences.cpp index f3bb0a82e0..3439233871 100644 --- a/ApplicationLibCode/Application/RiaPreferences.cpp +++ b/ApplicationLibCode/Application/RiaPreferences.cpp @@ -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(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Application/RiaPreferences.h b/ApplicationLibCode/Application/RiaPreferences.h index 1c56fd18e7..bcceb40a82 100644 --- a/ApplicationLibCode/Application/RiaPreferences.h +++ b/ApplicationLibCode/Application/RiaPreferences.h @@ -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 m_useQtChartsPlotByDefault; caf::PdmField m_gridCalculationExpressionFolder; + caf::PdmField m_summaryCalculationExpressionFolder; // Script paths caf::PdmField m_octaveExecutable; diff --git a/ApplicationLibCode/Commands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/CMakeLists_files.cmake index 027b0f28cf..d2fcebaf9a 100644 --- a/ApplicationLibCode/Commands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/CMakeLists_files.cmake @@ -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) diff --git a/ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.cpp b/ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.cpp new file mode 100644 index 0000000000..c2bd8c196e --- /dev/null +++ b/ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.cpp @@ -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 +// 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 +#include +#include + +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 calculations; + for ( auto calculation : calcColl->calculations() ) + { + if ( auto summaryCalculation = dynamic_cast( 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( 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" ) ); +} diff --git a/ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.h b/ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.h new file mode 100644 index 0000000000..51a477b9c0 --- /dev/null +++ b/ApplicationLibCode/Commands/RicExportSummaryCalculationExpressionsFeature.h @@ -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 +// 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; +}; diff --git a/ApplicationLibCode/Commands/RicGridCalculatorUi.cpp b/ApplicationLibCode/Commands/RicGridCalculatorUi.cpp index b1e9978d91..09d7f74799 100644 --- a/ApplicationLibCode/Commands/RicGridCalculatorUi.cpp +++ b/ApplicationLibCode/Commands/RicGridCalculatorUi.cpp @@ -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(); + } +} diff --git a/ApplicationLibCode/Commands/RicGridCalculatorUi.h b/ApplicationLibCode/Commands/RicGridCalculatorUi.h index 0a7e54be5e..db5f3425e8 100644 --- a/ApplicationLibCode/Commands/RicGridCalculatorUi.h +++ b/ApplicationLibCode/Commands/RicGridCalculatorUi.h @@ -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 m_exportCalculations; - caf::PdmField m_importCalculations; + void exportCalculations() override; + void importCalculations() override; }; diff --git a/ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.cpp b/ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.cpp new file mode 100644 index 0000000000..c595db5f55 --- /dev/null +++ b/ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.cpp @@ -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 +// 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 +#include +#include +#include + +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( 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( 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" ) ); +} diff --git a/ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.h b/ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.h new file mode 100644 index 0000000000..58d0367ce7 --- /dev/null +++ b/ApplicationLibCode/Commands/RicImportSummaryCalculationExpressionsFeature.h @@ -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 +// 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; +}; diff --git a/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp b/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp index 3456ede972..771f36f912 100644 --- a/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp +++ b/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.cpp @@ -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(); } @@ -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" ); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.h b/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.h index d8b052bdb5..13f8609adb 100644 --- a/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.h +++ b/ApplicationLibCode/Commands/RicUserDefinedCalculatorUi.h @@ -57,6 +57,9 @@ protected: QList 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 m_newCalculation; caf::PdmField m_deleteCalculation; + caf::PdmField m_exportCalculations; + caf::PdmField m_importCalculations; std::unique_ptr m_calcContextMenuMgr; }; diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.cpp b/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.cpp index acef817ca5..cfe135d6ba 100644 --- a/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.cpp +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.cpp @@ -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(); + } +} \ No newline at end of file diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.h b/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.h index 60f3728b24..6a61a2d913 100644 --- a/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.h +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorUi.h @@ -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; }; diff --git a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake index 582fccf6ca..310f3cfbd9 100644 --- a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake @@ -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}) diff --git a/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.cpp b/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.cpp index a9bb8817fb..1de9f37e2c 100644 --- a/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.cpp +++ b/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.cpp @@ -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 //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.h b/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.h index 8dddb06d52..5a1af9875f 100644 --- a/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.h +++ b/ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.h @@ -120,6 +120,8 @@ public: std::string ensembleStatisticsVectorName() const; + std::string toEclipseTextAddress() const; + // Derived properties std::string uiText() const; diff --git a/ApplicationLibCode/FileInterface/RifSummaryCalculation.h b/ApplicationLibCode/FileInterface/RifSummaryCalculation.h new file mode 100644 index 0000000000..6fac29335e --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifSummaryCalculation.h @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +//================================================================================================== +// +//================================================================================================== +struct RifSummaryCalculationVariable +{ + std::string name; + std::string address; +}; + +struct RifSummaryCalculation +{ + std::string expression; + std::string unit; + bool distributeToAllCases; + bool distributeToOther; + std::vector variables; +}; diff --git a/ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.cpp b/ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.cpp new file mode 100644 index 0000000000..9429bef710 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.cpp @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RifSummaryCalculationExporter.h" + +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RifSummaryCalculationExporter::writeToFile( const std::vector& 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 RifSummaryCalculationExporter::writeToStream( const std::vector& 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(), "" }; +} diff --git a/ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.h b/ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.h new file mode 100644 index 0000000000..22b92629ce --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifSummaryCalculationExporter.h @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RifSummaryCalculation.h" + +#include +#include + +//================================================================================================== +// +//================================================================================================== +class RifSummaryCalculationExporter +{ +public: + static std::pair writeToFile( const std::vector& calculations, const std::string& filePath ); + static std::pair writeToStream( const std::vector& calculations, std::ostream& stream ); +}; diff --git a/ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.cpp b/ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.cpp new file mode 100644 index 0000000000..1b8831e981 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.cpp @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RifSummaryCalculationImporter.h" + +#include + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair, 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::string> RifSummaryCalculationImporter::readFromStream( std::istream& stream ) +{ + try + { + toml::table tbl = toml::parse( stream ); + + auto calculationsVector = tbl["summary-calculation"]; + + std::vector 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( "" ); + if ( calculation.expression.empty() ) throw std::runtime_error( "Missing expression." ); + + calculation.distributeToOther = calc->at_path( "distribute-to-other-items" ).value_or( true ); + calculation.distributeToAllCases = calc->at_path( "distribute-to-all-cases" ).value_or( true ); + calculation.unit = calc->at_path( "unit" ).value_or( "" ); + + if ( toml::array* vars = calc->at_path( "variables" ).as_array() ) + { + std::vector variables; + for ( auto&& v : *vars ) + { + if ( toml::table* var = v.as_table() ) + { + RifSummaryCalculationVariable variable; + variable.name = var->at_path( "name" ).value_or( "" ); + variable.address = var->at_path( "address" ).value_or( "" ); + 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() }; + } +} diff --git a/ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.h b/ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.h new file mode 100644 index 0000000000..8a72e7950d --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifSummaryCalculationImporter.h @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RifSummaryCalculation.h" + +#include +#include + +//================================================================================================== +// +//================================================================================================== +class RifSummaryCalculationImporter +{ +public: + static std::pair, std::string> readFromFile( const std::string& filePath ); + static std::pair, std::string> readFromStream( std::istream& stream ); +}; diff --git a/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.cpp b/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.cpp index 4d04fbe5d2..111c7b7bad 100644 --- a/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.cpp @@ -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(); +} diff --git a/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.h b/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.h index 8d6b5d911a..8f73d7ce96 100644 --- a/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.h +++ b/ApplicationLibCode/ProjectDataModel/RimSummaryCalculation.h @@ -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; diff --git a/ApplicationLibCode/UnitTests/CMakeLists_files.cmake b/ApplicationLibCode/UnitTests/CMakeLists_files.cmake index 9590f662f2..aa33ac608d 100644 --- a/ApplicationLibCode/UnitTests/CMakeLists_files.cmake +++ b/ApplicationLibCode/UnitTests/CMakeLists_files.cmake @@ -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) diff --git a/ApplicationLibCode/UnitTests/RifSummaryCalculationIO-Test.cpp b/ApplicationLibCode/UnitTests/RifSummaryCalculationIO-Test.cpp new file mode 100644 index 0000000000..1964ecbe8b --- /dev/null +++ b/ApplicationLibCode/UnitTests/RifSummaryCalculationIO-Test.cpp @@ -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 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() ); +}