This commit adds logic and structures for bringing in constant flux aquifer objects-keyword AQUFLUX-from the restart file and forming the requisite dynamic objects in the Schedule. In particular, the 'RstAquifer' gets a new bare-bones representation of these aquifer types and we add new constant flux aquifer objects to the pertinent 'ScheduleState' when these exist. We also add this aquifer type to 'data::Aquifers' in preparation of reinitialising the simulator's aquifer container from the restart file. In particular, this needs the total produced volume from the aquifer so far.
493 lines
14 KiB
C++
493 lines
14 KiB
C++
/*
|
|
Copyright 2019 Statoil 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_AQUIFER_HPP
|
|
#define OPM_OUTPUT_AQUIFER_HPP
|
|
|
|
#include <cstddef>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
namespace Opm { namespace data {
|
|
|
|
enum class AquiferType
|
|
{
|
|
Fetkovich, CarterTracy, ConstantFlux, Numerical,
|
|
};
|
|
|
|
struct FetkovichData
|
|
{
|
|
double initVolume{};
|
|
double prodIndex{};
|
|
double timeConstant{};
|
|
|
|
bool operator==(const FetkovichData& other) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void write(MessageBufferType& buffer) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void read(MessageBufferType& buffer);
|
|
|
|
template<class Serializer>
|
|
void serializeOp(Serializer& serializer)
|
|
{
|
|
serializer(initVolume);
|
|
serializer(prodIndex);
|
|
serializer(timeConstant);
|
|
}
|
|
|
|
static FetkovichData serializationTestObject()
|
|
{
|
|
return FetkovichData{1.0, 2.0, 3.0};
|
|
}
|
|
};
|
|
|
|
struct CarterTracyData
|
|
{
|
|
double timeConstant{};
|
|
double influxConstant{};
|
|
double waterDensity{};
|
|
double waterViscosity{};
|
|
|
|
double dimensionless_time{};
|
|
double dimensionless_pressure{};
|
|
|
|
bool operator==(const CarterTracyData& other) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void write(MessageBufferType& buffer) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void read(MessageBufferType& buffer);
|
|
|
|
template<class Serializer>
|
|
void serializeOp(Serializer& serializer)
|
|
{
|
|
serializer(timeConstant);
|
|
serializer(influxConstant);
|
|
serializer(waterDensity);
|
|
serializer(waterViscosity);
|
|
serializer(dimensionless_time);
|
|
serializer(dimensionless_pressure);
|
|
}
|
|
|
|
static CarterTracyData serializationTestObject()
|
|
{
|
|
return CarterTracyData{1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
}
|
|
};
|
|
|
|
struct NumericAquiferData
|
|
{
|
|
std::vector<double> initPressure{};
|
|
|
|
bool operator==(const NumericAquiferData& other) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void write(MessageBufferType& buffer) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void read(MessageBufferType& buffer);
|
|
|
|
template<class Serializer>
|
|
void serializeOp(Serializer& serializer)
|
|
{
|
|
serializer(initPressure);
|
|
}
|
|
|
|
static NumericAquiferData serializationTestObject()
|
|
{
|
|
return NumericAquiferData{{1.0, 2.0, 3.0}};
|
|
}
|
|
};
|
|
|
|
namespace detail {
|
|
template <AquiferType>
|
|
struct TypeMap;
|
|
|
|
template <> struct TypeMap<AquiferType::CarterTracy>
|
|
{
|
|
using Alternative = CarterTracyData;
|
|
};
|
|
|
|
template <> struct TypeMap<AquiferType::Fetkovich>
|
|
{
|
|
using Alternative = FetkovichData;
|
|
};
|
|
|
|
template <> struct TypeMap<AquiferType::Numerical>
|
|
{
|
|
using Alternative = NumericAquiferData;
|
|
};
|
|
|
|
template <AquiferType t>
|
|
using TypeMap_t = typename TypeMap<t>::Alternative;
|
|
} // namespace detail
|
|
|
|
class TypeSpecificData
|
|
{
|
|
private:
|
|
template <typename T>
|
|
bool is() const
|
|
{
|
|
return std::holds_alternative<T>(this->options_);
|
|
}
|
|
|
|
template <typename T>
|
|
const T* get() const
|
|
{
|
|
return this->template is<T>()
|
|
? &std::get<T>(this->options_)
|
|
: nullptr;
|
|
}
|
|
|
|
template <typename T>
|
|
T* get()
|
|
{
|
|
return this->template is<T>()
|
|
? &std::get<T>(this->options_)
|
|
: nullptr;
|
|
}
|
|
|
|
public:
|
|
TypeSpecificData() = default;
|
|
|
|
TypeSpecificData(const TypeSpecificData&) = default;
|
|
TypeSpecificData(TypeSpecificData&&) = default;
|
|
|
|
TypeSpecificData& operator=(const TypeSpecificData&) = default;
|
|
TypeSpecificData& operator=(TypeSpecificData&&) = default;
|
|
|
|
bool operator==(const TypeSpecificData& that) const
|
|
{
|
|
return std::visit(Equal{}, this->options_, that.options_);
|
|
}
|
|
|
|
template <AquiferType t>
|
|
auto* create()
|
|
{
|
|
return &this->options_.emplace<detail::TypeMap_t<t>>();
|
|
}
|
|
|
|
template <AquiferType t>
|
|
bool is() const
|
|
{
|
|
return this->template is<detail::TypeMap_t<t>>();
|
|
}
|
|
|
|
template <AquiferType t>
|
|
auto const* get() const
|
|
{
|
|
return this->template get<detail::TypeMap_t<t>>();
|
|
}
|
|
|
|
template <AquiferType t>
|
|
auto* getMutable()
|
|
{
|
|
return this->template get<detail::TypeMap_t<t>>();
|
|
}
|
|
|
|
template <typename MessageBufferType>
|
|
void write(MessageBufferType& buffer) const
|
|
{
|
|
buffer.write(this->options_.index());
|
|
std::visit(Write<MessageBufferType>{buffer}, this->options_);
|
|
}
|
|
|
|
template <typename MessageBufferType>
|
|
void read(MessageBufferType& buffer)
|
|
{
|
|
auto type = 0 * this->options_.index();
|
|
buffer.read(type);
|
|
|
|
if (type < std::variant_size_v<Types>) {
|
|
this->create(type);
|
|
|
|
std::visit(Read<MessageBufferType>{buffer}, this->options_);
|
|
}
|
|
}
|
|
|
|
template<class Serializer>
|
|
void serializeOp(Serializer& serializer)
|
|
{
|
|
serializer(options_);
|
|
}
|
|
|
|
private:
|
|
using Types = std::variant<std::monostate,
|
|
CarterTracyData,
|
|
FetkovichData,
|
|
NumericAquiferData>;
|
|
|
|
struct Equal
|
|
{
|
|
template <typename T1, typename T2>
|
|
bool operator()(const T1&, const T2&) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator()(const T& e1, const T& e2) const
|
|
{
|
|
return e1 == e2;
|
|
}
|
|
|
|
bool operator()(const std::monostate&,
|
|
const std::monostate&) const
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template <typename MessageBufferType>
|
|
class Read
|
|
{
|
|
public:
|
|
explicit Read(MessageBufferType& buffer)
|
|
: buffer_{ buffer }
|
|
{}
|
|
|
|
template <typename T>
|
|
void operator()(T& alternative)
|
|
{
|
|
return alternative.read(this->buffer_);
|
|
}
|
|
|
|
void operator()(std::monostate&)
|
|
{}
|
|
|
|
private:
|
|
MessageBufferType& buffer_;
|
|
};
|
|
|
|
template <typename MessageBufferType>
|
|
class Write
|
|
{
|
|
public:
|
|
explicit Write(MessageBufferType& buffer)
|
|
: buffer_{ buffer }
|
|
{}
|
|
|
|
template <typename T>
|
|
void operator()(const T& alternative) const
|
|
{
|
|
return alternative.write(this->buffer_);
|
|
}
|
|
|
|
void operator()(const std::monostate&) const
|
|
{}
|
|
|
|
private:
|
|
MessageBufferType& buffer_;
|
|
};
|
|
|
|
Types options_{};
|
|
|
|
void create(const std::size_t option);
|
|
};
|
|
|
|
struct AquiferData
|
|
{
|
|
int aquiferID = 0; //< One-based ID, range 1..NANAQ
|
|
double pressure = 0.0; //< Aquifer pressure
|
|
double fluxRate = 0.0; //< Aquifer influx rate (liquid aquifer)
|
|
double volume = 0.0; //< Produced liquid volume
|
|
double initPressure = 0.0; //< Aquifer's initial pressure
|
|
double datumDepth = 0.0; //< Aquifer's pressure reference depth
|
|
|
|
TypeSpecificData typeData{};
|
|
|
|
double get(const std::string& key) const;
|
|
|
|
bool operator==(const AquiferData& other) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void write(MessageBufferType& buffer) const;
|
|
|
|
// MessageBufferType API should be similar to Dune::MessageBufferIF
|
|
template <class MessageBufferType>
|
|
void read(MessageBufferType& buffer);
|
|
|
|
template<class Serializer>
|
|
void serializeOp(Serializer& serializer)
|
|
{
|
|
serializer(aquiferID);
|
|
serializer(pressure);
|
|
serializer(fluxRate);
|
|
serializer(volume);
|
|
serializer(initPressure);
|
|
serializer(datumDepth);
|
|
serializer(typeData);
|
|
}
|
|
|
|
static AquiferData serializationTestObjectF()
|
|
{
|
|
auto aquifer = AquiferData {1, 123.456, 56.78, 9.0e10, 290.0, 2515.5};
|
|
auto* aquFet = aquifer.typeData.create<AquiferType::Fetkovich>();
|
|
aquFet->initVolume = 1.23;
|
|
aquFet->prodIndex = 45.67;
|
|
aquFet->timeConstant = 890.123;
|
|
|
|
return aquifer;
|
|
}
|
|
|
|
static AquiferData serializationTestObjectC()
|
|
{
|
|
auto aquifer = AquiferData {2, 123.456, 56.78, 9.0e10, 290.0, 2515.5};
|
|
auto* aquCT = aquifer.typeData.create<AquiferType::CarterTracy>();
|
|
|
|
aquCT->timeConstant = 987.65;
|
|
aquCT->influxConstant = 43.21;
|
|
aquCT->waterDensity = 1014.5;
|
|
aquCT->waterViscosity = 0.00318;
|
|
aquCT->dimensionless_time = 42.0;
|
|
aquCT->dimensionless_pressure = 2.34;
|
|
|
|
return aquifer;
|
|
}
|
|
|
|
static AquiferData serializationTestObjectN()
|
|
{
|
|
auto aquifer = AquiferData {3, 123.456, 56.78, 9.0e10, 290.0, 2515.5};
|
|
auto* aquNum = aquifer.typeData.create<AquiferType::Numerical>();
|
|
|
|
aquNum->initPressure = {1.234, 2.345, 3.4, 9.876};
|
|
|
|
return aquifer;
|
|
}
|
|
|
|
private:
|
|
using GetSummaryValue = double (AquiferData::*)() const;
|
|
using SummaryValueDispatchTable = std::unordered_map<std::string, GetSummaryValue>;
|
|
|
|
static SummaryValueDispatchTable summaryValueDispatchTable_;
|
|
|
|
double aquiferFlowRate() const;
|
|
double aquiferPressure() const;
|
|
double aquiferTotalProduction() const;
|
|
double carterTracyDimensionlessTime() const;
|
|
double carterTracyDimensionlessPressure() const;
|
|
};
|
|
|
|
// TODO: not sure what extension we will need
|
|
using Aquifers = std::map<int, AquiferData>;
|
|
|
|
template <class MessageBufferType>
|
|
void FetkovichData::write(MessageBufferType& buffer) const
|
|
{
|
|
buffer.write(this->initVolume);
|
|
buffer.write(this->prodIndex);
|
|
buffer.write(this->timeConstant);
|
|
}
|
|
|
|
template <class MessageBufferType>
|
|
void FetkovichData::read(MessageBufferType& buffer)
|
|
{
|
|
buffer.read(this->initVolume);
|
|
buffer.read(this->prodIndex);
|
|
buffer.read(this->timeConstant);
|
|
}
|
|
|
|
template <class MessageBufferType>
|
|
void CarterTracyData::write(MessageBufferType& buffer) const
|
|
{
|
|
buffer.write(this->timeConstant);
|
|
buffer.write(this->influxConstant);
|
|
buffer.write(this->waterDensity);
|
|
buffer.write(this->waterViscosity);
|
|
buffer.write(this->dimensionless_time);
|
|
buffer.write(this->dimensionless_pressure);
|
|
}
|
|
|
|
template <class MessageBufferType>
|
|
void CarterTracyData::read(MessageBufferType& buffer)
|
|
{
|
|
buffer.read(this->timeConstant);
|
|
buffer.read(this->influxConstant);
|
|
buffer.read(this->waterDensity);
|
|
buffer.read(this->waterViscosity);
|
|
buffer.read(this->dimensionless_time);
|
|
buffer.read(this->dimensionless_pressure);
|
|
}
|
|
|
|
template <class MessageBufferType>
|
|
void NumericAquiferData::write(MessageBufferType& buffer) const
|
|
{
|
|
buffer.write(this->initPressure.size());
|
|
|
|
for (const auto& pressure : this->initPressure) {
|
|
buffer.write(pressure);
|
|
}
|
|
}
|
|
|
|
template <class MessageBufferType>
|
|
void NumericAquiferData::read(MessageBufferType& buffer)
|
|
{
|
|
decltype(this->initPressure.size()) size{};
|
|
buffer.read(size);
|
|
|
|
this->initPressure.resize(size, 0.0);
|
|
for (auto& pressure : this->initPressure) {
|
|
buffer.read(pressure);
|
|
}
|
|
}
|
|
|
|
template <class MessageBufferType>
|
|
void AquiferData::write(MessageBufferType& buffer) const
|
|
{
|
|
buffer.write(this->aquiferID);
|
|
buffer.write(this->pressure);
|
|
buffer.write(this->fluxRate);
|
|
buffer.write(this->volume);
|
|
buffer.write(this->initPressure);
|
|
buffer.write(this->datumDepth);
|
|
|
|
this->typeData.write(buffer);
|
|
}
|
|
|
|
template <class MessageBufferType>
|
|
void AquiferData::read(MessageBufferType& buffer)
|
|
{
|
|
buffer.read(this->aquiferID);
|
|
buffer.read(this->pressure);
|
|
buffer.read(this->fluxRate);
|
|
buffer.read(this->volume);
|
|
buffer.read(this->initPressure);
|
|
buffer.read(this->datumDepth);
|
|
|
|
this->typeData.read(buffer);
|
|
}
|
|
}} // Opm::data
|
|
|
|
#endif // OPM_OUTPUT_AQUIFER_HPP
|