Add Restart Support for NETBALAN Keyword

This commit loads NETBALAN parameters from the restart file and
forms Network::Balance objects from these parameters.
This commit is contained in:
Bård Skaflestad 2022-08-09 18:21:39 +02:00
parent 1670c217ee
commit 418173bbcc
9 changed files with 563 additions and 0 deletions

View File

@ -302,6 +302,7 @@ if(ENABLE_ECL_OUTPUT)
src/opm/io/eclipse/rst/connection.cpp
src/opm/io/eclipse/rst/group.cpp
src/opm/io/eclipse/rst/header.cpp
src/opm/io/eclipse/rst/netbalan.cpp
src/opm/io/eclipse/rst/network.cpp
src/opm/io/eclipse/rst/udq.cpp
src/opm/io/eclipse/rst/segment.cpp
@ -474,6 +475,7 @@ if(ENABLE_ECL_OUTPUT)
tests/test_Restart.cpp
tests/test_RFT.cpp
tests/test_rst.cpp
tests/test_rst_netbalan.cpp
tests/test_Solution.cpp
tests/test_Inplace.cpp
tests/test_Summary.cpp
@ -930,6 +932,7 @@ if(ENABLE_ECL_OUTPUT)
opm/io/eclipse/rst/connection.hpp
opm/io/eclipse/rst/group.hpp
opm/io/eclipse/rst/header.hpp
opm/io/eclipse/rst/netbalan.hpp
opm/io/eclipse/rst/network.hpp
opm/io/eclipse/rst/segment.hpp
opm/io/eclipse/rst/state.hpp

View File

