Merge pull request #1340 from totto82/solventAndResv

Make it possible to combine solvent and RESV
This commit is contained in:
Atgeirr Flø Rasmussen
2017-11-27 07:20:24 +01:00
committed by GitHub
11 changed files with 154 additions and 91 deletions

View File

@@ -3,7 +3,7 @@
Copyright 2014, 2015 Dr. Blatt - HPC-Simulation-Software & Services
Copyright 2014, 2015 Statoil ASA.
Copyright 2015 NTNU
Copyright 2015 IRIS AS
Copyright 2015, 2016, 2017 IRIS AS
This file is part of the Open Porous Media project (OPM).
@@ -33,7 +33,6 @@
#include <opm/autodiff/GeoProps.hpp>
#include <opm/autodiff/BlackoilDetails.hpp>
#include <opm/autodiff/NewtonIterationBlackoilInterface.hpp>
#include <opm/autodiff/RateConverter.hpp>
#include <opm/core/grid.h>
#include <opm/core/simulator/SimulatorReport.hpp>
@@ -126,10 +125,6 @@ namespace Opm {
typedef ISTLSolver< MatrixBlockType, VectorBlockType, Indices::pressureSwitchIdx > ISTLSolverType;
//typedef typename SolutionVector :: value_type PrimaryVariables ;
// For the conversion between the surface volume rate and resrevoir voidage rate
using RateConverterType = RateConverter::
SurfaceToReservoirVoidage<FluidSystem, std::vector<int> >;
typedef Opm::FIPData FIPDataType;
// --------- Public methods ---------

View File

@@ -221,10 +221,14 @@ namespace Opm {
const Well* well_ecl = wells_ecl_[index_well];
// Use the pvtRegionIdx from the top cell
const int well_cell_top = wells()->well_cells[wells()->well_connpos[w]];
const int pvtreg = pvt_region_idx_[well_cell_top];
if ( !well_ecl->isMultiSegment(time_step) || !param_.use_multisegment_well_) {
well_container.emplace_back(new StandardWell<TypeTag>(well_ecl, time_step, wells(), param_) );
well_container.emplace_back(new StandardWell<TypeTag>(well_ecl, time_step, wells(), param_, *rateConverter_, pvtreg ) );
} else {
well_container.emplace_back(new MultisegmentWell<TypeTag>(well_ecl, time_step, wells(), param_) );
well_container.emplace_back(new MultisegmentWell<TypeTag>(well_ecl, time_step, wells(), param_, *rateConverter_, pvtreg) );
}
}
}

View File

