Add Protocol to Linearise Connection Flow Rates Into Subrange

This commit introduces a wrapper for a linear subrange of
consecutive elements of an arithmetic type that imposes an ordering
of the elements when treated as directional component surface flow
rates.  The wrapper distinguishes negative from positive flow rate
contributions and tracks those separately.  This is a building block
for accounting for the inter-region flows in a parallel context.
This commit is contained in:
Bård Skaflestad 2022-01-19 16:56:36 +01:00
parent 27da32d812
commit 7ef3d6c0b3
3 changed files with 857 additions and 0 deletions

View File

@ -460,6 +460,7 @@ if(ENABLE_ECL_OUTPUT)
tests/test_EclipseIO.cpp
tests/test_DoubHEAD.cpp
tests/test_InteHEAD.cpp
tests/test_data_InterRegFlow.cpp
tests/test_LinearisedOutputTable.cpp
tests/test_LogiHEAD.cpp
tests/test_LGOData.cpp
@ -935,6 +936,7 @@ if(ENABLE_ECL_OUTPUT)
opm/output/data/Cells.hpp
opm/output/data/GuideRateValue.hpp
opm/output/data/Groups.hpp
opm/output/data/InterRegFlow.hpp
opm/output/data/Solution.hpp
opm/output/data/Wells.hpp
opm/output/eclipse/VectorItems/action.hpp

View File

