void updateState(const V& dx, ReservoirState& reservoir_state, WellState& well_state) { // Naively, rs and rv can get overwritten, so we // avoid that by storing. std::vector<double> rs_old = reservoir_state.gasoilratio(); std::vector<double> rv_old = reservoir_state.rv(); auto hs_old = reservoir_state.hydroCarbonState(); auto phasecond_old = Base::phaseCondition_; auto isRs_old = Base::isRs_; auto isRv_old = Base::isRv_; auto isSg_old = Base::isSg_; // Compute the pressure range. const auto minmax_iters = std::minmax_element(reservoir_state.pressure().begin(), reservoir_state.pressure().end()); const double range = *minmax_iters.second - *minmax_iters.first; // Use the base class' updateState(). Base::updateState(dx, reservoir_state, well_state); // Compute relative change. max_dp_rel_ = dx.head(reservoir_state.pressure().size()).abs().maxCoeff() / range; // Restore rs and rv, also various state flags. reservoir_state.gasoilratio() = rs_old; reservoir_state.rv() = rv_old; reservoir_state.hydroCarbonState() = hs_old; Base::phaseCondition_ = phasecond_old; Base::isRs_ = isRs_old; Base::isRv_ = isRv_old; Base::isSg_ = isSg_old; }
SimulatorReport SimulatorBase<Implementation>::run(SimulatorTimer& timer, ReservoirState& state) { WellState prev_well_state; // Create timers and file for writing timing info. Opm::time::StopWatch solver_timer; double stime = 0.0; Opm::time::StopWatch step_timer; Opm::time::StopWatch total_timer; total_timer.start(); std::string tstep_filename = output_writer_.outputDirectory() + "/step_timing.txt"; std::ofstream tstep_os(tstep_filename.c_str()); // adaptive time stepping std::unique_ptr< AdaptiveTimeStepping > adaptiveTimeStepping; if( param_.getDefault("timestep.adaptive", true ) ) { adaptiveTimeStepping.reset( new AdaptiveTimeStepping( param_, solver_.parallelInformation() ) ); } // init output writer output_writer_.writeInit( timer ); std::string restorefilename = param_.getDefault("restorefile", std::string("") ); if( ! restorefilename.empty() ) { // -1 means that we'll take the last report step that was written const int desiredRestoreStep = param_.getDefault("restorestep", int(-1) ); output_writer_.restore( timer, state, prev_well_state, restorefilename, desiredRestoreStep ); } unsigned int totalNewtonIterations = 0; unsigned int totalLinearIterations = 0; // Main simulation loop. while (!timer.done()) { // Report timestep. step_timer.start(); if ( terminal_output_ ) { timer.report(std::cout); } // Create wells and well state. WellsManager wells_manager(eclipse_state_, timer.currentStepNum(), Opm::UgGridHelpers::numCells(grid_), Opm::UgGridHelpers::globalCell(grid_), Opm::UgGridHelpers::cartDims(grid_), Opm::UgGridHelpers::dimensions(grid_), Opm::UgGridHelpers::cell2Faces(grid_), Opm::UgGridHelpers::beginFaceCentroids(grid_), props_.permeability(), is_parallel_run_); const Wells* wells = wells_manager.c_wells(); WellState well_state; well_state.init(wells, state, prev_well_state); // give the polymer and surfactant simulators the chance to do their stuff asImpl().handleAdditionalWellInflow(timer, wells_manager, well_state, wells); // write simulation state at the report stage output_writer_.writeTimeStep( timer, state, well_state ); // Max oil saturation (for VPPARS), hysteresis update. props_.updateSatOilMax(state.saturation()); props_.updateSatHyst(state.saturation(), allcells_); // Compute reservoir volumes for RESV controls. asImpl().computeRESV(timer.currentStepNum(), wells, state, well_state); // Run a multiple steps of the solver depending on the time step control. solver_timer.start(); auto solver = asImpl().createSolver(wells); // If sub stepping is enabled allow the solver to sub cycle // in case the report steps are too large for the solver to converge // // \Note: The report steps are met in any case // \Note: The sub stepping will require a copy of the state variables if( adaptiveTimeStepping ) { adaptiveTimeStepping->step( timer, *solver, state, well_state, output_writer_ ); } else { // solve for complete report step solver->step(timer.currentStepLength(), state, well_state); } // take time that was used to solve system for this reportStep solver_timer.stop(); // accumulate the number of Newton and Linear Iterations totalNewtonIterations += solver->newtonIterations(); totalLinearIterations += solver->linearIterations(); // Report timing. const double st = solver_timer.secsSinceStart(); if ( terminal_output_ ) { std::cout << "Fully implicit solver took: " << st << " seconds." << std::endl; } stime += st; if ( output_writer_.output() ) { SimulatorReport step_report; step_report.pressure_time = st; step_report.total_time = step_timer.secsSinceStart(); step_report.reportParam(tstep_os); } // Increment timer, remember well state. ++timer; prev_well_state = well_state; } // Write final simulation state. output_writer_.writeTimeStep( timer, state, prev_well_state ); // Stop timer and create timing report total_timer.stop(); SimulatorReport report; report.pressure_time = stime; report.transport_time = 0.0; report.total_time = total_timer.secsSinceStart(); report.total_newton_iterations = totalNewtonIterations; report.total_linear_iterations = totalLinearIterations; return report; }
SimulatorReport SimulatorBase<Implementation>::run(SimulatorTimer& timer, ReservoirState& state) { WellState prev_well_state; if (output_writer_.isRestart()) { // This is a restart, populate WellState and ReservoirState state objects from restart file output_writer_.initFromRestartFile(props_.phaseUsage(), props_.permeability(), grid_, state, prev_well_state); } // Create timers and file for writing timing info. Opm::time::StopWatch solver_timer; double stime = 0.0; Opm::time::StopWatch step_timer; Opm::time::StopWatch total_timer; total_timer.start(); std::string tstep_filename = output_writer_.outputDirectory() + "/step_timing.txt"; std::ofstream tstep_os(tstep_filename.c_str()); const auto& schedule = eclipse_state_->getSchedule(); const auto& events = schedule->getEvents(); // adaptive time stepping std::unique_ptr< AdaptiveTimeStepping > adaptiveTimeStepping; if( param_.getDefault("timestep.adaptive", true ) ) { adaptiveTimeStepping.reset( new AdaptiveTimeStepping( param_, terminal_output_ ) ); } // init output writer output_writer_.writeInit( timer ); std::string restorefilename = param_.getDefault("restorefile", std::string("") ); if( ! restorefilename.empty() ) { // -1 means that we'll take the last report step that was written const int desiredRestoreStep = param_.getDefault("restorestep", int(-1) ); output_writer_.restore( timer, state, prev_well_state, restorefilename, desiredRestoreStep ); } unsigned int totalNonlinearIterations = 0; unsigned int totalLinearIterations = 0; bool is_well_potentials_computed = param_.getDefault("compute_well_potentials", false ); std::vector<double> well_potentials; // Main simulation loop. while (!timer.done()) { // Report timestep. step_timer.start(); if ( terminal_output_ ) { timer.report(std::cout); } // Create wells and well state. WellsManager wells_manager(eclipse_state_, timer.currentStepNum(), Opm::UgGridHelpers::numCells(grid_), Opm::UgGridHelpers::globalCell(grid_), Opm::UgGridHelpers::cartDims(grid_), Opm::UgGridHelpers::dimensions(grid_), Opm::UgGridHelpers::cell2Faces(grid_), Opm::UgGridHelpers::beginFaceCentroids(grid_), props_.permeability(), is_parallel_run_, well_potentials); const Wells* wells = wells_manager.c_wells(); WellState well_state; well_state.init(wells, state, prev_well_state); // give the polymer and surfactant simulators the chance to do their stuff asImpl().handleAdditionalWellInflow(timer, wells_manager, well_state, wells); // write simulation state at the report stage output_writer_.writeTimeStep( timer, state, well_state ); // Max oil saturation (for VPPARS), hysteresis update. props_.updateSatOilMax(state.saturation()); props_.updateSatHyst(state.saturation(), allcells_); // Compute reservoir volumes for RESV controls. asImpl().computeRESV(timer.currentStepNum(), wells, state, well_state); // Run a multiple steps of the solver depending on the time step control. solver_timer.start(); auto solver = asImpl().createSolver(wells); // If sub stepping is enabled allow the solver to sub cycle // in case the report steps are too large for the solver to converge // // \Note: The report steps are met in any case // \Note: The sub stepping will require a copy of the state variables if( adaptiveTimeStepping ) { adaptiveTimeStepping->step( timer, *solver, state, well_state, output_writer_ ); } else { // solve for complete report step solver->step(timer.currentStepLength(), state, well_state); } // update the derived geology (transmissibilities, pore volumes, etc) if the // has geology changed for the next report step const int nextTimeStepIdx = timer.currentStepNum() + 1; if (nextTimeStepIdx < timer.numSteps() && events.hasEvent(ScheduleEvents::GEO_MODIFIER, nextTimeStepIdx)) { // bring the contents of the keywords to the current state of the SCHEDULE // section // // TODO (?): handle the parallel case (maybe this works out of the box) DeckConstPtr miniDeck = schedule->getModifierDeck(nextTimeStepIdx); eclipse_state_->applyModifierDeck(miniDeck); geo_.update(grid_, props_, eclipse_state_, gravity_); } // take time that was used to solve system for this reportStep solver_timer.stop(); // accumulate the number of nonlinear and linear Iterations totalNonlinearIterations += solver->nonlinearIterations(); totalLinearIterations += solver->linearIterations(); // Report timing. const double st = solver_timer.secsSinceStart(); // accumulate total time stime += st; if ( terminal_output_ ) { std::cout << "Fully implicit solver took: " << st << " seconds. Total solver time taken: " << stime << " seconds." << std::endl; } if ( output_writer_.output() ) { SimulatorReport step_report; step_report.pressure_time = st; step_report.total_time = step_timer.secsSinceStart(); step_report.reportParam(tstep_os); } // Increment timer, remember well state. ++timer; prev_well_state = well_state; // The well potentials are only computed if they are needed // For now thay are only used to determine default guide rates for group controlled wells if ( is_well_potentials_computed ) { asImpl().computeWellPotentials(wells, well_state, well_potentials); } } // Write final simulation state. output_writer_.writeTimeStep( timer, state, prev_well_state ); // Stop timer and create timing report total_timer.stop(); SimulatorReport report; report.pressure_time = stime; report.transport_time = 0.0; report.total_time = total_timer.secsSinceStart(); report.total_newton_iterations = totalNonlinearIterations; report.total_linear_iterations = totalLinearIterations; return report; }