diff --git a/flowexperimental/flowexp.hpp b/flowexperimental/flowexp.hpp index 25d25a4c06e..0fbd12650bc 100644 --- a/flowexperimental/flowexp.hpp +++ b/flowexperimental/flowexp.hpp @@ -160,7 +160,6 @@ class FlowExpProblem : public FlowProblemBlackoil //, public FvBaseProb Parameters::Hide>(); Parameters::Hide>(); Parameters::Hide>(); - Parameters::Hide>(); Parameters::Hide(); Parameters::Hide(); Parameters::Hide>(); diff --git a/opm/simulators/flow/BlackoilModelParameters.cpp b/opm/simulators/flow/BlackoilModelParameters.cpp index 1e05f78a23c..5a3b4499171 100644 --- a/opm/simulators/flow/BlackoilModelParameters.cpp +++ b/opm/simulators/flow/BlackoilModelParameters.cpp @@ -56,10 +56,14 @@ BlackoilModelParameters::BlackoilModelParameters() tolerance_max_drs_ = Parameters::Get>(); tolerance_max_drv_ = Parameters::Get>(); tolerance_wells_ = Parameters::Get>(); - tolerance_well_control_ = Parameters::Get>(); + tolerance_wells_stopped_factor_ = Parameters::Get>(); + tolerance_wells_dynamic_thp_factor_ = Parameters::Get>(); max_welleq_iter_ = Parameters::Get(); use_multisegment_well_ = Parameters::Get(); tolerance_pressure_ms_wells_ = Parameters::Get>(); + tolerance_well_bhp_eq_ = Parameters::Get>(); + tolerance_well_thp_eq_ = Parameters::Get>(); + tolerance_well_grup_eq_ = Parameters::Get>(); relaxed_tolerance_flow_well_ = Parameters::Get>(); relaxed_tolerance_pressure_ms_well_ = Parameters::Get>(); max_pressure_change_ms_wells_ = Parameters::Get>(); @@ -70,6 +74,8 @@ BlackoilModelParameters::BlackoilModelParameters() max_niter_inner_well_iter_ = Parameters::Get(); shut_unsolvable_wells_ = Parameters::Get(); max_inner_iter_wells_ = Parameters::Get(); + min_iter_after_switch_wells_ = Parameters::Get(); + min_iter_after_switch_ms_wells_ = Parameters::Get(); max_well_status_switch_inner_iter_ = Parameters::Get(); max_well_status_switch_ = Parameters::Get(); maxSinglePrecisionTimeStep_ = Parameters::Get>() * 24 * 60 * 60; @@ -185,8 +191,12 @@ void BlackoilModelParameters::registerParameters() "of residual tolerances. Use with care!"); Parameters::Register> ("Well convergence tolerance"); - Parameters::Register> - ("Tolerance for the well control equations"); + Parameters::Register> + ("Multiplier applied to the well convergence tolerance for stopped wells " + "and wells under a zero rate target"); + Parameters::Register> + ("Multiplier applied to the well convergence tolerance for wells on a " + "dynamic THP limit, to help network convergence"); Parameters::Register ("Maximum number of iterations to determine solution the well equations"); Parameters::Register @@ -198,6 +208,12 @@ void BlackoilModelParameters::registerParameters() "or 'per-connection' (one linear tubing, a segment per connection)"); Parameters::Register> ("Tolerance for the pressure equations for multi-segment wells"); + Parameters::Register> + ("Tolerance for the BHP control equation residual of standard wells [Pa]"); + Parameters::Register> + ("Tolerance for the THP control equation residual of standard wells [Pa]"); + Parameters::Register> + ("Tolerance for the group-control equation residual of standard wells [m3/s]"); Parameters::Register> ("Relaxed tolerance for the well flow residual"); Parameters::Register> @@ -217,6 +233,12 @@ void BlackoilModelParameters::registerParameters() ("Shut unsolvable wells"); Parameters::Register ("Maximum number of inner iterations for standard wells"); + Parameters::Register + ("Inner iterations forced between two control switches of a standard well. " + "Values <= 1 let the inner solve cycle between controls."); + Parameters::Register + ("Inner iterations forced between two control switches of a multi-segment well. " + "Values <= 1 let the inner solve cycle between controls."); Parameters::Register ("Maximum number of status switching (stop<->open) for a well during inner iterations."); Parameters::Register @@ -230,7 +252,9 @@ void BlackoilModelParameters::registerParameters() "arithmetic can be used solving for the linear systems of equations"); Parameters::Register ("Minimum number of Newton iterations before relaxed tolerances " - "can be used for the CNV convergence criterion"); + "can be used for the CNV convergence criterion. " + "Default -1 means that the relaxed tolerance is used when maximum " + "number of Newton iterations are reached."); Parameters::Register ("Minimum number of Newton iterations before relaxed tolerances " "can be used for the MB convergence criterion. " diff --git a/opm/simulators/flow/BlackoilModelParameters.hpp b/opm/simulators/flow/BlackoilModelParameters.hpp index caadd0fc100..6b10b231bdf 100644 --- a/opm/simulators/flow/BlackoilModelParameters.hpp +++ b/opm/simulators/flow/BlackoilModelParameters.hpp @@ -91,7 +91,10 @@ template struct ToleranceWells { static constexpr Scalar value = 1e-4; }; template -struct ToleranceWellControl { static constexpr Scalar value = 1e-7; }; +struct ToleranceWellsStoppedFactor { static constexpr Scalar value = 1e-4; }; + +template +struct ToleranceWellsDynamicThpFactor { static constexpr Scalar value = 1e-1; }; struct MaxWelleqIter { static constexpr int value = 30; }; @@ -116,6 +119,14 @@ struct ConvertToMultisegmentWell { static constexpr auto value = "none"; }; template struct TolerancePressureMsWells { static constexpr Scalar value = 0.01*1e5; }; +/// Control-equation tolerances for standard wells. Defaults reproduce the values that +/// used to be hardcoded at the call site; MSW has had these as parameters all along. +template +struct ToleranceWellBhpEq { static constexpr Scalar value = 1.0e3; }; +template +struct ToleranceWellThpEq { static constexpr Scalar value = 1.0e4; }; +template +struct ToleranceWellGrupEq { static constexpr Scalar value = 1.0e-6; }; template struct MaxPressureChangeMsWells { static constexpr Scalar value = 10*1e5; }; @@ -123,6 +134,8 @@ struct MaxPressureChangeMsWells { static constexpr Scalar value = 10*1e5; }; struct MaxNewtonIterationsWithInnerWellIterations { static constexpr int value = 99; }; struct MaxInnerIterMsWells { static constexpr int value = 100; }; struct MaxInnerIterWells { static constexpr int value = 50; }; +struct MinIterAfterSwitchWells { static constexpr int value = 4; }; +struct MinIterAfterSwitchMsWells { static constexpr int value = 3; }; struct MaxWellStatusSwitchInInnerIterWells { static constexpr int value = 99; }; struct MaxWellStatusSwitchForWells { static constexpr int value = 99; }; struct ShutUnsolvableWells { static constexpr bool value = true; }; @@ -247,11 +260,16 @@ struct BlackoilModelParameters Scalar tolerance_max_drv_; /// Well convergence tolerance. Scalar tolerance_wells_; - /// Tolerance for the well control equations - // TODO: it might need to distinguish between rate control and pressure control later - Scalar tolerance_well_control_; + /// Multipliers applied to tolerance_wells_ for stopped/zero-rate wells and for + /// wells on a dynamic THP limit (the latter to help network convergence). + Scalar tolerance_wells_stopped_factor_; + Scalar tolerance_wells_dynamic_thp_factor_; /// Tolerance for the pressure equations for multisegment wells Scalar tolerance_pressure_ms_wells_; + /// standard-well control-equation tolerances (BHP/THP in Pa, GRUP in m3/s) + Scalar tolerance_well_bhp_eq_; + Scalar tolerance_well_thp_eq_; + Scalar tolerance_well_grup_eq_; /// Relaxed tolerance for for the well flow residual Scalar relaxed_tolerance_flow_well_; @@ -282,6 +300,11 @@ struct BlackoilModelParameters /// Maximum inner iteration number for standard wells int max_inner_iter_wells_; + /// Inner iterations forced between two control switches of the same well. + /// Values <= 1 are known to let the inner solve cycle between controls. + int min_iter_after_switch_wells_; + int min_iter_after_switch_ms_wells_; + /// Maximum iteration number of the well equation solution int max_welleq_iter_; diff --git a/opm/simulators/flow/NonlinearSolver.cpp b/opm/simulators/flow/NonlinearSolver.cpp index c2a194c30ea..130df95abab 100644 --- a/opm/simulators/flow/NonlinearSolver.cpp +++ b/opm/simulators/flow/NonlinearSolver.cpp @@ -146,6 +146,8 @@ NonlinearSolverParameters() // overload with given parameters relaxMax_ = Parameters::Get>(); + relaxIncrement_ = Parameters::Get>(); + relaxRelTol_ = Parameters::Get>(); const auto& relaxationTypeString = Parameters::Get(); if (relaxationTypeString == "dampen") { @@ -175,6 +177,12 @@ registerParameters() { Parameters::Register> ("The maximum relaxation factor of a Newton iteration"); + Parameters::Register> + ("Amount by which the Newton relaxation factor is reduced each time an " + "oscillation is detected"); + Parameters::Register> + ("Relative tolerance used to classify a residual history as oscillating " + "rather than stagnating"); Parameters::Register ("The type of relaxation used by Newton method. Valid options are: dampen or sor"); } diff --git a/opm/simulators/flow/NonlinearSolver.hpp b/opm/simulators/flow/NonlinearSolver.hpp index 5d51e634866..ddc36c63505 100644 --- a/opm/simulators/flow/NonlinearSolver.hpp +++ b/opm/simulators/flow/NonlinearSolver.hpp @@ -45,6 +45,12 @@ namespace Opm::Parameters { template struct NewtonMaxRelax { static constexpr Scalar value = 0.5; }; +template +struct NewtonRelaxIncrement { static constexpr Scalar value = 0.1; }; + +template +struct NewtonRelaxRelTol { static constexpr Scalar value = 0.2; }; + struct NewtonRelaxationType { static constexpr auto value = "dampen"; }; } // namespace Opm::Parameters diff --git a/opm/simulators/flow/NonlinearSystemBlackOilReservoir_impl.hpp b/opm/simulators/flow/NonlinearSystemBlackOilReservoir_impl.hpp index e39e61b4df0..ea7af498562 100644 --- a/opm/simulators/flow/NonlinearSystemBlackOilReservoir_impl.hpp +++ b/opm/simulators/flow/NonlinearSystemBlackOilReservoir_impl.hpp @@ -810,8 +810,8 @@ getReservoirConvergence(const double reportTime, || relax_iter_cnv || relax_dsol_cnv; - // Ensure that CNV convergence criteria is met when max. - // solution change tolerances have been fulfilled + // The solution-change criterion overrides CNV entirely rather than merely relaxing it: + // 1e20 is never exceeded, so a converged solution update accepts any CNV. Scalar tolerance_cnv_relaxed = relax_dsol_cnv ? 1e20 : this->param_.tolerance_cnv_relaxed_; const auto tol_cnv = use_relaxed_cnv ? tolerance_cnv_relaxed : this->param_.tolerance_cnv_; diff --git a/opm/simulators/wells/MultisegmentWell_impl.hpp b/opm/simulators/wells/MultisegmentWell_impl.hpp index 7c2c6a4d90b..775276f609d 100644 --- a/opm/simulators/wells/MultisegmentWell_impl.hpp +++ b/opm/simulators/wells/MultisegmentWell_impl.hpp @@ -1705,7 +1705,7 @@ namespace Opm // Always take a few (more than one) iterations after a switch before allowing a new switch // The optimal number here is subject to further investigation, but it has been observerved // that unless this number is >1, we may get stuck in a cycle - const int min_its_after_switch = 3; + const int min_its_after_switch = this->param_.min_iter_after_switch_ms_wells_; // We also want to restrict the number of status switches to avoid oscillation between STOP<->OPEN const int max_status_switch = this->param_.max_well_status_switch_inner_iter_; int its_since_last_switch = min_its_after_switch; diff --git a/opm/simulators/wells/StandardWellEval.cpp b/opm/simulators/wells/StandardWellEval.cpp index f97649ed701..f807eb47ffd 100644 --- a/opm/simulators/wells/StandardWellEval.cpp +++ b/opm/simulators/wells/StandardWellEval.cpp @@ -157,6 +157,9 @@ getWellConvergence(const WellState& well_state, const std::vector& B_avg, const Scalar maxResidualAllowed, const Scalar tol_wells, + const Scalar tol_bhp_eq, + const Scalar tol_thp_eq, + const Scalar tol_grup_eq, const Scalar relaxed_tolerance_flow, const bool relax_tolerance, const bool well_is_stopped, @@ -208,7 +211,7 @@ getWellConvergence(const WellState& well_state, WellConvergence(baseif_). checkConvergenceControlEq(well_state, - {1.e3, 1.e4, 1.e-4, 1.e-6, maxResidualAllowed}, + {tol_bhp_eq, tol_thp_eq, tol_wells, tol_grup_eq, maxResidualAllowed}, std::abs(this->linSys_.residual()[0][Bhp]), well_is_stopped, report, diff --git a/opm/simulators/wells/StandardWellEval.hpp b/opm/simulators/wells/StandardWellEval.hpp index 371f2e9a580..abd20275307 100644 --- a/opm/simulators/wells/StandardWellEval.hpp +++ b/opm/simulators/wells/StandardWellEval.hpp @@ -101,6 +101,9 @@ class StandardWellEval const std::vector& B_avg, const Scalar maxResidualAllowed, const Scalar tol_wells, + const Scalar tol_bhp_eq, + const Scalar tol_thp_eq, + const Scalar tol_grup_eq, const Scalar relaxed_tolerance_flow, const bool relax_tolerance, const bool well_is_stopped, diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index de9084e5a4b..cbe9c19a4d8 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -1238,9 +1238,9 @@ namespace Opm auto& deferred_logger = groupStateHelper.deferredLogger(); Scalar tol_wells = this->param_.tolerance_wells_; // use stricter tolerance for stopped wells and wells under zero rate target control. - constexpr Scalar stopped_factor = 1.e-4; + const Scalar stopped_factor = this->param_.tolerance_wells_stopped_factor_; // use stricter tolerance for dynamic thp to ameliorate network convergence - constexpr Scalar dynamic_thp_factor = 1.e-1; + const Scalar dynamic_thp_factor = this->param_.tolerance_wells_dynamic_thp_factor_; if (this->stoppedOrZeroRateTarget(groupStateHelper)) { tol_wells = tol_wells*stopped_factor; } else if (this->getDynamicThpLimit()) { @@ -1252,6 +1252,9 @@ namespace Opm B_avg, this->param_.max_residual_allowed_, tol_wells, + this->param_.tolerance_well_bhp_eq_, + this->param_.tolerance_well_thp_eq_, + this->param_.tolerance_well_grup_eq_, this->param_.relaxed_tolerance_flow_well_, relax_tolerance, this->wellIsStopped(), @@ -2479,7 +2482,7 @@ namespace Opm // Always take a few (more than one) iterations after a switch before allowing a new switch // The optimal number here is subject to further investigation, but it has been observerved // that unless this number is >1, we may get stuck in a cycle - constexpr int min_its_after_switch = 4; + const int min_its_after_switch = this->param_.min_iter_after_switch_wells_; // We also want to restrict the number of status switches to avoid oscillation between STOP<->OPEN const int max_status_switch = this->param_.max_well_status_switch_inner_iter_; int its_since_last_switch = min_its_after_switch;