/// Called once before each time step. /// \param[in] timer simulation timer void prepareStep(const SimulatorTimerInterface& timer) { // update the solution variables in ebos if ( timer.lastStepFailed() ) { ebosSimulator_.model().updateFailed(); } else { ebosSimulator_.model().advanceTimeLevel(); } // set the timestep size and episode index for ebos explicitly. ebos needs to // know the report step/episode index because of timing dependend data // despide the fact that flow uses its own time stepper. (The length of the // episode does not matter, though.) ebosSimulator_.setTime(timer.simulationTimeElapsed()); ebosSimulator_.setTimeStepSize(timer.currentStepLength()); ebosSimulator_.problem().beginTimeStep(); unsigned numDof = ebosSimulator_.model().numGridDof(); wasSwitched_.resize(numDof); std::fill(wasSwitched_.begin(), wasSwitched_.end(), false); if (param_.update_equations_scaling_) { std::cout << "equation scaling not suported yet" << std::endl; //updateEquationsScaling(); } }
void BlackoilMultiSegmentModel<Grid>:: prepareStep(const SimulatorTimerInterface& timer, const ReservoirState& reservoir_state, const WellState& well_state) { const double dt = timer.currentStepLength(); pvdt_ = geo_.poreVolume() / dt; if (active_[Gas]) { updatePrimalVariableFromState(reservoir_state); } const int nw = wellsMultiSegment().size(); if ( !msWellOps().has_multisegment_wells ) { wellModel().segVDt() = V::Zero(nw); return; } const int nseg_total = well_state.numSegments(); std::vector<double> segment_volume; segment_volume.reserve(nseg_total); for (int w = 0; w < nw; ++w) { WellMultiSegmentConstPtr well = wellsMultiSegment()[w]; const std::vector<double>& segment_volume_well = well->segmentVolume(); segment_volume.insert(segment_volume.end(), segment_volume_well.begin(), segment_volume_well.end()); } assert(int(segment_volume.size()) == nseg_total); wellModel().segVDt() = Eigen::Map<V>(segment_volume.data(), nseg_total) / dt; }
void BlackoilOutputWriter:: writeTimeStepSerial(const SimulatorTimerInterface& timer, const SimulationDataContainer& state, const WellState& wellState, const data::Solution& simProps, bool substep) { // Matlab output if( matlabWriter_ ) { matlabWriter_->writeTimeStep( timer, state, wellState, substep ); } // ECL output if ( eclWriter_ ) { const auto& initConfig = eclipseState_.getInitConfig(); if (initConfig.restartRequested() && ((initConfig.getRestartStep()) == (timer.currentStepNum()))) { std::cout << "Skipping restart write in start of step " << timer.currentStepNum() << std::endl; } else { data::Solution combined_sol = simToSolution(state, phaseUsage_); // Get "normal" data (SWAT, PRESSURE, ...) combined_sol.insert(simProps.begin(), simProps.end()); // ... insert "extra" data (KR, VISC, ...) eclWriter_->writeTimeStep(timer.reportStepNum(), substep, timer.simulationTimeElapsed(), combined_sol, wellState.report(phaseUsage_)); } } // write backup file if( backupfile_.is_open() ) { int reportStep = timer.reportStepNum(); int currentTimeStep = timer.currentStepNum(); if( (reportStep == currentTimeStep || // true for SimulatorTimer currentTimeStep == 0 || // true for AdaptiveSimulatorTimer at reportStep timer.done() ) // true for AdaptiveSimulatorTimer at reportStep && lastBackupReportStep_ != reportStep ) // only backup report step once { // store report step lastBackupReportStep_ = reportStep; // write resport step number backupfile_.write( (const char *) &reportStep, sizeof(int) ); try { backupfile_ << state; const WellStateFullyImplicitBlackoil& boWellState = static_cast< const WellStateFullyImplicitBlackoil& > (wellState); backupfile_ << boWellState; } catch ( const std::bad_cast& e ) { } backupfile_ << std::flush; } } // end backup }
void BlackoilOutputWriter:: writeTimeStepWithCellProperties( const SimulatorTimerInterface& timer, const SimulationDataContainer& localState, const WellState& localWellState, const data::Solution& cellData, bool substep) { // VTK output (is parallel if grid is parallel) if( vtkWriter_ ) { vtkWriter_->writeTimeStep( timer, localState, localWellState, false ); } bool isIORank = output_ ; if( parallelOutput_ && parallelOutput_->isParallel() ) { // If this is not the initial write and no substep, then the well // state used in the computation is actually the one of the last // step. We need that well state for the gathering. Otherwise // It an exception with a message like "global state does not // contain well ..." might be thrown. int wellStateStepNumber = ( ! substep && timer.reportStepNum() > 0) ? (timer.reportStepNum() - 1) : timer.reportStepNum(); // collect all solutions to I/O rank isIORank = parallelOutput_->collectToIORank( localState, localWellState, wellStateStepNumber ); } const SimulationDataContainer& state = (parallelOutput_ && parallelOutput_->isParallel() ) ? parallelOutput_->globalReservoirState() : localState; const WellState& wellState = (parallelOutput_ && parallelOutput_->isParallel() ) ? parallelOutput_->globalWellState() : localWellState; // serial output is only done on I/O rank if( isIORank ) { if( asyncOutput_ ) { // dispatch the write call to the extra thread asyncOutput_->dispatch( detail::WriterCall( *this, timer, state, wellState, cellData, substep ) ); } else { // just write the data to disk writeTimeStepSerial( timer, state, wellState, cellData, substep ); } } }
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_() { // reserve memory for sub steps steps_.reserve( 10 ); // set appropriate value for dt_ provideTimeStepEstimate( lastStepTaken ); }
void EclipseWriteRFTHandler::writeTimeStep(const std::string& filename, const ert_ecl_unit_enum ecl_unit, const SimulatorTimerInterface& simulatorTimer, std::vector<WellConstPtr>& wells, EclipseGridConstPtr eclipseGrid, std::vector<double>& pressure, std::vector<double>& swat, std::vector<double>& sgas) { std::vector<ecl_rft_node_type *> rft_nodes; for (std::vector<WellConstPtr>::const_iterator ci = wells.begin(); ci != wells.end(); ++ci) { WellConstPtr well = *ci; if ((well->getRFTActive(simulatorTimer.currentStepNum())) || (well->getPLTActive(simulatorTimer.currentStepNum()))) { ecl_rft_node_type * ecl_node = createEclRFTNode(well, simulatorTimer, eclipseGrid, pressure, swat, sgas); if (well->getPLTActive(simulatorTimer.currentStepNum())) { std::cerr << "PLT not supported, writing RFT data" << std::endl; } rft_nodes.push_back(ecl_node); } } if (rft_nodes.size() > 0) { ecl_rft_file_update(filename.c_str(), rft_nodes.data(), rft_nodes.size(), ecl_unit); } //Cleanup: The ecl_rft_file_update method takes care of freeing the ecl_rft_nodes that it receives. // Each ecl_rft_node is again responsible for freeing it's cells. }
explicit WriterCall( BlackoilOutputWriter& writer, const SimulatorTimerInterface& timer, const SimulationDataContainer& state, const WellState& wellState, const data::Solution& simProps, bool substep ) : writer_( writer ), timer_( timer.clone() ), state_( state ), wellState_( wellState ), simProps_( simProps ), substep_( substep ) { }
SimulatorReport nonlinearIteration(const int iteration, const SimulatorTimerInterface& timer, NonlinearSolverType& nonlinear_solver) { SimulatorReport report; failureReport_ = SimulatorReport(); Dune::Timer perfTimer; perfTimer.start(); if (iteration == 0) { // For each iteration we store in a vector the norms of the residual of // the mass balance for each active phase, the well flux and the well equations. residual_norms_history_.clear(); current_relaxation_ = 1.0; dx_old_ = 0.0; convergence_reports_.push_back({timer.reportStepNum(), timer.currentStepNum(), {}}); convergence_reports_.back().report.reserve(11); } report.total_linearizations = 1; try { report += assembleReservoir(timer, iteration); report.assemble_time += perfTimer.stop(); } catch (...) { report.assemble_time += perfTimer.stop(); failureReport_ += report; // todo (?): make the report an attribute of the class throw; // continue throwing the stick } std::vector<double> residual_norms; perfTimer.reset(); perfTimer.start(); // the step is not considered converged until at least minIter iterations is done { auto convrep = getConvergence(timer, iteration,residual_norms); report.converged = convrep.converged() && iteration > nonlinear_solver.minIter();; ConvergenceReport::Severity severity = convrep.severityOfWorstFailure(); convergence_reports_.back().report.push_back(std::move(convrep)); // Throw if any NaN or too large residual found. if (severity == ConvergenceReport::Severity::NotANumber) { OPM_THROW(Opm::NumericalIssue, "NaN residual found!"); } else if (severity == ConvergenceReport::Severity::TooLarge) { OPM_THROW(Opm::NumericalIssue, "Too large residual found!"); } } // checking whether the group targets are converged if (wellModel().wellCollection().groupControlActive()) { report.converged = report.converged && wellModel().wellCollection().groupTargetConverged(wellModel().wellState().wellRates()); } report.update_time += perfTimer.stop(); residual_norms_history_.push_back(residual_norms); if (!report.converged) { perfTimer.reset(); perfTimer.start(); report.total_newton_iterations = 1; // enable single precision for solvers when dt is smaller then 20 days //residual_.singlePrecision = (unit::convert::to(dt, unit::day) < 20.) ; // Compute the nonlinear update. const int nc = UgGridHelpers::numCells(grid_); BVector x(nc); // apply the Schur compliment of the well model to the reservoir linearized // equations wellModel().linearize(ebosSimulator().model().linearizer().jacobian(), ebosSimulator().model().linearizer().residual()); // Solve the linear system. linear_solve_setup_time_ = 0.0; try { solveJacobianSystem(x); report.linear_solve_setup_time += linear_solve_setup_time_; report.linear_solve_time += perfTimer.stop(); report.total_linear_iterations += linearIterationsLastSolve(); } catch (...) { report.linear_solve_setup_time += linear_solve_setup_time_; report.linear_solve_time += perfTimer.stop(); report.total_linear_iterations += linearIterationsLastSolve(); failureReport_ += report; throw; // re-throw up } perfTimer.reset(); perfTimer.start(); // handling well state update before oscillation treatment is a decision based // on observation to avoid some big performance degeneration under some circumstances. // there is no theorectical explanation which way is better for sure. wellModel().postSolve(x); if (param_.use_update_stabilization_) { // Stabilize the nonlinear update. bool isOscillate = false; bool isStagnate = false; nonlinear_solver.detectOscillations(residual_norms_history_, iteration, isOscillate, isStagnate); if (isOscillate) { current_relaxation_ -= nonlinear_solver.relaxIncrement(); current_relaxation_ = std::max(current_relaxation_, nonlinear_solver.relaxMax()); if (terminalOutputEnabled()) { std::string msg = " Oscillating behavior detected: Relaxation set to " + std::to_string(current_relaxation_); OpmLog::info(msg); } } nonlinear_solver.stabilizeNonlinearUpdate(x, dx_old_, current_relaxation_); } // Apply the update, with considering model-dependent limitations and // chopping of the update. updateSolution(x); report.update_time += perfTimer.stop(); } return report; }
void BlackoilOutputWriter:: restore(SimulatorTimerInterface& timer, BlackoilState& state, WellStateFullyImplicitBlackoil& wellState, const std::string& filename, const int desiredResportStep ) { std::ifstream restorefile( filename.c_str() ); if( restorefile ) { std::cout << "============================================================================"<<std::endl; std::cout << "Restoring from "; if( desiredResportStep < 0 ) { std::cout << "last"; } else { std::cout << desiredResportStep; } std::cout << " report step! filename = " << filename << std::endl << std::endl; int reportStep; restorefile.read( (char *) &reportStep, sizeof(int) ); const int readReportStep = (desiredResportStep < 0) ? std::numeric_limits<int>::max() : desiredResportStep; while( reportStep <= readReportStep && ! timer.done() && restorefile ) { restorefile >> state; restorefile >> wellState; // No per cell data is written for restore steps, but will be // for subsequent steps, when we have started simulating writeTimeStepWithoutCellProperties( timer, state, wellState ); // some output std::cout << "Restored step " << timer.reportStepNum() << " at day " << unit::convert::to(timer.simulationTimeElapsed(),unit::day) << std::endl; if( readReportStep == reportStep ) { break; } // if the stream is not valid anymore we just use the last state read if( ! restorefile ) { std::cerr << "Reached EOF, using last state read!" << std::endl; break; } // try to read next report step restorefile.read( (char *) &reportStep, sizeof(int) ); // if read failed, exit loop if( ! restorefile ) { break; } // next step timer.advance(); if( timer.reportStepNum() != reportStep ) { break; } } } else {