Merge pull request #2480 from bska/write-aqunum-restart

Add Restart Output for Numeric Aquifers
This commit is contained in:
Bård Skaflestad 2021-05-20 13:58:58 +02:00 committed by GitHub
commit 536265a8a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 451 additions and 38 deletions

View File

@ -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_;

View File

@ -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};

View File

@ -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))

View File

@ -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))

View File

@ -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);
});
}

View File

@ -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
};
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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&

View File

@ -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()

View File

@ -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();