From 28d093f54acca7447073715b63815a8ad95b5320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Jensen?= Date: Wed, 27 Jun 2018 10:31:07 +0200 Subject: [PATCH] #3086 Resampled plot export. When data are resampled, write all data into the same table in export file --- .../Tools/RiaTimeHistoryCurveResampler.cpp | 21 ++ .../Tools/RiaTimeHistoryCurveResampler.h | 4 +- .../Summary/RimSummaryPlot.cpp | 254 ++++++++++++------ 3 files changed, 201 insertions(+), 78 deletions(-) diff --git a/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.cpp b/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.cpp index 677746d8c0..dc3b6fc919 100644 --- a/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.cpp +++ b/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.cpp @@ -85,6 +85,27 @@ const std::vector& RiaTimeHistoryCurveResampler::resampledValues() const return m_values; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaTimeHistoryCurveResampler::timeStepsFromTimeRange(DateTimePeriod period, time_t minTime, time_t maxTime) +{ + CVF_ASSERT(minTime <= maxTime); + + auto firstOriginalTimeStep = QDT::fromTime_t(minTime); + auto lastOriginalTimeStep = QDT::fromTime_t(maxTime); + + auto currTimeStep = firstResampledTimeStep(firstOriginalTimeStep, period); + + std::vector timeSteps; + while (QDT::lessThanOrEqualTo(currTimeStep, lastOriginalTimeStep)) + { + timeSteps.push_back(currTimeStep.toTime_t()); + currTimeStep = QDT::addPeriod(currTimeStep, period); + } + return timeSteps; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.h b/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.h index ad92ceb7fe..6d191aa704 100644 --- a/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.h +++ b/ApplicationCode/Application/Tools/RiaTimeHistoryCurveResampler.h @@ -42,13 +42,15 @@ public: const std::vector& resampledTimeSteps() const; const std::vector& resampledValues() const; + static std::vector timeStepsFromTimeRange(DateTimePeriod period, time_t minTime, time_t maxTime); + private: void computeWeightedMeanValues(DateTimePeriod period); void computePeriodEndValues(DateTimePeriod period); void clearData(); void computeResampledTimeSteps(DateTimePeriod period); - QDateTime firstResampledTimeStep(const QDateTime& firstTimestep, DateTimePeriod period); + static QDateTime firstResampledTimeStep(const QDateTime& firstTimestep, DateTimePeriod period); inline double interpolatedValue(time_t t, time_t t1, double v1, time_t t2, double v2); private: diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp index c5e5a070ea..fb71d82672 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp @@ -58,10 +58,16 @@ #include #include +#include CAF_PDM_SOURCE_INIT(RimSummaryPlot, "SummaryPlot"); +//-------------------------------------------------------------------------------------------------- +/// Internal constants +//-------------------------------------------------------------------------------------------------- +#define DOUBLE_INF std::numeric_limits::infinity() + //-------------------------------------------------------------------------------------------------- /// Internal types //-------------------------------------------------------------------------------------------------- @@ -79,8 +85,19 @@ struct CurveData std::vector values; }; -struct CurvesData +class CurvesData { +public: + CurvesData() : resamplePeriod(DateTimePeriod::NONE) {} + void clear() + { + resamplePeriod = DateTimePeriod::NONE; + caseNames.clear(); + timeSteps.clear(); + allCurveData.clear(); + } + + DateTimePeriod resamplePeriod; std::vector caseNames; std::vector > timeSteps; std::vector> allCurveData; @@ -95,10 +112,12 @@ void populateTimeHistoryCurvesData(std::vector curves, void populateAsciiDataCurvesData(std::vector curves, CurvesData* curvesData); void prepareCaseCurvesForExport(DateTimePeriod period, ResampleAlgorithm algorithm, - const std::vector &timeSteps, const std::vector& curveData, - std::vector* exportTimeSteps, std::vector* exportValues); + const CurvesData& inputCurvesData, + CurvesData* resultCurvesData); -void appendToExportData(QString& out, const std::vector& timeSteps, const std::vector& curveData); +void appendToExportDataForCase(QString& out, const std::vector& timeSteps, const std::vector& curveData); +void appendToExportData(QString& out, const std::vector& curvesData); +CurvesData concatCurvesData(const std::vector& curvesData); //-------------------------------------------------------------------------------------------------- /// @@ -287,9 +306,7 @@ QString RimSummaryPlot::asciiDataForPlotExport(DateTimePeriod resamplingPeriod) QString out; RiaTimeHistoryCurveResampler resampler; - out += description(); - - // Summary curves + // Summary and time history (from grid) curves { std::vector curves; this->descendantsIncludingThisOfType(curves); @@ -297,49 +314,24 @@ QString RimSummaryPlot::asciiDataForPlotExport(DateTimePeriod resamplingPeriod) CurvesData summaryCurvesData; populateSummaryCurvesData(curves, &summaryCurvesData); - for (size_t i = 0; i < summaryCurvesData.timeSteps.size(); i++) //cases - { - // Data for export - std::vector expTimeSteps; - std::vector expCurveData; - - out += "\n\n"; - out += "Case: " + summaryCurvesData.caseNames[i]; - out += "\n"; - - prepareCaseCurvesForExport(resamplingPeriod, - ResampleAlgorithm::DATA_DECIDES, - summaryCurvesData.timeSteps[i], - summaryCurvesData.allCurveData[i], - &expTimeSteps, - &expCurveData); - appendToExportData(out, expTimeSteps, expCurveData); - } - } - - // Time history curves (from grid) - { CurvesData timeHistoryCurvesData; populateTimeHistoryCurvesData(m_gridTimeHistoryCurves.childObjects(), &timeHistoryCurvesData); - for (size_t i = 0; i < timeHistoryCurvesData.timeSteps.size(); i++) //cases - { - // Data for export - std::vector expTimeSteps; - std::vector expCurveData; + std::vector exportData(2); - out += "\n\n"; - out += "Case: " + timeHistoryCurvesData.caseNames[i]; - out += "\n"; + // Summary data for export + prepareCaseCurvesForExport(resamplingPeriod, + ResampleAlgorithm::DATA_DECIDES, + summaryCurvesData, + &exportData[0]); - prepareCaseCurvesForExport(resamplingPeriod, - ResampleAlgorithm::PERIOD_END, - timeHistoryCurvesData.timeSteps[i], - timeHistoryCurvesData.allCurveData[i], - &expTimeSteps, - &expCurveData); - appendToExportData(out, expTimeSteps, expCurveData); - } + // Time history data for export + prepareCaseCurvesForExport(resamplingPeriod, + ResampleAlgorithm::PERIOD_END, + timeHistoryCurvesData, + &exportData[1]); + + appendToExportData(out, exportData); } // Pasted observed data @@ -347,21 +339,11 @@ QString RimSummaryPlot::asciiDataForPlotExport(DateTimePeriod resamplingPeriod) CurvesData asciiCurvesData; populateAsciiDataCurvesData(m_asciiDataCurves.childObjects(), &asciiCurvesData); - for (size_t i = 0; i < asciiCurvesData.timeSteps.size(); i++) //cases + for (size_t i = 0; i < asciiCurvesData.timeSteps.size(); i++) { - // Data for export - std::vector expTimeSteps; - std::vector expCurveData; - out += "\n\n"; - prepareCaseCurvesForExport(DateTimePeriod::NONE, - ResampleAlgorithm::NONE, - asciiCurvesData.timeSteps[i], - asciiCurvesData.allCurveData[i], - &expTimeSteps, - &expCurveData); - appendToExportData(out, expTimeSteps, expCurveData); + appendToExportDataForCase(out, asciiCurvesData.timeSteps[i], asciiCurvesData.allCurveData[i]); } } @@ -1655,6 +1637,7 @@ void populateAsciiDataCurvesData(std::vector curves, CurvesD if (casePosInList == cvf::UNDEFINED_SIZE_T) { + curvesData->caseNames.push_back(""); curvesData->timeSteps.push_back(curve->timeSteps()); curvesData->allCurveData.push_back(std::vector({ curveData })); } @@ -1706,47 +1689,60 @@ void populateSummaryCurvesData(std::vector curves, CurvesData* /// //-------------------------------------------------------------------------------------------------- void prepareCaseCurvesForExport(DateTimePeriod period, ResampleAlgorithm algorithm, - const std::vector &timeSteps, const std::vector& curveData, - std::vector* exportTimeSteps, std::vector* exportCurveData) + const CurvesData& inputCurvesData, + CurvesData* resultCurvesData) { RiaTimeHistoryCurveResampler resampler; - exportTimeSteps->clear(); - exportCurveData->clear(); + resultCurvesData->clear(); if (period != DateTimePeriod::NONE) { - for (auto& curveDataItem : curveData) + for (int i = 0; i < inputCurvesData.caseNames.size(); i++) { - resampler.setCurveData(curveDataItem.values, timeSteps); + // Shortcuts to input data + auto& caseName = inputCurvesData.caseNames[i]; + auto& caseTimeSteps = inputCurvesData.timeSteps[i]; + auto& caseCurveData = inputCurvesData.allCurveData[i]; - if (curveDataItem.address.hasAccumulatedData() || algorithm == ResampleAlgorithm::PERIOD_END) + // Prepare result data + resultCurvesData->resamplePeriod = period; + //resultCurvesData->resampleAlgorithm = algorithm; + resultCurvesData->caseNames.push_back(caseName); + resultCurvesData->allCurveData.push_back(std::vector()); + + for (auto& curveDataItem : caseCurveData) { - resampler.resampleAndComputePeriodEndValues(period); - } - else - { - resampler.resampleAndComputeWeightedMeanValues(period); + resampler.setCurveData(curveDataItem.values, caseTimeSteps); + + if (curveDataItem.address.hasAccumulatedData() || algorithm == ResampleAlgorithm::PERIOD_END) + { + resampler.resampleAndComputePeriodEndValues(period); + } + else + { + resampler.resampleAndComputeWeightedMeanValues(period); + } + + auto cd = curveDataItem; + cd.values = resampler.resampledValues(); + auto& currResultCurveDataList = resultCurvesData->allCurveData[i]; + currResultCurveDataList.push_back(cd); } - auto cd = curveDataItem; - cd.values = resampler.resampledValues(); - exportCurveData->push_back(cd); + resultCurvesData->timeSteps.push_back(resampler.resampledTimeSteps()); } - - *exportTimeSteps = resampler.resampledTimeSteps(); } else { - *exportTimeSteps = timeSteps; - *exportCurveData = curveData; + *resultCurvesData = inputCurvesData; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void appendToExportData(QString& out, const std::vector& timeSteps, const std::vector& curveData) +void appendToExportDataForCase(QString& out, const std::vector& timeSteps, const std::vector& curveData) { for (size_t j = 0; j < timeSteps.size(); j++) //time steps & data points { @@ -1772,3 +1768,107 @@ void appendToExportData(QString& out, const std::vector& timeSteps, cons } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void appendToExportData(QString& out, const std::vector& curvesData) +{ + CurvesData data = concatCurvesData(curvesData); + + if (data.resamplePeriod != DateTimePeriod::NONE) + { + time_t minTimeStep = std::numeric_limits::max(); + time_t maxTimeStep = 0; + + for (auto& timeSteps : data.timeSteps) + { + if (!timeSteps.empty()) + { + if (timeSteps.front() < minTimeStep) minTimeStep = timeSteps.front(); + if (timeSteps.back() > maxTimeStep) maxTimeStep = timeSteps.back(); + } + } + + auto allTimeSteps = RiaTimeHistoryCurveResampler::timeStepsFromTimeRange(data.resamplePeriod, minTimeStep, maxTimeStep); + + out += "\n\n"; + out += "Date and time"; + for (size_t i = 0; i < data.caseNames.size(); i++) + { + for (size_t j = 0; j < data.allCurveData[i].size(); j++) + { + out += "\t" + data.allCurveData[i][j].name + " (" + data.caseNames[i] + ")"; + } + } + out += "\n"; + + std::vector currIndexes(data.caseNames.size()); + for (auto& i : currIndexes) i = 0; + + for (auto timeStep : allTimeSteps) + { + out += QDateTime::fromTime_t(timeStep).toUTC().toString("yyyy-MM-dd hh:mm:ss "); + + for (size_t i = 0; i < data.caseNames.size(); i++) // cases + { + // Check is time step exists in curr case + int& currIndex = currIndexes[i]; + bool timeStepExists = currIndex < data.timeSteps[i].size() && timeStep == data.timeSteps[i][currIndex]; + + for (size_t j = 0; j < data.allCurveData[i].size(); j++) // vectors + { + QString valueText; + if (timeStepExists) + { + valueText = QString::number(data.allCurveData[i][j].values[currIndex], 'g', 6); + } + else + { + valueText = "inf"; + } + out += "\t" + valueText; + } + + if (currIndex < data.timeSteps[i].size()) currIndex++; + } + out += "\n"; + } + } + else + { + for (size_t i = 0; i < data.caseNames.size(); i++) + { + out += "\n\n"; + out += "Case: " + data.caseNames[i]; + out += "\n"; + + appendToExportDataForCase(out, data.timeSteps[i], data.allCurveData[i]); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +CurvesData concatCurvesData(const std::vector& curvesData) +{ + CVF_ASSERT(!curvesData.empty()); + + DateTimePeriod period = curvesData.front().resamplePeriod; + CurvesData resultCurvesData; + + resultCurvesData.resamplePeriod = period; + + for (auto curvesDataItem : curvesData) + { + if (curvesDataItem.caseNames.empty()) continue; + + CVF_ASSERT(curvesDataItem.resamplePeriod == period); + + resultCurvesData.caseNames.insert(resultCurvesData.caseNames.end(), curvesDataItem.caseNames.begin(), curvesDataItem.caseNames.end()); + resultCurvesData.timeSteps.insert(resultCurvesData.timeSteps.end(), curvesDataItem.timeSteps.begin(), curvesDataItem.timeSteps.end()); + resultCurvesData.allCurveData.insert(resultCurvesData.allCurveData.end(), curvesDataItem.allCurveData.begin(), curvesDataItem.allCurveData.end()); + } + return resultCurvesData; +}