@ -0,0 +1,361 @@
/*
Copyright (c) 2022 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_DATA_INTERREGFLOW_HPP
#define OPM_OUTPUT_DATA_INTERREGFLOW_HPP
#include <algorithm>
#include <cassert>
#include <array>
#include <cmath>
#include <cstddef>
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
namespace Opm { namespace data {
/// Intermediary Protocol to Linearise Per-Connection Flow Rates Into Subrange.
///
/// \tparam RandIt Random access iterator type of subrange.
template <typename RandIt>
class InterRegFlow
{
public:
/// Subrange element type.
///
/// Typically \c double or \c float.
using ElmT = std::remove_cv_t<
std::remove_reference_t<
typename std::iterator_traits<RandIt>::value_type
>>;
/// Surface component flow type.
enum class Component : char {
Oil, Gas, Water, Disgas, Vapoil,
// Must be last enumerator
NumComponents,
};
/// Surface flow direction.
enum class Direction : char {
Positive, Negative,
};
/// Connection Flow Rates
class FlowRates
{
public:
/// Constructor.
FlowRates()
{
this->rate_.fill(ElmT{});
}
/// Element access.
///
/// \param[in] i Component ID for specific element.
///
/// \return Read/Write reference to internal flow rate element.
ElmT& operator[](const Component i)
{
return this->rate_[this->index(i)];
}
friend class InterRegFlow;
private:
/// Internal storage.
std::array<ElmT, static_cast<std::size_t>(Component::NumComponents)> rate_{};
/// Convert component ID into linear index.
///
/// \param[in] i Component ID for specific element.
///
/// \return Linear index to internal flow rate element identified by \p i.
std::size_t index(const Component i) const
{
return static_cast<std::size_t>(i);
}
};
/// Constructor.
///
/// \param[in] begin Beginning of subrange viewd by this instance.
/// \param[in] end One-past-the-end of subrange viewed by this instance.
explicit InterRegFlow(RandIt begin, RandIt end)
: elements_(begin, end)
{}
/// Deleted copy constructor.
InterRegFlow(const InterRegFlow&) = delete;
/// Move constructor.
///
/// Invalidates source range.
///
/// \param[in,out] rhs Source range.
InterRegFlow(InterRegFlow&& rhs)
: elements_(rhs.elements_.first, rhs.elements_.second)
{
rhs.elements_.second = rhs.elements_.first; // rhs -> empty
}
/// Assignment operator.
///
/// \param[in] rhs Source range.
///
/// \return \code *this \endcode.
InterRegFlow& operator=(const InterRegFlow& rhs)
{
this->copyIn(rhs);
return *this;
}
/// Move assignment operator.
///
/// Invalidates source range.
///
/// \param[in,out] rhs Source range.
///
/// \return \code *this \endcode.
InterRegFlow& operator=(InterRegFlow&& rhs)
{
if (! this->isValid()) {
this->elements_ = rhs.elements_;
}
else {
this->copyIn(rhs);
}
rhs.elements_.second = rhs.elements_.first; // rhs -> empty
return *this;
}
/// Addition operator
///
/// \tparam OtherRandIt Random access iterator, possibly different
/// from \c RandIt.
///
/// \param[in] rhs Source subrange.
///
/// \return \code *this \endcode.
template <typename OtherRandIt>
std::enable_if_t<
std::is_convertible_v<typename InterRegFlow<OtherRandIt>::ElmT, ElmT>,
InterRegFlow&> operator+=(const InterRegFlow<OtherRandIt>& rhs)
{
std::transform(this->begin(),
this->end(),
rhs .begin(),
this->begin(),
std::plus<>{});
return *this;
}
/// Assignment operator from different, but compatible, subrange.
///
/// Enables assigning into a subrange of \code vector<double>
/// \endcode from a subrange backed by \code array<float,N> \endcode
/// of compatible size.
///
/// \tparam OtherRandIt Random access iterator different from \c RandIt.
///
/// \param[in] rhs Source subrange.
///
/// \return \code *this \endcode.
template <typename OtherRandIt>
std::enable_if_t<
!std::is_same_v<RandIt, OtherRandIt> &&
std::is_convertible_v<typename InterRegFlow<OtherRandIt>::ElmT, ElmT>,
InterRegFlow&> operator=(const InterRegFlow<OtherRandIt>& rhs)
{
this->copyIn(rhs.begin(), rhs.end());
return *this;
}
/// Accumulate connection contribution into subrange.
///
/// \param[in] sign Flow rate sign--e.g., to flip direction if
/// needed in calling context.
///
/// \param[in] q Connection flow rates.
void addFlow(const ElmT sign, const FlowRates& q)
{
assert (this->isValid());
const auto numComp = static_cast<std::size_t>(Component::NumComponents);
for (auto component = 0*numComp; component < numComp; ++component) {
this->add(sign * q.rate_[component], component);
}
}
/// Buffer size (number of elements)
///
/// Storage buffer backing the \c InterRegFlow object must have at
/// least \code InterRegFlow::bufferSize() \endcode contiguous elements.
constexpr static std::size_t bufferSize() noexcept
{
return InterRegFlow::index(Component::NumComponents, Direction::Positive);
}
/// Total accumulated flow rate of particular surface rate component
/// for this region.
///
/// \param[in] component Component ID for specific element.
///
/// \return Flow rate.
constexpr ElmT flow(const Component component) const noexcept
{
// Add components since Positive and Negative are stored as
// signed quantities. In other words flow(x, Negative) <= 0
// while flow(x, Positive) >= 0).
return this->flow(component, Direction::Positive)
+ this->flow(component, Direction::Negative);
}
/// Accumulated flow rate for this region par of particular surface
/// rate component in particular direction.
///
/// Flow from source to destination is \c Positive while from from
/// destination to source is \c Negative. Numerical value in the \c
/// Positive direction is non-negative while the numerical value in
/// the \c Negative direction is non-positive.
///
/// \param[in] component Component ID for specific element.
///
/// \param[in] direction Flow direction.
///
/// \return Component flow rate in specified direction.
constexpr ElmT flow(const Component component,
const Direction direction) const noexcept
{
return *(this->elements_.first + InterRegFlow::index(component, direction));
}
/// Predicate for whether or not this \c InterRegFlow object is
/// backed by an empty range.
constexpr bool empty() const noexcept
{
return this->begin() == this->end();
}
/// Predicate for whether or not this \c InterRegFlow object is
/// backed by a valid range (size \code InterRegFlow::bufferSize()
/// \endcode).
constexpr bool isValid() const noexcept
{
using sz_t = decltype(InterRegFlow::bufferSize());
const auto& [begin, end] = this->elements_;
return static_cast<sz_t>(std::distance(begin, end))
== InterRegFlow::bufferSize();
}
/// Iterator to beginning of subrange.
RandIt begin() const noexcept
{
return this->elements_.first;
}
/// Iterator to one-past-end of subrange.
RandIt end() const noexcept
{
return this->elements_.second;
}
private:
/// Element subrange.
std::pair<RandIt, RandIt> elements_;
/// Convert directional component ID into linear index.
///
/// Overload for already converted component index.
///
/// \param[in] component Component index for specific element.
/// \param[in] direction Flow direction.
///
/// \return Linear index of ordered pair of component ID and flow
/// direction.
constexpr static std::size_t
index(const std::size_t component, const Direction direction)
{
return 2*component + (direction == Direction::Negative);
}
/// Convert directional component ID into linear index.
///
/// \param[in] component Component ID for specific element.
/// \param[in] direction Flow direction.
///
/// \return Linear index of ordered pair of component ID and flow
/// direction.
constexpr static std::size_t
index(const Component component, const Direction direction)
{
return InterRegFlow::index(static_cast<std::size_t>(component), direction);
}
/// Accumulate component flow rate into linearised subrange.
///
/// \param[in] rate Component flow rate.
/// \param[in] component Component index.
void add(const ElmT rate, const std::size_t component)
{
const auto direction = std::signbit(rate)
? Direction::Negative : Direction::Positive;
auto* rateVec = &*this->elements_.first;
rateVec[InterRegFlow::index(component, direction)] += rate;
}
/// Backend for assignment operator
///
/// \param[in] rhs Source subrange.
void copyIn(const InterRegFlow& rhs)
{
if (this->elements_ != rhs.elements_) {
this->copyIn(rhs.elements_.first, rhs.elements_.second);
}
}
/// Backend for assignment operator
///
/// Activated for compatible ranges.
///
/// \param[in] begin Beginning of source subrange.
/// \param[in] end One-past-end of source subrange.
template <typename OtherRandIt>
void copyIn(OtherRandIt begin, OtherRandIt end)
{
std::copy(begin, end, this->elements_.first);
}
};
}} // namespace Opm::data
#endif // OPM_OUTPUT_DATA_INTERREGFLOW_HPP

View File

@ -0,0 +1,494 @@
/*
Copyright (c) 2022 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#define BOOST_TEST_MODULE data_InterRegFlow
#include <boost/test/unit_test.hpp>
#include <opm/output/data/InterRegFlow.hpp>
#include <array>
#include <cstddef>
#include <type_traits>
#include <utility>
#include <vector>
BOOST_AUTO_TEST_SUITE(InterReg_View)
BOOST_AUTO_TEST_CASE(Construct)
{
using IRegFlow = Opm::data::InterRegFlow<decltype(std::declval<std::vector<double>>().begin())>;
using IRegRate = IRegFlow::FlowRates;
using Component = IRegFlow::Component;
using Direction = IRegFlow::Direction;
auto store = std::vector<double>(IRegFlow::bufferSize(), 0.0);
{
auto iregFlow = IRegFlow{ store.begin(), store.begin() }; // empty
BOOST_CHECK_MESSAGE(iregFlow.empty(), "[begin, begin) must be an empty range");
}
{
auto iregFlow = IRegFlow{ store.begin(), store.begin() + static_cast<std::size_t>(Component::NumComponents) };
BOOST_CHECK_MESSAGE(!iregFlow.isValid(), "Small range must be invalid");
}
auto iregFlow = IRegFlow{ store.begin(), store.end() };
BOOST_REQUIRE_MESSAGE(iregFlow.isValid(), "Valid range must be valid");
auto rate = IRegRate{};
rate[Component::Oil] = 1.0;
rate[Component::Gas] = 2.0;
rate[Component::Water] = 3.0;
rate[Component::Disgas] = 4.0;
rate[Component::Vapoil] = 5.0;
iregFlow.addFlow(1.0, rate); // 1->2
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil, Direction::Positive), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas, Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water, Direction::Positive), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas, Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil, Direction::Positive), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil, Direction::Negative), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas, Direction::Negative), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water, Direction::Negative), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas, Direction::Negative), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil, Direction::Negative), 0.0, 1.0e-6);
iregFlow.addFlow(-1.0, rate); // 2->1
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil), 0.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil, Direction::Positive), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas, Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water, Direction::Positive), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas, Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil, Direction::Positive), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil, Direction::Negative), -1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas, Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water, Direction::Negative), -3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas, Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil, Direction::Negative), -5.0, 1.0e-6);
iregFlow.addFlow(1.0, rate); // 1->2
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil, Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas, Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water, Direction::Positive), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas, Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil, Direction::Positive), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Oil, Direction::Negative), -1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Gas, Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Water, Direction::Negative), -3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Disgas, Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(Component::Vapoil, Direction::Negative), -5.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[9], - 5.0, 1.0e-6);
}
BOOST_AUTO_TEST_CASE(Copy_Move_Assign_Add)
{
using IRegFlow = Opm::data::InterRegFlow<decltype(std::declval<std::vector<double>>().begin())>;
using IRegRate = IRegFlow::FlowRates;
using Component = IRegFlow::Component;
using Direction = IRegFlow::Direction;
auto store = std::vector<double>(2 * IRegFlow::bufferSize(), 0.0);
{
auto iregFlow = IRegFlow{ store.begin(), store.begin() }; // empty
BOOST_CHECK_MESSAGE(iregFlow.empty(), "[begin, begin) must be an empty range");
}
{
auto iregFlow = IRegFlow{ store.begin(), store.end() };
BOOST_CHECK_MESSAGE(!iregFlow.isValid(), "Large range must be invalid");
}
auto iregFlow_1 = IRegFlow{ store.begin(), store.begin() + IRegFlow::bufferSize() };
auto iregFlow_2 = IRegFlow{ store.begin() + IRegFlow::bufferSize(), store.end() };
BOOST_REQUIRE_MESSAGE(iregFlow_1.isValid(), "Valid range 1 must be valid");
BOOST_REQUIRE_MESSAGE(iregFlow_2.isValid(), "Valid range 2 must be valid");
auto rate = IRegRate{};
rate[Component::Oil] = 1.0;
rate[Component::Gas] = 2.0;
rate[Component::Water] = 3.0;
rate[Component::Disgas] = 4.0;
rate[Component::Vapoil] = 5.0;
iregFlow_1.addFlow( 1.0, rate); // 1->2
iregFlow_1.addFlow(- 1.0, rate); // 2->1
iregFlow_1.addFlow( 1.0, rate); // 1->2
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Oil), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Gas), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Water), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Disgas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Vapoil), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Oil, Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Gas, Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Water, Direction::Positive), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Disgas, Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Vapoil, Direction::Positive), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Oil, Direction::Negative), -1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Gas, Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Water, Direction::Negative), -3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Disgas, Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Vapoil, Direction::Negative), -5.0, 1.0e-6);
const auto iregFlow_3 = std::move(iregFlow_1);
BOOST_CHECK_MESSAGE(! iregFlow_1.isValid(), "Moved-from range must be invalid");
BOOST_CHECK_MESSAGE( iregFlow_3.isValid(), "Move-constructed range must be valid");
BOOST_CHECK_CLOSE(store[0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[9], - 5.0, 1.0e-6);
iregFlow_2 = iregFlow_3;
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Oil), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Gas), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Water), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Disgas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Vapoil), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Oil, Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Gas, Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Water, Direction::Positive), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Disgas, Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Vapoil, Direction::Positive), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Oil, Direction::Negative), -1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Gas, Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Water, Direction::Negative), -3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Disgas, Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Vapoil, Direction::Negative), -5.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 9], - 5.0, 1.0e-6);
iregFlow_2 += iregFlow_3;
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Oil), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Gas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Water), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Disgas), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Vapoil), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Oil, Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Gas, Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Water, Direction::Positive), 12.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Disgas, Direction::Positive), 16.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Vapoil, Direction::Positive), 20.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Oil, Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Gas, Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Water, Direction::Negative), -6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Disgas, Direction::Negative), -8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_2.flow(Component::Vapoil, Direction::Negative), -10.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[9], - 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 0], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 1], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 2], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 3], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 4], 12.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 5], - 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 6], 16.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 7], - 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 8], 20.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 9], -10.0, 1.0e-6);
iregFlow_1 = std::move(iregFlow_2);
BOOST_CHECK_MESSAGE(! iregFlow_2.isValid(), "Moved-from source range must be invalid");
BOOST_CHECK_MESSAGE( iregFlow_1.isValid(), "Moved-assigned destination range must be valid");
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Oil), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Gas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Water), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Disgas), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Vapoil), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Oil, Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Gas, Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Water, Direction::Positive), 12.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Disgas, Direction::Positive), 16.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Vapoil, Direction::Positive), 20.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Oil, Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Gas, Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Water, Direction::Negative), -6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Disgas, Direction::Negative), -8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow_1.flow(Component::Vapoil, Direction::Negative), -10.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[9], - 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 0], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 1], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 2], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 3], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 4], 12.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 5], - 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 6], 16.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 7], - 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 8], 20.0, 1.0e-6);
BOOST_CHECK_CLOSE(store[10 + 9], -10.0, 1.0e-6);
}
BOOST_AUTO_TEST_CASE(Assign_Different_Iterator)
{
using IRegFlow = Opm::data::InterRegFlow<decltype(std::declval<std::vector<double>>().begin())>;
using ArrayBuffer = std::array<double, IRegFlow::bufferSize()>;
using IRegFlow_ArrayBacked = Opm::data::InterRegFlow<decltype(std::declval<ArrayBuffer>().begin())>;
using IRegRate = IRegFlow_ArrayBacked::FlowRates;
using Component = IRegFlow_ArrayBacked::Component;
auto buffer = ArrayBuffer{};
buffer.fill(0.0);
auto iregFlow_array = IRegFlow_ArrayBacked{ buffer.begin(), buffer.end() };
auto rate = IRegRate{};
rate[Component::Oil] = 1.0;
rate[Component::Gas] = 2.0;
rate[Component::Water] = 3.0;
rate[Component::Disgas] = 4.0;
rate[Component::Vapoil] = 5.0;
iregFlow_array.addFlow( 1.0, rate); // 1->2
iregFlow_array.addFlow(- 1.0, rate); // 2->1
iregFlow_array.addFlow( 1.0, rate); // 1->2
auto range = std::vector<double>(IRegFlow::bufferSize(), 0.0);
auto iregFlow = IRegFlow{ range.begin(), range.end() };
iregFlow = iregFlow_array;
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil, IRegFlow::Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas, IRegFlow::Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water, IRegFlow::Direction::Positive), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas, IRegFlow::Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil, IRegFlow::Direction::Positive), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil, IRegFlow::Direction::Negative), -1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas, IRegFlow::Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water, IRegFlow::Direction::Negative), -3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas, IRegFlow::Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil, IRegFlow::Direction::Negative), -5.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[9], - 5.0, 1.0e-6);
}
BOOST_AUTO_TEST_CASE(Assign_Different_ElmT)
{
using IRegFlow = Opm::data::InterRegFlow<decltype(std::declval<std::vector<double>>().begin())>;
using IRegFlow_float = Opm::data::InterRegFlow<decltype(std::declval<std::vector<float>>().begin())>;
using IRegRate = IRegFlow_float::FlowRates;
using Component = IRegFlow_float::Component;
auto buffer = std::vector<float>(IRegFlow_float::bufferSize(), 0.0f);
auto iregFlow_float = IRegFlow_float{ buffer.begin(), buffer.end() };
auto rate = IRegRate{};
rate[Component::Oil] = 1.0f;
rate[Component::Gas] = 2.0f;
rate[Component::Water] = 3.0f;
rate[Component::Disgas] = 4.0f;
rate[Component::Vapoil] = 5.0f;
iregFlow_float.addFlow( 1.0, rate); // 1->2
iregFlow_float.addFlow(- 1.0, rate); // 2->1
iregFlow_float.addFlow( 1.0, rate); // 1->2
auto range = std::vector<double>(IRegFlow::bufferSize(), 0.0);
auto iregFlow = IRegFlow{ range.begin(), range.end() };
iregFlow = iregFlow_float;
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil, IRegFlow::Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas, IRegFlow::Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water, IRegFlow::Direction::Positive), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas, IRegFlow::Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil, IRegFlow::Direction::Positive), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil, IRegFlow::Direction::Negative), -1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas, IRegFlow::Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water, IRegFlow::Direction::Negative), -3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas, IRegFlow::Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil, IRegFlow::Direction::Negative), -5.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[9], - 5.0, 1.0e-6);
}
BOOST_AUTO_TEST_CASE(Assign_Different_ElmT_Different_Iterator)
{
using IRegFlow = Opm::data::InterRegFlow<decltype(std::declval<std::vector<double>>().begin())>;
using ArrayBuffer = std::array<float, IRegFlow::bufferSize()>;
using IRegFlow_ArrayBacked = Opm::data::InterRegFlow<decltype(std::declval<ArrayBuffer>().begin())>;
using IRegRate = IRegFlow_ArrayBacked::FlowRates;
using Component = IRegFlow_ArrayBacked::Component;
auto buffer = ArrayBuffer{};
buffer.fill(0.0f);
auto iregFlow_array = IRegFlow_ArrayBacked{ buffer.begin(), buffer.end() };
auto rate = IRegRate{};
rate[Component::Oil] = 1.0f;
rate[Component::Gas] = 2.0f;
rate[Component::Water] = 3.0f;
rate[Component::Disgas] = 4.0f;
rate[Component::Vapoil] = 5.0f;
iregFlow_array.addFlow( 1.0, rate); // 1->2
iregFlow_array.addFlow(- 1.0, rate); // 2->1
iregFlow_array.addFlow( 1.0, rate); // 1->2
auto range = std::vector<double>(IRegFlow::bufferSize(), 0.0);
auto iregFlow = IRegFlow{ range.begin(), range.end() };
iregFlow = iregFlow_array;
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil), 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water), 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil), 5.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil, IRegFlow::Direction::Positive), 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas, IRegFlow::Direction::Positive), 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water, IRegFlow::Direction::Positive), 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas, IRegFlow::Direction::Positive), 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil, IRegFlow::Direction::Positive), 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Oil, IRegFlow::Direction::Negative), -1.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Gas, IRegFlow::Direction::Negative), -2.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Water, IRegFlow::Direction::Negative), -3.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Disgas, IRegFlow::Direction::Negative), -4.0, 1.0e-6);
BOOST_CHECK_CLOSE(iregFlow.flow(IRegFlow::Component::Vapoil, IRegFlow::Direction::Negative), -5.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[0], 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[1], - 1.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[2], 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[3], - 2.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[4], 6.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[5], - 3.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[6], 8.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[7], - 4.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[8], 10.0, 1.0e-6);
BOOST_CHECK_CLOSE(range[9], - 5.0, 1.0e-6);
}
BOOST_AUTO_TEST_SUITE_END() // InterReg_View