diff --git a/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp b/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp index acb1707cf..929d8660d 100644 --- a/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp +++ b/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp @@ -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 + void serializeOp(Serializer& serializer) + { + serializer(timeStepControlType_); + switch (timeStepControlType_) { + case TimeStepControlType::HardCodedTimeStep: + allocAndSerialize(serializer); + break; + case TimeStepControlType::PIDAndIterationCount: + allocAndSerialize(serializer); + break; + case TimeStepControlType::SimpleIterationCount: + allocAndSerialize(serializer); + break; + case TimeStepControlType::PID: + allocAndSerialize(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 serializationTestObjectHardcoded() + { + return serializationTestObject_(); + } + + static AdaptiveTimeSteppingEbos serializationTestObjectPID() + { + return serializationTestObject_(); + } + + static AdaptiveTimeSteppingEbos serializationTestObjectPIDIt() + { + return serializationTestObject_(); + } + + static AdaptiveTimeSteppingEbos serializationTestObjectSimple() + { + return serializationTestObject_(); + } + + bool operator==(const AdaptiveTimeSteppingEbos& rhs) + { + if (timeStepControlType_ != rhs.timeStepControlType_ || + (timeStepControl_ && !rhs.timeStepControl_) || + (!timeStepControl_ && rhs.timeStepControl_)) { + return false; + } + + bool result = false; + switch (timeStepControlType_) { + case TimeStepControlType::HardCodedTimeStep: + result = castAndComp(rhs); + break; + case TimeStepControlType::PIDAndIterationCount: + result = castAndComp(rhs); + break; + case TimeStepControlType::SimpleIterationCount: + result = castAndComp(rhs); + break; + case TimeStepControlType::PID: + result = castAndComp(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 + static AdaptiveTimeSteppingEbos serializationTestObject_() + { + AdaptiveTimeSteppingEbos 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::serializationTestObject()); + + return result; + } + template + void allocAndSerialize(Serializer& serializer) + { + if (!serializer.isSerializing()) { + timeStepControl_ = std::make_unique(); + } + serializer(*static_cast(timeStepControl_.get())); + } + + template + bool castAndComp(const AdaptiveTimeSteppingEbos& Rhs) const + { + const T* lhs = static_cast(timeStepControl_.get()); + const T* rhs = static_cast(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(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(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(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(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(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(filename); + timeStepControlType_ = TimeStepControlType::HardCodedTimeStep; } else OPM_THROW(std::runtime_error, @@ -782,9 +923,10 @@ namespace Opm { return failing_wells; } - using TimeStepControlType = std::unique_ptr; + using TimeStepController = std::unique_ptr; - 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 diff --git a/opm/simulators/timestepping/TimeStepControl.cpp b/opm/simulators/timestepping/TimeStepControl.cpp index 09a494b4d..5c70f287b 100644 --- a/opm/simulators/timestepping/TimeStepControl.cpp +++ b/opm/simulators/timestepping/TimeStepControl.cpp @@ -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(*this) == ctrl && + this->target_iterations_ == ctrl.target_iterations_ && + this->decayDampingFactor_ == ctrl.decayDampingFactor_ && + this->growthDampingFactor_ == ctrl.growthDampingFactor_ && + this->minTimeStepBasedOnIterations_ == ctrl.minTimeStepBasedOnIterations_; + } + } // end namespace Opm diff --git a/opm/simulators/timestepping/TimeStepControl.hpp b/opm/simulators/timestepping/TimeStepControl.hpp index 027a9661f..78e9e82b5 100644 --- a/opm/simulators/timestepping/TimeStepControl.hpp +++ b/opm/simulators/timestepping/TimeStepControl.hpp @@ -21,12 +21,20 @@ #ifndef OPM_TIMESTEPCONTROL_HEADER_INCLUDED #define OPM_TIMESTEPCONTROL_HEADER_INCLUDED -#include - #include +#include +#include + 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 + 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 + 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 + void serializeOp(Serializer& serializer) + { + serializer(static_cast(*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 + 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 subStepTime_; diff --git a/tests/test_RestartSerialization.cpp b/tests/test_RestartSerialization.cpp index ecc895293..f075d0fc0 100644 --- a/tests/test_RestartSerialization.cpp +++ b/tests/test_RestartSerialization.cpp @@ -19,9 +19,13 @@ #include +#include + #include +#include #include +#include #include #define BOOST_TEST_MODULE TestRestartSerialization @@ -41,7 +45,7 @@ std::tuple 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; } +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;