mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #1049 from akva2/import_adaptive_time_stepping
Import adaptive time stepping and associated classes
This commit is contained in:
commit
12adcdf218
@ -67,6 +67,9 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
opm/simulators/SimulatorIncompTwophase.cpp
|
||||
opm/simulators/WellSwitchingLogger.cpp
|
||||
opm/simulators/vtk/writeVtkData.cpp
|
||||
opm/simulators/timestepping/TimeStepControl.cpp
|
||||
opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp
|
||||
opm/simulators/timestepping/SimulatorTimer.cpp
|
||||
)
|
||||
|
||||
|
||||
@ -89,6 +92,7 @@ list (APPEND TEST_SOURCE_FILES
|
||||
tests/test_multisegmentwells.cpp
|
||||
# tests/test_thresholdpressure.cpp
|
||||
tests/test_wellswitchlogger.cpp
|
||||
tests/test_timer.cpp
|
||||
)
|
||||
|
||||
list (APPEND TEST_DATA_FILES
|
||||
@ -96,6 +100,7 @@ list (APPEND TEST_DATA_FILES
|
||||
tests/VFPPROD1
|
||||
tests/VFPPROD2
|
||||
tests/msw.data
|
||||
tests/TESTTIMER.DATA
|
||||
)
|
||||
|
||||
|
||||
@ -117,6 +122,7 @@ list (APPEND EXAMPLE_SOURCE_FILES
|
||||
examples/sim_poly2p_incomp_reorder.cpp
|
||||
examples/sim_poly_fi2p_comp_ad.cpp
|
||||
examples/flow_polymer.cpp
|
||||
examples/wells_example.cpp
|
||||
)
|
||||
|
||||
# programs listed here will not only be compiled, but also marked for
|
||||
@ -259,5 +265,12 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/simulators/thresholdPressures.hpp
|
||||
opm/simulators/WellSwitchingLogger.hpp
|
||||
opm/simulators/vtk/writeVtkData.hpp
|
||||
opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp
|
||||
opm/simulators/timestepping/AdaptiveTimeStepping.hpp
|
||||
opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp
|
||||
opm/simulators/timestepping/TimeStepControl.hpp
|
||||
opm/simulators/timestepping/TimeStepControlInterface.hpp
|
||||
opm/simulators/timestepping/SimulatorTimer.hpp
|
||||
opm/simulators/timestepping/SimulatorTimerInterface.hpp
|
||||
)
|
||||
|
||||
|
144
examples/wells_example.cpp
Normal file
144
examples/wells_example.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
|
||||
#include <opm/core/simulator/initState.hpp>
|
||||
#include <opm/simulators/timestepping/SimulatorTimer.hpp>
|
||||
#include <opm/core/wells/WellsManager.hpp>
|
||||
#include <opm/core/grid/GridManager.hpp>
|
||||
#include <opm/core/pressure/IncompTpfa.hpp>
|
||||
#include <opm/core/props/IncompPropertiesFromDeck.hpp>
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
#include <opm/core/simulator/TwophaseState.hpp>
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
#include <opm/core/pressure/FlowBCManager.hpp>
|
||||
#include <opm/core/linalg/LinearSolverFactory.hpp>
|
||||
#include <opm/core/props/rock/RockCompressibility.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
try
|
||||
{
|
||||
using namespace Opm::parameter;
|
||||
using namespace Opm;
|
||||
ParameterGroup parameters(argc, argv, false);
|
||||
std::string file_name = parameters.getDefault<std::string > ("inputdeck", "data.data");
|
||||
|
||||
SimulatorTimer simtimer;
|
||||
simtimer.init(parameters);
|
||||
|
||||
// Read input file
|
||||
ParseContext parseContext;
|
||||
Opm::Parser parser;
|
||||
Opm::Deck deck = parser.parseFile(file_name , parseContext);
|
||||
Opm::EclipseState eclipseState(deck , parseContext);
|
||||
std::cout << "Done!" << std::endl;
|
||||
|
||||
// Setup grid
|
||||
GridManager grid(eclipseState.getInputGrid());
|
||||
|
||||
// Define rock and fluid properties
|
||||
IncompPropertiesFromDeck incomp_properties(deck, eclipseState, *grid.c_grid());
|
||||
RockCompressibility rock_comp(eclipseState);
|
||||
|
||||
// Finally handle the wells
|
||||
WellsManager wells(eclipseState , 0 , *grid.c_grid());
|
||||
|
||||
double gravity[3] = {0.0, 0.0, parameters.getDefault<double>("gravity", 0.0)};
|
||||
Opm::LinearSolverFactory linsolver(parameters);
|
||||
double nl_pressure_residual_tolerance = 1e-8;
|
||||
double nl_pressure_change_tolerance = 0.0;
|
||||
int nl_pressure_maxiter = 100;
|
||||
if (rock_comp.isActive()) {
|
||||
nl_pressure_residual_tolerance = parameters.getDefault("nl_pressure_residual_tolerance", 1e-8);
|
||||
nl_pressure_change_tolerance = parameters.getDefault("nl_pressure_change_tolerance", 1.0); // in Pascal
|
||||
nl_pressure_maxiter = parameters.getDefault("nl_pressure_maxiter", 10);
|
||||
}
|
||||
|
||||
std::vector<double> src;
|
||||
Opm::FlowBCManager bcs;
|
||||
|
||||
// EXPERIMENT_ISTL
|
||||
IncompTpfa pressure_solver(*grid.c_grid(), incomp_properties, &rock_comp, linsolver,
|
||||
nl_pressure_residual_tolerance, nl_pressure_change_tolerance, nl_pressure_maxiter,
|
||||
gravity, wells.c_wells(), src, bcs.c_bcs());
|
||||
|
||||
|
||||
std::vector<int> all_cells;
|
||||
for (int i = 0; i < grid.c_grid()->number_of_cells; i++) {
|
||||
all_cells.push_back(i);
|
||||
}
|
||||
|
||||
Opm::TwophaseState state( grid.c_grid()->number_of_cells , grid.c_grid()->number_of_faces );
|
||||
|
||||
initStateFromDeck(*grid.c_grid(), incomp_properties, deck, gravity[2], state);
|
||||
|
||||
Opm::WellState well_state;
|
||||
well_state.init(wells.c_wells(), state);
|
||||
|
||||
pressure_solver.solve(simtimer.currentStepLength(), state, well_state);
|
||||
|
||||
const int np = incomp_properties.numPhases();
|
||||
std::vector<double> fractional_flows(grid.c_grid()->number_of_cells*np, 0.0);
|
||||
computeFractionalFlow(incomp_properties, all_cells, state.saturation(), fractional_flows);
|
||||
|
||||
// This will be refactored into a separate function once done
|
||||
std::vector<double> well_resflows(wells.c_wells()->number_of_wells*np, 0.0);
|
||||
computePhaseFlowRatesPerWell(*wells.c_wells(), well_state.perfRates(), fractional_flows, well_resflows);
|
||||
// We approximate (for _testing_ that resflows = surfaceflows)
|
||||
for (int wc_iter = 0; wc_iter < 10 && !wells.conditionsMet(well_state.bhp(), well_resflows, well_resflows); ++wc_iter) {
|
||||
std::cout << "Conditions not met for well, trying again" << std::endl;
|
||||
pressure_solver.solve(simtimer.currentStepLength(), state, well_state);
|
||||
std::cout << "Solved" << std::endl;
|
||||
|
||||
computePhaseFlowRatesPerWell(*wells.c_wells(), well_state.perfRates(), fractional_flows, well_resflows);
|
||||
}
|
||||
|
||||
#if 0
|
||||
std::vector<double> porevol;
|
||||
computePorevolume(*grid->c_grid(), incomp_properties, porevol);
|
||||
|
||||
|
||||
|
||||
TwophaseFluid fluid(incomp_properties);
|
||||
TransportContextl model(fluid, *grid->c_grid(), porevol, gravity[2], true);
|
||||
|
||||
TransportSolver tsolver(model);
|
||||
|
||||
TransportSource* tsrc = create_transport_source(2, 2);
|
||||
double ssrc[] = {1.0, 0.0};
|
||||
double ssink[] = {0.0, 1.0};
|
||||
double zdummy[] = {0.0, 0.0};
|
||||
|
||||
{
|
||||
int well_cell_index = 0;
|
||||
for (int well = 0; well < wells.c_wells()->number_of_wells; ++well) {
|
||||
for (int cell = wells.c_wells()->well_connpos[well]; cell < wells.c_wells()->well_connpos[well + 1]; ++cell) {
|
||||
if (well_rate_per_cell[well_cell_index] > 0.0) {
|
||||
append_transport_source(well_cell_index, 2, 0,
|
||||
well_rate_per_cell[well_cell_index], ssrc, zdummy, tsrc);
|
||||
} else if (well_rate_per_cell[well_cell_index] < 0.0) {
|
||||
append_transport_source(well_cell_index, 2, 0,
|
||||
well_rate_per_cell[well_cell_index], ssink, zdummy, tsrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tsolver.solve(*grid->c_grid(), tsrc, stepsize, ctrl, state, linsolve, rpt);
|
||||
|
||||
Opm::computeInjectedProduced(*props, state.saturation(), src, stepsize, injected, produced);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
std::cerr << "Program threw an exception: " << e.what() << "\n";
|
||||
throw;
|
||||
}
|
@ -48,7 +48,7 @@
|
||||
#include <opm/core/simulator/initState.hpp>
|
||||
#include <opm/core/simulator/initStateEquil.hpp>
|
||||
#include <opm/core/simulator/SimulatorReport.hpp>
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/simulators/timestepping/SimulatorTimer.hpp>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/simulators/thresholdPressures.hpp> // Note: the GridHelpers must be included before this (to make overloads available). \TODO: Fix.
|
||||
|
@ -40,8 +40,8 @@
|
||||
#include <opm/core/pressure/flow_bc.h>
|
||||
|
||||
#include <opm/core/simulator/SimulatorReport.hpp>
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/core/simulator/AdaptiveSimulatorTimer.hpp>
|
||||
#include <opm/simulators/timestepping/SimulatorTimer.hpp>
|
||||
#include <opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp>
|
||||
#include <opm/core/utility/StopWatch.hpp>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
#include <opm/core/utility/miscUtilitiesBlackoil.hpp>
|
||||
@ -49,7 +49,7 @@
|
||||
#include <opm/core/props/rock/RockCompressibility.hpp>
|
||||
|
||||
#include <opm/core/simulator/BlackoilState.hpp>
|
||||
#include <opm/core/simulator/AdaptiveTimeStepping.hpp>
|
||||
#include <opm/simulators/timestepping/AdaptiveTimeStepping.hpp>
|
||||
#include <opm/core/transport/reorder/TransportSolverCompressibleTwophaseReorder.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <opm/autodiff/RateConverter.hpp>
|
||||
#include <opm/autodiff/SimFIBODetails.hpp>
|
||||
|
||||
#include <opm/core/simulator/AdaptiveTimeStepping.hpp>
|
||||
#include <opm/simulators/timestepping/AdaptiveTimeStepping.hpp>
|
||||
#include <opm/core/utility/initHydroCarbonState.hpp>
|
||||
#include <opm/core/utility/StopWatch.hpp>
|
||||
|
||||
|
@ -42,14 +42,14 @@
|
||||
|
||||
#include <opm/core/simulator/SimulatorReport.hpp>
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
//#include <opm/core/simulator/AdaptiveSimulatorTimer.hpp>
|
||||
//#include <opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp>
|
||||
#include <opm/core/utility/StopWatch.hpp>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
#include <opm/core/utility/miscUtilitiesBlackoil.hpp>
|
||||
|
||||
#include <opm/core/props/rock/RockCompressibility.hpp>
|
||||
|
||||
//#include <opm/core/simulator/AdaptiveTimeStepping.hpp>
|
||||
//#include <opm/simulators/timestepping/AdaptiveTimeStepping.hpp>
|
||||
//#include <opm/core/transport/reorder/TransportSolverCompressibleTwophaseReorder.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
|
166
opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp
Normal file
166
opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright (c) 2014 IRIS AS
|
||||
|
||||
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 <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
#include <opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
AdaptiveSimulatorTimer::
|
||||
AdaptiveSimulatorTimer( const SimulatorTimerInterface& timer,
|
||||
const double lastStepTaken,
|
||||
const double maxTimeStep )
|
||||
: start_date_time_( timer.startDateTime() )
|
||||
, start_time_( timer.simulationTimeElapsed() )
|
||||
, total_time_( start_time_ + timer.currentStepLength() )
|
||||
, report_step_( timer.reportStepNum() )
|
||||
, max_time_step_( maxTimeStep )
|
||||
, current_time_( start_time_ )
|
||||
, dt_( 0.0 )
|
||||
, current_step_( 0 )
|
||||
, steps_()
|
||||
, lastStepFailed_( false )
|
||||
{
|
||||
// reserve memory for sub steps
|
||||
steps_.reserve( 10 );
|
||||
|
||||
// set appropriate value for dt_
|
||||
provideTimeStepEstimate( lastStepTaken );
|
||||
}
|
||||
|
||||
AdaptiveSimulatorTimer& AdaptiveSimulatorTimer::operator++ ()
|
||||
{
|
||||
++current_step_;
|
||||
current_time_ += dt_;
|
||||
// store used time step sizes
|
||||
steps_.push_back( dt_ );
|
||||
return *this;
|
||||
}
|
||||
|
||||
void AdaptiveSimulatorTimer::
|
||||
provideTimeStepEstimate( const double dt_estimate )
|
||||
{
|
||||
double remaining = (total_time_ - current_time_);
|
||||
// apply max time step if it was set
|
||||
dt_ = std::min( dt_estimate, max_time_step_ );
|
||||
|
||||
if( remaining > 0 ) {
|
||||
|
||||
// set new time step (depending on remaining time)
|
||||
if( 1.05 * dt_ > remaining ) {
|
||||
dt_ = remaining;
|
||||
// check max time step again and use half remaining if to large
|
||||
if( dt_ > max_time_step_ ) {
|
||||
dt_ = 0.5 * remaining;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// check for half interval step to avoid very small step at the end
|
||||
// remaining *= 0.5;
|
||||
|
||||
if( 1.5 * dt_ > remaining ) {
|
||||
dt_ = 0.5 * remaining;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AdaptiveSimulatorTimer::
|
||||
currentStepNum () const { return current_step_; }
|
||||
|
||||
int AdaptiveSimulatorTimer::
|
||||
reportStepNum () const { return report_step_; }
|
||||
|
||||
double AdaptiveSimulatorTimer::currentStepLength () const
|
||||
{
|
||||
return dt_;
|
||||
}
|
||||
|
||||
double AdaptiveSimulatorTimer::stepLengthTaken() const
|
||||
{
|
||||
assert( ! steps_.empty() );
|
||||
return steps_.back();
|
||||
}
|
||||
|
||||
|
||||
|
||||
double AdaptiveSimulatorTimer::totalTime() const { return total_time_; }
|
||||
|
||||
double AdaptiveSimulatorTimer::simulationTimeElapsed() const { return current_time_; }
|
||||
|
||||
bool AdaptiveSimulatorTimer::done () const { return (current_time_ >= total_time_) ; }
|
||||
|
||||
double AdaptiveSimulatorTimer::averageStepLength() const
|
||||
{
|
||||
const int size = steps_.size();
|
||||
if( size == 0 ) return 0.0;
|
||||
|
||||
const double sum = std::accumulate(steps_.begin(), steps_.end(), 0.0);
|
||||
return sum / double(size);
|
||||
}
|
||||
|
||||
/// \brief return max step length used so far
|
||||
double AdaptiveSimulatorTimer::maxStepLength () const
|
||||
{
|
||||
if( steps_.size() == 0 ) return 0.0;
|
||||
return *(std::max_element( steps_.begin(), steps_.end() ));
|
||||
}
|
||||
|
||||
/// \brief return min step length used so far
|
||||
double AdaptiveSimulatorTimer::minStepLength () const
|
||||
{
|
||||
if( steps_.size() == 0 ) return 0.0;
|
||||
return *(std::min_element( steps_.begin(), steps_.end() ));
|
||||
}
|
||||
|
||||
/// \brief report start and end time as well as used steps so far
|
||||
void AdaptiveSimulatorTimer::
|
||||
report(std::ostream& os) const
|
||||
{
|
||||
os << "Sub steps started at time = " << unit::convert::to( start_time_, unit::day ) << " (days)" << std::endl;
|
||||
for( size_t i=0; i<steps_.size(); ++i )
|
||||
{
|
||||
os << " step[ " << i << " ] = " << unit::convert::to( steps_[ i ], unit::day ) << " (days)" << std::endl;
|
||||
}
|
||||
os << "sub steps end time = " << unit::convert::to( simulationTimeElapsed(), unit::day ) << " (days)" << std::endl;
|
||||
}
|
||||
|
||||
boost::posix_time::ptime AdaptiveSimulatorTimer::startDateTime() const
|
||||
{
|
||||
return start_date_time_;
|
||||
}
|
||||
|
||||
/// return copy of object
|
||||
std::unique_ptr< SimulatorTimerInterface >
|
||||
AdaptiveSimulatorTimer::clone() const
|
||||
{
|
||||
return std::unique_ptr< SimulatorTimerInterface > (new AdaptiveSimulatorTimer( *this ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Opm
|
123
opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp
Normal file
123
opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright 2014 IRIS AS
|
||||
|
||||
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 OPM_ADAPTIVESIMULATORTIMER_HEADER_INCLUDED
|
||||
#define OPM_ADAPTIVESIMULATORTIMER_HEADER_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include <opm/simulators/timestepping/SimulatorTimerInterface.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \brief Simulation timer for adaptive time stepping
|
||||
///
|
||||
/////////////////////////////////////////////////////////
|
||||
class AdaptiveSimulatorTimer : public SimulatorTimerInterface
|
||||
{
|
||||
public:
|
||||
/// \brief constructor taking a simulator timer to determine start and end time
|
||||
/// \param timer in case of sub stepping this is the outer timer
|
||||
/// \param lastStepTaken last suggested time step
|
||||
/// \param maxTimeStep maximum time step allowed
|
||||
AdaptiveSimulatorTimer( const SimulatorTimerInterface& timer,
|
||||
const double lastStepTaken,
|
||||
const double maxTimeStep = std::numeric_limits<double>::max() );
|
||||
|
||||
/// \brief advance time by currentStepLength
|
||||
AdaptiveSimulatorTimer& operator++ ();
|
||||
|
||||
/// \brief advance time by currentStepLength
|
||||
void advance() { this->operator++ (); }
|
||||
|
||||
/// \brief provide and estimate for new time step size
|
||||
void provideTimeStepEstimate( const double dt_estimate );
|
||||
|
||||
/// \brief \copydoc SimulationTimer::currentStepNum
|
||||
int currentStepNum () const;
|
||||
|
||||
/// \brief return current report step
|
||||
int reportStepNum() const;
|
||||
|
||||
/// \brief \copydoc SimulationTimer::currentStepLength
|
||||
double currentStepLength () const;
|
||||
|
||||
/// \brief \copydoc SimulationTimer::totalTime
|
||||
double totalTime() const;
|
||||
|
||||
/// \brief \copydoc SimulationTimer::simulationTimeElapsed
|
||||
double simulationTimeElapsed() const;
|
||||
|
||||
/// \brief \copydoc SimulationTimer::done
|
||||
bool done () const;
|
||||
|
||||
/// \brief return average step length used so far
|
||||
double averageStepLength() const;
|
||||
|
||||
/// \brief return max step length used so far
|
||||
double maxStepLength () const;
|
||||
|
||||
/// \brief return min step length used so far
|
||||
double minStepLength () const;
|
||||
|
||||
/// \brief Previous step length. This is the length of the step that
|
||||
/// was taken to arrive at this time.
|
||||
double stepLengthTaken () const;
|
||||
|
||||
/// \brief report start and end time as well as used steps so far
|
||||
void report(std::ostream& os) const;
|
||||
|
||||
/// \brief start date time of simulation
|
||||
boost::posix_time::ptime startDateTime() const;
|
||||
|
||||
/// \brief Return true if last time step failed
|
||||
bool lastStepFailed() const {return lastStepFailed_;}
|
||||
|
||||
/// \brief tell the timestepper whether timestep failed or not
|
||||
void setLastStepFailed(bool lastStepFailed) {lastStepFailed_ = lastStepFailed;}
|
||||
|
||||
/// return copy of object
|
||||
virtual std::unique_ptr< SimulatorTimerInterface > clone() const;
|
||||
|
||||
protected:
|
||||
const boost::posix_time::ptime start_date_time_;
|
||||
const double start_time_;
|
||||
const double total_time_;
|
||||
const int report_step_;
|
||||
const double max_time_step_;
|
||||
|
||||
double current_time_;
|
||||
double dt_;
|
||||
int current_step_;
|
||||
|
||||
std::vector< double > steps_;
|
||||
bool lastStepFailed_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_SIMULATORTIMER_HEADER_INCLUDED
|
112
opm/simulators/timestepping/AdaptiveTimeStepping.hpp
Normal file
112
opm/simulators/timestepping/AdaptiveTimeStepping.hpp
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright 2014 IRIS AS
|
||||
Copyright 2015 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2015 Statoil AS
|
||||
|
||||
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 OPM_SUBSTEPPING_HEADER_INCLUDED
|
||||
#define OPM_SUBSTEPPING_HEADER_INCLUDED
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/simulators/timestepping/TimeStepControlInterface.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
|
||||
// AdaptiveTimeStepping
|
||||
//---------------------
|
||||
|
||||
class AdaptiveTimeStepping
|
||||
{
|
||||
public:
|
||||
//! \brief contructor taking parameter object
|
||||
//! \param param The parameter object
|
||||
//! \param pinfo The information about the data distribution
|
||||
//! and communication for a parallel run.
|
||||
AdaptiveTimeStepping( const parameter::ParameterGroup& param,
|
||||
const bool terminal_output = true );
|
||||
|
||||
//! \brief contructor taking parameter object
|
||||
//! \param tuning Pointer to ecl TUNING keyword
|
||||
//! \param time_step current report step
|
||||
//! \param param The parameter object
|
||||
//! \param pinfo The information about the data distribution
|
||||
//! and communication for a parallel run.
|
||||
AdaptiveTimeStepping( const Tuning& tuning,
|
||||
size_t time_step,
|
||||
const parameter::ParameterGroup& param,
|
||||
const bool terminal_output = true );
|
||||
|
||||
/** \brief step method that acts like the solver::step method
|
||||
in a sub cycle of time steps
|
||||
|
||||
\param timer simulator timer providing time and timestep
|
||||
\param solver solver object that must implement a method step( dt, state, well_state )
|
||||
\param state current state of the solution variables
|
||||
\param well_state additional well state object
|
||||
*/
|
||||
template <class Solver, class State, class WellState>
|
||||
SimulatorReport step( const SimulatorTimer& timer,
|
||||
Solver& solver, State& state, WellState& well_state );
|
||||
|
||||
/** \brief step method that acts like the solver::step method
|
||||
in a sub cycle of time steps
|
||||
|
||||
\param timer simulator timer providing time and timestep
|
||||
\param fipnum Fluid-in-place numbering array
|
||||
\param solver solver object that must implement a method step( dt, state, well_state )
|
||||
\param state current state of the solution variables
|
||||
\param well_state additional well state object
|
||||
\param outputWriter writer object to write sub steps
|
||||
*/
|
||||
template <class Solver, class State, class WellState, class Output>
|
||||
SimulatorReport step( const SimulatorTimer& timer,
|
||||
Solver& solver, State& state, WellState& well_state,
|
||||
Output& outputWriter,
|
||||
const std::vector<int>* fipnum = nullptr);
|
||||
|
||||
protected:
|
||||
template <class Solver, class State, class WellState, class Output>
|
||||
SimulatorReport stepImpl( const SimulatorTimer& timer,
|
||||
Solver& solver, State& state, WellState& well_state,
|
||||
Output* outputWriter,
|
||||
const std::vector<int>* fipnum);
|
||||
|
||||
void init(const parameter::ParameterGroup& param);
|
||||
|
||||
typedef std::unique_ptr< TimeStepControlInterface > TimeStepControlType;
|
||||
|
||||
TimeStepControlType timeStepControl_; //!< time step control object
|
||||
const double restart_factor_; //!< factor to multiply time step with when solver fails to converge
|
||||
const double growth_factor_; //!< factor to multiply time step when solver recovered from failed convergence
|
||||
const double max_growth_; //!< factor that limits the maximum growth of a time step
|
||||
const double max_time_step_; //!< maximal allowed time step size
|
||||
const int solver_restart_max_; //!< how many restart of solver are allowed
|
||||
const bool solver_verbose_; //!< solver verbosity
|
||||
const bool timestep_verbose_; //!< timestep verbosity
|
||||
double suggested_next_timestep_; //!< suggested size of next timestep
|
||||
bool full_timestep_initially_; //!< beginning with the size of the time step from data file
|
||||
};
|
||||
}
|
||||
|
||||
#include <opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp>
|
||||
#endif
|
356
opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp
Normal file
356
opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp
Normal file
@ -0,0 +1,356 @@
|
||||
/*
|
||||
Copyright 2014 IRIS AS
|
||||
|
||||
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 OPM_ADAPTIVETIMESTEPPING_IMPL_HEADER_INCLUDED
|
||||
#define OPM_ADAPTIVETIMESTEPPING_IMPL_HEADER_INCLUDED
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp>
|
||||
#include <opm/simulators/timestepping/TimeStepControl.hpp>
|
||||
#include <opm/core/utility/StopWatch.hpp>
|
||||
#include <opm/common/Exceptions.hpp>
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
#include <dune/istl/istlexception.hh>
|
||||
#include <dune/istl/ilu.hh> // For MatrixBlockException
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class Solver, class State>
|
||||
class SolutionTimeErrorSolverWrapper : public RelativeChangeInterface
|
||||
{
|
||||
const Solver& solver_;
|
||||
const State& previous_;
|
||||
const State& current_;
|
||||
public:
|
||||
SolutionTimeErrorSolverWrapper( const Solver& solver,
|
||||
const State& previous,
|
||||
const State& current )
|
||||
: solver_( solver ),
|
||||
previous_( previous ),
|
||||
current_( current )
|
||||
{}
|
||||
|
||||
/// return || u^n+1 - u^n || / || u^n+1 ||
|
||||
double relativeChange() const
|
||||
{
|
||||
return solver_.model().relativeChange( previous_, current_ );
|
||||
}
|
||||
};
|
||||
|
||||
template<class E>
|
||||
void logException(const E& exception, bool verbose)
|
||||
{
|
||||
if( verbose )
|
||||
{
|
||||
std::ostringstream message;
|
||||
message << "Caught Exception: " << exception.what();
|
||||
OpmLog::debug(message.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AdaptiveTimeStepping
|
||||
//---------------------
|
||||
|
||||
AdaptiveTimeStepping::AdaptiveTimeStepping( const Tuning& tuning,
|
||||
size_t time_step,
|
||||
const parameter::ParameterGroup& param,
|
||||
const bool terminal_output )
|
||||
: timeStepControl_()
|
||||
, restart_factor_( tuning.getTSFCNV(time_step) )
|
||||
, growth_factor_(tuning.getTFDIFF(time_step) )
|
||||
, max_growth_( tuning.getTSFMAX(time_step) )
|
||||
// default is 1 year, convert to seconds
|
||||
, max_time_step_( tuning.getTSMAXZ(time_step) )
|
||||
, solver_restart_max_( param.getDefault("solver.restart", int(10) ) )
|
||||
, solver_verbose_( param.getDefault("solver.verbose", bool(true) ) && terminal_output )
|
||||
, timestep_verbose_( param.getDefault("timestep.verbose", bool(true) ) && terminal_output )
|
||||
, suggested_next_timestep_( tuning.getTSINIT(time_step) )
|
||||
, full_timestep_initially_( param.getDefault("full_timestep_initially", bool(false) ) )
|
||||
{
|
||||
init(param);
|
||||
|
||||
}
|
||||
|
||||
AdaptiveTimeStepping::AdaptiveTimeStepping( const parameter::ParameterGroup& param,
|
||||
const bool terminal_output )
|
||||
: timeStepControl_()
|
||||
, restart_factor_( param.getDefault("solver.restartfactor", double(0.33) ) )
|
||||
, growth_factor_( param.getDefault("solver.growthfactor", double(2) ) )
|
||||
, max_growth_( param.getDefault("timestep.control.maxgrowth", double(3.0) ) )
|
||||
// default is 1 year, convert to seconds
|
||||
, max_time_step_( unit::convert::from(param.getDefault("timestep.max_timestep_in_days", 365.0 ), unit::day) )
|
||||
, solver_restart_max_( param.getDefault("solver.restart", int(10) ) )
|
||||
, solver_verbose_( param.getDefault("solver.verbose", bool(true) ) && terminal_output )
|
||||
, timestep_verbose_( param.getDefault("timestep.verbose", bool(true) ) && terminal_output )
|
||||
, suggested_next_timestep_( unit::convert::from(param.getDefault("timestep.initial_timestep_in_days", -1.0 ), unit::day) )
|
||||
, full_timestep_initially_( param.getDefault("full_timestep_initially", bool(false) ) )
|
||||
{
|
||||
init(param);
|
||||
}
|
||||
|
||||
void AdaptiveTimeStepping::
|
||||
init(const parameter::ParameterGroup& param)
|
||||
{
|
||||
// valid are "pid" and "pid+iteration"
|
||||
std::string control = param.getDefault("timestep.control", std::string("pid") );
|
||||
// iterations is the accumulation of all linear iterations over all newton steops per time step
|
||||
const int defaultTargetIterations = 30;
|
||||
|
||||
const double tol = param.getDefault("timestep.control.tol", double(1e-1) );
|
||||
if( control == "pid" ) {
|
||||
timeStepControl_ = TimeStepControlType( new PIDTimeStepControl( tol ) );
|
||||
}
|
||||
else if ( control == "pid+iteration" )
|
||||
{
|
||||
const int iterations = param.getDefault("timestep.control.targetiteration", defaultTargetIterations );
|
||||
timeStepControl_ = TimeStepControlType( new PIDAndIterationCountTimeStepControl( iterations, tol ) );
|
||||
}
|
||||
else if ( control == "iterationcount" )
|
||||
{
|
||||
const int iterations = param.getDefault("timestep.control.targetiteration", defaultTargetIterations );
|
||||
const double decayrate = param.getDefault("timestep.control.decayrate", double(0.75) );
|
||||
const double growthrate = param.getDefault("timestep.control.growthrate", double(1.25) );
|
||||
timeStepControl_ = TimeStepControlType( new SimpleIterationCountTimeStepControl( iterations, decayrate, growthrate ) );
|
||||
} else if ( control == "hardcoded") {
|
||||
const std::string filename = param.getDefault("timestep.control.filename", std::string("timesteps"));
|
||||
timeStepControl_ = TimeStepControlType( new HardcodedTimeStepControl( filename ) );
|
||||
|
||||
}
|
||||
else
|
||||
OPM_THROW(std::runtime_error,"Unsupported time step control selected "<< control );
|
||||
|
||||
// make sure growth factor is something reasonable
|
||||
assert( growth_factor_ >= 1.0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class Solver, class State, class WellState>
|
||||
SimulatorReport AdaptiveTimeStepping::
|
||||
step( const SimulatorTimer& simulatorTimer, Solver& solver, State& state, WellState& well_state )
|
||||
{
|
||||
return stepImpl( simulatorTimer, solver, state, well_state, nullptr, nullptr );
|
||||
}
|
||||
|
||||
template <class Solver, class State, class WellState, class Output>
|
||||
SimulatorReport AdaptiveTimeStepping::
|
||||
step( const SimulatorTimer& simulatorTimer,
|
||||
Solver& solver, State& state, WellState& well_state,
|
||||
Output& outputWriter,
|
||||
const std::vector<int>* fipnum)
|
||||
{
|
||||
return stepImpl( simulatorTimer, solver, state, well_state, &outputWriter, fipnum );
|
||||
}
|
||||
|
||||
|
||||
// implementation of the step method
|
||||
template <class Solver, class State, class WState, class Output >
|
||||
SimulatorReport AdaptiveTimeStepping::
|
||||
stepImpl( const SimulatorTimer& simulatorTimer,
|
||||
Solver& solver, State& state, WState& well_state,
|
||||
Output* outputWriter,
|
||||
const std::vector<int>* fipnum)
|
||||
{
|
||||
SimulatorReport report;
|
||||
const double timestep = simulatorTimer.currentStepLength();
|
||||
|
||||
// init last time step as a fraction of the given time step
|
||||
if( suggested_next_timestep_ < 0 ) {
|
||||
suggested_next_timestep_ = restart_factor_ * timestep;
|
||||
}
|
||||
|
||||
if (full_timestep_initially_) {
|
||||
suggested_next_timestep_ = timestep;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// take change in well state into account
|
||||
|
||||
// create adaptive step timer with previously used sub step size
|
||||
AdaptiveSimulatorTimer substepTimer( simulatorTimer, suggested_next_timestep_, max_time_step_ );
|
||||
|
||||
// copy states in case solver has to be restarted (to be revised)
|
||||
State last_state( state );
|
||||
WState last_well_state( well_state );
|
||||
|
||||
// counter for solver restarts
|
||||
int restarts = 0;
|
||||
|
||||
// sub step time loop
|
||||
while( ! substepTimer.done() )
|
||||
{
|
||||
// get current delta t
|
||||
const double dt = substepTimer.currentStepLength() ;
|
||||
if( timestep_verbose_ )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss <<" Substep " << substepTimer.currentStepNum() << ", stepsize "
|
||||
<< unit::convert::to(substepTimer.currentStepLength(), unit::day) << " days.";
|
||||
OpmLog::info(ss.str());
|
||||
}
|
||||
|
||||
SimulatorReport substepReport;
|
||||
try {
|
||||
substepReport = solver.step( substepTimer, state, well_state);
|
||||
report += substepReport;
|
||||
|
||||
if( solver_verbose_ ) {
|
||||
// report number of linear iterations
|
||||
OpmLog::note("Overall linear iterations used: " + std::to_string(substepReport.total_linear_iterations));
|
||||
}
|
||||
}
|
||||
catch (const Opm::NumericalProblem& e) {
|
||||
detail::logException(e, solver_verbose_);
|
||||
// since linearIterations is < 0 this will restart the solver
|
||||
}
|
||||
catch (const std::runtime_error& e) {
|
||||
detail::logException(e, solver_verbose_);
|
||||
// also catch linear solver not converged
|
||||
}
|
||||
catch (const Dune::ISTLError& e) {
|
||||
detail::logException(e, solver_verbose_);
|
||||
// also catch errors in ISTL AMG that occur when time step is too large
|
||||
}
|
||||
catch (const Dune::MatrixBlockError& e) {
|
||||
detail::logException(e, solver_verbose_);
|
||||
// this can be thrown by ISTL's ILU0 in block mode, yet is not an ISTLError
|
||||
}
|
||||
|
||||
if( substepReport.converged )
|
||||
{
|
||||
// advance by current dt
|
||||
++substepTimer;
|
||||
|
||||
// create object to compute the time error, simply forwards the call to the model
|
||||
detail::SolutionTimeErrorSolverWrapper< Solver, State >
|
||||
relativeChange( solver, last_state, state );
|
||||
|
||||
// compute new time step estimate
|
||||
double dtEstimate =
|
||||
timeStepControl_->computeTimeStepSize( dt, substepReport.total_linear_iterations, relativeChange, substepTimer.simulationTimeElapsed());
|
||||
|
||||
// limit the growth of the timestep size by the growth factor
|
||||
dtEstimate = std::min( dtEstimate, double(max_growth_ * dt) );
|
||||
|
||||
// further restrict time step size growth after convergence problems
|
||||
if( restarts > 0 ) {
|
||||
dtEstimate = std::min( growth_factor_ * dt, dtEstimate );
|
||||
// solver converged, reset restarts counter
|
||||
restarts = 0;
|
||||
}
|
||||
|
||||
if( timestep_verbose_ )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << " Substep summary: ";
|
||||
if (report.total_well_iterations != 0) {
|
||||
ss << "well iterations = " << report.total_well_iterations << ", ";
|
||||
}
|
||||
ss << "newton iterations = " << report.total_newton_iterations << ", "
|
||||
<< "linearizations = " << report.total_linearizations
|
||||
<< " (" << report.assemble_time << " sec), "
|
||||
<< "linear iterations = " << report.total_linear_iterations
|
||||
<< " (" << report.linear_solve_time << " sec)";
|
||||
OpmLog::info(ss.str());
|
||||
}
|
||||
|
||||
// write data if outputWriter was provided
|
||||
// if the time step is done we do not need
|
||||
// to write it as this will be done by the simulator
|
||||
// anyway.
|
||||
if( outputWriter && !substepTimer.done() ) {
|
||||
if (fipnum) {
|
||||
solver.computeFluidInPlace(state, *fipnum);
|
||||
}
|
||||
Opm::time::StopWatch perfTimer;
|
||||
perfTimer.start();
|
||||
bool substep = true;
|
||||
const auto& physicalModel = solver.model();
|
||||
outputWriter->writeTimeStep( substepTimer, state, well_state, physicalModel, substep);
|
||||
report.output_write_time += perfTimer.secsSinceStart();
|
||||
}
|
||||
|
||||
// set new time step length
|
||||
substepTimer.provideTimeStepEstimate( dtEstimate );
|
||||
|
||||
// update states
|
||||
last_state = state ;
|
||||
last_well_state = well_state;
|
||||
|
||||
report.converged = substepTimer.done();
|
||||
substepTimer.setLastStepFailed(false);
|
||||
|
||||
}
|
||||
else // in case of no convergence (linearIterations < 0)
|
||||
{
|
||||
report.converged = false;
|
||||
substepTimer.setLastStepFailed(true);
|
||||
// increase restart counter
|
||||
if( restarts >= solver_restart_max_ ) {
|
||||
const auto msg = std::string("Solver failed to converge after ")
|
||||
+ std::to_string(restarts) + " restarts.";
|
||||
if (solver_verbose_) {
|
||||
OpmLog::error(msg);
|
||||
}
|
||||
OPM_THROW_NOLOG(Opm::NumericalProblem, msg);
|
||||
}
|
||||
|
||||
const double newTimeStep = restart_factor_ * dt;
|
||||
// we need to revise this
|
||||
substepTimer.provideTimeStepEstimate( newTimeStep );
|
||||
if( solver_verbose_ ) {
|
||||
std::string msg;
|
||||
msg = "Solver convergence failed, restarting solver with new time step ("
|
||||
+ std::to_string(unit::convert::to( newTimeStep, unit::day )) + " days).\n";
|
||||
OpmLog::problem(msg);
|
||||
}
|
||||
// reset states
|
||||
state = last_state;
|
||||
well_state = last_well_state;
|
||||
|
||||
++restarts;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// store estimated time step for next reportStep
|
||||
suggested_next_timestep_ = substepTimer.currentStepLength();
|
||||
if( timestep_verbose_ )
|
||||
{
|
||||
std::ostringstream ss;
|
||||
substepTimer.report(ss);
|
||||
ss << "Suggested next step size = " << unit::convert::to( suggested_next_timestep_, unit::day ) << " (days)" << std::endl;
|
||||
OpmLog::note(ss.str());
|
||||
}
|
||||
|
||||
if( ! std::isfinite( suggested_next_timestep_ ) ) { // check for NaN
|
||||
suggested_next_timestep_ = timestep;
|
||||
}
|
||||
return report;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
171
opm/simulators/timestepping/SimulatorTimer.cpp
Normal file
171
opm/simulators/timestepping/SimulatorTimer.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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 "config.h"
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
#include <ostream>
|
||||
#include <numeric>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// Default constructor.
|
||||
SimulatorTimer::SimulatorTimer()
|
||||
: current_step_(0),
|
||||
current_time_(0.0),
|
||||
start_date_(2012,1,1) // A really arbitrary default starting value?!
|
||||
{
|
||||
}
|
||||
|
||||
/// Initialize from parameters. Accepts the following:
|
||||
/// num_psteps (default 1)
|
||||
/// stepsize_days (default 1)
|
||||
void SimulatorTimer::init(const parameter::ParameterGroup& param)
|
||||
{
|
||||
const int num_psteps = param.getDefault("num_psteps", 1);
|
||||
const double stepsize_days = param.getDefault("stepsize_days", 1.0);
|
||||
const double stepsize = Opm::unit::convert::from(stepsize_days, Opm::unit::day);
|
||||
timesteps_.clear();
|
||||
timesteps_.resize(num_psteps, stepsize);
|
||||
total_time_ = num_psteps*stepsize;
|
||||
}
|
||||
|
||||
/// Use the SimulatorTimer as a shim around opm-parser's Opm::TimeMap
|
||||
void SimulatorTimer::init(const TimeMap& timeMap, size_t report_step)
|
||||
{
|
||||
total_time_ = timeMap.getTotalTime();
|
||||
timesteps_.resize(timeMap.numTimesteps());
|
||||
for ( size_t i = 0; i < timeMap.numTimesteps(); ++i ) {
|
||||
timesteps_[i] = timeMap.getTimeStepLength(i);
|
||||
}
|
||||
|
||||
setCurrentStepNum(report_step);
|
||||
|
||||
boost::posix_time::ptime start_time = timeMap.getStartTime(0);
|
||||
start_date_ = start_time.date();
|
||||
}
|
||||
|
||||
/// Whether the current step is the first step.
|
||||
bool SimulatorTimer::initialStep() const
|
||||
{
|
||||
return (current_step_ == 0);
|
||||
}
|
||||
|
||||
/// Total number of steps.
|
||||
int SimulatorTimer::numSteps() const
|
||||
{
|
||||
return timesteps_.size();
|
||||
}
|
||||
|
||||
/// Current step number.
|
||||
int SimulatorTimer::currentStepNum() const
|
||||
{
|
||||
return current_step_;
|
||||
}
|
||||
|
||||
/// Set current step number.
|
||||
void SimulatorTimer::setCurrentStepNum(int step)
|
||||
{
|
||||
current_step_ = step;
|
||||
current_time_ = std::accumulate(timesteps_.begin(), timesteps_.begin() + step, 0.0);
|
||||
}
|
||||
|
||||
|
||||
/// Current step length.
|
||||
double SimulatorTimer::currentStepLength() const
|
||||
{
|
||||
assert(!done());
|
||||
return timesteps_[current_step_];
|
||||
}
|
||||
|
||||
double SimulatorTimer::stepLengthTaken() const
|
||||
{
|
||||
assert(current_step_ > 0);
|
||||
return timesteps_[current_step_ - 1];
|
||||
}
|
||||
|
||||
/// time elapsed since the start of the simulation [s].
|
||||
double SimulatorTimer::simulationTimeElapsed() const
|
||||
{
|
||||
return current_time_;
|
||||
}
|
||||
|
||||
boost::posix_time::ptime SimulatorTimer::startDateTime() const
|
||||
{
|
||||
return boost::posix_time::ptime(start_date_);
|
||||
}
|
||||
|
||||
|
||||
boost::posix_time::ptime SimulatorTimer::currentDateTime() const
|
||||
{
|
||||
return startDateTime() + boost::posix_time::seconds( (int) simulationTimeElapsed());
|
||||
}
|
||||
|
||||
/// Total time.
|
||||
double SimulatorTimer::totalTime() const
|
||||
{
|
||||
return total_time_;
|
||||
}
|
||||
|
||||
/// Set total time.
|
||||
/// This is primarily intended for multi-epoch schedules,
|
||||
/// where a timer for a given epoch does not have
|
||||
/// access to later timesteps.
|
||||
void SimulatorTimer::setTotalTime(double time)
|
||||
{
|
||||
total_time_ = time;
|
||||
}
|
||||
|
||||
/// Print a report with current and total time etc.
|
||||
void SimulatorTimer::report(std::ostream& os) const
|
||||
{
|
||||
os << "\n\n--------------- Simulation step number " << currentStepNum() << " ---------------"
|
||||
<< "\n Current time (days) " << Opm::unit::convert::to(simulationTimeElapsed(), Opm::unit::day)
|
||||
<< "\n Current stepsize (days) " << Opm::unit::convert::to(currentStepLength(), Opm::unit::day)
|
||||
<< "\n Total time (days) " << Opm::unit::convert::to(totalTime(), Opm::unit::day)
|
||||
<< "\n" << std::endl;
|
||||
}
|
||||
|
||||
/// Next step.
|
||||
SimulatorTimer& SimulatorTimer::operator++()
|
||||
{
|
||||
assert(!done());
|
||||
current_time_ += timesteps_[current_step_];
|
||||
++current_step_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return true if op++() has been called numSteps() times.
|
||||
bool SimulatorTimer::done() const
|
||||
{
|
||||
return int(timesteps_.size()) == current_step_;
|
||||
}
|
||||
|
||||
/// return copy of object
|
||||
std::unique_ptr< SimulatorTimerInterface >
|
||||
SimulatorTimer::clone() const
|
||||
{
|
||||
return std::unique_ptr< SimulatorTimerInterface > (new SimulatorTimer( *this ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Opm
|
131
opm/simulators/timestepping/SimulatorTimer.hpp
Normal file
131
opm/simulators/timestepping/SimulatorTimer.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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 OPM_SIMULATORTIMER_HEADER_INCLUDED
|
||||
#define OPM_SIMULATORTIMER_HEADER_INCLUDED
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
|
||||
#include <opm/simulators/timestepping/SimulatorTimerInterface.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
namespace parameter { class ParameterGroup; }
|
||||
|
||||
class SimulatorTimer : public SimulatorTimerInterface
|
||||
{
|
||||
public:
|
||||
// use default implementation of these methods
|
||||
using SimulatorTimerInterface::currentDateTime;
|
||||
using SimulatorTimerInterface::currentPosixTime;
|
||||
|
||||
/// Default constructor.
|
||||
SimulatorTimer();
|
||||
|
||||
/// Initialize from parameters. Accepts the following:
|
||||
/// num_psteps (default 1)
|
||||
/// stepsize_days (default 1)
|
||||
void init(const parameter::ParameterGroup& param);
|
||||
|
||||
/// Use the SimulatorTimer as a shim around opm-parser's Opm::TimeMap
|
||||
void init(const TimeMap& timeMap, size_t report_step = 0);
|
||||
|
||||
/// Whether the current step is the first step.
|
||||
bool initialStep() const;
|
||||
|
||||
/// Total number of steps.
|
||||
int numSteps() const;
|
||||
|
||||
/// Current step number. This is the number of timesteps that
|
||||
/// has been completed from the start of the run. The time
|
||||
/// after initialization but before the simulation has started
|
||||
/// is timestep number zero.
|
||||
int currentStepNum() const;
|
||||
|
||||
/// Set current step number.
|
||||
void setCurrentStepNum(int step);
|
||||
|
||||
/// Current step length. This is the length of the step
|
||||
/// the simulator will take in the next iteration.
|
||||
///
|
||||
/// @note if done(), it is an error to call currentStepLength().
|
||||
double currentStepLength() const;
|
||||
|
||||
/// Previous step length. This is the length of the step that
|
||||
/// was taken to arrive at this time.
|
||||
///
|
||||
/// @note if no increments have been done (i.e. the timer is
|
||||
/// still in its constructed state and currentStepNum() == 0),
|
||||
/// it is an error to call stepLengthTaken().
|
||||
double stepLengthTaken () const;
|
||||
|
||||
/// Time elapsed since the start of the simulation until the
|
||||
/// beginning of the current time step [s].
|
||||
double simulationTimeElapsed() const;
|
||||
|
||||
/// Total time.
|
||||
double totalTime() const;
|
||||
|
||||
/// Return start date of simulation
|
||||
boost::posix_time::ptime startDateTime() const;
|
||||
|
||||
/// Return current date.
|
||||
boost::posix_time::ptime currentDateTime() const;
|
||||
|
||||
/// Set total time.
|
||||
/// This is primarily intended for multi-epoch schedules,
|
||||
/// where a timer for a given epoch does not have
|
||||
/// access to later timesteps.
|
||||
void setTotalTime(double time);
|
||||
|
||||
/// Print a report with current and total time etc.
|
||||
/// Note: if done(), it is an error to call report().
|
||||
void report(std::ostream& os) const;
|
||||
|
||||
/// advance time by currentStepLength
|
||||
SimulatorTimer& operator++();
|
||||
|
||||
/// advance time by currentStepLength
|
||||
void advance() { this->operator++(); }
|
||||
|
||||
/// Return true if op++() has been called numSteps() times.
|
||||
bool done() const;
|
||||
|
||||
/// Always return false. Timestep failures is handled in the
|
||||
/// substepTimer
|
||||
bool lastStepFailed() const {return false;}
|
||||
|
||||
/// return copy of object
|
||||
virtual std::unique_ptr< SimulatorTimerInterface > clone() const;
|
||||
|
||||
private:
|
||||
std::vector<double> timesteps_;
|
||||
int current_step_;
|
||||
double current_time_;
|
||||
double total_time_;
|
||||
boost::gregorian::date start_date_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_SIMULATORTIMER_HEADER_INCLUDED
|
114
opm/simulators/timestepping/SimulatorTimerInterface.hpp
Normal file
114
opm/simulators/timestepping/SimulatorTimerInterface.hpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright (c) 2014 IRIS AS
|
||||
|
||||
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 OPM_SIMULATORTIMERINTERFACE_HEADER_INCLUDED
|
||||
#define OPM_SIMULATORTIMERINTERFACE_HEADER_INCLUDED
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
namespace parameter { class ParameterGroup; }
|
||||
|
||||
/// Interface class for SimulatorTimer objects, to be improved.
|
||||
class SimulatorTimerInterface
|
||||
{
|
||||
protected:
|
||||
/// Default constructor, protected to not allow explicit instances of this class.
|
||||
SimulatorTimerInterface() {}
|
||||
|
||||
public:
|
||||
/// destructor
|
||||
virtual ~SimulatorTimerInterface() {}
|
||||
|
||||
/// Current step number. This is the number of timesteps that
|
||||
/// has been completed from the start of the run. The time
|
||||
/// after initialization but before the simulation has started
|
||||
/// is timestep number zero.
|
||||
virtual int currentStepNum() const = 0;
|
||||
|
||||
/// Current report step number. This might differ from currentStepNum in case of sub stepping
|
||||
virtual int reportStepNum() const { return currentStepNum(); }
|
||||
|
||||
/// Current step length. This is the length of the step
|
||||
/// the simulator will take in the next iteration.
|
||||
///
|
||||
/// @note if done(), it is an error to call currentStepLength().
|
||||
virtual double currentStepLength() const = 0;
|
||||
|
||||
/// Previous step length. This is the length of the step that
|
||||
/// was taken to arrive at this time.
|
||||
///
|
||||
/// @note if no increments have been done (i.e. the timer is
|
||||
/// still in its constructed state and currentStepNum() == 0),
|
||||
/// it is an error to call stepLengthTaken().
|
||||
virtual double stepLengthTaken () const = 0;
|
||||
|
||||
/// Previous report step length. This is the length of the step that
|
||||
/// was taken to arrive at this report step time.
|
||||
///
|
||||
/// @note if no increments have been done (i.e. the timer is
|
||||
/// still in its constructed state and reportStepNum() == 0),
|
||||
/// it is an error to call stepLengthTaken().
|
||||
virtual double reportStepLengthTaken () const { return stepLengthTaken(); }
|
||||
|
||||
/// Time elapsed since the start of the simulation until the
|
||||
/// beginning of the current time step [s].
|
||||
virtual double simulationTimeElapsed() const = 0;
|
||||
|
||||
/// advance time by currentStepLength
|
||||
virtual void advance() = 0 ;
|
||||
|
||||
/// Return true if timer indicates that simulation of timer interval is finished
|
||||
virtual bool done() const = 0;
|
||||
|
||||
/// Return start date of simulation
|
||||
virtual boost::posix_time::ptime startDateTime() const = 0;
|
||||
|
||||
/// Return the current time as a posix time object.
|
||||
virtual boost::posix_time::ptime currentDateTime() const
|
||||
{
|
||||
return startDateTime() + boost::posix_time::seconds( (int) simulationTimeElapsed());
|
||||
//boost::posix_time::ptime(startDate()) + boost::posix_time::seconds( (int) simulationTimeElapsed());
|
||||
}
|
||||
|
||||
/// Time elapsed since the start of the POSIX epoch (Jan 1st,
|
||||
/// 1970) until the current time step begins [s].
|
||||
virtual time_t currentPosixTime() const
|
||||
{
|
||||
tm t = boost::posix_time::to_tm(currentDateTime());
|
||||
return std::mktime(&t);
|
||||
}
|
||||
|
||||
/// Return true if last time step failed
|
||||
virtual bool lastStepFailed() const = 0;
|
||||
|
||||
/// return copy of current timer instance
|
||||
virtual std::unique_ptr< SimulatorTimerInterface > clone () const = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_SIMULATORTIMER_HEADER_INCLUDED
|
192
opm/simulators/timestepping/TimeStepControl.cpp
Normal file
192
opm/simulators/timestepping/TimeStepControl.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
Copyright 2014 IRIS AS
|
||||
Copyright 2015 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2015 Statoil AS
|
||||
|
||||
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 <config.h>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
#include <opm/simulators/timestepping/TimeStepControl.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// InterationCountTimeStepControl Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
SimpleIterationCountTimeStepControl::
|
||||
SimpleIterationCountTimeStepControl( const int target_iterations,
|
||||
const double decayrate,
|
||||
const double growthrate,
|
||||
const bool verbose)
|
||||
: target_iterations_( target_iterations )
|
||||
, decayrate_( decayrate )
|
||||
, growthrate_( growthrate )
|
||||
, verbose_( verbose )
|
||||
{
|
||||
if( decayrate_ > 1.0 ) {
|
||||
OPM_THROW(std::runtime_error,"SimpleIterationCountTimeStepControl: decay should be <= 1 " << decayrate_ );
|
||||
}
|
||||
if( growthrate_ < 1.0 ) {
|
||||
OPM_THROW(std::runtime_error,"SimpleIterationCountTimeStepControl: growth should be >= 1 " << growthrate_ );
|
||||
}
|
||||
}
|
||||
|
||||
double SimpleIterationCountTimeStepControl::
|
||||
computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& /* relativeChange */, const double /*simulationTimeElapsed */) const
|
||||
{
|
||||
double dtEstimate = dt ;
|
||||
|
||||
// reduce the time step size if we exceed the number of target iterations
|
||||
if( iterations > target_iterations_ )
|
||||
{
|
||||
// scale dtEstimate down with a given rate
|
||||
dtEstimate *= decayrate_;
|
||||
}
|
||||
// increase the time step size if we are below the number of target iterations
|
||||
else if ( iterations < target_iterations_-1 )
|
||||
{
|
||||
dtEstimate *= growthrate_;
|
||||
}
|
||||
|
||||
return dtEstimate;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// HardcodedTimeStepControl Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
HardcodedTimeStepControl::
|
||||
HardcodedTimeStepControl( const std::string& filename)
|
||||
{
|
||||
std::ifstream infile (filename);
|
||||
if (!infile.is_open()) {
|
||||
OPM_THROW(std::runtime_error,"Incorrect or no filename is provided to the hardcodedTimeStep. Use timestep.control.filename=your_file_name");
|
||||
}
|
||||
std::string::size_type sz;
|
||||
std::string line;
|
||||
while ( std::getline(infile, line)) {
|
||||
if( line[0] != '-') { // ignore lines starting with '-'
|
||||
const double time = std::stod(line,&sz); // read the first number i.e. the actual substep time
|
||||
subStepTime_.push_back( time * unit::day );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
double HardcodedTimeStepControl::
|
||||
computeTimeStepSize( const double /*dt */, const int /*iterations */, const RelativeChangeInterface& /* relativeChange */ , const double simulationTimeElapsed) const
|
||||
{
|
||||
auto nextTime = std::upper_bound(subStepTime_.begin(), subStepTime_.end(), simulationTimeElapsed);
|
||||
return (*nextTime - simulationTimeElapsed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// PIDTimeStepControl Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
PIDTimeStepControl::PIDTimeStepControl( const double tol,
|
||||
const bool verbose )
|
||||
: tol_( tol )
|
||||
, errors_( 3, tol_ )
|
||||
, verbose_( verbose )
|
||||
{}
|
||||
|
||||
double PIDTimeStepControl::
|
||||
computeTimeStepSize( const double dt, const int /* iterations */, const RelativeChangeInterface& relChange, const double /*simulationTimeElapsed */) const
|
||||
{
|
||||
// shift errors
|
||||
for( int i=0; i<2; ++i ) {
|
||||
errors_[ i ] = errors_[i+1];
|
||||
}
|
||||
|
||||
// store new error
|
||||
const double error = relChange.relativeChange();
|
||||
errors_[ 2 ] = error;
|
||||
|
||||
if( error > tol_ )
|
||||
{
|
||||
// adjust dt by given tolerance
|
||||
const double newDt = dt * tol_ / error;
|
||||
if( verbose_ )
|
||||
std::cout << "Computed step size (tol): " << unit::convert::to( newDt, unit::day ) << " (days)" << std::endl;
|
||||
return newDt;
|
||||
}
|
||||
else
|
||||
{
|
||||
// values taking from turek time stepping paper
|
||||
const double kP = 0.075 ;
|
||||
const double kI = 0.175 ;
|
||||
const double kD = 0.01 ;
|
||||
const double newDt = (dt * std::pow( errors_[ 1 ] / errors_[ 2 ], kP ) *
|
||||
std::pow( tol_ / errors_[ 2 ], kI ) *
|
||||
std::pow( errors_[0]*errors_[0]/errors_[ 1 ]/errors_[ 2 ], kD ));
|
||||
if( verbose_ )
|
||||
std::cout << "Computed step size (pow): " << unit::convert::to( newDt, unit::day ) << " (days)" << std::endl;
|
||||
return newDt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PIDAndIterationCountTimeStepControl Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
PIDAndIterationCountTimeStepControl::
|
||||
PIDAndIterationCountTimeStepControl( const int target_iterations,
|
||||
const double tol,
|
||||
const bool verbose)
|
||||
: BaseType( tol, verbose )
|
||||
, target_iterations_( target_iterations )
|
||||
{}
|
||||
|
||||
double PIDAndIterationCountTimeStepControl::
|
||||
computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& relChange, const double simulationTimeElapsed ) const
|
||||
{
|
||||
double dtEstimate = BaseType :: computeTimeStepSize( dt, iterations, relChange, simulationTimeElapsed);
|
||||
|
||||
// further reduce step size if to many iterations were used
|
||||
if( iterations > target_iterations_ )
|
||||
{
|
||||
// if iterations was the same or dts were the same, do some magic
|
||||
dtEstimate *= double( target_iterations_ ) / double(iterations);
|
||||
}
|
||||
|
||||
return dtEstimate;
|
||||
}
|
||||
|
||||
} // end namespace Opm
|
147
opm/simulators/timestepping/TimeStepControl.hpp
Normal file
147
opm/simulators/timestepping/TimeStepControl.hpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright 2014 IRIS AS
|
||||
Copyright 2015 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2015 Statoil AS
|
||||
|
||||
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 OPM_TIMESTEPCONTROL_HEADER_INCLUDED
|
||||
#define OPM_TIMESTEPCONTROL_HEADER_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <opm/simulators/timestepping/TimeStepControlInterface.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// A simple iteration count based adaptive time step control.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class SimpleIterationCountTimeStepControl : public TimeStepControlInterface
|
||||
{
|
||||
public:
|
||||
/// \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)
|
||||
// \param growthrate growthrate of time step when target iterations are not met (should be >= 1)
|
||||
/// \param verbose if true get some output (default = false)
|
||||
SimpleIterationCountTimeStepControl( const int target_iterations,
|
||||
const double decayrate,
|
||||
const double growthrate,
|
||||
const bool verbose = false);
|
||||
|
||||
/// \brief \copydoc TimeStepControlInterface::computeTimeStepSize
|
||||
double computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& /* relativeChange */, const double /*simulationTimeElapsed */ ) const;
|
||||
|
||||
protected:
|
||||
const int target_iterations_;
|
||||
const double decayrate_;
|
||||
const double growthrate_;
|
||||
const bool verbose_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// PID controller based adaptive time step control as suggested in:
|
||||
/// Turek and Kuzmin. Algebraic Flux Correction III. Incompressible Flow Problems. Uni Dortmund.
|
||||
///
|
||||
/// See also:
|
||||
/// D. Kuzmin and S.Turek. Numerical simulation of turbulent bubbly flows. Techreport Uni Dortmund. 2004
|
||||
///
|
||||
/// and the original article:
|
||||
/// Valli, Coutinho, and Carey. Adaptive Control for Time Step Selection in Finite Element
|
||||
/// Simulation of Coupled Viscous Flow and Heat Transfer. Proc of the 10th
|
||||
/// International Conference on Numerical Methods in Fluids. 1998.
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class PIDTimeStepControl : public TimeStepControlInterface
|
||||
{
|
||||
public:
|
||||
/// \brief constructor
|
||||
/// \param tol tolerance for the relative changes of the numerical solution to be accepted
|
||||
/// in one time step (default is 1e-3)
|
||||
/// \param verbose if true get some output (default = false)
|
||||
PIDTimeStepControl( const double tol = 1e-3,
|
||||
const bool verbose = false );
|
||||
|
||||
/// \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_;
|
||||
|
||||
const bool verbose_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// PID controller based adaptive time step control as above that also takes
|
||||
/// an target iteration into account.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class PIDAndIterationCountTimeStepControl : public PIDTimeStepControl
|
||||
{
|
||||
typedef PIDTimeStepControl BaseType;
|
||||
public:
|
||||
/// \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
|
||||
/// in one time step (default is 1e-3)
|
||||
/// \param verbose if true get some output (default = false)
|
||||
PIDAndIterationCountTimeStepControl( const int target_iterations = 20,
|
||||
const double tol = 1e-3,
|
||||
const bool verbose = false);
|
||||
|
||||
/// \brief \copydoc TimeStepControlInterface::computeTimeStepSize
|
||||
double computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& relativeChange, const double /*simulationTimeElapsed */ ) const;
|
||||
|
||||
protected:
|
||||
const int target_iterations_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// HardcodedTimeStepControl
|
||||
/// Input generated from summary file using the ert application:
|
||||
///
|
||||
/// ecl_summary DECK TIME > filename
|
||||
///
|
||||
/// Assumes time is given in days
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class HardcodedTimeStepControl : public TimeStepControlInterface
|
||||
{
|
||||
public:
|
||||
/// \brief constructor
|
||||
/// \param filename filename contaning the timesteps
|
||||
explicit HardcodedTimeStepControl( const std::string& filename);
|
||||
|
||||
/// \brief \copydoc TimeStepControlInterface::computeTimeStepSize
|
||||
double computeTimeStepSize( const double dt, const int /* iterations */, const RelativeChangeInterface& /*relativeChange */, const double simulationTimeElapsed) const;
|
||||
|
||||
protected:
|
||||
// store the time (in days) of the substeps the simulator should use
|
||||
std::vector<double> subStepTime_;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Opm
|
||||
#endif
|
||||
|
66
opm/simulators/timestepping/TimeStepControlInterface.hpp
Normal file
66
opm/simulators/timestepping/TimeStepControlInterface.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2014 IRIS AS
|
||||
|
||||
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 OPM_TIMESTEPCONTROLINTERFACE_HEADER_INCLUDED
|
||||
#define OPM_TIMESTEPCONTROLINTERFACE_HEADER_INCLUDED
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// RelativeChangeInterface
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////
|
||||
class RelativeChangeInterface
|
||||
{
|
||||
protected:
|
||||
RelativeChangeInterface() {}
|
||||
public:
|
||||
/// \return || u^n+1 - u^n || / || u^n+1 ||
|
||||
virtual double relativeChange() const = 0;
|
||||
|
||||
/// virtual destructor (empty)
|
||||
virtual ~RelativeChangeInterface() {}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// TimeStepControlInterface
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////
|
||||
class TimeStepControlInterface
|
||||
{
|
||||
protected:
|
||||
TimeStepControlInterface() {}
|
||||
public:
|
||||
/// compute new time step size suggestions based on the PID controller
|
||||
/// \param dt time step size used in the current step
|
||||
/// \param iterations number of iterations used (linear/nonlinear)
|
||||
/// \param timeError object to compute || u^n+1 - u^n || / || u^n+1 ||
|
||||
///
|
||||
/// \return suggested time step size for the next step
|
||||
virtual double computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& relativeChange , const double simulationTimeElapsed) const = 0;
|
||||
|
||||
/// virtual destructor (empty)
|
||||
virtual ~TimeStepControlInterface () {}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
49
tests/TESTTIMER.DATA
Normal file
49
tests/TESTTIMER.DATA
Normal file
@ -0,0 +1,49 @@
|
||||
RUNSPEC
|
||||
|
||||
START
|
||||
26 'MAR' 2014 /
|
||||
|
||||
TSTEP
|
||||
1.0 2*5.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
7*10.0 14*25.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
19.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
18*13.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
17*10.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
13.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
18.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
11.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
17*5.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
19*6.0
|
||||
/
|
||||
|
||||
TSTEP
|
||||
21*5.0 /
|
||||
|
||||
END ==
|
115
tests/test_timer.cpp
Normal file
115
tests/test_timer.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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 <config.h>
|
||||
|
||||
#if HAVE_DYNAMIC_BOOST_TEST
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#endif
|
||||
|
||||
#define NVERBOSE // Suppress own messages when throw()ing
|
||||
|
||||
#define BOOST_TEST_MODULE OPM-TimerTest
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/simulators/timestepping/SimulatorTimer.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CreateTimer)
|
||||
{
|
||||
const std::string filename1 = "TESTTIMER.DATA";
|
||||
Opm::ParseContext parseContext;
|
||||
Opm::Parser parser;
|
||||
Opm::Deck parserDeck = parser.parseFile( filename1 , parseContext);
|
||||
|
||||
Opm::TimeMap timeMap( parserDeck );
|
||||
Opm::SimulatorTimer simtimer;
|
||||
|
||||
boost::gregorian::date defaultStartDate( 2012, 1, 1);
|
||||
BOOST_CHECK_EQUAL( boost::posix_time::ptime(defaultStartDate), simtimer.currentDateTime() );
|
||||
|
||||
simtimer.init(timeMap);
|
||||
boost::gregorian::date startDate( 2014, 3, 26);
|
||||
BOOST_CHECK_EQUAL( boost::posix_time::ptime(startDate), simtimer.currentDateTime() );
|
||||
|
||||
BOOST_CHECK_EQUAL( 0, simtimer.currentStepNum() );
|
||||
BOOST_CHECK_EQUAL( 0., simtimer.simulationTimeElapsed() );
|
||||
BOOST_CHECK_EQUAL( 120, simtimer.numSteps() );
|
||||
BOOST_CHECK_EQUAL( 1200., Opm::unit::convert::to(simtimer.totalTime(), Opm::unit::day) );
|
||||
BOOST_CHECK_EQUAL( 0., Opm::unit::convert::to(simtimer.simulationTimeElapsed(), Opm::unit::day) );
|
||||
|
||||
double testCurrentTime = 0.;
|
||||
BOOST_CHECK_EQUAL( Opm::unit::convert::to(testCurrentTime, Opm::unit::day),
|
||||
Opm::unit::convert::to(simtimer.simulationTimeElapsed(), Opm::unit::day) );
|
||||
|
||||
for ( int i = 0; i < simtimer.numSteps(); ++i ) {
|
||||
BOOST_CHECK_EQUAL( i, simtimer.currentStepNum() );
|
||||
BOOST_CHECK_EQUAL( Opm::unit::convert::to(testCurrentTime, Opm::unit::minute),
|
||||
Opm::unit::convert::to(simtimer.simulationTimeElapsed(), Opm::unit::minute) );
|
||||
testCurrentTime += simtimer.currentStepLength();
|
||||
++simtimer;
|
||||
}
|
||||
|
||||
for ( int i = 0; i <= simtimer.numSteps(); ++i ) {
|
||||
simtimer.setCurrentStepNum(i);
|
||||
BOOST_CHECK_EQUAL( i, simtimer.currentStepNum() );
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL( true, simtimer.done() );
|
||||
simtimer.setCurrentStepNum(0);
|
||||
BOOST_CHECK_EQUAL( false, simtimer.done() );
|
||||
BOOST_CHECK_EQUAL( 0., Opm::unit::convert::to(simtimer.simulationTimeElapsed(), Opm::unit::day) );
|
||||
|
||||
simtimer.setCurrentStepNum(120);
|
||||
BOOST_CHECK_EQUAL( Opm::unit::convert::to(simtimer.simulationTimeElapsed(), Opm::unit::day),
|
||||
Opm::unit::convert::to(simtimer.totalTime(), Opm::unit::day) );
|
||||
|
||||
int i = 0;
|
||||
double testCurrentTime1 = 0.;
|
||||
double testCurrentTime2 = 0.;
|
||||
simtimer.setCurrentStepNum(0);
|
||||
|
||||
while (!simtimer.done()) {
|
||||
testCurrentTime1 += simtimer.currentStepLength();
|
||||
BOOST_CHECK_EQUAL( i, simtimer.currentStepNum() );
|
||||
++i;
|
||||
++simtimer;
|
||||
testCurrentTime2 += simtimer.stepLengthTaken();
|
||||
BOOST_CHECK_EQUAL( Opm::unit::convert::to(testCurrentTime1, Opm::unit::minute),
|
||||
Opm::unit::convert::to(simtimer.simulationTimeElapsed(), Opm::unit::minute) );
|
||||
BOOST_CHECK_EQUAL( Opm::unit::convert::to(testCurrentTime2, Opm::unit::minute),
|
||||
Opm::unit::convert::to(simtimer.simulationTimeElapsed(), Opm::unit::minute) );
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL( true, simtimer.done() );
|
||||
BOOST_CHECK_EQUAL( Opm::unit::convert::to(testCurrentTime1, Opm::unit::minute),
|
||||
Opm::unit::convert::to(simtimer.totalTime(), Opm::unit::minute) );
|
||||
BOOST_CHECK_EQUAL( Opm::unit::convert::to(testCurrentTime2, Opm::unit::minute),
|
||||
Opm::unit::convert::to(simtimer.totalTime(), Opm::unit::minute) );
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user