@@ -41,6 +41,8 @@ namespace Opm
using typename Base::ModelParameters;
using typename Base::MaterialLaw;
using typename Base::BlackoilIndices;
using typename Base::RateConverterType;
/// the number of reservior equations
using Base::numEq;
@@ -97,7 +99,10 @@ namespace Opm
// TODO: for now, we only use one type to save some implementation efforts, while improve later.
typedef DenseAd::Evaluation<double, /*size=*/numEq + numWellEq> EvalWell;
MultisegmentWell(const Well* well, const int time_step, const Wells* wells, const ModelParameters& param);
MultisegmentWell(const Well* well, const int time_step, const Wells* wells,
const ModelParameters& param,
const RateConverterType& rate_converter,
const int pvtRegionIdx);
virtual void init(const PhaseUsage* phase_usage_arg,
const std::vector<bool>* active_arg,
@@ -188,6 +193,7 @@ namespace Opm
using Base::flowPhaseToEbosPhaseIdx;
using Base::flowPhaseToEbosCompIdx;
using Base::getAllowCrossFlow;
using Base::scalingFactor;
// TODO: trying to use the information from the Well opm-parser as much
// as possible, it will possibly be re-implemented later for efficiency reason.
@@ -329,8 +335,6 @@ namespace Opm
void updateWellStateFromPrimaryVariables(WellState& well_state) const;
double scalingFactor(const int comp_idx) const;
bool frictionalPressureLossConsidered() const;
bool accelerationalPressureLossConsidered() const;

View File

@@ -27,8 +27,11 @@ namespace Opm
template <typename TypeTag>
MultisegmentWell<TypeTag>::
MultisegmentWell(const Well* well, const int time_step, const Wells* wells, const ModelParameters& param)
: Base(well, time_step, wells, param)
MultisegmentWell(const Well* well, const int time_step, const Wells* wells,
const ModelParameters& param,
const RateConverterType& rate_converter,
const int pvtRegionIdx)
: Base(well, time_step, wells, param, rate_converter, pvtRegionIdx)
, segment_perforations_(numberOfSegments())
, segment_inlets_(numberOfSegments())
, cell_perforation_depth_diffs_(number_of_perforations_, 0.0)
@@ -1666,40 +1669,6 @@ namespace Opm
template <typename TypeTag>
double
MultisegmentWell<TypeTag>::
scalingFactor(const int comp_idx) const
{
const double* distr = well_controls_get_current_distr(well_controls_);
if (well_controls_get_current_type(well_controls_) == RESERVOIR_RATE) {
// if (has_solvent && phaseIdx == contiSolventEqIdx )
// OPM_THROW(std::runtime_error, "RESERVOIR_RATE control in combination with solvent is not implemented");
return distr[comp_idx];
}
const PhaseUsage& pu = phaseUsage();
if (active()[Water] && pu.phase_pos[Water] == comp_idx)
return 1.0;
if (active()[Oil] && pu.phase_pos[Oil] == comp_idx)
return 1.0;
if (active()[Gas] && pu.phase_pos[Gas] == comp_idx)
return 0.01;
// if (has_solvent && phaseIdx == contiSolventEqIdx )
// return 0.01;
// we should not come this far
assert(false);
return 1.0;
}
template <typename TypeTag>
bool
MultisegmentWell<TypeTag>::

View File

@@ -1,6 +1,7 @@
/*
Copyright 2014, 2015 SINTEF ICT, Applied Mathematics.
Copyright 2014, 2015 Statoil ASA.
Copyright 2017, IRIS
This file is part of the Open Porous Media Project (OPM).
@@ -638,6 +639,31 @@ namespace Opm {
}
}
/**
* Compute coefficients for surface-to-reservoir voidage
* conversion for solvent.
*
*
* \param[in] r Fluid-in-place region of the well
* \param[in] pvtRegionIdx PVT region of the well
*
*
* \param[out] double Surface-to-reservoir conversion
* coefficients for solvent.
*/
template <class SolventModule>
void
calcCoeffSolvent(const RegionId r, const int pvtRegionIdx, double& coeff) const
{
const auto& ra = attr_.attributes(r);
const double p = ra.pressure;
const double T = ra.temperature;
const auto& solventPvt = SolventModule::solventPvt();
const double bs = solventPvt.inverseFormationVolumeFactor(pvtRegionIdx, T, p);
coeff = 1.0 / bs;
}
private:
/**
* Fluid property object.

View File

@@ -68,7 +68,6 @@ public:
typedef BlackoilModelParameters ModelParameters;
typedef NonlinearSolver<Model> Solver;
typedef BlackoilWellModel<TypeTag> WellModel;
typedef RateConverter::SurfaceToReservoirVoidage<FluidSystem, std::vector<int> > RateConverterType;
/// Initialise from parameters and objects to observe.

View File

@@ -26,6 +26,7 @@
#include <opm/autodiff/WellInterface.hpp>
#include <opm/autodiff/ISTLSolver.hpp>
#include <opm/autodiff/RateConverter.hpp>
namespace Opm
{
@@ -47,6 +48,7 @@ namespace Opm
using typename Base::ModelParameters;
using typename Base::BlackoilIndices;
using typename Base::PolymerModule;
using typename Base::RateConverterType;
using Base::numEq;
@@ -111,7 +113,10 @@ namespace Opm
static const int polymerConcentrationIdx = BlackoilIndices::polymerConcentrationIdx;
StandardWell(const Well* well, const int time_step, const Wells* wells, const ModelParameters& param);
StandardWell(const Well* well, const int time_step, const Wells* wells,
const ModelParameters& param,
const RateConverterType& rate_converter,
const int pvtRegionIdx);
virtual void init(const PhaseUsage* phase_usage_arg,
const std::vector<bool>* active_arg,
@@ -169,6 +174,7 @@ namespace Opm
using Base::wpolymer;
using Base::wellHasTHPConstraints;
using Base::mostStrictBhpFromBhpLimits;
using Base::scalingFactor;
// protected member variables from the Base class
using Base::vfp_properties_;
@@ -302,7 +308,6 @@ namespace Opm
const int perf,
std::vector<EvalWell>& mob) const;
double scalingFactor(const int comp_idx) const;
};
}

View File

@@ -24,8 +24,11 @@ namespace Opm
{
template<typename TypeTag>
StandardWell<TypeTag>::
StandardWell(const Well* well, const int time_step, const Wells* wells, const ModelParameters& param)
: Base(well, time_step, wells, param)
StandardWell(const Well* well, const int time_step, const Wells* wells,
const ModelParameters& param,
const RateConverterType& rate_converter,
const int pvtRegionIdx)
: Base(well, time_step, wells, param, rate_converter, pvtRegionIdx)
, perf_densities_(number_of_perforations_)
, perf_pressure_diffs_(number_of_perforations_)
, primary_variables_(numWellEq, 0.0)
@@ -861,13 +864,7 @@ namespace Opm
primary_variables_[SFrac] = F_solvent;
}
// F_solvent is added to F_gas. This means that well_rate[Gas] also contains solvent.
// More testing is needed to make sure this is correct for well groups and THP.
if (has_solvent){
F[pu.phase_pos[Gas]] += F_solvent;
}
// The interpretation of the first well variable depends on the well control
// The interpretation of the first well variable depends on the well control
const WellControls* wc = well_controls_;
// TODO: we should only maintain one current control either from the well_state or from well_controls struct.
@@ -884,6 +881,13 @@ namespace Opm
}
}
// F_solvent is added to F_gas. This means that well_rate[Gas] also contains solvent.
// More testing is needed to make sure this is correct for well groups and THP.
if (has_solvent){
F_solvent /= scalingFactor(contiSolventEqIdx);
F[pu.phase_pos[Gas]] += F_solvent;
}
switch (well_controls_iget_type(wc, current)) {
case THP: // The BHP and THP both uses the total rate as first well variable.
case BHP:
@@ -1973,33 +1977,7 @@ namespace Opm
return thp;
}
template<typename TypeTag>
double
StandardWell<TypeTag>::scalingFactor(const int phaseIdx) const
{
const WellControls* wc = well_controls_;
const double* distr = well_controls_get_current_distr(wc);
if (well_controls_get_current_type(wc) == RESERVOIR_RATE) {
if (has_solvent && phaseIdx == contiSolventEqIdx )
OPM_THROW(std::runtime_error, "RESERVOIR_RATE control in combination with solvent is not implemented");
return distr[phaseIdx];
}
const auto& pu = phaseUsage();
if (active()[Water] && pu.phase_pos[Water] == phaseIdx)
return 1.0;
if (active()[Oil] && pu.phase_pos[Oil] == phaseIdx)
return 1.0;
if (active()[Gas] && pu.phase_pos[Gas] == phaseIdx)
return 0.01;
if (has_solvent && phaseIdx == contiSolventEqIdx )
return 0.01;
// we should not come this far
assert(false);
return 1.0;
}
}

View File

@@ -1,6 +1,7 @@
/*
Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2017 Statoil ASA.
Copyright 2017 IRIS
This file is part of the Open Porous Media project (OPM).
@@ -37,6 +38,7 @@
#include <opm/autodiff/WellHelpers.hpp>
#include <opm/autodiff/WellStateFullyImplicitBlackoil.hpp>
#include <opm/autodiff/BlackoilModelParameters.hpp>
#include <opm/autodiff/RateConverter.hpp>
#include <opm/simulators/WellSwitchingLogger.hpp>
@@ -89,9 +91,18 @@ namespace Opm
static const bool has_solvent = GET_PROP_VALUE(TypeTag, EnableSolvent);
static const bool has_polymer = GET_PROP_VALUE(TypeTag, EnablePolymer);
static const int contiSolventEqIdx = BlackoilIndices::contiSolventEqIdx;
// For the conversion between the surface volume rate and resrevoir voidage rate
using RateConverterType = RateConverter::
SurfaceToReservoirVoidage<FluidSystem, std::vector<int> >;
/// Constructor
WellInterface(const Well* well, const int time_step, const Wells* wells, const ModelParameters& param);
WellInterface(const Well* well, const int time_step, const Wells* wells,
const ModelParameters& param,
const RateConverterType& rate_converter,
const int pvtRegionIdx);
/// Virutal destructor
virtual ~WellInterface() {}
@@ -264,6 +275,13 @@ namespace Opm
double gravity_;
// For the conversion between the surface volume rate and resrevoir voidage rate
const RateConverterType& rateConverter_;
// The pvt region of the well. We assume
// We assume a well to not penetrate more than one pvt region.
const int pvtRegionIdx_;
const std::vector<bool>& active() const;
const PhaseUsage& phaseUsage() const;
@@ -304,6 +322,9 @@ namespace Opm
RatioCheckTuple checkRatioEconLimits(const WellEconProductionLimits& econ_production_limits,
const WellState& well_state) const;
double scalingFactor(const int comp_idx) const;
};
}

View File

@@ -25,10 +25,15 @@ namespace Opm
template<typename TypeTag>
WellInterface<TypeTag>::
WellInterface(const Well* well, const int time_step, const Wells* wells, const ModelParameters& param)
WellInterface(const Well* well, const int time_step, const Wells* wells,
const ModelParameters& param,
const RateConverterType& rate_converter,
const int pvtRegionIdx)
: well_ecl_(well)
, current_step_(time_step)
, param_(param)
, rateConverter_(rate_converter)
, pvtRegionIdx_(pvtRegionIdx)
{
if (!well) {
OPM_THROW(std::invalid_argument, "Null pointer of Well is used to construct WellInterface");
@@ -850,4 +855,36 @@ namespace Opm
}
}
template<typename TypeTag>
double
WellInterface<TypeTag>::scalingFactor(const int phaseIdx) const
{
const WellControls* wc = well_controls_;
const double* distr = well_controls_get_current_distr(wc);
if (well_controls_get_current_type(wc) == RESERVOIR_RATE) {
if (has_solvent && phaseIdx == contiSolventEqIdx ) {
typedef Ewoms::BlackOilSolventModule<TypeTag> SolventModule;
double coeff = 0;
rateConverter_.template calcCoeffSolvent<SolventModule>(0, pvtRegionIdx_, coeff);
return coeff;
}
// TODO: use the rateConverter here as well.
return distr[phaseIdx];
}
const auto& pu = phaseUsage();
if (active()[Water] && pu.phase_pos[Water] == phaseIdx)
return 1.0;
if (active()[Oil] && pu.phase_pos[Oil] == phaseIdx)
return 1.0;
if (active()[Gas] && pu.phase_pos[Gas] == phaseIdx)
return 0.01;
if (has_solvent && phaseIdx == contiSolventEqIdx )
return 0.01;
// we should not come this far
assert(false);
return 1.0;
}
}