adding BHP to the primary variables for StandardWell

This commit is contained in:
Kai Bao 2018-05-08 10:54:57 +02:00
parent 0e769afe9b
commit eb851b6580
2 changed files with 60 additions and 175 deletions

View File

@ -58,14 +58,24 @@ namespace Opm
using Base::has_energy;
// the positions of the primary variables for StandardWell
// there are three primary variables, the second and the third ones are F_w and F_g
// the first one can be total rate (G_t) or bhp, based on the control
// there are four primary variables, the second and the third ones are F_w and F_g
// the first one is the weighted total rate (G_t), the second and the third ones are F_w and F_g
// the last one is the BHP.
// the fraction of the solvent, as an extension of the blackoil model, is behind the BHP
// correspondingly, we have four well equations for blackoil model, the first three are mass
// converstation equations, and the last one is the well control equation.
// TODO: in the current implementation, we use the well rate as the first primary variables for injectors
// TODO: not sure we should change it.
static const bool gasoil = numEq == 2 && (Indices::compositionSwitchIdx >= 0);
static const int XvarWell = 0;
static const int GTotal = 0;
static const int WFrac = gasoil? -1000: 1;
static const int GFrac = gasoil? 1: 2;
static const int SFrac = !has_solvent ? -1000 : 3;
// TODO: it is possible the order of Bhp and SFrac need to switched, due to scalingFactor function
// TODO: we will do that when we see the problem.
static const int Bhp = gasoil? 2 : 3;
static const int SFrac = !has_solvent ? -1000 : Bhp + 1;
using typename Base::Scalar;
using typename Base::ConvergenceReport;

View File

