mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
removing updateWellStateWithTarget from StandardWellsDense
and also fixing the assertion error related to disabling the residual() function of StandardWellsDense.
This commit is contained in:
parent
8130b32791
commit
a02a0d8599
@ -763,7 +763,7 @@ namespace Opm {
|
||||
std::vector< Scalar >& R_sum,
|
||||
std::vector< Scalar >& maxCoeff,
|
||||
std::vector< Scalar >& B_avg,
|
||||
std::vector< Scalar >& maxNormWell )
|
||||
std::vector< Scalar >& maxNormWell)
|
||||
{
|
||||
// Compute total pore volume (use only owned entries)
|
||||
double pvSum = pvSumLocal;
|
||||
@ -893,15 +893,15 @@ namespace Opm {
|
||||
}
|
||||
|
||||
// compute maximum of local well residuals
|
||||
const Vector& wellResidual = wellModel().residual();
|
||||
const int nw = wellResidual.size() / numComp;
|
||||
assert(nw * numComp == int(wellResidual.size()));
|
||||
for( int compIdx = 0; compIdx < numComp; ++compIdx )
|
||||
// const Vector& wellResidual = wellModel().residual();
|
||||
// const int nw = wellResidual.size() / numComp;
|
||||
// assert(nw * numComp == int(wellResidual.size()));
|
||||
/* for( int compIdx = 0; compIdx < numComp; ++compIdx )
|
||||
{
|
||||
for ( int w = 0; w < nw; ++w ) {
|
||||
maxNormWell[compIdx] = std::max(maxNormWell[compIdx], std::abs(wellResidual[nw*compIdx + w]));
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
// compute global sum and max of quantities
|
||||
const double pvSum = convergenceReduction(grid_.comm(), pvSumLocal,
|
||||
|
@ -355,11 +355,6 @@ enum WellVariablePositions {
|
||||
const WellState& well_state,
|
||||
const WellMapEntryType& map_entry) const;
|
||||
|
||||
void updateWellStateWithTarget(const WellControls* wc,
|
||||
const int current,
|
||||
const int well_index,
|
||||
WellState& xw) const;
|
||||
|
||||
double wsolvent(const int well_index) const;
|
||||
|
||||
double wpolymer(const int well_index) const;
|
||||
|
@ -1004,7 +1004,7 @@ namespace Opm {
|
||||
WellControls* wc = wells().ctrls[w];
|
||||
const int control = well_controls_get_current(wc);
|
||||
well_state.currentControls()[w] = control;
|
||||
updateWellStateWithTarget(wc, control, w, well_state);
|
||||
well_container_[w]->updateWellStateWithTarget(control, well_state);
|
||||
|
||||
// The wells are not considered to be newly added
|
||||
// for next time step
|
||||
@ -1374,229 +1374,6 @@ namespace Opm {
|
||||
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
StandardWellsDense<TypeTag>::
|
||||
updateWellStateWithTarget(const WellControls* wc,
|
||||
const int current,
|
||||
const int well_index,
|
||||
WellState& xw) const
|
||||
{
|
||||
// number of phases
|
||||
const int np = wells().number_of_phases;
|
||||
// Updating well state and primary variables.
|
||||
// Target values are used as initial conditions for BHP, THP, and SURFACE_RATE
|
||||
const double target = well_controls_iget_target(wc, current);
|
||||
const double* distr = well_controls_iget_distr(wc, current);
|
||||
switch (well_controls_iget_type(wc, current)) {
|
||||
case BHP:
|
||||
xw.bhp()[well_index] = target;
|
||||
// TODO: similar to the way below to handle THP
|
||||
// we should not something related to thp here when there is thp constraint
|
||||
break;
|
||||
|
||||
case THP: {
|
||||
xw.thp()[well_index] = target;
|
||||
|
||||
double aqua = 0.0;
|
||||
double liquid = 0.0;
|
||||
double vapour = 0.0;
|
||||
|
||||
const Opm::PhaseUsage& pu = phase_usage_;
|
||||
|
||||
if (active_[ Water ]) {
|
||||
aqua = xw.wellRates()[well_index*np + pu.phase_pos[ Water ] ];
|
||||
}
|
||||
if (active_[ Oil ]) {
|
||||
liquid = xw.wellRates()[well_index*np + pu.phase_pos[ Oil ] ];
|
||||
}
|
||||
if (active_[ Gas ]) {
|
||||
vapour = xw.wellRates()[well_index*np + pu.phase_pos[ Gas ] ];
|
||||
}
|
||||
|
||||
const int vfp = well_controls_iget_vfp(wc, current);
|
||||
const double& thp = well_controls_iget_target(wc, current);
|
||||
const double& alq = well_controls_iget_alq(wc, current);
|
||||
|
||||
//Set *BHP* target by calculating bhp from THP
|
||||
const WellType& well_type = wells().type[well_index];
|
||||
|
||||
// pick the density in the top layer
|
||||
const int perf = wells().well_connpos[well_index];
|
||||
const double rho = well_perforation_densities_[perf];
|
||||
|
||||
if (well_type == INJECTOR) {
|
||||
const double dp = wellhelpers::computeHydrostaticCorrection(
|
||||
wells(), well_index, vfp_properties_->getInj()->getTable(vfp)->getDatumDepth(),
|
||||
rho, gravity_);
|
||||
|
||||
xw.bhp()[well_index] = vfp_properties_->getInj()->bhp(vfp, aqua, liquid, vapour, thp) - dp;
|
||||
}
|
||||
else if (well_type == PRODUCER) {
|
||||
const double dp = wellhelpers::computeHydrostaticCorrection(
|
||||
wells(), well_index, vfp_properties_->getProd()->getTable(vfp)->getDatumDepth(),
|
||||
rho, gravity_);
|
||||
|
||||
xw.bhp()[well_index] = vfp_properties_->getProd()->bhp(vfp, aqua, liquid, vapour, thp, alq) - dp;
|
||||
}
|
||||
else {
|
||||
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RESERVOIR_RATE: // intentional fall-through
|
||||
case SURFACE_RATE:
|
||||
// checking the number of the phases under control
|
||||
int numPhasesWithTargetsUnderThisControl = 0;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
if (distr[phase] > 0.0) {
|
||||
numPhasesWithTargetsUnderThisControl += 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(numPhasesWithTargetsUnderThisControl > 0);
|
||||
|
||||
const WellType& well_type = wells().type[well_index];
|
||||
if (well_type == INJECTOR) {
|
||||
// assign target value as initial guess for injectors
|
||||
// only handles single phase control at the moment
|
||||
assert(numPhasesWithTargetsUnderThisControl == 1);
|
||||
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
if (distr[phase] > 0.) {
|
||||
xw.wellRates()[np*well_index + phase] = target / distr[phase];
|
||||
} else {
|
||||
xw.wellRates()[np * well_index + phase] = 0.;
|
||||
}
|
||||
}
|
||||
} else if (well_type == PRODUCER) {
|
||||
// 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,
|
||||
// assuming the mobility ratio does not change for the production wells
|
||||
double original_rates_under_phase_control = 0.0;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
if (distr[phase] > 0.0) {
|
||||
original_rates_under_phase_control += xw.wellRates()[np * well_index + phase] * distr[phase];
|
||||
}
|
||||
}
|
||||
|
||||
if (original_rates_under_phase_control != 0.0 ) {
|
||||
double scaling_factor = target / original_rates_under_phase_control;
|
||||
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
xw.wellRates()[np * well_index + phase] *= scaling_factor;
|
||||
}
|
||||
} else { // scaling factor is not well defied when original_rates_under_phase_control is zero
|
||||
// separating targets equally between phases under control
|
||||
const double target_rate_divided = target / numPhasesWithTargetsUnderThisControl;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
if (distr[phase] > 0.0) {
|
||||
xw.wellRates()[np * well_index + phase] = target_rate_divided / distr[phase];
|
||||
} else {
|
||||
// this only happens for SURFACE_RATE control
|
||||
xw.wellRates()[np * well_index + phase] = target_rate_divided;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
|
||||
}
|
||||
|
||||
break;
|
||||
} // end of switch
|
||||
|
||||
|
||||
std::vector<double> g = {1.0, 1.0, 0.01};
|
||||
if (well_controls_iget_type(wc, current) == RESERVOIR_RATE) {
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
g[phase] = distr[phase];
|
||||
}
|
||||
}
|
||||
|
||||
// the number of wells
|
||||
const int nw = wells().number_of_wells;
|
||||
|
||||
switch (well_controls_iget_type(wc, current)) {
|
||||
case THP:
|
||||
case BHP: {
|
||||
const WellType& well_type = wells().type[well_index];
|
||||
xw.wellSolutions()[nw*XvarWell + well_index] = 0.0;
|
||||
if (well_type == INJECTOR) {
|
||||
for (int p = 0; p < np; ++p) {
|
||||
xw.wellSolutions()[nw*XvarWell + well_index] += xw.wellRates()[np*well_index + p] * wells().comp_frac[np*well_index + p];
|
||||
}
|
||||
} else {
|
||||
for (int p = 0; p < np; ++p) {
|
||||
xw.wellSolutions()[nw*XvarWell + well_index] += g[p] * xw.wellRates()[np*well_index + p];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESERVOIR_RATE: // Intentional fall-through
|
||||
case SURFACE_RATE:
|
||||
xw.wellSolutions()[nw*XvarWell + well_index] = xw.bhp()[well_index];
|
||||
break;
|
||||
} // end of switch
|
||||
|
||||
double tot_well_rate = 0.0;
|
||||
for (int p = 0; p < np; ++p) {
|
||||
tot_well_rate += g[p] * xw.wellRates()[np*well_index + p];
|
||||
}
|
||||
if(std::abs(tot_well_rate) > 0) {
|
||||
if (active_[ Water ]) {
|
||||
xw.wellSolutions()[WFrac*nw + well_index] = g[Water] * xw.wellRates()[np*well_index + Water] / tot_well_rate;
|
||||
}
|
||||
if (active_[ Gas ]) {
|
||||
xw.wellSolutions()[GFrac*nw + well_index] = g[Gas] * (xw.wellRates()[np*well_index + Gas] - xw.solventWellRate(well_index)) / tot_well_rate ;
|
||||
}
|
||||
if (has_solvent_) {
|
||||
xw.wellSolutions()[SFrac*nw + well_index] = g[Gas] * xw.solventWellRate(well_index) / tot_well_rate ;
|
||||
}
|
||||
} else {
|
||||
const WellType& well_type = wells().type[well_index];
|
||||
if (well_type == INJECTOR) {
|
||||
// only single phase injection handled
|
||||
if (active_[Water]) {
|
||||
if (distr[Water] > 0.0) {
|
||||
xw.wellSolutions()[WFrac * nw + well_index] = 1.0;
|
||||
} else {
|
||||
xw.wellSolutions()[WFrac * nw + well_index] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (active_[Gas]) {
|
||||
if (distr[Gas] > 0.0) {
|
||||
xw.wellSolutions()[GFrac * nw + well_index] = 1.0 - wsolvent(well_index);
|
||||
if (has_solvent_) {
|
||||
xw.wellSolutions()[SFrac * nw + well_index] = wsolvent(well_index);
|
||||
}
|
||||
} else {
|
||||
xw.wellSolutions()[GFrac * nw + well_index] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: it is possible to leave injector as a oil well,
|
||||
// when F_w and F_g both equals to zero, not sure under what kind of circumstance
|
||||
// this will happen.
|
||||
} else if (well_type == PRODUCER) { // producers
|
||||
if (active_[Water]) {
|
||||
xw.wellSolutions()[WFrac * nw + well_index] = 1.0 / np;
|
||||
}
|
||||
if (active_[Gas]) {
|
||||
xw.wellSolutions()[GFrac * nw + well_index] = 1.0 / np;
|
||||
}
|
||||
} else {
|
||||
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
double
|
||||
StandardWellsDense<TypeTag>::
|
||||
|
Loading…
Reference in New Issue
Block a user