/*
Copyright 2017 SINTEF ICT, Applied Mathematics.
Copyright 2017 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see .
*/
#ifndef OPM_STANDARDWELL_HEADER_INCLUDED
#define OPM_STANDARDWELL_HEADER_INCLUDED
#include
namespace Opm
{
template
class StandardWell: public WellInterface
{
public:
// TODO: some functions working with AD variables handles only with values (double) without
// dealing with derivatives. It can be beneficial to make functions can work with either AD or scalar value.
// And also, it can also be beneficial to make these functions hanle different types of AD variables.
// TODO: several functions related to polymer and PLYSHLOG are not incorprated yet,
// like the function wpolymer, setupCompressedToCartesian, computeRepRadiusPerfLength,
// They are introduced though PR 1220 and will be included later.
using typename WellInterface::Simulator;
using typename WellInterface::WellState;
using typename WellInterface::IntensiveQuantities;
using typename WellInterface::FluidSystem;
using typename WellInterface::MaterialLaw;
using typename WellInterface::ModelParameters;
using typename WellInterface::BlackoilIndices;
// 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
enum WellVariablePositions {
XvarWell = 0,
WFrac = 1,
GFrac = 2,
SFrac = 3
};
using typename WellInterface::Scalar;
using typename WellInterface::VectorBlockType;
using typename WellInterface::MatrixBlockType;
using typename WellInterface::Mat;
using typename WellInterface::BVector;
using typename WellInterface::Eval;
using typename WellInterface::PolymerModule;
using WellInterface::numEq;
static const int numWellEq = GET_PROP_VALUE(TypeTag, EnablePolymer)? numEq-1 : numEq; // //numEq; //number of wellEq is only numEq for polymer
// TODO: should these go to WellInterface?
static const int contiSolventEqIdx = BlackoilIndices::contiSolventEqIdx;
static const int contiPolymerEqIdx = BlackoilIndices::contiPolymerEqIdx;
static const int solventSaturationIdx = BlackoilIndices::solventSaturationIdx;
static const int polymerConcentrationIdx = BlackoilIndices::polymerConcentrationIdx;
typedef DenseAd::Evaluation EvalWell;
StandardWell(const Well* well, const int time_step, const Wells* wells);
/// the densities of the fluid in each perforation
virtual const std::vector& perfDensities() const;
virtual std::vector& perfDensities();
/// the pressure difference between different perforations
virtual const std::vector& perfPressureDiffs() const;
virtual std::vector& perfPressureDiffs();
virtual void setWellVariables(const WellState& well_state);
EvalWell wellVolumeFractionScaled(const int phase) const;
EvalWell wellVolumeFraction(const int phase) const;
EvalWell wellSurfaceVolumeFraction(const int phase) const;
EvalWell extendEval(const Eval& in) const;
// TODO: to check whether all the paramters are required
void computePerfRate(const IntensiveQuantities& intQuants,
const std::vector& mob_perfcells_dense,
const double Tw, const EvalWell& bhp, const double& cdp,
const bool& allow_cf, std::vector& cq_s) const;
virtual void assembleWellEq(Simulator& ebosSimulator,
const double dt,
WellState& well_state,
bool only_wells);
virtual bool crossFlowAllowed(const Simulator& ebosSimulator) const;
void getMobility(const Simulator& ebosSimulator,
const int perf,
std::vector& mob) const;
// TODO: the parameters need to be optimized/adjusted
virtual void init(const PhaseUsage* phase_usage_arg,
const std::vector* active_arg,
const VFPProperties* vfp_properties_arg,
const double gravity_arg,
const int num_cells);
// Update the well_state based on solution
void updateWellState(const BVector& dwells,
const BlackoilModelParameters& param,
WellState& well_state) const;
// TODO: later will check wheter we need current
virtual void updateWellStateWithTarget(const int current,
WellState& xw) const;
// TODO: this should go to the WellInterface, while updateWellStateWithTarget
// will need touch different types of well_state, we will see.
virtual void updateWellControl(WellState& xw) const;
virtual bool getWellConvergence(Simulator& ebosSimulator,
const std::vector& B_avg,
const ModelParameters& param) const;
virtual void computeAccumWell();
virtual void computeWellConnectionPressures(const Simulator& ebosSimulator,
const WellState& xw);
// Ax = Ax - C D^-1 B x
virtual void apply(const BVector& x, BVector& Ax) const;
// r = r - C D^-1 Rw
virtual void apply(BVector& r) const;
// using the solution x to recover the solution xw for wells and applying
// xw to update Well State
virtual void applySolutionWellState(const BVector& x, const ModelParameters& param,
WellState& well_state) const;
virtual void computeWellPotentials(const Simulator& ebosSimulator,
const WellState& well_state,
std::vector& well_potentials) const;
using WellInterface::has_solvent;
using WellInterface::has_polymer;
using WellInterface::phaseUsage;
using WellInterface::active;
using WellInterface::numberOfPerforations;
using WellInterface::wellCells;
using WellInterface::saturationTableNumber;
using WellInterface::indexOfWell;
using WellInterface::name;
using WellInterface::wellType;
using WellInterface::wellControls;
using WellInterface::compFrac;
using WellInterface::numberOfPhases;
using WellInterface::perfDepth;
using WellInterface::flowToEbosPvIdx;
using WellInterface::flowPhaseToEbosPhaseIdx;
using WellInterface::flowPhaseToEbosCompIdx;
using WellInterface::numComponents;
using WellInterface::numPhases;
using WellInterface::wellIndex;
using WellInterface::wsolvent;
using WellInterface::wpolymer;
protected:
// TODO: maybe this function can go to some helper file.
void localInvert(Mat& istlA) const;
// xw = inv(D)*(rw - C*x)
void recoverSolutionWell(const BVector& x, BVector& xw) const;
// TODO: decide wether to use member function to refer to private member later
using WellInterface::vfp_properties_;
using WellInterface::gravity_;
using WellInterface::well_efficiency_factor_;
using WellInterface::phase_usage_;
using WellInterface::first_perf_;
using WellInterface::ref_depth_;
using WellInterface::perf_depth_;
using WellInterface::allow_cf_;
using WellInterface::perf_rep_radius_;
using WellInterface::perf_length_;
using WellInterface::bore_diameters_;
// densities of the fluid in each perforation
std::vector perf_densities_;
// pressure drop between different perforations
std::vector perf_pressure_diffs_;
// TODO: probably, they should be moved to the WellInterface, when
// we decide the template paramters.
// two off-diagonal matrices
Mat duneB_;
Mat duneC_;
// diagonal matrix for the well
Mat invDuneD_;
// several vector used in the matrix calculation
mutable BVector Bx_;
mutable BVector invDrw_;
mutable BVector scaleAddRes_;
BVector resWell_;
std::vector well_variables_;
std::vector F0_;
// TODO: this function should be moved to the base class.
// while it faces chanllenges for MSWell later, since the calculation of bhp
// based on THP is never implemented for MSWell yet.
EvalWell getBhp() const;
// TODO: it is also possible to be moved to the base class.
EvalWell getQs(const int comp_idx) const;
// calculate the properties for the well connections
// to calulate the pressure difference between well connections.
void computePropertiesForWellConnectionPressures(const Simulator& ebosSimulator,
const WellState& xw,
std::vector& b_perf,
std::vector& rsmax_perf,
std::vector& rvmax_perf,
std::vector& surf_dens_perf) const;
// TODO: not total sure whether it is a good idea to put here
// the major reason to put here is to avoid the usage of Wells struct
void computeConnectionDensities(const std::vector& perfComponentRates,
const std::vector& b_perf,
const std::vector& rsmax_perf,
const std::vector& rvmax_perf,
const std::vector& surf_dens_perf);
void computeConnectionPressureDelta();
void computeWellConnectionDensitesPressures(const WellState& xw,
const std::vector& b_perf,
const std::vector& rsmax_perf,
const std::vector& rvmax_perf,
const std::vector& surf_dens_perf);
virtual void wellEqIteration(Simulator& ebosSimulator,
const ModelParameters& param,
WellState& well_state);
using WellInterface::wellHasTHPConstraints;
using WellInterface::mostStrictBhpFromBhpLimits;
// TODO: maybe we should provide a light version of computeWellFlux, which does not include the
// calculation of the derivatives
void computeWellRatesWithBhp(const Simulator& ebosSimulator,
const EvalWell& bhp,
std::vector& well_flux) const;
std::vector computeWellPotentialWithTHP(const Simulator& ebosSimulator,
const double initial_bhp, // bhp from BHP constraints
const std::vector& initial_potential) const;
};
}
#include "StandardWell_impl.hpp"
#endif // OPM_STANDARDWELL_HEADER_INCLUDED