@ -28,6 +28,10 @@ namespace Opm {
class UnitSystem;
} // namespace Opm
namespace Opm { namespace RestartIO {
class RstNetbalan;
}} // namespace Opm::RestartIO
namespace Opm { namespace Network {
class Balance
@ -43,6 +47,7 @@ public:
Balance();
explicit Balance(const DeckKeyword& keyword);
explicit Balance(bool network_active);
explicit Balance(const RestartIO::RstNetbalan& netbalan);
static Balance serializeObject();

View File

@ -0,0 +1,96 @@
/*
Copyright 2022 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RST_NETBALAN_HPP
#define RST_NETBALAN_HPP
#include <cstddef>
#include <memory>
#include <optional>
#include <vector>
namespace Opm {
class UnitSystem;
} // namespace Opm
namespace Opm { namespace RestartIO {
class RstNetbalan
{
public:
explicit RstNetbalan(const std::vector<int>& intehead,
const std::vector<double>& doubhead,
const UnitSystem& usys);
double interval() const
{
return this->calc_interval_;
}
double pressureTolerance() const
{
return this->ptol_;
}
std::size_t pressureMaxIter() const
{
return this->pressure_max_iter_;
}
double thpTolerance() const
{
return this->thp_tolerance_;
}
std::size_t thpMaxIter() const
{
return this->thp_max_iter_;
}
const std::optional<double>& targetBalanceError() const
{
return this->target_branch_balance_error_;
}
const std::optional<double>& maxBalanceError() const
{
return this->max_branch_balance_error_;
}
const std::optional<double>& minTstep() const
{
return this->min_tstep_;
}
private:
double calc_interval_;
double ptol_;
std::size_t pressure_max_iter_;
double thp_tolerance_;
std::size_t thp_max_iter_;
std::optional<double> target_branch_balance_error_{};
std::optional<double> max_branch_balance_error_{};
std::optional<double> min_tstep_{};
};
}} // namespace Opm::RestartIO
#endif // RST_NETBALAN_HPP

View File

@ -24,6 +24,7 @@
#include <opm/io/eclipse/rst/aquifer.hpp>
#include <opm/io/eclipse/rst/group.hpp>
#include <opm/io/eclipse/rst/header.hpp>
#include <opm/io/eclipse/rst/netbalan.hpp>
#include <opm/io/eclipse/rst/network.hpp>
#include <opm/io/eclipse/rst/udq.hpp>
#include <opm/io/eclipse/rst/well.hpp>
@ -65,6 +66,7 @@ struct RstState
::Opm::UnitSystem unit_system;
RstHeader header;
RstAquifer aquifers;
RstNetbalan netbalan;
RstNetwork network;
std::vector<RstWell> wells;
std::vector<RstGroup> groups;

View File

@ -19,6 +19,8 @@
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
#include <opm/io/eclipse/rst/netbalan.hpp>
#include <opm/input/eclipse/Units/UnitSystem.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/N.hpp>
@ -117,6 +119,18 @@ Balance::Balance(const bool network_active)
}
}
Balance::Balance(const RestartIO::RstNetbalan& netbalan)
: calc_mode (getNetworkBalancingMode(netbalan.interval()))
, calc_interval (netbalan.interval())
, ptol (netbalan.pressureTolerance())
, m_pressure_max_iter (netbalan.pressureMaxIter())
, m_thp_tolerance (netbalan.thpTolerance())
, m_thp_max_iter (netbalan.thpMaxIter())
, target_branch_balance_error(netbalan.targetBalanceError())
, max_branch_balance_error (netbalan.maxBalanceError())
, m_min_tstep (netbalan.minTstep())
{}
Balance::CalcMode Balance::mode() const {
return this->calc_mode;
}

View File

@ -42,6 +42,7 @@
#include <opm/input/eclipse/Schedule/MSW/SICD.hpp>
#include <opm/input/eclipse/Schedule/MSW/Valve.hpp>
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
#include <opm/input/eclipse/Schedule/Network/Node.hpp>
#include <opm/input/eclipse/Schedule/OilVaporizationProperties.hpp>
#include <opm/input/eclipse/Schedule/RPTConfig.hpp>
@ -1756,6 +1757,7 @@ namespace {
this->snapshots.back().wtest_config.update( WellTestConfig{rst_state, report_step});
this->snapshots.back().network_balance.update(Network::Balance { rst_state.netbalan });
if (!rst_state.wlists.empty())
this->snapshots.back().wlist_manager.update( WListManager(rst_state) );

View File

@ -0,0 +1,120 @@
/*
Copyright 2022 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/io/eclipse/rst/netbalan.hpp>
#include <opm/io/eclipse/RestartFileView.hpp>
#include <opm/output/eclipse/VectorItems/intehead.hpp>
#include <opm/output/eclipse/VectorItems/doubhead.hpp>
#include <opm/input/eclipse/Units/UnitSystem.hpp>
#include <cmath>
#include <cstddef>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
namespace {
std::size_t maxBalanceIter(const std::vector<int>& intehead)
{
return intehead[VI::intehead::NetbalMaxBalanceIter];
}
std::size_t maxTHPIter(const std::vector<int>& intehead)
{
return intehead[VI::intehead::NetbalMaxTHPIter];
}
double calcInterval(const std::vector<double>& doubhead,
const Opm::UnitSystem& usys)
{
return usys.to_si(Opm::UnitSystem::measure::time,
doubhead[VI::doubhead::Netbalint]);
}
double pressureToleranceValue(const std::vector<double>& doubhead,
const Opm::UnitSystem& usys)
{
return usys.to_si(Opm::UnitSystem::measure::pressure,
doubhead[VI::doubhead::Netbalnpre]);
}
double thpToleranceValue(const std::vector<double>& doubhead,
const Opm::UnitSystem& usys)
{
return usys.to_si(Opm::UnitSystem::measure::pressure,
doubhead[VI::doubhead::Netbalthpc]);
}
bool is_finite_float(const double x)
{
return std::abs(static_cast<float>(x)) < 1.0e+20f;
}
std::optional<double>
targetBranchBalanceError(const std::vector<double>& doubhead,
const Opm::UnitSystem& usys)
{
const auto trgBE = doubhead[VI::doubhead::Netbaltarerr];
return is_finite_float(trgBE)
? std::optional<double>{ usys.to_si(Opm::UnitSystem::measure::pressure, trgBE) }
: std::nullopt;
}
std::optional<double>
maxBranchBalanceError(const std::vector<double>& doubhead,
const Opm::UnitSystem& usys)
{
const auto maxBE = doubhead[VI::doubhead::Netbalmaxerr];
return is_finite_float(maxBE)
? std::optional<double>{ usys.to_si(Opm::UnitSystem::measure::pressure, maxBE) }
: std::nullopt;
}
std::optional<double>
minimumTimestepSize(const std::vector<double>& doubhead,
const Opm::UnitSystem& usys)
{
const auto minTStep = doubhead[VI::doubhead::Netbalstepsz];
return (minTStep != VI::DoubHeadValue::NetBalMinTSDefault)
? std::optional<double>{ usys.to_si(Opm::UnitSystem::measure::time, minTStep) }
: std::nullopt;
}
}
Opm::RestartIO::RstNetbalan::RstNetbalan(const std::vector<int>& intehead,
const std::vector<double>& doubhead,
const UnitSystem& usys)
: calc_interval_ (calcInterval(doubhead, usys))
, ptol_ (pressureToleranceValue(doubhead, usys))
, pressure_max_iter_ (maxBalanceIter(intehead))
, thp_tolerance_ (thpToleranceValue(doubhead, usys))
, thp_max_iter_ (maxTHPIter(intehead))
, target_branch_balance_error_(targetBranchBalanceError(doubhead, usys))
, max_branch_balance_error_ (maxBranchBalanceError(doubhead, usys))
, min_tstep_ (minimumTimestepSize(doubhead, usys))
{}

View File

@ -86,6 +86,7 @@ RstState::RstState(std::shared_ptr<EclIO::RestartFileView> rstView,
: unit_system(rstView->intehead()[VI::intehead::UNIT])
, header(runspec, unit_system, rstView->intehead(), rstView->logihead(), rstView->doubhead())
, aquifers(rstView, grid, unit_system)
, netbalan(rstView->intehead(), rstView->doubhead(), unit_system)
, network(rstView, unit_system)
{
this->load_tuning(rstView->intehead(), rstView->doubhead());

320
tests/test_rst_netbalan.cpp Normal file
View File

@ -0,0 +1,320 @@
/*
Copyright 2022 Equinor ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#define BOOST_TEST_MODULE test_rst_netbalan
#include <boost/test/unit_test.hpp>
#include <opm/io/eclipse/rst/netbalan.hpp>
#include <opm/output/eclipse/InteHEAD.hpp>
#include <opm/output/eclipse/DoubHEAD.hpp>
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
#include <opm/input/eclipse/Units/UnitSystem.hpp>
#include <opm/input/eclipse/Units/Units.hpp>
#include <cstddef>
#include <utility>
#include <vector>
using NBDims = Opm::RestartIO::InteHEAD::NetBalanceDims;
using NBParams = Opm::RestartIO::DoubHEAD::NetBalanceParams;
namespace {
Opm::RestartIO::RstNetbalan restart(const NBDims& dims, const NBParams& params)
{
const auto intehead = Opm::RestartIO::InteHEAD{}.netBalanceData(dims).data();
const auto doubhead = Opm::RestartIO::DoubHEAD{}.netBalParams(params).data();
return Opm::RestartIO::RstNetbalan {
intehead, doubhead, Opm::UnitSystem::newMETRIC()
};
}
NBDims defaultDims()
{
return { 0, 10 };
}
NBParams defaultParams()
{
return NBParams { Opm::UnitSystem::newMETRIC() };
}
NBParams norneParams()
{
// Using
//
// NETBALAN
// 0.0 0.2 6* /
//
// as defined in the NORNE_ATW2013.DATA simulation model (opm-tests).
auto params = NBParams { Opm::UnitSystem::newMETRIC() };
params.convTolNodPres = 0.2; // (barsa)
return params;
}
NBDims iotaDims()
{
// Using synthetic
//
// NETBALAN
// 1.0 2.0 3 4.0 5 6.0 7.0 8.0 /
return { 3, 5 };
}
NBParams iotaParams()
{
// Using synthetic
//
// NETBALAN
// 1.0 2.0 3 4.0 5 6.0 7.0 8.0 /
auto params = NBParams { Opm::UnitSystem::newMETRIC() };
params.balancingInterval = 1.0;
params.convTolNodPres = 2.0;
params.convTolTHPCalc = 4.0;
params.targBranchBalError = 6.0;
params.maxBranchBalError = 7.0;
params.minTimeStepSize = 8.0;
return params;
}
NBParams nupcolParams()
{
auto params = NBParams { Opm::UnitSystem::newMETRIC() };
params.balancingInterval = -1.0;
return params;
}
} // namespace
// ===========================================================================
BOOST_AUTO_TEST_SUITE(Restart)
BOOST_AUTO_TEST_CASE(No_Active_Network)
{
const auto netbalan = restart(defaultDims(), defaultParams());
BOOST_CHECK_CLOSE(netbalan.interval(), 0.0, 1.0e-7);
BOOST_CHECK_CLOSE(netbalan.pressureTolerance(), 0.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.pressureMaxIter(), std::size_t{0});
BOOST_CHECK_CLOSE(netbalan.thpTolerance(), 0.01*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.thpMaxIter(), std::size_t{10});
BOOST_CHECK_MESSAGE(! netbalan.targetBalanceError().has_value(),
"Inactive network must not have branch "
"target balance error at restart");
BOOST_CHECK_MESSAGE(! netbalan.maxBalanceError().has_value(),
"Inactive network must not have maximum "
"balance error tolerance at restart");
BOOST_CHECK_MESSAGE(! netbalan.minTstep().has_value(),
"Inactive network must not have a minimum "
"timestep value at restart");
}
BOOST_AUTO_TEST_CASE(Norne)
{
// Using
//
// NETBALAN
// 0.0 0.2 6* /
//
// as defined in the NORNE_ATW2013.DATA simulation model (opm-tests)
const auto netbalan = restart(defaultDims(), norneParams());
BOOST_CHECK_CLOSE(netbalan.interval(), 0.0, 1.0e-7);
BOOST_CHECK_CLOSE(netbalan.pressureTolerance(), 0.2*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.pressureMaxIter(), std::size_t{0});
BOOST_CHECK_CLOSE(netbalan.thpTolerance(), 0.01*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.thpMaxIter(), std::size_t{10});
BOOST_CHECK_MESSAGE(! netbalan.targetBalanceError().has_value(),
"Norne network must not have branch "
"target balance error at restart");
BOOST_CHECK_MESSAGE(! netbalan.maxBalanceError().has_value(),
"Norne network must not have maximum "
"balance error tolerance at restart");
BOOST_CHECK_MESSAGE(! netbalan.minTstep().has_value(),
"Norne network must not have a minimum "
"timestep value at restart");
}
BOOST_AUTO_TEST_CASE(Iota)
{
const auto netbalan = restart(iotaDims(), iotaParams());
BOOST_CHECK_CLOSE(netbalan.interval(), 1.0*Opm::unit::day, 1.0e-7);
BOOST_CHECK_CLOSE(netbalan.pressureTolerance(), 2.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.pressureMaxIter(), std::size_t{3});
BOOST_CHECK_CLOSE(netbalan.thpTolerance(), 4.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.thpMaxIter(), std::size_t{5});
BOOST_CHECK_MESSAGE(netbalan.targetBalanceError().has_value(),
"IOTA network must have branch "
"target balance error at restart");
BOOST_CHECK_CLOSE(netbalan.targetBalanceError().value(), 6.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_MESSAGE(netbalan.maxBalanceError().has_value(),
"IOTA network must have maximum "
"balance error tolerance at restart");
BOOST_CHECK_CLOSE(netbalan.maxBalanceError().value(), 7.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_MESSAGE(netbalan.minTstep().has_value(),
"IOTA network must have a minimum "
"timestep value at restart");
BOOST_CHECK_CLOSE(netbalan.minTstep().value(), 8.0*Opm::unit::day, 1.0e-7);
}
BOOST_AUTO_TEST_CASE(Nupcol)
{
const auto netbalan = restart(defaultDims(), nupcolParams());
BOOST_CHECK_CLOSE(netbalan.interval(), -1.0*Opm::unit::day, 1.0e-7);
}
BOOST_AUTO_TEST_SUITE_END() // Restart
// ---------------------------------------------------------------------------
BOOST_AUTO_TEST_SUITE(Balance_Object)
BOOST_AUTO_TEST_CASE(No_Active_Network)
{
const auto netbalan = Opm::Network::Balance {
restart(defaultDims(), defaultParams())
};
BOOST_CHECK_MESSAGE(netbalan.mode() == Opm::Network::Balance::CalcMode::TimeStepStart,
"Inactive network must have \"TimeStepStart\" "
"NETBALAN calculation mode");
BOOST_CHECK_CLOSE(netbalan.interval(), 0.0, 1.0e-7);
BOOST_CHECK_CLOSE(netbalan.pressure_tolerance(), 0.0, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.pressure_max_iter(), std::size_t{0});
BOOST_CHECK_CLOSE(netbalan.thp_tolerance(), 0.01*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.thp_max_iter(), std::size_t{10});
BOOST_CHECK_MESSAGE(! netbalan.target_balance_error().has_value(),
"Inactive network must not have branch "
"target balance error at restart");
BOOST_CHECK_MESSAGE(! netbalan.max_balance_error().has_value(),
"Inactive network must not have maximum "
"balance error tolerance at restart");
BOOST_CHECK_MESSAGE(! netbalan.min_tstep().has_value(),
"Inactive network must not have a minimum "
"timestep value at restart");
}
BOOST_AUTO_TEST_CASE(Norne)
{
const auto netbalan = Opm::Network::Balance {
restart(defaultDims(), norneParams())
};
BOOST_CHECK_MESSAGE(netbalan.mode() == Opm::Network::Balance::CalcMode::TimeStepStart,
"Norne network must have \"TimeStepStart\" "
"NETBALAN calculation mode");
BOOST_CHECK_CLOSE(netbalan.interval(), 0.0, 1.0e-7);
BOOST_CHECK_CLOSE(netbalan.pressure_tolerance(), 0.2*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.pressure_max_iter(), std::size_t{0});
BOOST_CHECK_CLOSE(netbalan.thp_tolerance(), 0.01*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.thp_max_iter(), std::size_t{10});
BOOST_CHECK_MESSAGE(! netbalan.target_balance_error().has_value(),
"Norne network must not have branch "
"target balance error at restart");
BOOST_CHECK_MESSAGE(! netbalan.max_balance_error().has_value(),
"Norne network must not have maximum "
"balance error tolerance at restart");
BOOST_CHECK_MESSAGE(! netbalan.min_tstep().has_value(),
"Norne network must not have a minimum "
"timestep value at restart");
}
BOOST_AUTO_TEST_CASE(Iota)
{
const auto netbalan = Opm::Network::Balance {
restart(iotaDims(), iotaParams())
};
BOOST_CHECK_MESSAGE(netbalan.mode() == Opm::Network::Balance::CalcMode::TimeInterval,
"IOTA network must have \"TimeInterval\" "
"NETBALAN calculation mode");
BOOST_CHECK_CLOSE(netbalan.interval(), 1.0*Opm::unit::day, 1.0e-7);
BOOST_CHECK_CLOSE(netbalan.pressure_tolerance(), 2.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.pressure_max_iter(), std::size_t{3});
BOOST_CHECK_CLOSE(netbalan.thp_tolerance(), 4.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_EQUAL(netbalan.thp_max_iter(), std::size_t{5});
BOOST_CHECK_MESSAGE(netbalan.target_balance_error().has_value(),
"IOTA network must have branch "
"target balance error at restart");
BOOST_CHECK_CLOSE(netbalan.target_balance_error().value(), 6.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_MESSAGE(netbalan.max_balance_error().has_value(),
"IOTA network must have maximum "
"balance error tolerance at restart");
BOOST_CHECK_CLOSE(netbalan.max_balance_error().value(), 7.0*Opm::unit::barsa, 1.0e-7);
BOOST_CHECK_MESSAGE(netbalan.min_tstep().has_value(),
"IOTA network must have a minimum "
"timestep value at restart");
BOOST_CHECK_CLOSE(netbalan.min_tstep().value(), 8.0*Opm::unit::day, 1.0e-7);
}
BOOST_AUTO_TEST_CASE(Nupcol)
{
const auto netbalan = Opm::Network::Balance {
restart(defaultDims(), nupcolParams())
};
BOOST_CHECK_MESSAGE(netbalan.mode() == Opm::Network::Balance::CalcMode::NUPCOL,
"NUPCOL network must have \"NUPCOL\" "
"NETBALAN calculation mode");
}
BOOST_AUTO_TEST_SUITE_END() // Balance_Object