Merge pull request #2480 from bska/write-aqunum-restart
Add Restart Output for Numeric Aquifers
This commit is contained in:
commit
536265a8a3
@ -112,6 +112,18 @@ namespace Opm { namespace RestartIO { namespace Helpers {
|
||||
return this->doubleprecAnalyticAq_.data();
|
||||
}
|
||||
|
||||
/// Retrieve Integer Aquifer Data Array for Numeric Aquifers.
|
||||
const std::vector<int>& getNumericAquiferIntegerData() const
|
||||
{
|
||||
return this->integerNumericAq_.data();
|
||||
}
|
||||
|
||||
/// Retrieve Double Precision Aquifer Data Array for Numeric Aquifers.
|
||||
const std::vector<double>& getNumericAquiferDoublePrecData() const
|
||||
{
|
||||
return this->doubleprecNumericAq_.data();
|
||||
}
|
||||
|
||||
/// Retrieve Integer Aquifer Connection Data Array (analytic aquifers)
|
||||
///
|
||||
/// \param[in] aquiferID Aquifer for which to retrieve integer
|
||||
@ -160,6 +172,12 @@ namespace Opm { namespace RestartIO { namespace Helpers {
|
||||
/// Aggregate 'XAAQ' array (Double Precision) for all analytic aquifers.
|
||||
WindowedArray<double> doubleprecAnalyticAq_;
|
||||
|
||||
/// Aggregate 'IAQN' array (integer) for all numeric aquifers.
|
||||
WindowedArray<int> integerNumericAq_;
|
||||
|
||||
/// Aggregate 'RAQN' array (Double Precision) for all numeric aquifers.
|
||||
WindowedArray<double> doubleprecNumericAq_;
|
||||
|
||||
/// Aggregate ICAQ array (Integer) for all analytic aquifer
|
||||
/// connections. Separate array for each aquifer.
|
||||
std::vector<WindowedArray<int>> integerAnalyticAquiferConn_;
|
||||
|
@ -154,6 +154,9 @@ namespace Opm { namespace RestartIO {
|
||||
// Maximum aquifer ID across all of the model's analytic aquifers.
|
||||
int maxAquiferID {0};
|
||||
|
||||
// Number of numeric aquifer records (lines of AQUNUM data)
|
||||
int numNumericAquiferRecords {0};
|
||||
|
||||
// Number of data elements per aquifer in IAAQ array.
|
||||
int numIntAquiferElem {18};
|
||||
|
||||
@ -163,6 +166,12 @@ namespace Opm { namespace RestartIO {
|
||||
// Number of data elements per aquifer in XAAQ array.
|
||||
int numDoubAquiferElem {10};
|
||||
|
||||
// Number of data elements in IAQN array per numeric aquifer record.
|
||||
int numNumericAquiferIntElem {10};
|
||||
|
||||
// Number of data elements in RAQN array per numeric aquifer record.
|
||||
int numNumericAquiferDoubleElem {13};
|
||||
|
||||
// Number of data elements per coonnection in ICAQ array.
|
||||
int numIntConnElem {7};
|
||||
|
||||
|
@ -60,6 +60,38 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
|
||||
} // Value
|
||||
} // IAnalyticAquiferConn
|
||||
|
||||
namespace INumericAquifer {
|
||||
enum index : std::vector<int>::size_type {
|
||||
AquiferID = 0, // ID of numeric aquifer
|
||||
Cell_I = 1, // I coordinate of aquifer cell
|
||||
Cell_J = 2, // J coordinate of aquifer cell
|
||||
Cell_K = 3, // K coordinate of aquifer cell
|
||||
PVTTableID = 4, // PVT Table ID of numeric aquifer
|
||||
SatFuncID = 5, // Saturation function ID of numeric aquifer
|
||||
};
|
||||
} // INumericAquifer
|
||||
|
||||
namespace RNumericAquifer {
|
||||
enum index : std::vector<double>::size_type {
|
||||
Area = 0, // Aquifer inflow area, AQUNUM(5)
|
||||
Length = 1, // Aquifer length, AQUNUM(6)
|
||||
Porosity = 2, // Aquifer porosity, AQUNUM(7)
|
||||
Permeability = 3, // Aquifer permeability, AQUNUM(8)
|
||||
Depth = 4, // Aquifer depth, AQUNUM(9)
|
||||
Pressure = 5, // Aquifer pressure, AQUNUM(10)
|
||||
|
||||
Unknown_1 = 6, // Unknown item, = 1.0
|
||||
Unknown_2 = 7, // Unknown item, = 1.0
|
||||
Unknown_3 = 8, // Unknown item, = 1.0
|
||||
|
||||
PoreVolume = 9, // Total aquifer pore-volume (= Area * Length * Porosity)
|
||||
|
||||
FlowRate = 10, // Aquifer inflow rate (ANQR:N)
|
||||
ProdVolume = 11, // Total liquid volume produced from aquifer (AQNT:N)
|
||||
DynPressure = 12, // Dynamic aquifer pressure (ANQP:N)
|
||||
};
|
||||
} // RNumericAquifer
|
||||
|
||||
namespace SAnalyticAquifer {
|
||||
enum index : std::vector<float>::size_type {
|
||||
Compressibility = 0, // Total aquifer compressibility (AQUCT(6), AQUFETP(5))
|
||||
|
@ -141,6 +141,11 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems
|
||||
|
||||
WSEGITR_IT2 = 208, // NR - maximum no of times that a new iteration cycle with a reduced Wp will be started
|
||||
|
||||
NIIAQN = 223, // Number of data elements in IAQN array pr AQUNUM record
|
||||
NIRAQN = 224, // Number of data elements in RAQN array pr AQUNUM record
|
||||
|
||||
NUM_AQUNUM_RECORDS = 226, // Number of AQUNUM records (lines of AQUNUM data)
|
||||
|
||||
MAX_ACT_COND = 245, // Maximum number of conditions pr action
|
||||
MAX_AN_AQUIFER_ID = 252, // Maximum aquifer ID of all analytic aquifers (<= AQUDIMS(5))
|
||||
|
||||
|
@ -51,6 +51,15 @@
|
||||
namespace VI = Opm::RestartIO::Helpers::VectorItems;
|
||||
|
||||
namespace {
|
||||
double getSummaryVariable(const Opm::SummaryState& summaryState,
|
||||
const std::string& variable,
|
||||
const int aquiferID)
|
||||
{
|
||||
const auto key = fmt::format("{}:{}", variable, aquiferID);
|
||||
|
||||
return summaryState.get(key, 0.0);
|
||||
}
|
||||
|
||||
template <typename AquiferCallBack>
|
||||
void CarterTracyAquiferLoop(const Opm::AquiferConfig& aqConfig,
|
||||
AquiferCallBack&& aquiferOp)
|
||||
@ -69,6 +78,24 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename AquiferCallBack>
|
||||
void numericAquiferLoop(const Opm::AquiferConfig& aqConfig,
|
||||
AquiferCallBack&& aquiferOp)
|
||||
{
|
||||
if (! aqConfig.hasNumericalAquifer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& [aquiferID, aquifer] : aqConfig.numericalAquifers().aquifers()) {
|
||||
const auto numCells = aquifer.numCells();
|
||||
|
||||
for (auto cellIndex = 0*numCells; cellIndex < numCells; ++cellIndex) {
|
||||
const auto* aqCell = aquifer.getCellPrt(cellIndex);
|
||||
aquiferOp(static_cast<int>(aquiferID), cellIndex == 0*numCells, *aqCell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ConnectionCallBack>
|
||||
void analyticAquiferConnectionLoop(const Opm::AquiferConfig& aqConfig,
|
||||
ConnectionCallBack&& connectionOp)
|
||||
@ -139,6 +166,37 @@ namespace {
|
||||
} // Fetckovich
|
||||
} // IntegerAnalyticAquifer
|
||||
|
||||
namespace IntegerNumericAquifer
|
||||
{
|
||||
Opm::RestartIO::Helpers::WindowedArray<int>
|
||||
allocate(const Opm::RestartIO::InteHEAD::AquiferDims& aqDims)
|
||||
{
|
||||
using WA = Opm::RestartIO::Helpers::WindowedArray<int>;
|
||||
|
||||
return WA {
|
||||
WA::NumWindows{ static_cast<WA::Idx>(aqDims.numNumericAquiferRecords) },
|
||||
WA::WindowSize{ static_cast<WA::Idx>(aqDims.numNumericAquiferIntElem) }
|
||||
};
|
||||
}
|
||||
|
||||
template <typename IAqnArray>
|
||||
void staticContrib(const Opm::NumericalAquiferCell& aqCell,
|
||||
const int aquiferID,
|
||||
IAqnArray& iaqn)
|
||||
{
|
||||
using Ix = VI::INumericAquifer::index;
|
||||
|
||||
iaqn[Ix::AquiferID] = aquiferID;
|
||||
|
||||
iaqn[Ix::Cell_I] = static_cast<int>(aqCell.I) + 1;
|
||||
iaqn[Ix::Cell_J] = static_cast<int>(aqCell.J) + 1;
|
||||
iaqn[Ix::Cell_K] = static_cast<int>(aqCell.K) + 1;
|
||||
|
||||
iaqn[Ix::PVTTableID] = aqCell.pvttable;
|
||||
iaqn[Ix::SatFuncID] = aqCell.sattable;
|
||||
}
|
||||
} // IntegerNumericAquifer
|
||||
|
||||
namespace IntegerAnalyticAquiferConn
|
||||
{
|
||||
std::vector<Opm::RestartIO::Helpers::WindowedArray<int>>
|
||||
@ -311,15 +369,6 @@ namespace {
|
||||
return usys.from_si(M::length, usys.from_si(M::length, tot_influx));
|
||||
}
|
||||
|
||||
double getSummaryVariable(const Opm::SummaryState& summaryState,
|
||||
const std::string& variable,
|
||||
const int aquiferID)
|
||||
{
|
||||
const auto key = fmt::format("{}:{}", variable, aquiferID);
|
||||
|
||||
return summaryState.get(key, 0.0);
|
||||
}
|
||||
|
||||
Opm::RestartIO::Helpers::WindowedArray<double>
|
||||
allocate(const Opm::RestartIO::InteHEAD::AquiferDims& aqDims)
|
||||
{
|
||||
@ -395,6 +444,50 @@ namespace {
|
||||
} // Fetkovich
|
||||
} // DoublePrecAnalyticAquifer
|
||||
|
||||
namespace DoublePrecNumericAquifer
|
||||
{
|
||||
Opm::RestartIO::Helpers::WindowedArray<double>
|
||||
allocate(const Opm::RestartIO::InteHEAD::AquiferDims& aqDims)
|
||||
{
|
||||
using WA = Opm::RestartIO::Helpers::WindowedArray<double>;
|
||||
|
||||
return WA {
|
||||
WA::NumWindows{ static_cast<WA::Idx>(aqDims.numNumericAquiferRecords) },
|
||||
WA::WindowSize{ static_cast<WA::Idx>(aqDims.numNumericAquiferDoubleElem) }
|
||||
};
|
||||
}
|
||||
|
||||
template <typename SummaryVariable, typename RAqnArray>
|
||||
void dynamicContrib(const Opm::NumericalAquiferCell& aqCell,
|
||||
SummaryVariable&& summaryVariable,
|
||||
const Opm::UnitSystem& usys,
|
||||
RAqnArray& raqn)
|
||||
{
|
||||
using M = Opm::UnitSystem::measure;
|
||||
using Ix = VI::RNumericAquifer::index;
|
||||
|
||||
raqn[Ix::Area] = usys.from_si(M::length, usys.from_si(M::length, aqCell.area));
|
||||
raqn[Ix::Length] = usys.from_si(M::length, aqCell.length);
|
||||
raqn[Ix::Porosity] = aqCell.porosity;
|
||||
raqn[Ix::Permeability] = usys.from_si(M::permeability, aqCell.permeability);
|
||||
raqn[Ix::Depth] = usys.from_si(M::length, aqCell.depth);
|
||||
|
||||
if (aqCell.init_pressure.has_value()) {
|
||||
raqn[Ix::Pressure] = usys.from_si(M::pressure, aqCell.init_pressure.value());
|
||||
}
|
||||
|
||||
raqn[Ix::Unknown_1] = 1.0; // Unknown item. 1.0 in all cases so far.
|
||||
raqn[Ix::Unknown_2] = 1.0; // Unknown item. 1.0 in all cases so far.
|
||||
raqn[Ix::Unknown_3] = 1.0; // Unknown item. 1.0 in all cases so far.
|
||||
|
||||
raqn[Ix::PoreVolume] = usys.from_si(M::volume, aqCell.poreVolume());
|
||||
|
||||
raqn[Ix::FlowRate] = summaryVariable("ANQR");
|
||||
raqn[Ix::ProdVolume] = summaryVariable("ANQT");
|
||||
raqn[Ix::DynPressure] = summaryVariable("ANQP");
|
||||
}
|
||||
} // IntegerNumericAquifer
|
||||
|
||||
namespace DoublePrecAnalyticAquiferConn
|
||||
{
|
||||
std::vector<Opm::RestartIO::Helpers::WindowedArray<double>>
|
||||
@ -420,10 +513,16 @@ AggregateAquiferData(const InteHEAD::AquiferDims& aqDims,
|
||||
, integerAnalyticAq_ { IntegerAnalyticAquifer:: allocate(aqDims) }
|
||||
, singleprecAnalyticAq_ { SinglePrecAnalyticAquifer:: allocate(aqDims) }
|
||||
, doubleprecAnalyticAq_ { DoublePrecAnalyticAquifer:: allocate(aqDims) }
|
||||
, integerNumericAq_ { IntegerNumericAquifer:: allocate(aqDims) }
|
||||
, doubleprecNumericAq_ { DoublePrecNumericAquifer:: allocate(aqDims) }
|
||||
, integerAnalyticAquiferConn_ { IntegerAnalyticAquiferConn:: allocate(aqDims) }
|
||||
, singleprecAnalyticAquiferConn_{ SinglePrecAnalyticAquiferConn::allocate(aqDims) }
|
||||
, doubleprecAnalyticAquiferConn_{ DoublePrecAnalyticAquiferConn::allocate(aqDims) }
|
||||
{
|
||||
if (! aqConfig.hasAnalyticalAquifer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto map = buildColumnarActiveIndexMappingTables(grid);
|
||||
|
||||
// Aquifer connections do not change in SCHEDULE. Leverage that
|
||||
@ -472,8 +571,7 @@ captureDynamicdAquiferData(const AquiferConfig& aqConfig,
|
||||
const auto tot_influx = this->totalInflux_[aquIndex];
|
||||
auto sumVar = [&summaryState, &aquifer](const std::string& vector)
|
||||
{
|
||||
return DoublePrecAnalyticAquifer::
|
||||
getSummaryVariable(summaryState, vector, aquifer.aquiferID);
|
||||
return getSummaryVariable(summaryState, vector, aquifer.aquiferID);
|
||||
};
|
||||
DoublePrecAnalyticAquifer::Fetkovich::dynamicContrib(sumVar, tot_influx, usys, xaaq);
|
||||
});
|
||||
@ -498,10 +596,23 @@ captureDynamicdAquiferData(const AquiferConfig& aqConfig,
|
||||
const auto tot_influx = this->totalInflux_[aquIndex];
|
||||
auto sumVar = [&summaryState, &aquifer](const std::string& vector)
|
||||
{
|
||||
return DoublePrecAnalyticAquifer::
|
||||
getSummaryVariable(summaryState, vector, aquifer.aquiferID);
|
||||
return getSummaryVariable(summaryState, vector, aquifer.aquiferID);
|
||||
};
|
||||
DoublePrecAnalyticAquifer::CarterTracy::dynamicContrib(sumVar, aquifer, pvtw,
|
||||
tot_influx, usys, xaaq);
|
||||
});
|
||||
|
||||
numericAquiferLoop(aqConfig, [this, &summaryState, &usys]
|
||||
(const int aquiferID, const bool isNewID, const NumericalAquiferCell& aqCell)
|
||||
{
|
||||
auto iaqn = this->integerNumericAq_[aqCell.record_id];
|
||||
IntegerNumericAquifer::staticContrib(aqCell, aquiferID, iaqn);
|
||||
|
||||
auto raqn = this->doubleprecNumericAq_[aqCell.record_id];
|
||||
auto sumVar = [&summaryState, aquiferID, isNewID](const std::string& vector)
|
||||
{
|
||||
return !isNewID ? 0.0 : getSummaryVariable(summaryState, vector, aquiferID);
|
||||
};
|
||||
DoublePrecNumericAquifer::dynamicContrib(aqCell, sumVar, usys, raqn);
|
||||
});
|
||||
}
|
||||
|
@ -131,10 +131,12 @@ EclipseIO::Impl::Impl( const EclipseState& eclipseState,
|
||||
, summary( eclipseState, summaryConfig, grid , schedule )
|
||||
, output_enabled( eclipseState.getIOConfig().getOutputEnabled() )
|
||||
{
|
||||
if (this->es.aquifer().hasAnalyticalAquifer()) {
|
||||
const auto& aqConfig = this->es.aquifer();
|
||||
|
||||
if (aqConfig.hasAnalyticalAquifer() || aqConfig.hasNumericalAquifer()) {
|
||||
this->aquiferData = RestartIO::Helpers::AggregateAquiferData {
|
||||
RestartIO::inferAquiferDimensions(this->es),
|
||||
this->es.aquifer(),
|
||||
aqConfig,
|
||||
this->grid
|
||||
};
|
||||
}
|
||||
|
@ -271,10 +271,10 @@ enum index : std::vector<int>::size_type {
|
||||
ih_220 = 220 , // 0
|
||||
ih_221 = 221 , // 0
|
||||
ih_222 = 222 , // 0
|
||||
NIIAQN = 223 , // 0 NIIAQN = number of lines of integer AQUNUM data.
|
||||
NIRAQN = 224 , // 0 NIRAQN = number of lines of real AQUNUM data.
|
||||
NIIAQN = VI::intehead::NIIAQN, // 0 NIIAQN = Number of integer data elements in IAQN array pr. numeric aquifer record in AQUNUM.
|
||||
NIRAQN = VI::intehead::NIRAQN, // 0 NIRAQN = number of double precision data elements in RAQN array pr. numeric aquifer record in AQUNUM.
|
||||
ih_225 = 225 , // 0
|
||||
NUMAQN = 226 , // 0 NUMAQN = number of lines of AQUNUM data entered.
|
||||
NUMAQN = VI::intehead::NUM_AQUNUM_RECORDS, // 0 NUMAQN = number of lines of AQUNUM data entered (#records).
|
||||
ih_227 = 227 , // 0
|
||||
ih_228 = 228 , // 0
|
||||
ih_229 = 229 , // 0
|
||||
@ -615,6 +615,11 @@ aquiferDimensions(const AquiferDims& aqdims)
|
||||
this -> data_[NACAQZ] = aqdims.numDoubConnElem;
|
||||
|
||||
this -> data_[NGCAUS] = aqdims.maxNumActiveAquiferConn;
|
||||
|
||||
this -> data_[NIIAQN] = aqdims.numNumericAquiferIntElem;
|
||||
this -> data_[NIRAQN] = aqdims.numNumericAquiferDoubleElem;
|
||||
this -> data_[NUMAQN] = aqdims.numNumericAquiferRecords;
|
||||
|
||||
this -> data_[MAAQID] = aqdims.maxAquiferID;
|
||||
|
||||
// Not characterised. Equal to NAQUIF in all cases seen this far.
|
||||
@ -897,5 +902,9 @@ Opm::RestartIO::inferAquiferDimensions(const EclipseState& es)
|
||||
dim.maxAquiferID = getMaximumAnalyticAquiferID(cfg);
|
||||
}
|
||||
|
||||
if (cfg.hasNumericalAquifer()) {
|
||||
dim.numNumericAquiferRecords = cfg.numericalAquifers().numRecords();
|
||||
}
|
||||
|
||||
return dim;
|
||||
}
|
||||
|
@ -424,21 +424,14 @@ namespace {
|
||||
rstFile.write("XCON", connectionData.getXConn());
|
||||
}
|
||||
|
||||
void updateAndWriteAquiferData(const AquiferConfig& aqConfig,
|
||||
const SummaryState& summaryState,
|
||||
const TableManager& tables,
|
||||
const UnitSystem& usys,
|
||||
Helpers::AggregateAquiferData& aquiferData,
|
||||
void writeAnalyticAquiferData(const Helpers::AggregateAquiferData& aquiferData,
|
||||
EclIO::OutputStream::Restart& rstFile)
|
||||
{
|
||||
aquiferData.captureDynamicdAquiferData(aqConfig, summaryState,
|
||||
tables.getPvtwTable(),
|
||||
tables.getDensityTable(), usys);
|
||||
|
||||
rstFile.write("IAAQ", aquiferData.getIntegerAquiferData());
|
||||
rstFile.write("SAAQ", aquiferData.getSinglePrecAquiferData());
|
||||
rstFile.write("XAAQ", aquiferData.getDoublePrecAquiferData());
|
||||
|
||||
// Aquifer IDs in 1..maxID inclusive.
|
||||
const auto maxAquiferID = aquiferData.maximumActiveAnalyticAquiferID();
|
||||
for (auto aquiferID = 1 + 0*maxAquiferID; aquiferID <= maxAquiferID; ++aquiferID) {
|
||||
const auto xCAQnum = std::vector<int>{ aquiferID };
|
||||
@ -454,6 +447,33 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
void writeNumericAquiferData(const Helpers::AggregateAquiferData& aquiferData,
|
||||
EclIO::OutputStream::Restart& rstFile)
|
||||
{
|
||||
rstFile.write("IAQN", aquiferData.getNumericAquiferIntegerData());
|
||||
rstFile.write("RAQN", aquiferData.getNumericAquiferDoublePrecData());
|
||||
}
|
||||
|
||||
void updateAndWriteAquiferData(const AquiferConfig& aqConfig,
|
||||
const SummaryState& summaryState,
|
||||
const TableManager& tables,
|
||||
const UnitSystem& usys,
|
||||
Helpers::AggregateAquiferData& aquiferData,
|
||||
EclIO::OutputStream::Restart& rstFile)
|
||||
{
|
||||
aquiferData.captureDynamicdAquiferData(aqConfig, summaryState,
|
||||
tables.getPvtwTable(),
|
||||
tables.getDensityTable(), usys);
|
||||
|
||||
if (aqConfig.hasAnalyticalAquifer()) {
|
||||
writeAnalyticAquiferData(aquiferData, rstFile);
|
||||
}
|
||||
|
||||
if (aqConfig.hasNumericalAquifer()) {
|
||||
writeNumericAquiferData(aquiferData, rstFile);
|
||||
}
|
||||
}
|
||||
|
||||
void writeDynamicData(const int sim_step,
|
||||
const bool ecl_compatible_rst,
|
||||
const Phases& phases,
|
||||
@ -497,7 +517,9 @@ namespace {
|
||||
wells, wellSol, action_state, sumState, inteHD, rstFile);
|
||||
}
|
||||
|
||||
if (es.aquifer().hasAnalyticalAquifer() && aquiferData.has_value()) {
|
||||
if ((es.aquifer().hasAnalyticalAquifer() || es.aquifer().hasNumericalAquifer()) &&
|
||||
aquiferData.has_value())
|
||||
{
|
||||
updateAndWriteAquiferData(es.aquifer(), sumState, es.getTableManager(),
|
||||
units, aquiferData.value(), rstFile);
|
||||
}
|
||||
|
@ -310,6 +310,29 @@ namespace {
|
||||
return entities;
|
||||
}
|
||||
|
||||
std::vector<Opm::EclIO::SummaryNode>
|
||||
requiredNumericAquiferVectors(const std::vector<int>& aquiferIDs)
|
||||
{
|
||||
auto entities = std::vector<Opm::EclIO::SummaryNode> {};
|
||||
|
||||
const auto vectors = std::vector<ParamCTorArgs> {
|
||||
{ "ANQR" , Opm::EclIO::SummaryNode::Type::Rate },
|
||||
{ "ANQP" , Opm::EclIO::SummaryNode::Type::Pressure },
|
||||
{ "ANQT" , Opm::EclIO::SummaryNode::Type::Total },
|
||||
};
|
||||
|
||||
using Cat = Opm::EclIO::SummaryNode::Category;
|
||||
|
||||
for (const auto& aquiferID : aquiferIDs) {
|
||||
for (const auto& vector : vectors) {
|
||||
entities.push_back({ vector.kw, Cat::Aquifer,
|
||||
vector.type, "", aquiferID, {} });
|
||||
}
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
Opm::TimeStampUTC make_sim_time(const Opm::Schedule& sched, const Opm::SummaryState& st, double sim_step) {
|
||||
auto elapsed = st.get_elapsed() + sim_step;
|
||||
return Opm::TimeStampUTC( sched.getStartTime() ) + std::chrono::duration<double>(elapsed);
|
||||
@ -3609,6 +3632,13 @@ configureRequiredRestartParameters(const SummaryConfig& sumcfg,
|
||||
for (const auto& node : requiredAquiferVectors(aquiferIDs))
|
||||
makeEvaluator(node);
|
||||
}
|
||||
|
||||
if (aqConfig.hasNumericalAquifer()) {
|
||||
const auto aquiferIDs = numericAquiferIDs(aqConfig);
|
||||
|
||||
for (const auto& node : requiredNumericAquiferVectors(aquiferIDs))
|
||||
makeEvaluator(node);
|
||||
}
|
||||
}
|
||||
|
||||
Opm::out::Summary::SummaryImplementation::MiniStep&
|
||||
|
@ -361,6 +361,58 @@ namespace {
|
||||
};
|
||||
}
|
||||
|
||||
Opm::AquiferConfig createNumericAquiferConfig()
|
||||
{
|
||||
const auto deck = Opm::Parser{}.parseString(R"(
|
||||
START -- 0
|
||||
10 MAY 2007 /
|
||||
RUNSPEC
|
||||
|
||||
DIMENS
|
||||
10 10 10 /
|
||||
REGDIMS
|
||||
3/
|
||||
AQUDIMS
|
||||
4 4 1* 1* 3 200 1* 1* /
|
||||
|
||||
GRID
|
||||
DXV
|
||||
10*400 /
|
||||
DYV
|
||||
10*400 /
|
||||
DZV
|
||||
10*400 /
|
||||
TOPS
|
||||
100*2202 /
|
||||
PERMX
|
||||
1000*0.25 /
|
||||
COPY
|
||||
PERMX PERMY /
|
||||
PERMX PERMZ /
|
||||
/
|
||||
PORO
|
||||
1000*0.15 /
|
||||
AQUNUM
|
||||
--ID I J K Area Len Phi K Depth P0 PVT SAT
|
||||
1 1 1 1 15000 5000 0.3 30 2700 285 /
|
||||
1 2 1 1 160000 6000 0.4 400 2705 295 1* 3 /
|
||||
1 3 1 1 150000 7000 0.5 5000 2710 1* 2 /
|
||||
2 4 1 1 140000 9000 0.3 300 2715 250 2 3 / aq cell
|
||||
/
|
||||
AQUCON
|
||||
-- # I1 I2 J1 J2 K1 K2 Face
|
||||
1 1 1 16 18 19 20 'I-' /
|
||||
1 2 2 16 18 19 20 'I-' /
|
||||
1 3 3 16 18 19 20 'I-' /
|
||||
2 4 4 16 18 19 20 'I-' /
|
||||
/
|
||||
|
||||
END
|
||||
)");
|
||||
|
||||
return Opm::EclipseState { deck }.aquifer();
|
||||
}
|
||||
|
||||
Opm::EclipseGrid createGrid()
|
||||
{
|
||||
auto grid = Opm::EclipseGrid { 20, 5, 10, 5.0, 4.0, 0.2 };
|
||||
@ -390,6 +442,15 @@ namespace {
|
||||
return aqDims;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::AquiferDims syntheticNumericAquiferDimensions()
|
||||
{
|
||||
auto aqDims = Opm::RestartIO::InteHEAD::AquiferDims{};
|
||||
|
||||
aqDims.numNumericAquiferRecords = 4;
|
||||
|
||||
return aqDims;
|
||||
}
|
||||
|
||||
Opm::RestartIO::InteHEAD::AquiferDims parseAquiferDimensions()
|
||||
{
|
||||
const auto deck = Opm::Parser{}.parseString(R"(RUNSPEC
|
||||
@ -398,7 +459,7 @@ DIMENS
|
||||
|
||||
AQUDIMS
|
||||
-- MXNAQN MXNAQC NIFTBL NRIFTB NANAQU NNCAMAX
|
||||
1* 1* 5 100 5 1000 /
|
||||
4 4 5 100 5 1000 /
|
||||
|
||||
GRID
|
||||
|
||||
@ -421,6 +482,19 @@ EQUALS
|
||||
'PORO' 0.0 2 3 2 2 2 2 /
|
||||
'PORO' 0.0 20 20 2 3 7 7 /
|
||||
/
|
||||
AQUNUM
|
||||
4 1 1 1 15000 5000 0.3 30 2700 / aq cell
|
||||
5 2 1 1 150000 9000 0.3 30 2700 / aq cell
|
||||
6 3 1 1 150000 9000 0.3 30 2700 / aq cell
|
||||
7 4 1 1 150000 9000 0.3 30 2700 / aq cell
|
||||
/
|
||||
AQUCON
|
||||
-- # I1 I2 J1 J2 K1 K2 Face
|
||||
4 1 1 16 18 19 20 'I-' / connecting cells
|
||||
5 2 2 16 18 19 20 'I-' / connecting cells
|
||||
6 3 3 16 18 19 20 'I-' / connecting cells
|
||||
7 4 4 16 18 19 20 'I-' / connecting cells
|
||||
/
|
||||
|
||||
SOLUTION
|
||||
|
||||
@ -470,6 +544,21 @@ AQUANCON
|
||||
return state;
|
||||
}
|
||||
|
||||
Opm::SummaryState aqunum_sim_state()
|
||||
{
|
||||
auto state = Opm::SummaryState{Opm::TimeService::now()};
|
||||
|
||||
state.update("ANQP:1", 123.456);
|
||||
state.update("ANQR:1", 234.567);
|
||||
state.update("ANQT:1", 3456.789);
|
||||
|
||||
state.update("ANQP:2", 121.212);
|
||||
state.update("ANQR:2", 222.333);
|
||||
state.update("ANQT:2", 333.444);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
template <class Coll1, class Coll2>
|
||||
void check_is_close(const Coll1& coll1, const Coll2& coll2, const double tol)
|
||||
{
|
||||
@ -497,6 +586,7 @@ BOOST_AUTO_TEST_CASE(AquiferDimensions)
|
||||
BOOST_CHECK_EQUAL(aqDims.maxNumAquiferConn, 1000); // AQUDIMS(6)
|
||||
BOOST_CHECK_EQUAL(aqDims.maxNumActiveAquiferConn, 13); // In aquifer ID 2
|
||||
BOOST_CHECK_EQUAL(aqDims.maxAquiferID, 4); // Maximum aquifer ID
|
||||
BOOST_CHECK_EQUAL(aqDims.numNumericAquiferRecords, 4); // Number of lines of AQUNUM data
|
||||
|
||||
// # Data items per analytic aquifer
|
||||
BOOST_CHECK_EQUAL(aqDims.numIntAquiferElem, 18); // # Integer
|
||||
@ -507,6 +597,10 @@ BOOST_AUTO_TEST_CASE(AquiferDimensions)
|
||||
BOOST_CHECK_EQUAL(aqDims.numIntConnElem, 7); // # Integer
|
||||
BOOST_CHECK_EQUAL(aqDims.numRealConnElem, 2); // # Single precision
|
||||
BOOST_CHECK_EQUAL(aqDims.numDoubConnElem, 4); // # Double precision
|
||||
|
||||
// # Data items per numeric aquifer
|
||||
BOOST_CHECK_EQUAL(aqDims.numNumericAquiferIntElem, 10); // # Integer
|
||||
BOOST_CHECK_EQUAL(aqDims.numNumericAquiferDoubleElem, 13); // # Double precision
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Static_Information_Analytic_Aquifers)
|
||||
@ -813,4 +907,62 @@ BOOST_AUTO_TEST_CASE(Dynamic_Information_Analytic_Aquifers)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Dynamic_Information_Numeric_Aquifers)
|
||||
{
|
||||
const auto aqDims = syntheticNumericAquiferDimensions();
|
||||
const auto aqConfig = createNumericAquiferConfig();
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(aqConfig.hasNumericalAquifer(), "Aquifer configuration object must have numeric aquifers");
|
||||
|
||||
auto aquiferData = Opm::RestartIO::Helpers::
|
||||
AggregateAquiferData{ aqDims, aqConfig, createGrid() };
|
||||
|
||||
{
|
||||
BOOST_CHECK_EQUAL(aquiferData.maximumActiveAnalyticAquiferID(), 0);
|
||||
BOOST_CHECK_MESSAGE(aquiferData.getIntegerAquiferData().empty(), "IAAQ must be empty");
|
||||
BOOST_CHECK_MESSAGE(aquiferData.getSinglePrecAquiferData().empty(), "SAAQ must be empty");
|
||||
BOOST_CHECK_MESSAGE(aquiferData.getDoublePrecAquiferData().empty(), "XAAQ must be empty");
|
||||
|
||||
BOOST_CHECK_EQUAL(aquiferData.getNumericAquiferIntegerData().size(), 4u * 10);
|
||||
BOOST_CHECK_EQUAL(aquiferData.getNumericAquiferDoublePrecData().size(), 4u * 13);
|
||||
}
|
||||
|
||||
aquiferData.captureDynamicdAquiferData(aqConfig, aqunum_sim_state(),
|
||||
pvtw(), density(),
|
||||
Opm::UnitSystem::newMETRIC());
|
||||
|
||||
// IAQN
|
||||
{
|
||||
const auto expect = std::vector<int> {
|
||||
1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 0.. 9 (record 0)
|
||||
1, 2, 1, 1, 1, 3, 0, 0, 0, 0, // 10..19 (record 1)
|
||||
1, 3, 1, 1, 2, 1, 0, 0, 0, 0, // 20..29 (record 2)
|
||||
2, 4, 1, 1, 2, 3, 0, 0, 0, 0, // 30..39 (record 3)
|
||||
};
|
||||
|
||||
const auto& iaqn = aquiferData.getNumericAquiferIntegerData();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(iaqn.begin(), iaqn.end(), expect.begin(), expect.end());
|
||||
}
|
||||
|
||||
// RAQN
|
||||
{
|
||||
const auto pv = std::vector<double> {
|
||||
15.0e3 * 5.0e3 * 0.3,
|
||||
160.0e3 * 6.0e3 * 0.4,
|
||||
150.0e3 * 7.0e3 * 0.5,
|
||||
140.0e3 * 9.0e3 * 0.3,
|
||||
};
|
||||
|
||||
const auto expect = std::vector<double> {
|
||||
15.0e3, 5.0e3, 0.3, 30.0, 2700.0, 285.0, 1.0, 1.0, 1.0, pv[0], 234.567, 3456.789, 123.456, // 0..12 (record 0)
|
||||
160.0e3, 6.0e3, 0.4, 400.0, 2705.0, 295.0, 1.0, 1.0, 1.0, pv[1], 0.0 , 0.0 , 0.0 , // 13..25 (record 1)
|
||||
150.0e3, 7.0e3, 0.5, 5000.0, 2710.0, 0.0, 1.0, 1.0, 1.0, pv[2], 0.0 , 0.0 , 0.0 , // 26..38 (record 2)
|
||||
140.0e3, 9.0e3, 0.3, 300.0, 2715.0, 250.0, 1.0, 1.0, 1.0, pv[3], 222.333, 333.444, 121.212, // 39..51 (record 3)
|
||||
};
|
||||
|
||||
const auto& raqn = aquiferData.getNumericAquiferDoublePrecData();
|
||||
check_is_close(raqn, expect, 1.0e-10);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -316,7 +316,20 @@ BOOST_AUTO_TEST_CASE(Analytic_Aquifer_Parameters)
|
||||
{
|
||||
// https://oeis.org/A001622
|
||||
const auto aqudims = Opm::RestartIO::InteHEAD::AquiferDims {
|
||||
1, 61, 803, 3988, 74989, 484820, 45868, 3436, 563, 81, 1177203
|
||||
1, // numAquifers
|
||||
61, // maxNumAquifers
|
||||
803, // maxNumAquiferConn
|
||||
3988, // maxNumActiveAquiferConn
|
||||
74989, // maxAquiferID
|
||||
484820, // numNumericAquiferRecords
|
||||
45868, // numIntAquiferElem
|
||||
3436, // numRealAquiferElem
|
||||
563, // numDoubAquiferElem
|
||||
81, // numNumericAquiferIntElem
|
||||
17, // numNumericAquiferDoubleElem
|
||||
720, // numIntConnElem
|
||||
30, // numRealConnElem
|
||||
9, // numDoubConnElem
|
||||
};
|
||||
|
||||
const auto ih = Opm::RestartIO::InteHEAD{}
|
||||
@ -326,17 +339,21 @@ BOOST_AUTO_TEST_CASE(Analytic_Aquifer_Parameters)
|
||||
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NAQUIF], 1);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NCAMAX], 803);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NIAAQZ], 484820);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NSAAQZ], 45868);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NXAAQZ], 3436);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NICAQZ], 563);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NSCAQZ], 81);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NACAQZ], 1177203);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NIAAQZ], 45868);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NSAAQZ], 3436);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NXAAQZ], 563);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NICAQZ], 720);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NSCAQZ], 30);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NACAQZ], 9);
|
||||
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::MAX_ACT_ANLYTIC_AQUCONN], 3988);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::MAX_AN_AQUIFER_ID], 74989);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::AQU_UNKNOWN_1], 1);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::MAX_ANALYTIC_AQUIFERS], 61);
|
||||
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NIIAQN], 81);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NIRAQN], 17);
|
||||
BOOST_CHECK_EQUAL(v[VI::intehead::NUM_AQUNUM_RECORDS], 484820);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Time_and_report_step)
|
||||
@ -564,6 +581,9 @@ BOOST_AUTO_TEST_CASE(TestHeader) {
|
||||
const auto nicaqz = 111111;
|
||||
const auto nscaqz = 1111111;
|
||||
const auto nacaqz = 11111111;
|
||||
const auto niiaqn = 22222222;
|
||||
const auto niraqn = 2222222;
|
||||
const auto numaqn = 222222;
|
||||
const auto tstep = 78;
|
||||
const auto report_step = 12;
|
||||
const auto newtmx = 17;
|
||||
@ -586,7 +606,10 @@ BOOST_AUTO_TEST_CASE(TestHeader) {
|
||||
const auto ngroup = 8;
|
||||
|
||||
const auto aqudims = Opm::RestartIO::InteHEAD::AquiferDims {
|
||||
1, 61, ncamax, 3988, 74989, niaaqz, nsaaqz, nxaaqz, nicaqz, nscaqz, nacaqz
|
||||
1, 61, ncamax, 3988, 74989,
|
||||
numaqn, niaaqz, nsaaqz, nxaaqz,
|
||||
niiaqn, niraqn,
|
||||
nicaqz, nscaqz, nacaqz
|
||||
};
|
||||
|
||||
auto unit_system = Opm::UnitSystem::newMETRIC();
|
||||
|
Loading…
Reference in New Issue
Block a user