From 4d9ce5b10c84f611b988e1af49dec64fa5ab4e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Fri, 14 Oct 2022 18:35:11 +0200 Subject: [PATCH] Support Additional Dynamic Phase Quantities Per Segment In particular, provide a container for holding/communicating the per-phase, per-segment quantities at local flow conditions - Flow velocities - Holdup fractions - Viscosities --- opm/output/data/Wells.hpp | 195 +++++++++++++++++++++++++++++++---- tests/test_Serialization.cpp | 1 + 2 files changed, 174 insertions(+), 22 deletions(-) diff --git a/opm/output/data/Wells.hpp b/opm/output/data/Wells.hpp index 0a6b7c3ee..68dfcea67 100644 --- a/opm/output/data/Wells.hpp +++ b/opm/output/data/Wells.hpp @@ -20,7 +20,13 @@ #ifndef OPM_OUTPUT_WELLS_HPP #define OPM_OUTPUT_WELLS_HPP +#include +#include + +#include + #include +#include #include #include #include @@ -30,10 +36,6 @@ #include #include -#include -#include -#include - namespace Opm { namespace data { @@ -316,16 +318,151 @@ namespace Opm { } }; - struct Segment { - Rates rates; - SegmentPressures pressures; - std::size_t segNumber; + class SegmentPhaseQuantity + { + public: + enum class Item : std::size_t { + Oil, Gas, Water, + + // -- Must be last enumerator -- + NumItems, + }; + + void clear() + { + this->has_ = static_cast(0); + this->value_.fill(0.0); + } + + constexpr bool has(const Item p) const + { + const auto i = this->index(p); + + return (i < Size) && this->hasItem(i); + } + + bool operator==(const SegmentPhaseQuantity& vec) const + { + return (this->has_ == vec.has_) + && (this->value_ == vec.value_); + } + + double get(const Item p) const + { + if (! this->has(p)) { + throw std::invalid_argument { + "Request for Unset Item Value for " + this->itemName(p) + }; + } + + return this->value_[ this->index(p) ]; + } + + SegmentPhaseQuantity& set(const Item p, const double value) + { + const auto i = this->index(p); + + if (i >= Size) { + throw std::invalid_argument { + "Cannot Assign Item Value for Unsupported Item '" + + this->itemName(p) + '\'' + }; + } + + this->has_ |= 1 << i; + this->value_[i] = value; + + return *this; + } + + template + void write(MessageBufferType& buffer) const + { + buffer.write(this->has_); + + for (const auto& x : this->value_) { + buffer.write(x); + } + } + + template + void read(MessageBufferType& buffer) + { + this->clear(); + buffer.read(this->has_); + + for (auto& x : this->value_) { + buffer.read(x); + } + } + + template + void serializeOp(Serializer& serializer) + { + serializer(this->has_); + serializer(this->value_); + } + + static SegmentPhaseQuantity serializationTestObject() + { + return SegmentPhaseQuantity{} + .set(Item::Oil , 1.0) + .set(Item::Gas , 7.0) + .set(Item::Water, 2.9); + } + + private: + enum { Size = static_cast(Item::NumItems) }; + + /// Whether or not item has a defined value. We use the bottom + /// 'Size' bits. + unsigned char has_{}; + + /// Numerical value of each item. + std::array value_{}; + + constexpr std::size_t index(const Item p) const noexcept + { + return static_cast(p); + } + + bool hasItem(const std::size_t i) const + { + return (this->has_ & (1 << i)) != 0; + } + + std::string itemName(const Item p) const + { + switch (p) { + case Item::Oil: return "Oil"; + case Item::Gas: return "Gas"; + case Item::Water: return "Water"; + + case Item::NumItems: + return "Out of bounds (NumItems)"; + } + + return "Unknown (" + std::to_string(this->index(p)) + ')'; + } + }; + + struct Segment + { + Rates rates{}; + SegmentPressures pressures{}; + SegmentPhaseQuantity velocity{}; + SegmentPhaseQuantity holdup{}; + SegmentPhaseQuantity viscosity{}; + std::size_t segNumber{}; bool operator==(const Segment& seg2) const { - return rates == seg2.rates && - pressures == seg2.pressures && - segNumber == seg2.segNumber; + return (rates == seg2.rates) + && (pressures == seg2.pressures) + && (velocity == seg2.velocity) + && (holdup == seg2.holdup) + && (viscosity == seg2.viscosity) + && (segNumber == seg2.segNumber); } template @@ -334,20 +471,27 @@ namespace Opm { template void read(MessageBufferType& buffer); - template + template void serializeOp(Serializer& serializer) { - serializer(rates); - serializer(pressures); - serializer(segNumber); + serializer(this->rates); + serializer(this->pressures); + serializer(this->velocity); + serializer(this->holdup); + serializer(this->viscosity); + serializer(this->segNumber); } static Segment serializationTestObject() { - return Segment{Rates::serializationTestObject(), - SegmentPressures::serializationTestObject(), - 10 - }; + return { + Rates::serializationTestObject(), + SegmentPressures::serializationTestObject(), + SegmentPhaseQuantity::serializationTestObject(), // velocity + SegmentPhaseQuantity::serializationTestObject(), // holdup + SegmentPhaseQuantity::serializationTestObject(), // viscosity + 10 + }; } }; @@ -797,7 +941,6 @@ namespace Opm { buffer.write(this->trans_factor); } - void Connection::init_json(Json::JsonObject& json_data) const { auto json_rates = json_data.add_object("rates"); this->rates.init_json(json_rates); @@ -813,10 +956,14 @@ namespace Opm { } template - void Segment::write(MessageBufferType& buffer) const { + void Segment::write(MessageBufferType& buffer) const + { buffer.write(this->segNumber); this->rates.write(buffer); this->pressures.write(buffer); + this->velocity.write(buffer); + this->holdup.write(buffer); + this->viscosity.write(buffer); } template @@ -913,10 +1060,14 @@ namespace Opm { } template - void Segment::read(MessageBufferType& buffer) { + void Segment::read(MessageBufferType& buffer) + { buffer.read(this->segNumber); this->rates.read(buffer); this->pressures.read(buffer); + this->velocity.read(buffer); + this->holdup.read(buffer); + this->viscosity.read(buffer); } template diff --git a/tests/test_Serialization.cpp b/tests/test_Serialization.cpp index 230750bdb..5adba6abc 100644 --- a/tests/test_Serialization.cpp +++ b/tests/test_Serialization.cpp @@ -193,6 +193,7 @@ TEST_FOR_TYPE_NAMED(data::NumericAquiferData, NumericAquiferData) TEST_FOR_TYPE_NAMED(data::Rates, Rates) TEST_FOR_TYPE_NAMED(data::Segment, dataSegment) TEST_FOR_TYPE_NAMED(data::SegmentPressures, SegmentPressures) +TEST_FOR_TYPE_NAMED(data::SegmentPhaseQuantity, SegmentPhaseQuantity) TEST_FOR_TYPE_NAMED(data::Solution, Solution) TEST_FOR_TYPE_NAMED(data::Well, dataWell) TEST_FOR_TYPE_NAMED(data::Wells, Wells)