Merge pull request #4417 from akva2/adaptivetimesteppingebos_serialize

AdaptiveTimeSteppingEbos: add serialization support
This commit is contained in:
Bård Skaflestad 2023-02-14 11:22:18 +01:00 committed by GitHub
commit afba3f948c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 303 additions and 22 deletions

View File

@ -286,6 +286,8 @@ namespace Opm {
}
public:
AdaptiveTimeSteppingEbos() = default;
//! \brief contructor taking parameter object
AdaptiveTimeSteppingEbos(const UnitSystem& unitSystem,
const bool terminalOutput = true)
@ -676,6 +678,140 @@ namespace Opm {
timestepAfterEvent_ = tuning.TMAXWC;
}
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(timeStepControlType_);
switch (timeStepControlType_) {
case TimeStepControlType::HardCodedTimeStep:
allocAndSerialize<HardcodedTimeStepControl>(serializer);
break;
case TimeStepControlType::PIDAndIterationCount:
allocAndSerialize<PIDAndIterationCountTimeStepControl>(serializer);
break;
case TimeStepControlType::SimpleIterationCount:
allocAndSerialize<SimpleIterationCountTimeStepControl>(serializer);
break;
case TimeStepControlType::PID:
allocAndSerialize<PIDTimeStepControl>(serializer);
break;
}
serializer(restartFactor_);
serializer(growthFactor_);
serializer(maxGrowth_);
serializer(maxTimeStep_);
serializer(minTimeStep_);
serializer(ignoreConvergenceFailure_);
serializer(solverRestartMax_);
serializer(solverVerbose_);
serializer(timestepVerbose_);
serializer(suggestedNextTimestep_);
serializer(fullTimestepInitially_);
serializer(timestepAfterEvent_);
serializer(useNewtonIteration_);
serializer(minTimeStepBeforeShuttingProblematicWells_);
}
static AdaptiveTimeSteppingEbos<TypeTag> serializationTestObjectHardcoded()
{
return serializationTestObject_<HardcodedTimeStepControl>();
}
static AdaptiveTimeSteppingEbos<TypeTag> serializationTestObjectPID()
{
return serializationTestObject_<PIDTimeStepControl>();
}
static AdaptiveTimeSteppingEbos<TypeTag> serializationTestObjectPIDIt()
{
return serializationTestObject_<PIDAndIterationCountTimeStepControl>();
}
static AdaptiveTimeSteppingEbos<TypeTag> serializationTestObjectSimple()
{
return serializationTestObject_<SimpleIterationCountTimeStepControl>();
}
bool operator==(const AdaptiveTimeSteppingEbos<TypeTag>& rhs)
{
if (timeStepControlType_ != rhs.timeStepControlType_ ||
(timeStepControl_ && !rhs.timeStepControl_) ||
(!timeStepControl_ && rhs.timeStepControl_)) {
return false;
}
bool result = false;
switch (timeStepControlType_) {
case TimeStepControlType::HardCodedTimeStep:
result = castAndComp<HardcodedTimeStepControl>(rhs);
break;
case TimeStepControlType::PIDAndIterationCount:
result = castAndComp<PIDAndIterationCountTimeStepControl>(rhs);
break;
case TimeStepControlType::SimpleIterationCount:
result = castAndComp<SimpleIterationCountTimeStepControl>(rhs);
break;
case TimeStepControlType::PID:
result = castAndComp<PIDTimeStepControl>(rhs);
break;
}
return result &&
this->restartFactor_ == rhs.restartFactor_ &&
this->growthFactor_ == rhs.growthFactor_ &&
this->maxGrowth_ == rhs.maxGrowth_ &&
this->maxTimeStep_ == rhs.maxTimeStep_ &&
this->minTimeStep_ == rhs.minTimeStep_ &&
this->ignoreConvergenceFailure_ == rhs.ignoreConvergenceFailure_ &&
this->solverRestartMax_== rhs.solverRestartMax_ &&
this->solverVerbose_ == rhs.solverVerbose_ &&
this->fullTimestepInitially_ == rhs.fullTimestepInitially_ &&
this->timestepAfterEvent_ == rhs.timestepAfterEvent_ &&
this->useNewtonIteration_ == rhs.useNewtonIteration_ &&
this->minTimeStepBeforeShuttingProblematicWells_ ==
rhs.minTimeStepBeforeShuttingProblematicWells_;
}
private:
template<class Controller>
static AdaptiveTimeSteppingEbos<TypeTag> serializationTestObject_()
{
AdaptiveTimeSteppingEbos<TypeTag> result;
result.restartFactor_ = 1.0;
result.growthFactor_ = 2.0;
result.maxGrowth_ = 3.0;
result.maxTimeStep_ = 4.0;
result.minTimeStep_ = 5.0;
result.ignoreConvergenceFailure_ = true;
result.solverRestartMax_ = 6;
result.solverVerbose_ = true;
result.timestepVerbose_ = true;
result.suggestedNextTimestep_ = 7.0;
result.fullTimestepInitially_ = 8.0;
result.useNewtonIteration_ = true;
result.minTimeStepBeforeShuttingProblematicWells_ = 9.0;
result.timeStepControlType_ = Controller::Type;
result.timeStepControl_ = std::make_unique<Controller>(Controller::serializationTestObject());
return result;
}
template<class T, class Serializer>
void allocAndSerialize(Serializer& serializer)
{
if (!serializer.isSerializing()) {
timeStepControl_ = std::make_unique<T>();
}
serializer(*static_cast<T*>(timeStepControl_.get()));
}
template<class T>
bool castAndComp(const AdaptiveTimeSteppingEbos<TypeTag>& Rhs) const
{
const T* lhs = static_cast<const T*>(timeStepControl_.get());
const T* rhs = static_cast<const T*>(Rhs.timeStepControl_.get());
return *lhs == *rhs;
}
protected:
void init_(const UnitSystem& unitSystem)
@ -685,13 +821,15 @@ namespace Opm {
const double tol = EWOMS_GET_PARAM(TypeTag, double, TimeStepControlTolerance); // 1e-1
if (control == "pid") {
timeStepControl_ = TimeStepControlType(new PIDTimeStepControl(tol));
timeStepControl_ = std::make_unique<PIDTimeStepControl>(tol);
timeStepControlType_ = TimeStepControlType::PID;
}
else if (control == "pid+iteration") {
const int iterations = EWOMS_GET_PARAM(TypeTag, int, TimeStepControlTargetIterations); // 30
const double decayDampingFactor = EWOMS_GET_PARAM(TypeTag, double, TimeStepControlDecayDampingFactor); // 1.0
const double growthDampingFactor = EWOMS_GET_PARAM(TypeTag, double, TimeStepControlGrowthDampingFactor); // 3.2
timeStepControl_ = TimeStepControlType(new PIDAndIterationCountTimeStepControl(iterations, decayDampingFactor, growthDampingFactor, tol));
timeStepControl_ = std::make_unique<PIDAndIterationCountTimeStepControl>(iterations, decayDampingFactor, growthDampingFactor, tol);
timeStepControlType_ = TimeStepControlType::PIDAndIterationCount;
}
else if (control == "pid+newtoniteration") {
const int iterations = EWOMS_GET_PARAM(TypeTag, int, TimeStepControlTargetNewtonIterations); // 8
@ -700,27 +838,30 @@ namespace Opm {
const double nonDimensionalMinTimeStepIterations = EWOMS_GET_PARAM(TypeTag, double, MinTimeStepBasedOnNewtonIterations); // 0.0 by default
// the min time step can be reduced by the newton iteration numbers
double minTimeStepReducedByIterations = unitSystem.to_si(UnitSystem::measure::time, nonDimensionalMinTimeStepIterations);
timeStepControl_ = TimeStepControlType(new PIDAndIterationCountTimeStepControl(iterations, decayDampingFactor,
growthDampingFactor, tol, minTimeStepReducedByIterations));
timeStepControl_ = std::make_unique<PIDAndIterationCountTimeStepControl>(iterations, decayDampingFactor,
growthDampingFactor, tol, minTimeStepReducedByIterations);
timeStepControlType_ = TimeStepControlType::PIDAndIterationCount;
useNewtonIteration_ = true;
}
else if (control == "iterationcount") {
const int iterations = EWOMS_GET_PARAM(TypeTag, int, TimeStepControlTargetIterations); // 30
const double decayrate = EWOMS_GET_PARAM(TypeTag, double, TimeStepControlDecayRate); // 0.75
const double growthrate = EWOMS_GET_PARAM(TypeTag, double, TimeStepControlGrowthRate); // 1.25
timeStepControl_ = TimeStepControlType(new SimpleIterationCountTimeStepControl(iterations, decayrate, growthrate));
timeStepControl_ = std::make_unique<SimpleIterationCountTimeStepControl>(iterations, decayrate, growthrate);
timeStepControlType_ = TimeStepControlType::SimpleIterationCount;
}
else if (control == "newtoniterationcount") {
const int iterations = EWOMS_GET_PARAM(TypeTag, int, TimeStepControlTargetNewtonIterations); // 8
const double decayrate = EWOMS_GET_PARAM(TypeTag, double, TimeStepControlDecayRate); // 0.75
const double growthrate = EWOMS_GET_PARAM(TypeTag, double, TimeStepControlGrowthRate); // 1.25
timeStepControl_ = TimeStepControlType(new SimpleIterationCountTimeStepControl(iterations, decayrate, growthrate));
timeStepControl_ = std::make_unique<SimpleIterationCountTimeStepControl>(iterations, decayrate, growthrate);
useNewtonIteration_ = true;
timeStepControlType_ = TimeStepControlType::SimpleIterationCount;
}
else if (control == "hardcoded") {
const std::string filename = EWOMS_GET_PARAM(TypeTag, std::string, TimeStepControlFileName); // "timesteps"
timeStepControl_ = TimeStepControlType(new HardcodedTimeStepControl(filename));
timeStepControl_ = std::make_unique<HardcodedTimeStepControl>(filename);
timeStepControlType_ = TimeStepControlType::HardCodedTimeStep;
}
else
OPM_THROW(std::runtime_error,
@ -782,9 +923,10 @@ namespace Opm {
return failing_wells;
}
using TimeStepControlType = std::unique_ptr<TimeStepControlInterface>;
using TimeStepController = std::unique_ptr<TimeStepControlInterface>;
TimeStepControlType timeStepControl_; //!< time step control object
TimeStepControlType timeStepControlType_; //!< type of time step control object
TimeStepController timeStepControl_; //!< time step control object
double restartFactor_; //!< factor to multiply time step with when solver fails to converge
double growthFactor_; //!< factor to multiply time step when solver recovered from failed convergence
double maxGrowth_; //!< factor that limits the maximum growth of a time step

View File

@ -66,6 +66,12 @@ namespace Opm
}
}
SimpleIterationCountTimeStepControl
SimpleIterationCountTimeStepControl::serializationTestObject()
{
return {1, 1.0, 2.0, true};
}
double SimpleIterationCountTimeStepControl::
computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& /* relativeChange */, const double /*simulationTimeElapsed */) const
{
@ -86,6 +92,15 @@ namespace Opm
return dtEstimate;
}
bool SimpleIterationCountTimeStepControl::
operator==(const SimpleIterationCountTimeStepControl& ctrl) const
{
return this->target_iterations_ == ctrl.target_iterations_ &&
this->decayrate_ == ctrl.decayrate_ &&
this->growthrate_ == ctrl.growthrate_ &&
this->verbose_ == ctrl.verbose_;
}
////////////////////////////////////////////////////////
//
// HardcodedTimeStepControl Implementation
@ -93,7 +108,7 @@ namespace Opm
////////////////////////////////////////////////////////
HardcodedTimeStepControl::
HardcodedTimeStepControl( const std::string& filename)
HardcodedTimeStepControl(const std::string& filename)
{
std::ifstream infile (filename);
if (!infile.is_open()) {
@ -110,6 +125,14 @@ namespace Opm
}
}
HardcodedTimeStepControl HardcodedTimeStepControl::serializationTestObject()
{
HardcodedTimeStepControl result;
result.subStepTime_ = {1.0, 2.0};
return result;
}
double HardcodedTimeStepControl::
computeTimeStepSize( const double /*dt */, const int /*iterations */, const RelativeChangeInterface& /* relativeChange */ , const double simulationTimeElapsed) const
{
@ -117,6 +140,11 @@ namespace Opm
return (*nextTime - simulationTimeElapsed);
}
bool HardcodedTimeStepControl::operator==(const HardcodedTimeStepControl& ctrl) const
{
return this->subStepTime_ == ctrl.subStepTime_;
}
////////////////////////////////////////////////////////
@ -132,6 +160,15 @@ namespace Opm
, verbose_( verbose )
{}
PIDTimeStepControl
PIDTimeStepControl::serializationTestObject()
{
PIDTimeStepControl result(1.0, true);
result.errors_ = {2.0, 3.0};
return result;;
}
double PIDTimeStepControl::
computeTimeStepSize( const double dt, const int /* iterations */, const RelativeChangeInterface& relChange, const double /*simulationTimeElapsed */) const
{
@ -176,6 +213,13 @@ namespace Opm
}
}
bool PIDTimeStepControl::operator==(const PIDTimeStepControl& ctrl) const
{
return this->tol_ == ctrl.tol_ &&
this->errors_ == ctrl.errors_ &&
this->verbose_ == ctrl.verbose_;
}
////////////////////////////////////////////////////////////
@ -198,6 +242,12 @@ namespace Opm
, minTimeStepBasedOnIterations_(minTimeStepBasedOnIterations)
{}
PIDAndIterationCountTimeStepControl
PIDAndIterationCountTimeStepControl::serializationTestObject()
{
return {1, 2.0, 3.0, 4.0, 5.0, true};
}
double PIDAndIterationCountTimeStepControl::
computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& relChange, const double simulationTimeElapsed ) const
{
@ -220,4 +270,13 @@ namespace Opm
return std::min(dtEstimatePID, dtEstimateIter);
}
bool PIDAndIterationCountTimeStepControl::operator==(const PIDAndIterationCountTimeStepControl& ctrl) const
{
return static_cast<const PIDTimeStepControl&>(*this) == ctrl &&
this->target_iterations_ == ctrl.target_iterations_ &&
this->decayDampingFactor_ == ctrl.decayDampingFactor_ &&
this->growthDampingFactor_ == ctrl.growthDampingFactor_ &&
this->minTimeStepBasedOnIterations_ == ctrl.minTimeStepBasedOnIterations_;
}
} // end namespace Opm

