From 2eef98938920c03eb51d1f4ab7c7bc0ad83b3bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Jensen?= Date: Wed, 20 Jun 2018 09:41:01 +0200 Subject: [PATCH] #3060 Resampled plot export. Implement dialog. Resample plot data according to spec from Equinor --- .../Application/Tools/RiaQDateTimeTools.cpp | 18 +++ .../Application/Tools/RiaQDateTimeTools.h | 16 ++ .../Commands/CMakeLists_files.cmake | 3 + .../Commands/RicResampleDialog.cpp | 140 ++++++++++++++++++ ApplicationCode/Commands/RicResampleDialog.h | 79 ++++++++++ .../RicAsciiExportSummaryPlotFeature.cpp | 24 ++- .../RicAsciiExportSummaryPlotFeature.h | 6 +- .../Summary/RimSummaryPlot.cpp | 45 ++++-- 8 files changed, 308 insertions(+), 23 deletions(-) create mode 100644 ApplicationCode/Commands/RicResampleDialog.cpp create mode 100644 ApplicationCode/Commands/RicResampleDialog.h diff --git a/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp b/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp index 0f9d6f533a..7087977be0 100644 --- a/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp +++ b/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp @@ -296,3 +296,21 @@ QDateTime RiaQDateTimeTools::truncateTime(const QDateTime& dt, DateTimePeriod pe CVF_ASSERT(false); return createUtcDateTime(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaQDateTimeTools::dateTimePeriodInfoList() +{ + return std::vector( + { + { DateTimePeriod::NONE, "None" }, + { DateTimePeriod::DECADE, "Decade" }, + { DateTimePeriod::YEAR, "Year" }, + { DateTimePeriod::HALFYEAR, "Half Year" }, + { DateTimePeriod::QUARTER, "Quarter" }, + { DateTimePeriod::MONTH, "Month" }, + { DateTimePeriod::WEEK, "Week" }, + { DateTimePeriod::DAY, "Day" }, + }); +} diff --git a/ApplicationCode/Application/Tools/RiaQDateTimeTools.h b/ApplicationCode/Application/Tools/RiaQDateTimeTools.h index 6d7417b22e..01b247a2ad 100644 --- a/ApplicationCode/Application/Tools/RiaQDateTimeTools.h +++ b/ApplicationCode/Application/Tools/RiaQDateTimeTools.h @@ -21,12 +21,16 @@ #include #include +#include + #include +#include class QDateTime; class QDate; class QTime; class DateTimeSpan; +class DateTimePeriodInfo; //================================================================================================== // @@ -85,6 +89,8 @@ public: static const DateTimeSpan timeSpan(DateTimePeriod period); static QDateTime truncateTime(const QDateTime& dt, DateTimePeriod period); + static std::vector dateTimePeriodInfoList(); + private: static quint64 secondsInDay(); static quint64 secondsInYear(); @@ -110,3 +116,13 @@ private: int m_months; int m_days; }; + +//================================================================================================== +/// +//================================================================================================== +class DateTimePeriodInfo +{ +public: + DateTimePeriod period; + QString name; +}; \ No newline at end of file diff --git a/ApplicationCode/Commands/CMakeLists_files.cmake b/ApplicationCode/Commands/CMakeLists_files.cmake index e29002127c..c3c5171beb 100644 --- a/ApplicationCode/Commands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CMakeLists_files.cmake @@ -70,6 +70,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicSummaryCaseRestartDialog.h ${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryGroupFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicConvertGroupToEnsembleFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicResampleDialog.h ) @@ -138,6 +139,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicSummaryCaseRestartDialog.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryGroupFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicConvertGroupToEnsembleFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicResampleDialog.cpp ) @@ -153,6 +155,7 @@ list(APPEND QT_MOC_HEADERS ${CMAKE_CURRENT_LIST_DIR}/RicGridStatisticsDialog.h ${CMAKE_CURRENT_LIST_DIR}/RicFileHierarchyDialog.h ${CMAKE_CURRENT_LIST_DIR}/RicSummaryCaseRestartDialog.h +${CMAKE_CURRENT_LIST_DIR}/RicResampleDialog.h ) source_group( "CommandFeature" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/Commands/RicResampleDialog.cpp b/ApplicationCode/Commands/RicResampleDialog.cpp new file mode 100644 index 0000000000..4227f34b45 --- /dev/null +++ b/ApplicationCode/Commands/RicResampleDialog.cpp @@ -0,0 +1,140 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicResampleDialog.h" + +#include "RiaApplication.h" + +#include "RiuTools.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEFAULT_DIALOG_WIDTH 250 +#define DEFAULT_DIALOG_HEIGHT 100 +#define DEFAULT_DIALOG_TITLE "Export Plot Data" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicResampleDialog::RicResampleDialog(QWidget* parent) + : QDialog(parent, RiuTools::defaultDialogFlags()) +{ + // Create widgets + m_label = new QLabel(); + m_timePeriodCombo = new QComboBox(); + + m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + // Connect to signals + connect(m_buttons, SIGNAL(accepted()), this, SLOT(slotDialogOkClicked())); + connect(m_buttons, SIGNAL(rejected()), this, SLOT(slotDialogCancelClicked())); + + // Set widget properties + m_label->setText("Resampling Period"); + + // Define layout + QVBoxLayout* dialogLayout = new QVBoxLayout(); + + QHBoxLayout* periodLayout = new QHBoxLayout(); + periodLayout->addWidget(m_label); + periodLayout->addWidget(m_timePeriodCombo); + + dialogLayout->addLayout(periodLayout); + dialogLayout->addWidget(m_buttons); + + setLayout(dialogLayout); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicResampleDialog::~RicResampleDialog() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicResampleDialogResult RicResampleDialog::openDialog(QWidget *parent /*= 0*/, + const QString &caption /*= QString()*/) +{ + RicResampleDialog dialog(parent); + + if(!caption.isEmpty()) dialog.setWindowTitle(caption); + else dialog.setWindowTitle(DEFAULT_DIALOG_TITLE); + + dialog.setPeriodOptions(RiaQDateTimeTools::dateTimePeriodInfoList()); + + dialog.resize(DEFAULT_DIALOG_WIDTH, DEFAULT_DIALOG_HEIGHT); + dialog.exec(); + + return RicResampleDialogResult(dialog.result() == QDialog::Accepted, dialog.selectedDateTimePeriod()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicResampleDialog::setPeriodOptions(const std::vector& dateTimePeriodInfos) +{ + QStringList s; + for (auto& item : dateTimePeriodInfos) + { + QString text = item.period != DateTimePeriod::NONE ? item.name : "No Resampling"; + m_timePeriodCombo->addItem(text, QVariant((int)item.period)); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +DateTimePeriod RicResampleDialog::selectedDateTimePeriod() const +{ + int currIndex = m_timePeriodCombo->currentIndex(); + return (DateTimePeriod)m_timePeriodCombo->itemData(currIndex).toInt(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicResampleDialog::slotDialogOkClicked() +{ + accept(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicResampleDialog::slotDialogCancelClicked() +{ + reject(); +} diff --git a/ApplicationCode/Commands/RicResampleDialog.h b/ApplicationCode/Commands/RicResampleDialog.h new file mode 100644 index 0000000000..390882d880 --- /dev/null +++ b/ApplicationCode/Commands/RicResampleDialog.h @@ -0,0 +1,79 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaQDateTimeTools.h" + +#include "cafPdmPointer.h" + +#include + +class QLabel; +class QComboBox; +class QLineEdit; +class QTextEdit; +class QDialogButtonBox; +class QPushButton; +class QMainWindow; +class QListWidget; +class RicResampleDialogResult; +class DateTimePeriodInfo; + +//================================================================================================== +/// +//================================================================================================== +class RicResampleDialog : public QDialog +{ + Q_OBJECT + +public: + RicResampleDialog(QWidget* parent); + ~RicResampleDialog(); + + static RicResampleDialogResult openDialog(QWidget *parent = nullptr, + const QString& caption = QString()); + +private: + void setPeriodOptions(const std::vector& dateTimePeriodInfos); + DateTimePeriod selectedDateTimePeriod() const; + +private slots: + void slotDialogOkClicked(); + void slotDialogCancelClicked(); + +private: + QLabel* m_label; + QComboBox* m_timePeriodCombo; + + QDialogButtonBox* m_buttons; +}; + + +//================================================================================================== +/// +//================================================================================================== +class RicResampleDialogResult +{ +public: + RicResampleDialogResult(bool ok, DateTimePeriod period) : + ok(ok), period(period) {} + + bool ok; + DateTimePeriod period; +}; \ No newline at end of file diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.cpp index 42800378a9..1d1543b0ca 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.cpp @@ -21,6 +21,8 @@ #include "RiaApplication.h" #include "RiaLogging.h" +#include "RicResampleDialog.h" + #include "RimSummaryPlot.h" #include "RiuMainWindow.h" @@ -67,8 +69,9 @@ void RicAsciiExportSummaryPlotFeature::onActionTriggered(bool isChecked) caf::SelectionManager::instance()->objectsByType(&selectedSummaryPlots); QString defaultDir = RiaApplication::instance()->lastUsedDialogDirectoryWithFallback("PLOT_ASCIIEXPORT_DIR", projectFolder); - caf::ProgressInfo pi(selectedSummaryPlots.size(), QString("Exporting plot data to ASCII")); - size_t progress = 0; + // Ask user about resampling + auto result = RicResampleDialog::openDialog(); + if (!result.ok) return; if (selectedSummaryPlots.size() == 1) { @@ -76,7 +79,11 @@ void RicAsciiExportSummaryPlotFeature::onActionTriggered(bool isChecked) QString defaultFileName = defaultDir + "/" + caf::Utils::makeValidFileBasename((summaryPlot->description())) + ".ascii"; QString fileName = QFileDialog::getSaveFileName(nullptr, "Select File for Summary Plot Export", defaultFileName, "Text File(*.ascii);;All files(*.*)"); if (fileName.isEmpty()) return; - RicAsciiExportSummaryPlotFeature::exportAsciiForSummaryPlot(fileName, summaryPlot); + + caf::ProgressInfo pi(selectedSummaryPlots.size(), QString("Exporting plot data to ASCII")); + size_t progress = 0; + + RicAsciiExportSummaryPlotFeature::exportAsciiForSummaryPlot(fileName, summaryPlot, result.period); progress++; pi.setProgress(progress); @@ -94,11 +101,14 @@ void RicAsciiExportSummaryPlotFeature::onActionTriggered(bool isChecked) bool writeFiles = caf::Utils::getSaveDirectoryAndCheckOverwriteFiles(defaultDir, fileNames, &saveDir); if (!writeFiles) return; + caf::ProgressInfo pi(selectedSummaryPlots.size(), QString("Exporting plot data to ASCII")); + size_t progress = 0; + RiaLogging::info(QString("Writing to directory %1").arg(saveDir)); for (RimSummaryPlot* summaryPlot : selectedSummaryPlots) { QString fileName = saveDir + "/" + caf::Utils::makeValidFileBasename(summaryPlot->description()) + ".ascii"; - RicAsciiExportSummaryPlotFeature::exportAsciiForSummaryPlot(fileName, summaryPlot); + RicAsciiExportSummaryPlotFeature::exportAsciiForSummaryPlot(fileName, summaryPlot, result.period); progress++; pi.setProgress(progress); } @@ -117,7 +127,9 @@ void RicAsciiExportSummaryPlotFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicAsciiExportSummaryPlotFeature::exportAsciiForSummaryPlot(const QString& fileName, const RimSummaryPlot* summaryPlot) +bool RicAsciiExportSummaryPlotFeature::exportAsciiForSummaryPlot(const QString& fileName, + const RimSummaryPlot* summaryPlot, + DateTimePeriod resamplingPeriod) { QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) @@ -130,7 +142,7 @@ bool RicAsciiExportSummaryPlotFeature::exportAsciiForSummaryPlot(const QString& QTextStream out(&file); out << summaryPlot->description(); - out << summaryPlot->asciiDataForPlotExport(); + out << summaryPlot->asciiDataForPlotExport(resamplingPeriod); out << "\n\n"; RiaLogging::info(QString("Competed writing values for summary plot(s) to file %1").arg(fileName)); diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.h b/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.h index b603b23777..e008fd5bba 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.h +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.h @@ -18,6 +18,8 @@ #pragma once +#include "RiaQDateTimeTools.h" + #include "cafCmdFeature.h" class RimSummaryPlot; @@ -35,5 +37,7 @@ protected: virtual void setupActionLook(QAction* actionToSetup) override; private: - static bool exportAsciiForSummaryPlot(const QString& fileName, const RimSummaryPlot* selectedSummaryPlots); + static bool exportAsciiForSummaryPlot(const QString& fileName, + const RimSummaryPlot* selectedSummaryPlots, + DateTimePeriod resamplingPeriod); }; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp index cd9a3b33f8..803edcd01e 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp @@ -63,8 +63,15 @@ CAF_PDM_SOURCE_INIT(RimSummaryPlot, "SummaryPlot"); //-------------------------------------------------------------------------------------------------- -/// Internal data +/// Internal types //-------------------------------------------------------------------------------------------------- +enum class ResampleAlgorithm +{ + NONE, + DATA_DECIDES, + PERIOD_END +}; + struct CurveData { QString name; @@ -75,9 +82,9 @@ struct CurveData //-------------------------------------------------------------------------------------------------- /// Internal functions //-------------------------------------------------------------------------------------------------- -void prepareCaseCurvesForExport(DateTimePeriod period, +void prepareCaseCurvesForExport(DateTimePeriod period, ResampleAlgorithm algorithm, const std::vector &timeSteps, const std::vector& curveData, - std::vector* resampledTimeSteps, std::vector* resampledValues); + std::vector* exportTimeSteps, std::vector* exportValues); void appendToExportData(QString& out, const std::vector& timeSteps, const std::vector& curveData); @@ -315,7 +322,7 @@ QString RimSummaryPlot::asciiDataForPlotExport(DateTimePeriod resamplingPeriod) out += "Case: " + caseNames[i]; out += "\n"; - prepareCaseCurvesForExport(resamplingPeriod, timeSteps[i], allCurveData[i], &expTimeSteps, &expCurveData); + prepareCaseCurvesForExport(resamplingPeriod, ResampleAlgorithm::DATA_DECIDES, timeSteps[i], allCurveData[i], &expTimeSteps, &expCurveData); appendToExportData(out, expTimeSteps, expCurveData); } } @@ -362,7 +369,7 @@ QString RimSummaryPlot::asciiDataForPlotExport(DateTimePeriod resamplingPeriod) out += "Case: " + caseNames[i]; out += "\n"; - prepareCaseCurvesForExport(resamplingPeriod, timeSteps[i], allCurveData[i], &expTimeSteps, &expCurveData); + prepareCaseCurvesForExport(resamplingPeriod, ResampleAlgorithm::PERIOD_END, timeSteps[i], allCurveData[i], &expTimeSteps, &expCurveData); appendToExportData(out, expTimeSteps, expCurveData); } } @@ -400,7 +407,7 @@ QString RimSummaryPlot::asciiDataForPlotExport(DateTimePeriod resamplingPeriod) out += "\n\n"; - prepareCaseCurvesForExport(resamplingPeriod, timeSteps[i], allCurveData[i], &expTimeSteps, &expCurveData); + prepareCaseCurvesForExport(DateTimePeriod::NONE, ResampleAlgorithm::NONE, timeSteps[i], allCurveData[i], &expTimeSteps, &expCurveData); appendToExportData(out, expTimeSteps, expCurveData); } } @@ -1640,14 +1647,14 @@ void RimSummaryPlot::defineEditorAttribute(const caf::PdmFieldHandle* field, QSt //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void prepareCaseCurvesForExport(DateTimePeriod period, +void prepareCaseCurvesForExport(DateTimePeriod period, ResampleAlgorithm algorithm, const std::vector &timeSteps, const std::vector& curveData, - std::vector* resampledTimeSteps, std::vector* resampledCurveData) + std::vector* exportTimeSteps, std::vector* exportCurveData) { RiaTimeHistoryCurveResampler resampler; - resampledTimeSteps->clear(); - resampledCurveData->clear(); + exportTimeSteps->clear(); + exportCurveData->clear(); if (period != DateTimePeriod::NONE) { @@ -1655,20 +1662,26 @@ void prepareCaseCurvesForExport(DateTimePeriod period, { resampler.setCurveData(curveDataItem.values, timeSteps); - if (curveDataItem.address.hasAccumulatedData()) resampler.resampleAndComputePeriodEndValues(period); - else resampler.resampleAndComputeWeightedMeanValues(period); + if (curveDataItem.address.hasAccumulatedData() || algorithm == ResampleAlgorithm::PERIOD_END) + { + resampler.resampleAndComputePeriodEndValues(period); + } + else + { + resampler.resampleAndComputeWeightedMeanValues(period); + } auto cd = curveDataItem; cd.values = resampler.resampledValues(); - resampledCurveData->push_back(cd); + exportCurveData->push_back(cd); } - *resampledTimeSteps = resampler.resampledTimeSteps(); + *exportTimeSteps = resampler.resampledTimeSteps(); } else { - *resampledTimeSteps = timeSteps; - *resampledCurveData = curveData; + *exportTimeSteps = timeSteps; + *exportCurveData = curveData; } }