From 686a47587bcb01878db1a8b0829582e37f111ff1 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 21 Nov 2017 08:10:28 +0100 Subject: [PATCH] #2125 Curve Calculations : Add TimeHistoryCurveMerger --- .../ReservoirDataModel/CMakeLists_files.cmake | 2 + .../ReservoirDataModel/RigCurveDataTools.cpp | 219 ---------------- .../ReservoirDataModel/RigCurveDataTools.h | 45 +--- .../RigTimeHistoryCurveMerger.cpp | 215 ++++++++++++++++ .../RigTimeHistoryCurveMerger.h | 68 +++++ .../UnitTests/CMakeLists_files.cmake | 1 + .../RigTimeCurveHistoryMerger-Test.cpp | 187 ++++++++++++++ .../RimWellLogExtractionCurveImpl-Test.cpp | 241 ------------------ 8 files changed, 474 insertions(+), 504 deletions(-) create mode 100644 ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.cpp create mode 100644 ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.h create mode 100644 ApplicationCode/UnitTests/RigTimeCurveHistoryMerger-Test.cpp diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 59fbda7c9e..d3da9952ff 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -64,6 +64,7 @@ ${CEE_CURRENT_LIST_DIR}RigTofAccumulatedPhaseFractionsCalculator.h ${CEE_CURRENT_LIST_DIR}RigTransmissibilityEquations.h ${CEE_CURRENT_LIST_DIR}RigNumberOfFloodedPoreVolumesCalculator.h ${CEE_CURRENT_LIST_DIR}RigWeightedMeanCalc.h +${CEE_CURRENT_LIST_DIR}RigTimeHistoryCurveMerger.h ) if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_FRACTURES) @@ -134,6 +135,7 @@ ${CEE_CURRENT_LIST_DIR}RigTofAccumulatedPhaseFractionsCalculator.cpp ${CEE_CURRENT_LIST_DIR}RigTransmissibilityEquations.cpp ${CEE_CURRENT_LIST_DIR}RigNumberOfFloodedPoreVolumesCalculator.cpp ${CEE_CURRENT_LIST_DIR}RigWeightedMeanCalc.cpp +${CEE_CURRENT_LIST_DIR}RigTimeHistoryCurveMerger.cpp ) if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_FRACTURES) diff --git a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp index 7b26ebb343..6ddfeedb28 100644 --- a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp @@ -19,10 +19,8 @@ #include "RigCurveDataTools.h" -#include #include // Needed for HUGE_VAL on Linux -#include //-------------------------------------------------------------------------------------------------- @@ -107,220 +105,3 @@ bool RigCurveDataTools::isValidValue(double value, bool removeNegativeValues) return true; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RigCurveDataTools::isValidValue(double value) -{ - if (value == HUGE_VAL || value == -HUGE_VAL || value != value) - { - return false; - } - - return true; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigCurveDataInterpolationTools::RigCurveDataInterpolationTools(const std::vector& valuesA, - const std::vector& timeStepsA, - const std::vector& valuesB, - const std::vector& timeStepsB) - : m_valuesA(valuesA), - m_timeStepsA(timeStepsA), - m_valuesB(valuesB), - m_timeStepsB(timeStepsB) -{ - computeInterpolatedValues(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigCurveDataTools::CurveIntervals RigCurveDataInterpolationTools::validIntervals() const -{ - return m_curveIntervals; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector> RigCurveDataInterpolationTools::interpolatedCurveData() const -{ - return m_interpolatedValues; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigCurveDataInterpolationTools::computeInterpolatedValues() -{ - if (m_valuesA.size() != m_timeStepsA.size() || m_valuesB.size() != m_timeStepsB.size()) - { - return; - } - - const bool removeNegativeValues = false; - - auto validIntervalsA = RigCurveDataTools::calculateIntervalsOfValidValues(m_valuesA, removeNegativeValues); - - std::vector> validTimeStepsA; - for (const auto& interval : validIntervalsA) - { - validTimeStepsA.push_back(std::make_pair(m_timeStepsA[interval.first], m_timeStepsA[interval.second])); - } - - auto validIntervalsB = RigCurveDataTools::calculateIntervalsOfValidValues(m_valuesB, removeNegativeValues); - for (const auto& interval : validIntervalsB) - { - const QDateTime& from = m_timeStepsB[interval.first]; - const QDateTime& to = m_timeStepsB[interval.second]; - - auto intervals = intersectingValidIntervals(from, to, validTimeStepsA); - - for (const auto& i : intervals) - { - std::set validTimeSteps; - - // Add all time steps from curve A inside interval - for (const auto& d : m_timeStepsA) - { - if (i.first <= d && d <= i.second) - { - validTimeSteps.insert(d); - } - } - - // Add all time steps from curve B inside interval - for (const auto& d : m_timeStepsB) - { - if (i.first <= d && d <= i.second) - { - validTimeSteps.insert(d); - } - } - - size_t firstIndex = m_interpolatedValues.size(); - for (const auto& dt : validTimeSteps) - { - double valueA = RigCurveDataInterpolationTools::interpolatedValue(dt, m_valuesA, m_timeStepsA); - double valueB = RigCurveDataInterpolationTools::interpolatedValue(dt, m_valuesB, m_timeStepsB); - - m_interpolatedValues.push_back(std::make_tuple(dt, valueA, valueB)); - } - size_t lastIndex = m_interpolatedValues.size() - 1; - - m_curveIntervals.push_back(std::make_pair(firstIndex, lastIndex)); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector> RigCurveDataInterpolationTools::intersectingValidIntervals(const QDateTime& a, - const QDateTime& b, - const std::vector>& intervals) -{ - std::vector> validIntervals; - - for (const auto& interval : intervals) - { - const QDateTime& c = interval.first; - const QDateTime& d = interval.second; - - if (d < a) - { - continue; - } - - if (b < c) - { - // We assume the intervals are increasing, and all other intervals are larger - break; - } - - if (c <= a) - { - if (b <= d) - { - validIntervals.push_back(std::make_pair(a, b)); - } - else - { - validIntervals.push_back(std::make_pair(a, d)); - } - } - else - { - if (b <= d) - { - validIntervals.push_back(std::make_pair(c, b)); - } - else - { - validIntervals.push_back(std::make_pair(c, d)); - } - } - } - - return validIntervals; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RigCurveDataInterpolationTools::interpolatedValue(const QDateTime& dt, const std::vector& values, const std::vector& timeSteps) -{ - if (values.size() != timeSteps.size()) return HUGE_VAL; - - for (size_t firstI = 0; firstI < timeSteps.size(); firstI++) - { - size_t secondI = firstI + 1; - - if (secondI == timeSteps.size()) - { - if (timeSteps[firstI] == dt) - { - return values[firstI]; - } - } - - if (secondI < timeSteps.size() && - timeSteps[firstI] <= dt && - timeSteps[secondI] > dt) - { - const double& firstValue = values[firstI]; - const double& secondValue = values[secondI]; - - bool isFirstValid = RigCurveDataTools::isValidValue(firstValue); - bool isSecondValid = RigCurveDataTools::isValidValue(secondValue); - - if (!isFirstValid && !isSecondValid) - { - CVF_ASSERT(false); - - return HUGE_VAL; - } - - if (!isFirstValid) return secondValue; - if (!isSecondValid) return firstValue; - - double firstDiff = timeSteps[firstI].secsTo(dt); - double secondDiff = dt.secsTo(timeSteps[secondI]); - - double firstWeight = secondDiff / (firstDiff + secondDiff); - double secondWeight = firstDiff / (firstDiff + secondDiff); - - double val = (firstValue * firstWeight) + (secondValue * secondWeight); - - CVF_ASSERT(RigCurveDataTools::isValidValue(val)); - - return val; - } - } - - return HUGE_VAL; -} - diff --git a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h index df17f589a3..9f559324aa 100644 --- a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h +++ b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include class QDateTime; @@ -63,48 +63,5 @@ public: // Helper methods, available as public to be able to access from unit tests static bool isValidValue(double value, bool removeNegativeValues); - static bool isValidValue(double value); }; - -//================================================================================================== -/// -//================================================================================================== -class RigCurveDataInterpolationTools -{ -public: - RigCurveDataInterpolationTools(const std::vector& valuesA, - const std::vector& timeStepsA, - const std::vector& valuesB, - const std::vector& timeStepsB); - - - - RigCurveDataTools::CurveIntervals validIntervals() const; - std::vector> interpolatedCurveData() const; - - - -public: - // Helper methods, available as public to be able to access from unit tests - - static std::vector> intersectingValidIntervals(const QDateTime& from, - const QDateTime& to, - const std::vector>& intervals); - - static double interpolatedValue(const QDateTime& dt, - const std::vector& values, - const std::vector& timeSteps); - -private: - void computeInterpolatedValues(); - -private: - const std::vector& m_valuesA; - const std::vector& m_timeStepsA; - const std::vector& m_valuesB; - const std::vector& m_timeStepsB; - - std::vector> m_interpolatedValues; - RigCurveDataTools::CurveIntervals m_curveIntervals; -}; diff --git a/ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.cpp b/ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.cpp new file mode 100644 index 0000000000..37e88709d4 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.cpp @@ -0,0 +1,215 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RigTimeHistoryCurveMerger.h" + + +#include // Needed for HUGE_VAL on Linux + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigTimeHistoryCurveMerger::RigTimeHistoryCurveMerger() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTimeHistoryCurveMerger::addCurveData(const std::vector& values, const std::vector& timeSteps) +{ + CVF_ASSERT(values.size() == timeSteps.size()); + + m_originalValues.push_back(std::make_pair(values, timeSteps)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCurveDataTools::CurveIntervals RigTimeHistoryCurveMerger::validIntervalsForAllTimeSteps() const +{ + return m_validIntervalsForAllTimeSteps; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigTimeHistoryCurveMerger::allTimeSteps() const +{ + return m_allTimeSteps; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigTimeHistoryCurveMerger::interpolatedCurveValuesForAllTimeSteps(size_t curveIdx) const +{ + CVF_ASSERT(curveIdx < m_interpolatedValuesForAllCurves.size()); + + return m_interpolatedValuesForAllCurves[curveIdx]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector& RigTimeHistoryCurveMerger::interpolatedCurveValuesForAllTimeSteps(size_t curveIdx) +{ + CVF_ASSERT(curveIdx < m_interpolatedValuesForAllCurves.size()); + + return m_interpolatedValuesForAllCurves[curveIdx]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTimeHistoryCurveMerger::computeInterpolatedValues() +{ + m_validIntervalsForAllTimeSteps.clear(); + m_allTimeSteps.clear(); + m_interpolatedValuesForAllCurves.clear(); + + computeUnionOfTimeSteps(); + + const size_t curveCount = m_originalValues.size(); + if (curveCount == 0) + { + return; + } + + const size_t dataValueCount = m_allTimeSteps.size(); + if (dataValueCount == 0) + { + return; + } + + m_interpolatedValuesForAllCurves.resize(curveCount); + + std::vector accumulatedValidValues(dataValueCount, 1.0); + + for (size_t curveIdx = 0; curveIdx < curveCount; curveIdx++) + { + std::vector& curveValues = m_interpolatedValuesForAllCurves[curveIdx]; + curveValues.resize(dataValueCount); + + for (size_t valueIndex = 0; valueIndex < dataValueCount; valueIndex++) + { + double interpolValue = interpolationValue(m_allTimeSteps[valueIndex], m_originalValues[curveIdx].first, m_originalValues[curveIdx].second); + if (!RigCurveDataTools::isValidValue(interpolValue, false)) + { + accumulatedValidValues[valueIndex] = HUGE_VAL; + } + + curveValues[valueIndex] = interpolValue; + } + } + + m_validIntervalsForAllTimeSteps = RigCurveDataTools::calculateIntervalsOfValidValues(accumulatedValidValues, false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTimeHistoryCurveMerger::computeUnionOfTimeSteps() +{ + m_allTimeSteps.clear(); + + std::set unionOfTimeSteps; + + for (const auto& curveData : m_originalValues) + { + for (const auto& dt : curveData.second) + { + unionOfTimeSteps.insert(dt); + } + } + + for (const auto& dt : unionOfTimeSteps) + { + m_allTimeSteps.push_back(dt); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigTimeHistoryCurveMerger::interpolationValue(const time_t& interpolationTimeStep, + const std::vector& curveValues, + const std::vector& curveTimeSteps) +{ + if (curveValues.size() != curveTimeSteps.size()) return HUGE_VAL; + + const bool removeInterpolatedValues = false; + + for (size_t firstI = 0; firstI < curveTimeSteps.size(); firstI++) + { + if (curveTimeSteps.at(firstI) == interpolationTimeStep) + { + const double& firstValue = curveValues.at(firstI); + if (!RigCurveDataTools::isValidValue(firstValue, removeInterpolatedValues)) + { + return HUGE_VAL; + } + + return firstValue; + } + + size_t secondI = firstI + 1; + + if (secondI < curveTimeSteps.size() && + curveTimeSteps.at(firstI) <= interpolationTimeStep && + curveTimeSteps.at(secondI) > interpolationTimeStep) + { + if (curveTimeSteps.at(secondI) == interpolationTimeStep) + { + const double& secondValue = curveValues.at(secondI); + if (!RigCurveDataTools::isValidValue(secondValue, removeInterpolatedValues)) + { + return HUGE_VAL; + } + + return secondValue; + } + + const double& firstValue = curveValues.at(firstI); + const double& secondValue = curveValues.at(secondI); + + bool isFirstValid = RigCurveDataTools::isValidValue(firstValue, removeInterpolatedValues); + if (!isFirstValid) return HUGE_VAL; + + bool isSecondValid = RigCurveDataTools::isValidValue(secondValue, removeInterpolatedValues); + if (!isSecondValid) return HUGE_VAL; + + double firstDiff = interpolationTimeStep - curveTimeSteps.at(firstI); + double secondDiff = curveTimeSteps.at(secondI) - interpolationTimeStep; + + double firstWeight = secondDiff / (firstDiff + secondDiff); + double secondWeight = firstDiff / (firstDiff + secondDiff); + + double val = (firstValue * firstWeight) + (secondValue * secondWeight); + + CVF_ASSERT(RigCurveDataTools::isValidValue(val, removeInterpolatedValues)); + + return val; + } + } + + return HUGE_VAL; +} + diff --git a/ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.h b/ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.h new file mode 100644 index 0000000000..5a1de82f9d --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigTimeHistoryCurveMerger.h @@ -0,0 +1,68 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RigCurveDataTools.h" + +#include + + +//================================================================================================== +/// +//================================================================================================== +class RigTimeHistoryCurveMerger +{ +public: + RigTimeHistoryCurveMerger(); + + + void addCurveData(const std::vector& values, + const std::vector& timeSteps); + + void computeInterpolatedValues(); + + RigCurveDataTools::CurveIntervals validIntervalsForAllTimeSteps() const; + const std::vector& allTimeSteps() const; + const std::vector& interpolatedCurveValuesForAllTimeSteps(size_t curveIdx) const; + + // Non-const access is not required by any clients, but the expression parser has no available const interface + // for specifying a data source for an expression variable. Allow non-const access to avoid copy of the contained + // values, interpolated for all time steps + // + // See ExpressionParserImpl::assignVector() + std::vector& interpolatedCurveValuesForAllTimeSteps(size_t curveIdx); + +public: + // Helper methods, available as public to be able to access from unit tests + + static double interpolationValue(const time_t& interpolationTimeStep, + const std::vector& curveValues, + const std::vector& curveTimeSteps); + +private: + void computeUnionOfTimeSteps(); + +private: + std::vector, std::vector>> m_originalValues; + + RigCurveDataTools::CurveIntervals m_validIntervalsForAllTimeSteps; + + std::vector m_allTimeSteps; + std::vector> m_interpolatedValuesForAllCurves; +}; diff --git a/ApplicationCode/UnitTests/CMakeLists_files.cmake b/ApplicationCode/UnitTests/CMakeLists_files.cmake index 6706b092a9..8598672a90 100644 --- a/ApplicationCode/UnitTests/CMakeLists_files.cmake +++ b/ApplicationCode/UnitTests/CMakeLists_files.cmake @@ -33,6 +33,7 @@ ${CEE_CURRENT_LIST_DIR}EclipseRftReader-Test.cpp ${CEE_CURRENT_LIST_DIR}RicExpressionParser-Test.cpp ${CEE_CURRENT_LIST_DIR}RiuSummaryVectorDescriptionMap-Test.cpp ${CEE_CURRENT_LIST_DIR}FixedWidthDataParser-Test.cpp +${CEE_CURRENT_LIST_DIR}RigTimeCurveHistoryMerger-Test.cpp ) if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_FRACTURES) diff --git a/ApplicationCode/UnitTests/RigTimeCurveHistoryMerger-Test.cpp b/ApplicationCode/UnitTests/RigTimeCurveHistoryMerger-Test.cpp new file mode 100644 index 0000000000..5b69e3fcbd --- /dev/null +++ b/ApplicationCode/UnitTests/RigTimeCurveHistoryMerger-Test.cpp @@ -0,0 +1,187 @@ +#include "gtest/gtest.h" + +#include "RigTimeHistoryCurveMerger.h" + +#include // Needed for HUGE_VAL on Linux + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RigTimeHistoryCurveMergerTest, TestDateInterpolation) +{ + std::vector values{ 2.0, 3.5, 5.0, 6.0}; + std::vector timeSteps{ 1, 5, 10, 15}; + + { + double val = RigTimeHistoryCurveMerger::interpolationValue(1, values, timeSteps); + + EXPECT_EQ(2.0, val); + } + + { + double val = RigTimeHistoryCurveMerger::interpolationValue(0, values, timeSteps); + + EXPECT_EQ(HUGE_VAL, val); + } + + { + double val = RigTimeHistoryCurveMerger::interpolationValue(20, values, timeSteps); + + EXPECT_EQ(HUGE_VAL, val); + } + + { + double val = RigTimeHistoryCurveMerger::interpolationValue(3, values, timeSteps); + + EXPECT_EQ(2.75, val); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RigTimeHistoryCurveMergerTest, ExtractIntervalsWithSameTimeSteps) +{ + std::vector valuesA { HUGE_VAL, 1.0, HUGE_VAL, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, HUGE_VAL }; + std::vector valuesB { 10, 20, 30, 40, 45, HUGE_VAL, HUGE_VAL, 5.0, 6.0, HUGE_VAL }; + + EXPECT_EQ(valuesA.size(), valuesB.size()); + + std::vector timeSteps; + for (size_t i = 0; i < 10; i++) + { + timeSteps.push_back(i); + } + + RigTimeHistoryCurveMerger interpolate; + interpolate.addCurveData(valuesA, timeSteps); + interpolate.addCurveData(valuesB, timeSteps); + interpolate.computeInterpolatedValues(); + + auto interpolatedTimeSteps = interpolate.allTimeSteps(); + auto intervals = interpolate.validIntervalsForAllTimeSteps(); + + EXPECT_EQ(10, static_cast(interpolatedTimeSteps.size())); + EXPECT_EQ(3, static_cast(intervals.size())); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RigTimeHistoryCurveMergerTest, ExtractIntervalsWithSameTimeStepsOneComplete) +{ + std::vector valuesA { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; + std::vector valuesB { 10, 20, 30, HUGE_VAL, 50, HUGE_VAL, 70 }; + + EXPECT_EQ(valuesA.size(), valuesB.size()); + + std::vector timeSteps; + for (size_t i = 0; i < 7; i++) + { + timeSteps.push_back(i); + } + + RigTimeHistoryCurveMerger interpolate; + interpolate.addCurveData(valuesA, timeSteps); + interpolate.addCurveData(valuesB, timeSteps); + interpolate.computeInterpolatedValues(); + + auto interpolatedTimeSteps = interpolate.allTimeSteps(); + auto intervals = interpolate.validIntervalsForAllTimeSteps(); + + EXPECT_EQ(7, static_cast(interpolatedTimeSteps.size())); + EXPECT_EQ(3, static_cast(intervals.size())); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RigTimeHistoryCurveMergerTest, ExtractIntervalsWithSameTimeStepsBothComplete) +{ + std::vector valuesA{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; + std::vector valuesB{ 10, 20, 30, 40, 50, 60, 70 }; + + EXPECT_EQ(valuesA.size(), valuesB.size()); + + std::vector timeSteps; + for (size_t i = 0; i < 7; i++) + { + timeSteps.push_back(i); + } + + RigTimeHistoryCurveMerger interpolate; + interpolate.addCurveData(valuesA, timeSteps); + interpolate.addCurveData(valuesB, timeSteps); + interpolate.computeInterpolatedValues(); + + auto interpolatedTimeSteps = interpolate.allTimeSteps(); + auto intervals = interpolate.validIntervalsForAllTimeSteps(); + + EXPECT_EQ(7, static_cast(interpolatedTimeSteps.size())); + EXPECT_EQ(1, static_cast(intervals.size())); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RigTimeHistoryCurveMergerTest, OverlappintTimes) +{ + std::vector valuesA{ 1, 2, 3, 4, 5 }; + std::vector valuesB{ 10, 20, 30, 40, 50 }; + + EXPECT_EQ(valuesA.size(), valuesB.size()); + + std::vector timeStepsA{ 0, 10, 11, 15, 20 }; + std::vector timeStepsB{ 1, 2, 3, 5, 7 }; + + RigTimeHistoryCurveMerger interpolate; + interpolate.addCurveData(valuesA, timeStepsA); + interpolate.addCurveData(valuesB, timeStepsB); + interpolate.computeInterpolatedValues(); + + auto interpolatedTimeSteps = interpolate.allTimeSteps(); + auto intervals = interpolate.validIntervalsForAllTimeSteps(); + + EXPECT_EQ(10, static_cast(interpolatedTimeSteps.size())); + EXPECT_EQ(1, static_cast(intervals.size())); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RigTimeHistoryCurveMergerTest, RobustUse) +{ + { + RigTimeHistoryCurveMerger curveMerger; + curveMerger.computeInterpolatedValues(); + EXPECT_EQ(0, static_cast(curveMerger.allTimeSteps().size())); + } + + std::vector valuesA{ 1, 2, 3, 4, 5 }; + std::vector valuesB{ 10, 20, 30 }; + + std::vector timeStepsA{ 0, 10, 11, 15, 20 }; + std::vector timeStepsB{ 1, 2, 3 }; + + { + RigTimeHistoryCurveMerger curveMerger; + curveMerger.addCurveData(valuesA, timeStepsA); + curveMerger.computeInterpolatedValues(); + EXPECT_EQ(timeStepsA.size(), curveMerger.allTimeSteps().size()); + EXPECT_EQ(timeStepsA.size(), curveMerger.interpolatedCurveValuesForAllTimeSteps(0).size()); + } + + { + RigTimeHistoryCurveMerger curveMerger; + curveMerger.addCurveData(valuesA, timeStepsA); + curveMerger.addCurveData(valuesB, timeStepsB); + + // Execute interpolation twice is allowed + curveMerger.computeInterpolatedValues(); + curveMerger.computeInterpolatedValues(); + EXPECT_EQ(8, static_cast(curveMerger.allTimeSteps().size())); + EXPECT_EQ(8, static_cast(curveMerger.interpolatedCurveValuesForAllTimeSteps(0).size())); + EXPECT_EQ(8, static_cast(curveMerger.interpolatedCurveValuesForAllTimeSteps(1).size())); + } +} + diff --git a/ApplicationCode/UnitTests/RimWellLogExtractionCurveImpl-Test.cpp b/ApplicationCode/UnitTests/RimWellLogExtractionCurveImpl-Test.cpp index 383ccb6941..9f3d65ccc1 100644 --- a/ApplicationCode/UnitTests/RimWellLogExtractionCurveImpl-Test.cpp +++ b/ApplicationCode/UnitTests/RimWellLogExtractionCurveImpl-Test.cpp @@ -3,7 +3,6 @@ #include "RigCurveDataTools.h" #include // Needed for HUGE_VAL on Linux -#include "QDateTime" #include @@ -52,243 +51,3 @@ TEST(RimWellLogExtractionCurveImplTest, StripOffHugeValAtEndsAndInteriorOfVector EXPECT_EQ(6, static_cast(valuesIntervals[1].second)); } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RimWellLogExtractionCurveImplTest, DateOverlap) -{ - std::vector> dayIntervalsA { {5, 7}, {9, 12}, {15, 15}, {20, 30} , {30, 31}}; - std::vector> dayIntervalsB { {3, 5}, {8, 13}, {15, 15}, {21, 22}, {25, 27}}; - - QDateTime startDate; - - std::vector> intervalsA; - for (const auto& interval : dayIntervalsA) - { - intervalsA.push_back(std::make_pair(startDate.addDays(interval.first), startDate.addDays(interval.second))); - } - - std::vector> intervalsB; - for (const auto& interval : dayIntervalsB) - { - intervalsB.push_back(std::make_pair(startDate.addDays(interval.first), startDate.addDays(interval.second))); - } - - std::vector> allDayIntervals; - - for (const auto& intervalA : intervalsA) - { - auto intersecting = RigCurveDataInterpolationTools::intersectingValidIntervals(intervalA.first, intervalA.second, intervalsB); - for (const auto& i : intersecting) - { - allDayIntervals.push_back(std::make_pair(startDate.daysTo(i.first), startDate.daysTo(i.second))); - } - } - - EXPECT_EQ(5, static_cast(allDayIntervals.size())); - - EXPECT_EQ(5, allDayIntervals[0].first); - EXPECT_EQ(5, allDayIntervals[0].second); - - EXPECT_EQ( 9, allDayIntervals[1].first); - EXPECT_EQ(12, allDayIntervals[1].second); - - EXPECT_EQ(15, allDayIntervals[2].first); - EXPECT_EQ(15, allDayIntervals[2].second); - - EXPECT_EQ(21, allDayIntervals[3].first); - EXPECT_EQ(22, allDayIntervals[3].second); - - EXPECT_EQ(25, allDayIntervals[4].first); - EXPECT_EQ(27, allDayIntervals[4].second); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RimWellLogExtractionCurveImplTest, TestDateInterpolation) -{ - std::vector values{ 2.0, 3.5, 5.0, 6.0}; - std::vector days{ 1, 5, 10, 15}; - - QDateTime startDate; - - std::vector timeSteps; - for (const auto& day : days) - { - timeSteps.push_back(startDate.addDays(day)); - } - - { - QDateTime dt = startDate.addDays(1); - double val = RigCurveDataInterpolationTools::interpolatedValue(dt, values, timeSteps); - - EXPECT_EQ(2.0, val); - } - - { - QDateTime dt = startDate.addDays(0); - double val = RigCurveDataInterpolationTools::interpolatedValue(dt, values, timeSteps); - - EXPECT_EQ(HUGE_VAL, val); - } - - { - QDateTime dt = startDate.addDays(20); - double val = RigCurveDataInterpolationTools::interpolatedValue(dt, values, timeSteps); - - EXPECT_EQ(HUGE_VAL, val); - } - - { - QDateTime dt = startDate.addDays(3); - double val = RigCurveDataInterpolationTools::interpolatedValue(dt, values, timeSteps); - - EXPECT_EQ(2.75, val); - } - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RimWellLogExtractionCurveImplTest, ExtractIntervalsWithSameTimeSteps) -{ - std::vector valuesA { HUGE_VAL, 1.0, HUGE_VAL, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, HUGE_VAL }; - std::vector valuesB { 10, 20, 30, 40, 45, HUGE_VAL, HUGE_VAL, 5.0, 6.0, HUGE_VAL }; - - EXPECT_EQ(valuesA.size(), valuesB.size()); - - std::vector days(10); - std::iota(days.begin(), days.end(), 10); - - QDateTime startDate; - - std::vector timeSteps; - for (const auto& day : days) - { - timeSteps.push_back(startDate.addDays(day)); - } - - RigCurveDataInterpolationTools interpolate(valuesA, timeSteps, valuesB, timeSteps); - - auto values = interpolate.interpolatedCurveData(); - auto intervals = interpolate.validIntervals(); - - EXPECT_EQ(5, static_cast(values.size())); - EXPECT_EQ(3, static_cast(intervals.size())); - - EXPECT_EQ( 1.0, std::get<1>(values[0])); - EXPECT_EQ(20.0, std::get<2>(values[0])); - - EXPECT_EQ( 2.0, std::get<1>(values[1])); - EXPECT_EQ(40.0, std::get<2>(values[1])); - - EXPECT_EQ( 2.5, std::get<1>(values[2])); - EXPECT_EQ(45.0, std::get<2>(values[2])); - - EXPECT_EQ(5.0, std::get<1>(values[3])); - EXPECT_EQ(5.0, std::get<2>(values[3])); - - EXPECT_EQ(6.0, std::get<1>(values[4])); - EXPECT_EQ(6.0, std::get<2>(values[4])); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RimWellLogExtractionCurveImplTest, ExtractIntervalsWithSameTimeStepsOneComplete) -{ - std::vector valuesA { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; - std::vector valuesB { 10, 20, 30, HUGE_VAL, 50, HUGE_VAL, 70 }; - - EXPECT_EQ(valuesA.size(), valuesB.size()); - - std::vector days(7); - std::iota(days.begin(), days.end(), 10); - - QDateTime startDate; - - std::vector timeSteps; - for (const auto& day : days) - { - timeSteps.push_back(startDate.addDays(day)); - } - - RigCurveDataInterpolationTools interpolate(valuesA, timeSteps, valuesB, timeSteps); - - auto values = interpolate.interpolatedCurveData(); - auto intervals = interpolate.validIntervals(); - - EXPECT_EQ(5, static_cast(values.size())); - EXPECT_EQ(3, static_cast(intervals.size())); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RimWellLogExtractionCurveImplTest, ExtractIntervalsWithSameTimeStepsBothComplete) -{ - std::vector valuesA{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; - std::vector valuesB{ 10, 20, 30, 40, 50, 60, 70 }; - - EXPECT_EQ(valuesA.size(), valuesB.size()); - - std::vector days(7); - std::iota(days.begin(), days.end(), 10); - - QDateTime startDate; - - std::vector timeSteps; - for (const auto& day : days) - { - timeSteps.push_back(startDate.addDays(day)); - } - - RigCurveDataInterpolationTools interpolate(valuesA, timeSteps, valuesB, timeSteps); - - auto values = interpolate.interpolatedCurveData(); - auto intervals = interpolate.validIntervals(); - - EXPECT_EQ(7, static_cast(values.size())); - EXPECT_EQ(1, static_cast(intervals.size())); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RimWellLogExtractionCurveImplTest, OverlappintTimes) -{ - std::vector valuesA{ 1, 2, 3, 4, 5 }; - std::vector valuesB{ 10, 20, 30, 40, 50 }; - - EXPECT_EQ(valuesA.size(), valuesB.size()); - - std::vector daysA{ 0, 10, 11, 15, 20 }; - std::vector daysB{ 1, 2, 3, 5, 7 }; - - QDateTime startDate; - - std::vector timeStepsA; - for (const auto& day : daysA) - { - timeStepsA.push_back(startDate.addDays(day)); - } - - std::vector timeStepsB; - for (const auto& day : daysB) - { - timeStepsB.push_back(startDate.addDays(day)); - } - - - RigCurveDataInterpolationTools interpolate(valuesA, timeStepsA, valuesB, timeStepsB); - - auto values = interpolate.interpolatedCurveData(); - auto intervals = interpolate.validIntervals(); - - EXPECT_EQ(5, static_cast(values.size())); - EXPECT_EQ(1, static_cast(intervals.size())); -}