View File

@ -21,12 +21,20 @@
#ifndef OPM_TIMESTEPCONTROL_HEADER_INCLUDED
#define OPM_TIMESTEPCONTROL_HEADER_INCLUDED
#include <vector>
#include <opm/simulators/timestepping/TimeStepControlInterface.hpp>
#include <string>
#include <vector>
namespace Opm
{
enum class TimeStepControlType {
SimpleIterationCount,
PID,
PIDAndIterationCount,
HardCodedTimeStep
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// A simple iteration count based adaptive time step control.
@ -35,6 +43,9 @@ namespace Opm
class SimpleIterationCountTimeStepControl : public TimeStepControlInterface
{
public:
static constexpr TimeStepControlType Type = TimeStepControlType::SimpleIterationCount;
SimpleIterationCountTimeStepControl() = default;
/// \brief constructor
/// \param target_iterations number of desired iterations (e.g. Newton iterations) per time step in one time step
// \param decayrate decayrate of time step when target iterations are not met (should be <= 1)
@ -45,14 +56,27 @@ namespace Opm
const double growthrate,
const bool verbose = false);
static SimpleIterationCountTimeStepControl serializationTestObject();
/// \brief \copydoc TimeStepControlInterface::computeTimeStepSize
double computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& /* relativeChange */, const double /*simulationTimeElapsed */ ) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(target_iterations_);
serializer(decayrate_);
serializer(growthrate_);
serializer(verbose_);
}
bool operator==(const SimpleIterationCountTimeStepControl&) const;
protected:
const int target_iterations_;
const double decayrate_;
const double growthrate_;
const bool verbose_;
const int target_iterations_ = 0;
const double decayrate_ = 0.0;
const double growthrate_ = 0.0;
const bool verbose_ = false;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -72,6 +96,7 @@ namespace Opm
class PIDTimeStepControl : public TimeStepControlInterface
{
public:
static constexpr TimeStepControlType Type = TimeStepControlType::PID;
/// \brief constructor
/// \param tol tolerance for the relative changes of the numerical solution to be accepted
/// in one time step (default is 1e-3)
@ -79,14 +104,26 @@ namespace Opm
PIDTimeStepControl( const double tol = 1e-3,
const bool verbose = false );
static PIDTimeStepControl serializationTestObject();
/// \brief \copydoc TimeStepControlInterface::computeTimeStepSize
double computeTimeStepSize( const double dt, const int /* iterations */, const RelativeChangeInterface& relativeChange, const double /*simulationTimeElapsed */ ) const;
protected:
const double tol_;
mutable std::vector< double > errors_;
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(tol_);
serializer(errors_);
serializer(verbose_);
}
const bool verbose_;
bool operator==(const PIDTimeStepControl&) const;
protected:
const double tol_ = 1e-3;
mutable std::vector< double > errors_{};
const bool verbose_ = false;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -99,6 +136,8 @@ namespace Opm
{
typedef PIDTimeStepControl BaseType;
public:
static constexpr TimeStepControlType Type = TimeStepControlType::PIDAndIterationCount;
/// \brief constructor
/// \param target_iterations number of desired iterations per time step
/// \param tol tolerance for the relative changes of the numerical solution to be accepted
@ -111,9 +150,23 @@ namespace Opm
const double minTimeStepBasedOnIterations = 0.,
const bool verbose = false);
static PIDAndIterationCountTimeStepControl serializationTestObject();
/// \brief \copydoc TimeStepControlInterface::computeTimeStepSize
double computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& relativeChange, const double /*simulationTimeElapsed */ ) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(static_cast<PIDTimeStepControl&>(*this));
serializer(target_iterations_);
serializer(decayDampingFactor_);
serializer(growthDampingFactor_);
serializer(minTimeStepBasedOnIterations_);
}
bool operator==(const PIDAndIterationCountTimeStepControl&) const;
protected:
const int target_iterations_;
const double decayDampingFactor_;
@ -133,13 +186,26 @@ namespace Opm
class HardcodedTimeStepControl : public TimeStepControlInterface
{
public:
static constexpr TimeStepControlType Type = TimeStepControlType::HardCodedTimeStep;
HardcodedTimeStepControl() = default;
/// \brief constructor
/// \param filename filename contaning the timesteps
explicit HardcodedTimeStepControl( const std::string& filename);
static HardcodedTimeStepControl serializationTestObject();
/// \brief \copydoc TimeStepControlInterface::computeTimeStepSize
double computeTimeStepSize( const double dt, const int /* iterations */, const RelativeChangeInterface& /*relativeChange */, const double simulationTimeElapsed) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(subStepTime_);
}
bool operator==(const HardcodedTimeStepControl&) const;
protected:
// store the time (in days) of the substeps the simulator should use
std::vector<double> subStepTime_;

