mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #4519 from bska/unify-analytic-aquifer-construction
Refactor Construction of Analytic Aquifer Objects
This commit is contained in:
commit
1bbec4e4fb
@ -20,41 +20,50 @@
|
|||||||
#ifndef OPM_AQUIFERCONSTANTFLUX_HPP
|
#ifndef OPM_AQUIFERCONSTANTFLUX_HPP
|
||||||
#define OPM_AQUIFERCONSTANTFLUX_HPP
|
#define OPM_AQUIFERCONSTANTFLUX_HPP
|
||||||
|
|
||||||
#include <opm/material/common/MathToolbox.hpp>
|
|
||||||
#include <opm/material/densead/Evaluation.hpp>
|
|
||||||
|
|
||||||
#include <opm/simulators/aquifers/AquiferInterface.hpp>
|
#include <opm/simulators/aquifers/AquiferInterface.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/Aquifer/Aquancon.hpp>
|
#include <opm/input/eclipse/EclipseState/Aquifer/Aquancon.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Aquifer/AquiferFlux.hpp>
|
#include <opm/input/eclipse/EclipseState/Aquifer/AquiferFlux.hpp>
|
||||||
|
#include <opm/input/eclipse/EclipseState/Grid/FaceDir.hpp>
|
||||||
|
|
||||||
|
#include <opm/common/ErrorMacros.hpp>
|
||||||
|
|
||||||
|
#include <opm/material/common/MathToolbox.hpp>
|
||||||
|
#include <opm/material/densead/Evaluation.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
class AquiferConstantFlux : public AquiferInterface<TypeTag> {
|
class AquiferConstantFlux : public AquiferInterface<TypeTag>
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
|
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
|
||||||
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
|
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
|
||||||
using ElementMapper = GetPropType<TypeTag, Properties::ElementMapper>;
|
using ElementMapper = GetPropType<TypeTag, Properties::ElementMapper>;
|
||||||
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
|
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
|
||||||
using BlackoilIndices = GetPropType<TypeTag, Properties::Indices>;
|
using BlackoilIndices = GetPropType<TypeTag, Properties::Indices>;
|
||||||
|
|
||||||
static constexpr int numEq = BlackoilIndices::numEq;
|
static constexpr int numEq = BlackoilIndices::numEq;
|
||||||
using Eval = DenseAd::Evaluation<double, /*size=*/numEq>;
|
using Eval = DenseAd::Evaluation<double, /*size=*/numEq>;
|
||||||
|
|
||||||
AquiferConstantFlux(const SingleAquiferFlux& aquifer,
|
AquiferConstantFlux(const std::vector<Aquancon::AquancCell>& connections,
|
||||||
const std::vector<Aquancon::AquancCell>& connections,
|
const Simulator& ebos_simulator,
|
||||||
const Simulator& ebos_simulator)
|
const SingleAquiferFlux& aquifer)
|
||||||
: AquiferInterface<TypeTag>(aquifer.id, ebos_simulator)
|
: AquiferInterface<TypeTag>(aquifer.id, ebos_simulator)
|
||||||
, connections_(connections)
|
, connections_ (connections)
|
||||||
, aquifer_data_(aquifer)
|
, aquifer_data_ (aquifer)
|
||||||
|
, connection_flux_ (connections_.size(), Eval{0})
|
||||||
{
|
{
|
||||||
// init_cumulative_flux is the flux volume from previoius running
|
|
||||||
this->initializeConnections();
|
this->initializeConnections();
|
||||||
connection_flux_.resize(this->connections_.size(), {0});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static AquiferConstantFlux serializationTestObject(const Simulator& ebos_simulator)
|
static AquiferConstantFlux serializationTestObject(const Simulator& ebos_simulator)
|
||||||
{
|
{
|
||||||
AquiferConstantFlux<TypeTag> result({}, {}, ebos_simulator);
|
AquiferConstantFlux<TypeTag> result({}, ebos_simulator, {});
|
||||||
result.cumulative_flux_ = 1.0;
|
result.cumulative_flux_ = 1.0;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -62,7 +71,8 @@ public:
|
|||||||
|
|
||||||
virtual ~AquiferConstantFlux() = default;
|
virtual ~AquiferConstantFlux() = default;
|
||||||
|
|
||||||
void updateAquifer(const SingleAquiferFlux& aquifer) {
|
void updateAquifer(const SingleAquiferFlux& aquifer)
|
||||||
|
{
|
||||||
aquifer_data_ = aquifer;
|
aquifer_data_ = aquifer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,31 +82,32 @@ public:
|
|||||||
void initialSolutionApplied() override {
|
void initialSolutionApplied() override {
|
||||||
}
|
}
|
||||||
|
|
||||||
void beginTimeStep() override {
|
|
||||||
}
|
|
||||||
|
|
||||||
void endTimeStep() override {
|
void beginTimeStep() override
|
||||||
this->flux_rate_ = 0.;
|
{}
|
||||||
for (const auto& q : this->connection_flux_) {
|
|
||||||
this->flux_rate_ += Opm::getValue(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->cumulative_flux_ += this->flux_rate_ * this->ebos_simulator_.timeStepSize();
|
void endTimeStep() override
|
||||||
|
{
|
||||||
|
this->flux_rate_ = this->totalFluxRate();
|
||||||
|
this->cumulative_flux_ +=
|
||||||
|
this->flux_rate_ * this->ebos_simulator_.timeStepSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
data::AquiferData aquiferData() const override
|
data::AquiferData aquiferData() const override
|
||||||
{
|
{
|
||||||
data::AquiferData data;
|
data::AquiferData data;
|
||||||
|
|
||||||
data.aquiferID = this->aquifer_data_.id;
|
data.aquiferID = this->aquifer_data_.id;
|
||||||
// pressure for constant flux aquifer is 0
|
|
||||||
data.pressure = 0.;
|
// Pressure for constant flux aquifer is 0
|
||||||
data.fluxRate = 0.;
|
data.pressure = 0.0;
|
||||||
for (const auto& q : this->connection_flux_) {
|
data.fluxRate = this->totalFluxRate();
|
||||||
data.fluxRate += q.value();
|
|
||||||
}
|
|
||||||
data.volume = this->cumulative_flux_;
|
data.volume = this->cumulative_flux_;
|
||||||
|
|
||||||
// not totally sure whether initPressure matters
|
// not totally sure whether initPressure matters
|
||||||
data.initPressure = 0.;
|
data.initPressure = 0.0;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,19 +115,17 @@ public:
|
|||||||
const unsigned cellIdx,
|
const unsigned cellIdx,
|
||||||
const unsigned timeIdx) override
|
const unsigned timeIdx) override
|
||||||
{
|
{
|
||||||
const auto& model = this->ebos_simulator_.model();
|
|
||||||
|
|
||||||
const int idx = this->cellToConnectionIdx_[cellIdx];
|
const int idx = this->cellToConnectionIdx_[cellIdx];
|
||||||
if (idx < 0)
|
if (idx < 0) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* intQuantsPtr = model.cachedIntensiveQuantities(cellIdx, timeIdx);
|
|
||||||
if (intQuantsPtr == nullptr) {
|
|
||||||
throw std::logic_error("Invalid intensive quantities cache detected in AquiferAnalytical::addToSource()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const double fw = this->aquifer_data_.flux;
|
const auto& model = this->ebos_simulator_.model();
|
||||||
|
|
||||||
|
const auto fw = this->aquifer_data_.flux;
|
||||||
|
|
||||||
this->connection_flux_[idx] = fw * this->connections_[idx].effective_facearea;
|
this->connection_flux_[idx] = fw * this->connections_[idx].effective_facearea;
|
||||||
|
|
||||||
rates[BlackoilIndices::conti0EqIdx + compIdx_()]
|
rates[BlackoilIndices::conti0EqIdx + compIdx_()]
|
||||||
+= this->connection_flux_[idx] / model.dofTotalVolume(cellIdx);
|
+= this->connection_flux_[idx] / model.dofTotalVolume(cellIdx);
|
||||||
}
|
}
|
||||||
@ -134,17 +143,19 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<Aquancon::AquancCell>& connections_;
|
const std::vector<Aquancon::AquancCell>& connections_;
|
||||||
|
|
||||||
SingleAquiferFlux aquifer_data_;
|
SingleAquiferFlux aquifer_data_;
|
||||||
std::vector<int> cellToConnectionIdx_;
|
std::vector<Eval> connection_flux_{};
|
||||||
std::vector<Eval> connection_flux_;
|
std::vector<int> cellToConnectionIdx_{};
|
||||||
double flux_rate_ {};
|
double flux_rate_{};
|
||||||
double cumulative_flux_ = 0.;
|
double cumulative_flux_{};
|
||||||
|
|
||||||
void initializeConnections() {
|
void initializeConnections() {
|
||||||
this->cellToConnectionIdx_.resize(this->ebos_simulator_.gridView().size(/*codim=*/0), -1);
|
this->cellToConnectionIdx_.resize(this->ebos_simulator_.gridView().size(/*codim=*/0), -1);
|
||||||
for (std::size_t idx = 0; idx < this->connections_.size(); ++idx) {
|
for (std::size_t idx = 0; idx < this->connections_.size(); ++idx) {
|
||||||
const auto global_index = this->connections_[idx].global_index;
|
const auto global_index = this->connections_[idx].global_index;
|
||||||
const int cell_index = this->ebos_simulator_.vanguard().compressedIndexForInterior(global_index);
|
const int cell_index = this->ebos_simulator_.vanguard()
|
||||||
|
.compressedIndexForInterior(global_index);
|
||||||
|
|
||||||
if (cell_index < 0) {
|
if (cell_index < 0) {
|
||||||
continue;
|
continue;
|
||||||
@ -152,8 +163,10 @@ private:
|
|||||||
|
|
||||||
this->cellToConnectionIdx_[cell_index] = idx;
|
this->cellToConnectionIdx_[cell_index] = idx;
|
||||||
}
|
}
|
||||||
// TODO: at the moment, we are using the effective_facearea from the parser. Should we update the facearea here if
|
|
||||||
// the grid changed during the preprocessing?
|
// TODO: At the moment, we are using the effective_facearea from the
|
||||||
|
// parser. Should we update the facearea here if the grid changed
|
||||||
|
// during the preprocessing?
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is a function from AquiferAnalytical
|
// TODO: this is a function from AquiferAnalytical
|
||||||
@ -164,7 +177,18 @@ private:
|
|||||||
|
|
||||||
return FluidSystem::waterCompIdx;
|
return FluidSystem::waterCompIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double totalFluxRate() const
|
||||||
|
{
|
||||||
|
return std::accumulate(this->connection_flux_.begin(),
|
||||||
|
this->connection_flux_.end(), 0.0,
|
||||||
|
[](const double rate, const auto& q)
|
||||||
|
{
|
||||||
|
return rate + getValue(q);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
} // namespace Opm
|
||||||
|
|
||||||
#endif //OPM_AQUIFERCONSTANTFLUX_HPP
|
#endif //OPM_AQUIFERCONSTANTFLUX_HPP
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace Opm
|
namespace Opm
|
||||||
{
|
{
|
||||||
@ -125,8 +126,20 @@ protected:
|
|||||||
// TODO: possibly better to use unorder_map here for aquifers
|
// TODO: possibly better to use unorder_map here for aquifers
|
||||||
std::vector<std::unique_ptr<AquiferInterface<TypeTag>>> aquifers;
|
std::vector<std::unique_ptr<AquiferInterface<TypeTag>>> aquifers;
|
||||||
|
|
||||||
// This initialization function is used to connect the parser objects with the ones needed by AquiferCarterTracy
|
// This initialization function is used to connect the parser objects
|
||||||
|
// with the ones needed by AquiferCarterTracy
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createDynamicAquifers(const int episode_index);
|
||||||
|
|
||||||
|
void initializeStaticAquifers();
|
||||||
|
|
||||||
|
template <typename AquiferType, typename AquiferData>
|
||||||
|
std::unique_ptr<AquiferType>
|
||||||
|
createAnalyticAquiferPointer(const AquiferData& aqData,
|
||||||
|
const int aquiferID,
|
||||||
|
std::string_view aqType) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace Opm
|
namespace Opm
|
||||||
{
|
{
|
||||||
@ -60,33 +61,12 @@ template <typename TypeTag>
|
|||||||
void
|
void
|
||||||
BlackoilAquiferModel<TypeTag>::beginEpisode()
|
BlackoilAquiferModel<TypeTag>::beginEpisode()
|
||||||
{
|
{
|
||||||
// probably function name beginReportStep() is more appropriate.
|
// Probably function name beginReportStep() is more appropriate.
|
||||||
// basically, we want to update the aquifer related information from SCHEDULE setup in this section
|
//
|
||||||
// it is the beginning of a report step
|
// Basically, we want to update the aquifer related information from
|
||||||
const auto& connections = this->simulator_.vanguard().eclState().aquifer().connections();
|
// SCHEDULE setup in this section it is the beginning of a report step
|
||||||
const int report_step = this->simulator_.episodeIndex();
|
|
||||||
const auto& aqufluxs = this->simulator_.vanguard().schedule()[report_step].aqufluxs;
|
this->createDynamicAquifers(this->simulator_.episodeIndex());
|
||||||
for (const auto& elem : aqufluxs) {
|
|
||||||
const int id = elem.first;
|
|
||||||
auto find = std::find_if(begin(this->aquifers), end(this->aquifers), [id](auto& v){ return v->aquiferID() == id; });
|
|
||||||
if (find == this->aquifers.end()) {
|
|
||||||
// the aquifer id does not exist in BlackoilAquiferModel yet
|
|
||||||
const auto& aquinfo = elem.second;
|
|
||||||
auto aqf = std::make_unique<AquiferConstantFlux<TypeTag>>(aquinfo, connections.getConnections(aquinfo.id), this->simulator_);
|
|
||||||
this->aquifers.push_back(std::move(aqf));
|
|
||||||
} else {
|
|
||||||
const auto& aquinfo = elem.second;
|
|
||||||
auto aqu = dynamic_cast<AquiferConstantFlux<TypeTag>*> (find->get());
|
|
||||||
if (!aqu) {
|
|
||||||
// if the aquifers can return types easily, we might be able to give a better message with type information
|
|
||||||
const auto msg = fmt::format("Aquifer {} is updated with constant flux aquifer keyword AQUFLUX at report step {},"
|
|
||||||
" while it might be specified to be a different type of aquifer before this. We do not support the conversion between"
|
|
||||||
" different types of aquifer.\n", id, report_step);
|
|
||||||
OPM_THROW(std::runtime_error, msg);
|
|
||||||
}
|
|
||||||
aqu->updateAquifer(aquinfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TypeTag>
|
template <typename TypeTag>
|
||||||
@ -167,62 +147,12 @@ BlackoilAquiferModel<TypeTag>::deserialize(Restarter& /* res */)
|
|||||||
|
|
||||||
// Initialize the aquifers in the deck
|
// Initialize the aquifers in the deck
|
||||||
template <typename TypeTag>
|
template <typename TypeTag>
|
||||||
void
|
void BlackoilAquiferModel<TypeTag>::init()
|
||||||
BlackoilAquiferModel<TypeTag>::init()
|
|
||||||
{
|
{
|
||||||
const auto& aquifer = this->simulator_.vanguard().eclState().aquifer();
|
if (this->simulator_.vanguard().eclState().aquifer().active()) {
|
||||||
|
this->initializeStaticAquifers();
|
||||||
if (!aquifer.active()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& connections = aquifer.connections();
|
|
||||||
for (const auto& aq : aquifer.ct()) {
|
|
||||||
if (!connections.hasAquiferConnections(aq.aquiferID)) {
|
|
||||||
auto msg = fmt::format("No valid connections for Carter-Tracy aquifer {}, aquifer {} will be ignored.",
|
|
||||||
aq.aquiferID, aq.aquiferID);
|
|
||||||
OpmLog::warning(msg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto aqf = std::make_unique<AquiferCarterTracy<TypeTag>>(connections.getConnections(aq.aquiferID),
|
|
||||||
this->simulator_, aq);
|
|
||||||
aquifers.push_back(std::move(aqf));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& aq : aquifer.fetp()) {
|
|
||||||
if (!connections.hasAquiferConnections(aq.aquiferID)) {
|
|
||||||
auto msg = fmt::format("No valid connections for Fetkovich aquifer {}, aquifer {} will be ignored.",
|
|
||||||
aq.aquiferID, aq.aquiferID);
|
|
||||||
OpmLog::warning(msg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto aqf = std::make_unique<AquiferFetkovich<TypeTag>>(connections.getConnections(aq.aquiferID),
|
|
||||||
this->simulator_, aq);
|
|
||||||
aquifers.push_back(std::move(aqf));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& [id, aq] : aquifer.aquflux()) {
|
|
||||||
// make sure not dummy constant flux aquifers
|
|
||||||
if ( !aq.active ) continue;
|
|
||||||
|
|
||||||
if (!connections.hasAquiferConnections(id)) {
|
|
||||||
auto msg = fmt::format("No valid connections for constant flux aquifer {}, aquifer {} will be ignored.",
|
|
||||||
id, id);
|
|
||||||
OpmLog::warning(msg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto aqf = std::make_unique<AquiferConstantFlux<TypeTag>>(aq, connections.getConnections(id), this->simulator_);
|
|
||||||
this->aquifers.push_back(std::move(aqf));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aquifer.hasNumericalAquifer()) {
|
|
||||||
const auto& num_aquifers = aquifer.numericalAquifers().aquifers();
|
|
||||||
for ([[maybe_unused]]const auto& [id, aqu] : num_aquifers) {
|
|
||||||
auto aqf = std::make_unique<AquiferNumerical<TypeTag>>(aqu, this->simulator_);
|
|
||||||
aquifers.push_back(std::move(aqf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
@ -259,4 +189,119 @@ serializeOp(Serializer& serializer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TypeTag>
|
||||||
|
void BlackoilAquiferModel<TypeTag>::initializeStaticAquifers()
|
||||||
|
{
|
||||||
|
const auto& aquifer =
|
||||||
|
this->simulator_.vanguard().eclState().aquifer();
|
||||||
|
|
||||||
|
for (const auto& aquCT : aquifer.ct()) {
|
||||||
|
auto aquCTPtr = this->template createAnalyticAquiferPointer
|
||||||
|
<AquiferCarterTracy<TypeTag>>(aquCT, aquCT.aquiferID, "Carter-Tracy");
|
||||||
|
|
||||||
|
if (aquCTPtr != nullptr) {
|
||||||
|
this->aquifers.push_back(std::move(aquCTPtr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& aquFetp : aquifer.fetp()) {
|
||||||
|
auto aquFetpPtr = this->template createAnalyticAquiferPointer
|
||||||
|
<AquiferFetkovich<TypeTag>>(aquFetp, aquFetp.aquiferID, "Fetkovich");
|
||||||
|
|
||||||
|
if (aquFetpPtr != nullptr) {
|
||||||
|
this->aquifers.push_back(std::move(aquFetpPtr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& [id, aquFlux] : aquifer.aquflux()) {
|
||||||
|
// Make sure not dummy constant flux aquifers
|
||||||
|
if (! aquFlux.active) { continue; }
|
||||||
|
|
||||||
|
auto aquFluxPtr = this->template createAnalyticAquiferPointer
|
||||||
|
<AquiferConstantFlux<TypeTag>>(aquFlux, id, "Constant Flux");
|
||||||
|
|
||||||
|
if (aquFluxPtr != nullptr) {
|
||||||
|
this->aquifers.push_back(std::move(aquFluxPtr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aquifer.hasNumericalAquifer()) {
|
||||||
|
for (const auto& aquNum : aquifer.numericalAquifers().aquifers()) {
|
||||||
|
auto aquNumPtr = std::make_unique<AquiferNumerical<TypeTag>>
|
||||||
|
(aquNum.second, this->simulator_);
|
||||||
|
|
||||||
|
this->aquifers.push_back(std::move(aquNumPtr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TypeTag>
|
||||||
|
template <typename AquiferType, typename AquiferData>
|
||||||
|
std::unique_ptr<AquiferType>
|
||||||
|
BlackoilAquiferModel<TypeTag>::
|
||||||
|
createAnalyticAquiferPointer(const AquiferData& aqData,
|
||||||
|
const int aquiferID,
|
||||||
|
std::string_view aqType) const
|
||||||
|
{
|
||||||
|
const auto& connections =
|
||||||
|
this->simulator_.vanguard().eclState().aquifer().connections();
|
||||||
|
|
||||||
|
if (! connections.hasAquiferConnections(aquiferID)) {
|
||||||
|
const auto msg = fmt::format("No valid connections for {} aquifer {}. "
|
||||||
|
"Aquifer {} will be ignored.",
|
||||||
|
aqType, aquiferID, aquiferID);
|
||||||
|
OpmLog::warning(msg);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<AquiferType>
|
||||||
|
(connections.getConnections(aquiferID), this->simulator_, aqData);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TypeTag>
|
||||||
|
void BlackoilAquiferModel<TypeTag>::createDynamicAquifers(const int episode_index)
|
||||||
|
{
|
||||||
|
const auto& sched = this->simulator_.vanguard().schedule()[episode_index];
|
||||||
|
|
||||||
|
for (const auto& [id, aquFlux] : sched.aqufluxs) {
|
||||||
|
auto aquPos =
|
||||||
|
std::find_if(std::begin(this->aquifers),
|
||||||
|
std::end(this->aquifers),
|
||||||
|
[id](const auto& aquPtr)
|
||||||
|
{
|
||||||
|
return aquPtr->aquiferID() == id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (aquPos == std::end(this->aquifers)) {
|
||||||
|
// An aquifer with this 'id' does not yet exist in
|
||||||
|
// the collection managed by this object. Create it.
|
||||||
|
auto aquFluxPtr = this->template createAnalyticAquiferPointer
|
||||||
|
<AquiferConstantFlux<TypeTag>>(aquFlux, id, "Constant Flux");
|
||||||
|
|
||||||
|
if (aquFluxPtr != nullptr) {
|
||||||
|
this->aquifers.push_back(std::move(aquFluxPtr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto aquFluxPtr = dynamic_cast<AquiferConstantFlux<TypeTag>*>(aquPos->get());
|
||||||
|
if (aquFluxPtr == nullptr) {
|
||||||
|
// If the aquifers can return types easily, we might be able
|
||||||
|
// to give a better message with type information.
|
||||||
|
const auto msg =
|
||||||
|
fmt::format("Aquifer {} is updated with constant flux "
|
||||||
|
"aquifer keyword AQUFLUX at report step {}, "
|
||||||
|
"while it might be specified to be a "
|
||||||
|
"different type of aquifer before this. "
|
||||||
|
"We do not support the conversion between "
|
||||||
|
"different types of aquifer.\n", id, episode_index);
|
||||||
|
|
||||||
|
OPM_THROW(std::runtime_error, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
aquFluxPtr->updateAquifer(aquFlux);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
@ -491,7 +491,7 @@ BOOST_AUTO_TEST_CASE(AquiferConstantFlux)
|
|||||||
Opm::Serializer ser(packer);
|
Opm::Serializer ser(packer);
|
||||||
ser.pack(data_out);
|
ser.pack(data_out);
|
||||||
const size_t pos1 = ser.position();
|
const size_t pos1 = ser.position();
|
||||||
decltype(data_out) data_in({}, {}, sim);
|
decltype(data_out) data_in({}, sim, {});
|
||||||
ser.unpack(data_in);
|
ser.unpack(data_in);
|
||||||
const size_t pos2 = ser.position();
|
const size_t pos2 = ser.position();
|
||||||
BOOST_CHECK_MESSAGE(pos1 == pos2, "Packed size differ from unpack size for AquiferConstantFlux");
|
BOOST_CHECK_MESSAGE(pos1 == pos2, "Packed size differ from unpack size for AquiferConstantFlux");
|
||||||
|
Loading…
Reference in New Issue
Block a user