Add Numeric Aquifer Restart Output
This commit generates the IAQN and RAQN restart vectors pertaining to numeric aquifers. The arrays are sized according to the number of records in the input AQUNUM keyword. RAQN is a mix of static and dynamic information, including the cumulative total inflow volume of water from the aquifer into the model. IAQN is exclusively static information. We add new members to 'AggregateAquiferData' and ensure that the numeric aquifer arrays remain empty when no numeric aquifers exist in the model. Add unit tests for these new arrays and update existing unit tests to account for new dimension items.
This commit is contained in:
@@ -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};
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
EclIO::OutputStream::Restart& rstFile)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user