View File

@ -19,9 +19,13 @@
#include <config.h>
#include <ebos/ebos.hh>
#include <opm/common/utility/Serializer.hpp>
#include <opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp>
#include <opm/simulators/timestepping/SimulatorTimer.hpp>
#include <opm/simulators/timestepping/TimeStepControl.hpp>
#include <opm/simulators/utils/SerializationPackers.hpp>
#define BOOST_TEST_MODULE TestRestartSerialization
@ -41,7 +45,7 @@ std::tuple<T,int,int> PackUnpack(T& in)
ser.unpack(out);
size_t pos2 = ser.position();
return std::make_tuple(out, pos1, pos2);
return std::make_tuple(std::move(out), pos1, pos2);
}
#define TEST_FOR_TYPE_NAMED_OBJ(TYPE, NAME, OBJ) \
@ -59,8 +63,18 @@ BOOST_AUTO_TEST_CASE(NAME) \
#define TEST_FOR_TYPE(TYPE) \
TEST_FOR_TYPE_NAMED(TYPE, TYPE)
TEST_FOR_TYPE(HardcodedTimeStepControl)
TEST_FOR_TYPE(PIDAndIterationCountTimeStepControl)
TEST_FOR_TYPE(PIDTimeStepControl)
TEST_FOR_TYPE(SimpleIterationCountTimeStepControl)
TEST_FOR_TYPE(SimulatorTimer)
namespace Opm { using ATE = AdaptiveTimeSteppingEbos<Opm::Properties::TTag::EbosTypeTag>; }
TEST_FOR_TYPE_NAMED_OBJ(ATE, AdaptiveTimeSteppingEbosHardcoded, serializationTestObjectHardcoded)
TEST_FOR_TYPE_NAMED_OBJ(ATE, AdaptiveTimeSteppingEbosPID, serializationTestObjectPID)
TEST_FOR_TYPE_NAMED_OBJ(ATE, AdaptiveTimeSteppingEbosPIDIt, serializationTestObjectPIDIt)
TEST_FOR_TYPE_NAMED_OBJ(ATE, AdaptiveTimeSteppingEbosSimple, serializationTestObjectSimple)
bool init_unit_test_func()
{
return true;