@ -126,30 +126,7 @@ namespace Opm
StandardWell<TypeTag>::
getBhp() const
{
const WellControls* wc = well_controls_;
if (well_controls_get_current_type(wc) == BHP) {
EvalWell bhp = 0.0;
const double target_rate = well_controls_get_current_target(wc);
bhp.setValue(target_rate);
return bhp;
} else if (well_controls_get_current_type(wc) == THP) {
const int control = well_controls_get_current(wc);
const Opm::PhaseUsage& pu = phaseUsage();
std::vector<EvalWell> rates(3, 0.0);
if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
rates[ Water ]= getQs(pu.phase_pos[ Water]);
}
if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
rates[ Oil ] = getQs(pu.phase_pos[ Oil ]);
}
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
rates[ Gas ] = getQs(pu.phase_pos[ Gas ]);
}
return calculateBhpFromThp(rates, control);
}
return primary_variables_evaluation_[XvarWell];
return primary_variables_evaluation_[Bhp];
}
@ -161,19 +138,17 @@ namespace Opm
StandardWell<TypeTag>::
getQs(const int comp_idx) const // TODO: phase or component?
{
EvalWell qs = 0.0;
const WellControls* wc = well_controls_;
const int np = number_of_phases_;
const double target_rate = well_controls_get_current_target(wc);
// TODO: not sure the best way to handle solvent injection
// TODO: we need to come back to hanlde the solvent case here, the following implementation does not
// TODO: consider solvent injection yet.
// TODO: currently, the GTotal definition is still depends on Injector/Producer.
assert(comp_idx < num_components_);
const auto pu = phaseUsage();
const int legacyCompIdx = ebosCompIdxToFlowCompIdx(comp_idx);
// TODO: the formulation for the injectors decides it only work with single phase
// surface rate injection control. Improvement will be required.
if (well_type_ == INJECTOR) {
if (well_type_ == INJECTOR) { // only single phase injection
EvalWell qs = 0.0;
const auto pu = phaseUsage();
const int legacyCompIdx = ebosCompIdxToFlowCompIdx(comp_idx);
if (has_solvent) {
// TODO: investigate whether the use of the comp_frac is justified.
// The usage of the comp_frac is not correct, which should be changed later.
@ -185,113 +160,12 @@ namespace Opm
} else {
comp_frac = comp_frac_[legacyCompIdx];
}
if (comp_frac == 0.0) {
return qs; //zero
}
if (well_controls_get_current_type(wc) == BHP || well_controls_get_current_type(wc) == THP) {
return comp_frac * primary_variables_evaluation_[XvarWell];
}
qs.setValue(comp_frac * target_rate);
return qs;
return comp_frac * primary_variables_evaluation_[GTotal];
}
const double comp_frac = comp_frac_[legacyCompIdx];
if (comp_frac == 0.0) {
return qs;
}
if (well_controls_get_current_type(wc) == BHP || well_controls_get_current_type(wc) == THP) {
return primary_variables_evaluation_[XvarWell];
}
qs.setValue(target_rate);
return qs;
}
// Producers
if (well_controls_get_current_type(wc) == BHP || well_controls_get_current_type(wc) == THP ) {
return primary_variables_evaluation_[XvarWell] * wellVolumeFractionScaled(comp_idx);
}
if (well_controls_get_current_type(wc) == SURFACE_RATE) {
// checking how many phases are included in the rate control
// to decide wheter it is a single phase rate control or not
const double* distr = well_controls_get_current_distr(wc);
int num_phases_under_rate_control = 0;
for (int phase = 0; phase < np; ++phase) {
if (distr[phase] > 0.0) {
num_phases_under_rate_control += 1;
}
}
// there should be at least one phase involved
assert(num_phases_under_rate_control > 0);
// when it is a single phase rate limit
if (num_phases_under_rate_control == 1) {
// looking for the phase under control
int phase_under_control = -1;
for (int phase = 0; phase < np; ++phase) {
if (distr[phase] > 0.0) {
phase_under_control = phase;
break;
}
}
assert(phase_under_control >= 0);
const int compIdx_under_control = flowPhaseToEbosCompIdx(phase_under_control);
EvalWell wellVolumeFractionScaledPhaseUnderControl = wellVolumeFractionScaled(compIdx_under_control);
if (has_solvent && phase_under_control == Gas) {
// for GRAT controlled wells solvent is included in the target
wellVolumeFractionScaledPhaseUnderControl += wellVolumeFractionScaled(contiSolventEqIdx);
}
if (comp_idx == compIdx_under_control) {
if (has_solvent && compIdx_under_control == FluidSystem::gasCompIdx) {
qs.setValue(target_rate * wellVolumeFractionScaled(compIdx_under_control).value() / wellVolumeFractionScaledPhaseUnderControl.value() );
return qs;
}
qs.setValue(target_rate);
return qs;
}
// TODO: not sure why the single phase under control will have near zero fraction
const double eps = 1e-6;
if (wellVolumeFractionScaledPhaseUnderControl < eps) {
return qs;
}
return (target_rate * wellVolumeFractionScaled(comp_idx) / wellVolumeFractionScaledPhaseUnderControl);
}
// when it is a combined two phase rate limit, such like LRAT
// we neec to calculate the rate for the certain phase
if (num_phases_under_rate_control == 2) {
EvalWell combined_volume_fraction = 0.;
for (int p = 0; p < np; ++p) {
const unsigned compIdxTmp = flowPhaseToEbosCompIdx(p);
if (distr[p] == 1.0) {
combined_volume_fraction += wellVolumeFractionScaled(compIdxTmp);
}
}
return (target_rate * wellVolumeFractionScaled(comp_idx) / combined_volume_fraction);
}
// TODO: three phase surface rate control is not tested yet
if (num_phases_under_rate_control == 3) {
return target_rate * wellSurfaceVolumeFraction(comp_idx);
}
} else if (well_controls_get_current_type(wc) == RESERVOIR_RATE) {
// ReservoirRate
return target_rate * wellVolumeFractionScaled(comp_idx);
return primary_variables_evaluation_[GTotal];
} else {
OPM_THROW(std::logic_error, "Unknown control type for well " << name());
return primary_variables_evaluation_[GTotal] * wellVolumeFractionScaled(comp_idx);
}
// avoid warning of condition reaches end of non-void function
return qs;
}
@ -734,8 +608,10 @@ namespace Opm
// do the local inversion of D.
// we do this manually with invertMatrix to always get our
// specializations in for 3x3 and 4x4 matrices.
auto original = invDuneD_[0][0];
Dune::FMatrixHelp::invertMatrix(original, invDuneD_[0][0]);
// auto original = invDuneD_[0][0];
// Dune::FMatrixHelp::invertMatrix(original, invDuneD_[0][0]);
Dune::ISTLUtility::invertMatrix(invDuneD_[0][0]);
// invDuneD_[0][0].invert();
}
@ -1930,48 +1806,43 @@ namespace Opm
StandardWell<TypeTag>::
updatePrimaryVariables(const WellState& well_state) const
{
const int np = number_of_phases_;
const int well_index = index_of_well_;
const int np = number_of_phases_;
// the weighted total well rate
double total_well_rate = 0.0;
for (int p = 0; p < np; ++p) {
total_well_rate += scalingFactor(p) * well_state.wellRates()[np * well_index + p];
}
// TODO: not sure whether we should distinguish the firs primary variable based on Producer/Injector
// it will be determined based on testing as a separate issue.
if (well_type_ == INJECTOR) {
for (int p = 0; p < np; ++p) {
primary_variables_[GTotal] += well_state.wellRates()[np * well_index + p] * comp_frac_[p];
}
} else {
for (int p = 0; p < np; ++p) {
primary_variables_[GTotal] = total_well_rate;
}
}
const WellControls* wc = well_controls_;
const double* distr = well_controls_get_current_distr(wc);
const auto pu = phaseUsage();
switch (well_controls_get_current_type(wc)) {
case THP:
case BHP: {
primary_variables_[XvarWell] = 0.0;
if (well_type_ == INJECTOR) {
for (int p = 0; p < np; ++p) {
primary_variables_[XvarWell] += well_state.wellRates()[np*well_index + p] * comp_frac_[p];
}
} else {
for (int p = 0; p < np; ++p) {
primary_variables_[XvarWell] += scalingFactor(p) * well_state.wellRates()[np*well_index + p];
}
}
break;
}
case RESERVOIR_RATE: // Intentional fall-through
case SURFACE_RATE:
primary_variables_[XvarWell] = well_state.bhp()[well_index];
break;
} // end of switch
double tot_well_rate = 0.0;
for (int p = 0; p < np; ++p) {
tot_well_rate += scalingFactor(p) * well_state.wellRates()[np*well_index + p];
}
if(std::abs(tot_well_rate) > 0) {
if(std::abs(total_well_rate) > 0.) {
if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
primary_variables_[WFrac] = scalingFactor(pu.phase_pos[Water]) * well_state.wellRates()[np*well_index + pu.phase_pos[Water]] / tot_well_rate;
primary_variables_[WFrac] = scalingFactor(pu.phase_pos[Water]) * well_state.wellRates()[np*well_index + pu.phase_pos[Water]] / total_well_rate;
}
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
primary_variables_[GFrac] = scalingFactor(pu.phase_pos[Gas]) * (well_state.wellRates()[np*well_index + pu.phase_pos[Gas]] - well_state.solventWellRate(well_index)) / tot_well_rate ;
primary_variables_[GFrac] = scalingFactor(pu.phase_pos[Gas]) * (well_state.wellRates()[np*well_index + pu.phase_pos[Gas]] - well_state.solventWellRate(well_index)) / total_well_rate ;
}
if (has_solvent) {
primary_variables_[SFrac] = scalingFactor(pu.phase_pos[Gas]) * well_state.solventWellRate(well_index) / tot_well_rate ;
primary_variables_[SFrac] = scalingFactor(pu.phase_pos[Gas]) * well_state.solventWellRate(well_index) / total_well_rate ;
}
} else { // tot_well_rate == 0
} else { // total_well_rate == 0
if (well_type_ == INJECTOR) {
// only single phase injection handled
if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
@ -2008,6 +1879,10 @@ namespace Opm
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
}
}
// BHP
primary_variables_[Bhp] = well_state.bhp()[index_of_well_];
}