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 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. }
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; }