mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
various improvement and bug fixing.
fixed one invalid memory reading of perforation_segment_depth_diffs_ in computePerfRate, which caused different results for different running.
This commit is contained in:
parent
1a7b5571b6
commit
6a4260c264
@ -54,6 +54,7 @@ namespace Opm
|
|||||||
max_welleq_iter_ = param.getDefault("max_welleq_iter", max_welleq_iter_);
|
max_welleq_iter_ = param.getDefault("max_welleq_iter", max_welleq_iter_);
|
||||||
max_pressure_change_ms_wells_ = param.getDefault("max_pressure_change_ms_wells", max_pressure_change_ms_wells_);
|
max_pressure_change_ms_wells_ = param.getDefault("max_pressure_change_ms_wells", max_pressure_change_ms_wells_);
|
||||||
use_inner_iterations_ms_wells_ = param.getDefault("use_inner_iterations_ms_wells", use_inner_iterations_ms_wells_);
|
use_inner_iterations_ms_wells_ = param.getDefault("use_inner_iterations_ms_wells", use_inner_iterations_ms_wells_);
|
||||||
|
max_inner_iter_ms_wells_ = param.getDefault("max_inner_iter_ms_wells", max_inner_iter_ms_wells_);
|
||||||
maxSinglePrecisionTimeStep_ = unit::convert::from(
|
maxSinglePrecisionTimeStep_ = unit::convert::from(
|
||||||
param.getDefault("max_single_precision_days", unit::convert::to( maxSinglePrecisionTimeStep_, unit::day) ), unit::day );
|
param.getDefault("max_single_precision_days", unit::convert::to( maxSinglePrecisionTimeStep_, unit::day) ), unit::day );
|
||||||
max_strict_iter_ = param.getDefault("max_strict_iter",8);
|
max_strict_iter_ = param.getDefault("max_strict_iter",8);
|
||||||
@ -80,10 +81,11 @@ namespace Opm
|
|||||||
tolerance_cnv_ = 1.0e-2;
|
tolerance_cnv_ = 1.0e-2;
|
||||||
tolerance_wells_ = 1.0e-4;
|
tolerance_wells_ = 1.0e-4;
|
||||||
tolerance_well_control_ = 1.0e-7;
|
tolerance_well_control_ = 1.0e-7;
|
||||||
tolerance_pressure_ms_wells_ = 100.0;
|
tolerance_pressure_ms_wells_ = 1000.0; // 0.01 bar
|
||||||
max_welleq_iter_ = 15;
|
max_welleq_iter_ = 15;
|
||||||
max_pressure_change_ms_wells_ = 200000.; // 2.0 bar
|
max_pressure_change_ms_wells_ = 200000.; // 2.0 bar
|
||||||
use_inner_iterations_ms_wells_ = true;
|
use_inner_iterations_ms_wells_ = true;
|
||||||
|
max_inner_iter_ms_wells_ = 10;
|
||||||
maxSinglePrecisionTimeStep_ = unit::convert::from( 20.0, unit::day );
|
maxSinglePrecisionTimeStep_ = unit::convert::from( 20.0, unit::day );
|
||||||
solve_welleq_initially_ = true;
|
solve_welleq_initially_ = true;
|
||||||
update_equations_scaling_ = false;
|
update_equations_scaling_ = false;
|
||||||
|
@ -59,6 +59,9 @@ namespace Opm
|
|||||||
/// Whether to use inner iterations for ms wells
|
/// Whether to use inner iterations for ms wells
|
||||||
bool use_inner_iterations_ms_wells_;
|
bool use_inner_iterations_ms_wells_;
|
||||||
|
|
||||||
|
/// Maximum inner iteration number for ms wells
|
||||||
|
int max_inner_iter_ms_wells_;
|
||||||
|
|
||||||
/// Maximum iteration number of the well equation solution
|
/// Maximum iteration number of the well equation solution
|
||||||
int max_welleq_iter_;
|
int max_welleq_iter_;
|
||||||
|
|
||||||
|
@ -190,6 +190,11 @@ namespace Opm {
|
|||||||
if (param_.solve_welleq_initially_ && iterationIdx == 0) {
|
if (param_.solve_welleq_initially_ && iterationIdx == 0) {
|
||||||
// solve the well equations as a pre-processing step
|
// solve the well equations as a pre-processing step
|
||||||
report = solveWellEq(ebosSimulator, dt, well_state);
|
report = solveWellEq(ebosSimulator, dt, well_state);
|
||||||
|
if (report.converged) {
|
||||||
|
std::cout << " solveWellEq converged ! " << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << " solveWellEq does not get converged ! " << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assembleWellEq(ebosSimulator, dt, well_state, false);
|
assembleWellEq(ebosSimulator, dt, well_state, false);
|
||||||
|
|
||||||
|
@ -264,6 +264,11 @@ namespace Opm
|
|||||||
const BlackoilModelParameters& param,
|
const BlackoilModelParameters& param,
|
||||||
WellState& well_state) const;
|
WellState& well_state) const;
|
||||||
|
|
||||||
|
// initialize the segment rates with well rates
|
||||||
|
// when there is no more accurate way to initialize the segment rates, we initialize
|
||||||
|
// the segment rates based on well rates with a simple strategy
|
||||||
|
void initSegmentRatesWithWellRates(WellState& well_state) const;
|
||||||
|
|
||||||
// computing the accumulation term for later use in well mass equations
|
// computing the accumulation term for later use in well mass equations
|
||||||
void computeInitialComposition();
|
void computeInitialComposition();
|
||||||
|
|
||||||
|
@ -317,6 +317,9 @@ namespace Opm
|
|||||||
well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] = 0.;
|
well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] = 0.;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initSegmentRatesWithWellRates(well_state);
|
||||||
|
|
||||||
} else if (well_type_ == PRODUCER) {
|
} else if (well_type_ == PRODUCER) {
|
||||||
// update the rates of phases under control based on the target,
|
// update the rates of phases under control based on the target,
|
||||||
// and also update rates of phases not under control to keep the rate ratio,
|
// and also update rates of phases not under control to keep the rate ratio,
|
||||||
@ -333,8 +336,14 @@ namespace Opm
|
|||||||
|
|
||||||
for (int phase = 0; phase < number_of_phases_; ++phase) {
|
for (int phase = 0; phase < number_of_phases_; ++phase) {
|
||||||
well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] *= scaling_factor;
|
well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] *= scaling_factor;
|
||||||
|
|
||||||
|
// scaling the segment rates with the same way with well rates
|
||||||
|
const int top_segment_location = well_state.topSegmentLocation(index_of_well_);
|
||||||
|
for (int seg = 0; seg < numberOfSegments(); ++seg) {
|
||||||
|
well_state.segRates()[number_of_phases_ * (seg + top_segment_location) + phase] *= scaling_factor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else { // scaling factor is not well defied when original_rates_under_phase_control is zero
|
} else { // scaling factor is not well defined when original_rates_under_phase_control is zero
|
||||||
// separating targets equally between phases under control
|
// separating targets equally between phases under control
|
||||||
const double target_rate_divided = target / numPhasesWithTargetsUnderThisControl;
|
const double target_rate_divided = target / numPhasesWithTargetsUnderThisControl;
|
||||||
for (int phase = 0; phase < number_of_phases_; ++phase) {
|
for (int phase = 0; phase < number_of_phases_; ++phase) {
|
||||||
@ -345,37 +354,10 @@ namespace Opm
|
|||||||
well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] = target_rate_divided;
|
well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] = target_rate_divided;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
initSegmentRatesWithWellRates(well_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the perforation rates and then segment rates
|
|
||||||
// TODO: it is something different from the StandardWell. In StandardWell, we do not update the perforation rates
|
|
||||||
// when we update the well rates to the target rates. Here, we update the perforation rates so that we can update the
|
|
||||||
// segment rates. This will make the calculation of the explicit quantities different, which relies on the perforation rates
|
|
||||||
// from the last time step. Maybe the better way to do this is to scale the perforation rates based on the well rates
|
|
||||||
// update, so that the compositon inside the wellbore will be preserved.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// It is just difficult to initialize the segment rates without initializing the perforation rates.
|
|
||||||
{
|
|
||||||
for (int phase = 0; phase < number_of_phases_; ++phase) {
|
|
||||||
const double perf_phaserate = well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] / number_of_perforations_;
|
|
||||||
for (int perf = 0; perf < number_of_perforations_; ++perf) {
|
|
||||||
well_state.perfPhaseRates()[number_of_phases_ * (first_perf_ + perf) + phase] = perf_phaserate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<double> perforation_rates(well_state.perfPhaseRates().begin() + number_of_phases_ * first_perf_,
|
|
||||||
well_state.perfPhaseRates().begin() + number_of_phases_ * (first_perf_ + number_of_perforations_) );
|
|
||||||
std::vector<double> segment_rates;
|
|
||||||
WellState::calculateSegmentRates(segment_inlets_, segment_perforations_, perforation_rates, number_of_phases_,
|
|
||||||
0 /* top segment */, segment_rates);
|
|
||||||
const int top_segment_location = well_state.topSegmentLocation(index_of_well_);
|
|
||||||
std::copy(segment_rates.begin(), segment_rates.end(),
|
|
||||||
well_state.segRates().begin() + number_of_phases_ * top_segment_location );
|
|
||||||
// we need to check the top segment rates should be same with the well rates
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
} // end of switch
|
} // end of switch
|
||||||
|
|
||||||
@ -386,6 +368,34 @@ namespace Opm
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename TypeTag>
|
||||||
|
void
|
||||||
|
MultisegmentWell<TypeTag>::
|
||||||
|
initSegmentRatesWithWellRates(WellState& well_state) const
|
||||||
|
{
|
||||||
|
for (int phase = 0; phase < number_of_phases_; ++phase) {
|
||||||
|
const double perf_phaserate = well_state.wellRates()[number_of_phases_ * index_of_well_ + phase] / number_of_perforations_;
|
||||||
|
for (int perf = 0; perf < number_of_perforations_; ++perf) {
|
||||||
|
well_state.perfPhaseRates()[number_of_phases_ * (first_perf_ + perf) + phase] = perf_phaserate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<double> perforation_rates(well_state.perfPhaseRates().begin() + number_of_phases_ * first_perf_,
|
||||||
|
well_state.perfPhaseRates().begin() +
|
||||||
|
number_of_phases_ * (first_perf_ + number_of_perforations_) );
|
||||||
|
std::vector<double> segment_rates;
|
||||||
|
WellState::calculateSegmentRates(segment_inlets_, segment_perforations_, perforation_rates, number_of_phases_,
|
||||||
|
0, segment_rates);
|
||||||
|
const int top_segment_location = well_state.topSegmentLocation(index_of_well_);
|
||||||
|
std::copy(segment_rates.begin(), segment_rates.end(),
|
||||||
|
well_state.segRates().begin() + number_of_phases_ * top_segment_location );
|
||||||
|
// we need to check the top segment rates should be same with the well rates
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename TypeTag>
|
template <typename TypeTag>
|
||||||
typename MultisegmentWell<TypeTag>::ConvergenceReport
|
typename MultisegmentWell<TypeTag>::ConvergenceReport
|
||||||
MultisegmentWell<TypeTag>::
|
MultisegmentWell<TypeTag>::
|
||||||
@ -450,6 +460,8 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << " maximum_residual " << maximum_residual[0] << " " << maximum_residual[1] << " " << maximum_residual[2] << " " << maximum_residual[3] << std::endl;
|
||||||
|
|
||||||
if ( !(report.nan_residual_found || report.too_large_residual_found) ) { // no abnormal residual value found
|
if ( !(report.nan_residual_found || report.too_large_residual_found) ) { // no abnormal residual value found
|
||||||
// check convergence for flux residuals
|
// check convergence for flux residuals
|
||||||
for ( int comp_idx = 0; comp_idx < numComponents(); ++comp_idx)
|
for ( int comp_idx = 0; comp_idx < numComponents(); ++comp_idx)
|
||||||
@ -723,7 +735,7 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
const bool use_inner_iterations = param.use_inner_iterations_ms_wells_;
|
const bool use_inner_iterations = param.use_inner_iterations_ms_wells_;
|
||||||
|
|
||||||
const double relaxation_factor = use_inner_iterations ? 0.4 : 1.0;
|
const double relaxation_factor = use_inner_iterations ? 0.2 : 1.0;
|
||||||
|
|
||||||
// I guess the following can also be applied to the segmnet pressure
|
// I guess the following can also be applied to the segmnet pressure
|
||||||
// maybe better to give it a different name
|
// maybe better to give it a different name
|
||||||
@ -752,7 +764,7 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
const int sign = dwells[seg][SPres] > 0.? 1 : -1;
|
const int sign = dwells[seg][SPres] > 0.? 1 : -1;
|
||||||
const double current_pressure = old_primary_variables[seg][SPres];
|
const double current_pressure = old_primary_variables[seg][SPres];
|
||||||
const double dx_limited = sign * std::min(std::abs(dwells[seg][SPres]), max_pressure_change);
|
const double dx_limited = sign * std::min(std::abs(dwells[seg][SPres]), relaxation_factor * max_pressure_change);
|
||||||
primary_variables_[seg][SPres] = old_primary_variables[seg][SPres] - dx_limited;
|
primary_variables_[seg][SPres] = old_primary_variables[seg][SPres] - dx_limited;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,7 +988,7 @@ namespace Opm
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// pressure difference between the segment and the perforation
|
// pressure difference between the segment and the perforation
|
||||||
const EvalWell perf_seg_press_diff = gravity_ * segment_densities_[seg] * perforation_segment_depth_diffs_[seg];
|
const EvalWell perf_seg_press_diff = gravity_ * segment_densities_[seg] * perforation_segment_depth_diffs_[perf];
|
||||||
// pressure difference between the perforation and the grid cell
|
// pressure difference between the perforation and the grid cell
|
||||||
const double cell_perf_press_diff = cell_perforation_pressure_diffs_[perf];
|
const double cell_perf_press_diff = cell_perforation_pressure_diffs_[perf];
|
||||||
|
|
||||||
@ -1774,16 +1786,15 @@ namespace Opm
|
|||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state)
|
WellState& well_state)
|
||||||
{
|
{
|
||||||
std::cout << " beginning iterateWellEquations " << std::endl;
|
|
||||||
// basically, it only iterate through the equations.
|
// basically, it only iterate through the equations.
|
||||||
// we update the primary variables
|
// we update the primary variables
|
||||||
// if converged, we can update the well_state.
|
// if converged, we can update the well_state.
|
||||||
// the function updateWellState() should have a flag to show
|
// the function updateWellState() should have a flag to show
|
||||||
// if we will update the well state.
|
// if we will update the well state.
|
||||||
// assembleWellEq(
|
const int max_iter_number = param.max_inner_iter_ms_wells_;
|
||||||
const int max_iter_number = 3;
|
|
||||||
int it = 0;
|
int it = 0;
|
||||||
for (; it < max_iter_number; ++it) {
|
for (; it < max_iter_number; ++it) {
|
||||||
|
std::cout << " iterateWellEquations it " << it << std::endl;
|
||||||
|
|
||||||
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state, true);
|
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state, true);
|
||||||
|
|
||||||
@ -1791,8 +1802,9 @@ namespace Opm
|
|||||||
|
|
||||||
// TODO: use these small values for now, not intend to reach the convergence
|
// TODO: use these small values for now, not intend to reach the convergence
|
||||||
// in this stage, but, should we?
|
// in this stage, but, should we?
|
||||||
|
// We should try to avoid hard-code values in the code.
|
||||||
// If we want to use the real one, we need to find a way to get them.
|
// If we want to use the real one, we need to find a way to get them.
|
||||||
const std::vector<double> B {0.1, 0.1, 0.001};
|
const std::vector<double> B {0.5, 0.5, 0.005};
|
||||||
|
|
||||||
const ConvergenceReport report = getWellConvergence(ebosSimulator, B, param);
|
const ConvergenceReport report = getWellConvergence(ebosSimulator, B, param);
|
||||||
|
|
||||||
@ -1805,10 +1817,6 @@ namespace Opm
|
|||||||
|
|
||||||
initPrimaryVariablesEvaluation();
|
initPrimaryVariablesEvaluation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it >= max_iter_number) {
|
|
||||||
std::cout << " the iterateWellEquations did not converged " << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user