Exemple #1
0
    SimulatorReport AdaptiveTimeStepping::
    stepImpl( const SimulatorTimer& simulatorTimer,
              Solver& solver, State& state, WState& well_state,
              Output* outputWriter )
    {
        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() ) {
                    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();

            }
            else // in case of no convergence (linearIterations < 0)
            {
                report.converged = false;

                // 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;
    }
void AdaptiveTimeStepping::
stepImpl( const SimulatorTimer& simulatorTimer,
          Solver& solver, State& state, WState& well_state,
          OutputWriter* outputWriter )
{
    const double timestep = simulatorTimer.currentStepLength();

    // init last time step as a fraction of the given time step
    if( last_timestep_ < 0 ) {
        last_timestep_ = restart_factor_ * timestep;
    }

    // TODO
    // take change in well state into account

    // create adaptive step timer with previously used sub step size
    AdaptiveSimulatorTimer substepTimer( simulatorTimer, last_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() ;

        // initialize time step control in case current state is needed later
        timeStepControl_->initialize( state );

        if( timestep_verbose_ )
        {
            std::cout <<"Substep( " << substepTimer.currentStepNum() << " ), try with stepsize "
                      << unit::convert::to(substepTimer.currentStepLength(), unit::day) << " (days)." << std::endl;
        }

        int linearIterations = -1;
        try {
            // (linearIterations < 0 means on convergence in solver)
            linearIterations = solver.step( dt, state, well_state);

            if( solver_verbose_ ) {
                // report number of linear iterations
                std::cout << "Overall linear iterations used: " << linearIterations << std::endl;
            }
        }
        catch (const Opm::NumericalProblem& e) {
            std::cerr << e.what() << std::endl;
            // since linearIterations is < 0 this will restart the solver
        }
        catch (const std::runtime_error& e) {
            std::cerr << e.what() << std::endl;
            // also catch linear solver not converged
        }

        // (linearIterations < 0 means no convergence in solver)
        if( linearIterations >= 0 )
        {
            // advance by current dt
            ++substepTimer;

            // compute new time step estimate
            double dtEstimate =
                timeStepControl_->computeTimeStepSize( dt, linearIterations, state );

            // avoid time step size growth
            if( restarts > 0 ) {
                dtEstimate = std::min( growth_factor_ * dt, dtEstimate );
                // solver converged, reset restarts counter
                restarts = 0;
            }

            if( timestep_verbose_ )
            {
                std::cout << "Substep( " << substepTimer.currentStepNum()-1 // it was already advanced by ++
                          << " ) finished at time " << unit::convert::to(substepTimer.simulationTimeElapsed(),unit::day) << " (days)." << std::endl << std::endl;
            }

            // write data if outputWriter was provided
            if( outputWriter ) {
                outputWriter->writeTimeStep( substepTimer, state, well_state );
            }

            // set new time step length
            substepTimer.provideTimeStepEstimate( dtEstimate );

            // update states
            last_state      = state ;
            last_well_state = well_state;

        }
        else // in case of no convergence (linearIterations < 0)
        {
            // increase restart counter
            if( restarts >= solver_restart_max_ ) {
                OPM_THROW(Opm::NumericalProblem,"Solver failed to converge after " << restarts << " restarts.");
            }

            const double newTimeStep = restart_factor_ * dt;
            // we need to revise this
            substepTimer.provideTimeStepEstimate( newTimeStep );
            if( solver_verbose_ )
                std::cerr << "Solver convergence failed, restarting solver with new time step ("
                          << unit::convert::to( newTimeStep, unit::day ) <<" days)." << std::endl;

            // reset states
            state      = last_state;
            well_state = last_well_state;

            ++restarts;
        }
    }


    // store max of the small time step for next reportStep
    last_timestep_ = substepTimer.averageStepLength();
    if( timestep_verbose_ )
    {
        substepTimer.report( std::cout );
        std::cout << "Suggested next step size = " << unit::convert::to( last_timestep_, unit::day ) << " (days)" << std::endl;
    }

    if( ! std::isfinite( last_timestep_ ) ) { // check for NaN
        last_timestep_ = timestep;
    }
}