mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
flow: let the wells be managed by EclProblem
This commit is contained in:
@@ -72,7 +72,6 @@ BEGIN_PROPERTIES
|
|||||||
|
|
||||||
NEW_TYPE_TAG(EclFlowProblem, INHERITS_FROM(BlackOilModel, EclBaseProblem, FlowNonLinearSolver, FlowIstlSolver, FlowModelParameters, FlowTimeSteppingParameters));
|
NEW_TYPE_TAG(EclFlowProblem, INHERITS_FROM(BlackOilModel, EclBaseProblem, FlowNonLinearSolver, FlowIstlSolver, FlowModelParameters, FlowTimeSteppingParameters));
|
||||||
SET_STRING_PROP(EclFlowProblem, OutputDir, "");
|
SET_STRING_PROP(EclFlowProblem, OutputDir, "");
|
||||||
SET_BOOL_PROP(EclFlowProblem, DisableWells, true);
|
|
||||||
SET_BOOL_PROP(EclFlowProblem, EnableDebuggingChecks, false);
|
SET_BOOL_PROP(EclFlowProblem, EnableDebuggingChecks, false);
|
||||||
// default in flow is to formulate the equations in surface volumes
|
// default in flow is to formulate the equations in surface volumes
|
||||||
SET_BOOL_PROP(EclFlowProblem, BlackoilConserveSurfaceVolume, true);
|
SET_BOOL_PROP(EclFlowProblem, BlackoilConserveSurfaceVolume, true);
|
||||||
@@ -87,6 +86,8 @@ SET_BOOL_PROP(EclFlowProblem, EnableSolvent, false);
|
|||||||
SET_BOOL_PROP(EclFlowProblem, EnableTemperature, true);
|
SET_BOOL_PROP(EclFlowProblem, EnableTemperature, true);
|
||||||
SET_BOOL_PROP(EclFlowProblem, EnableEnergy, false);
|
SET_BOOL_PROP(EclFlowProblem, EnableEnergy, false);
|
||||||
|
|
||||||
|
SET_TYPE_PROP(EclFlowProblem, EclWellModel, Opm::BlackoilWellModel<TypeTag>);
|
||||||
|
|
||||||
END_PROPERTIES
|
END_PROPERTIES
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
@@ -209,8 +210,6 @@ namespace Opm {
|
|||||||
wasSwitched_.resize(numDof);
|
wasSwitched_.resize(numDof);
|
||||||
std::fill(wasSwitched_.begin(), wasSwitched_.end(), false);
|
std::fill(wasSwitched_.begin(), wasSwitched_.end(), false);
|
||||||
|
|
||||||
wellModel().beginTimeStep(timer.reportStepNum(), timer.simulationTimeElapsed());
|
|
||||||
|
|
||||||
if (param_.update_equations_scaling_) {
|
if (param_.update_equations_scaling_) {
|
||||||
std::cout << "equation scaling not suported yet" << std::endl;
|
std::cout << "equation scaling not suported yet" << std::endl;
|
||||||
//updateEquationsScaling();
|
//updateEquationsScaling();
|
||||||
@@ -302,7 +301,7 @@ namespace Opm {
|
|||||||
// handling well state update before oscillation treatment is a decision based
|
// handling well state update before oscillation treatment is a decision based
|
||||||
// on observation to avoid some big performance degeneration under some circumstances.
|
// on observation to avoid some big performance degeneration under some circumstances.
|
||||||
// there is no theorectical explanation which way is better for sure.
|
// there is no theorectical explanation which way is better for sure.
|
||||||
wellModel().recoverWellSolutionAndUpdateWellState(x);
|
wellModel().postSolve(x);
|
||||||
|
|
||||||
if (param_.use_update_stabilization_) {
|
if (param_.use_update_stabilization_) {
|
||||||
// Stabilize the nonlinear update.
|
// Stabilize the nonlinear update.
|
||||||
@@ -343,9 +342,7 @@ namespace Opm {
|
|||||||
/// \param[in] timer simulation timer
|
/// \param[in] timer simulation timer
|
||||||
void afterStep(const SimulatorTimerInterface& OPM_UNUSED timer)
|
void afterStep(const SimulatorTimerInterface& OPM_UNUSED timer)
|
||||||
{
|
{
|
||||||
wellModel().timeStepSucceeded(timer.simulationTimeElapsed());
|
|
||||||
ebosSimulator_.problem().endTimeStep();
|
ebosSimulator_.problem().endTimeStep();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assemble the residual and Jacobian of the nonlinear system.
|
/// Assemble the residual and Jacobian of the nonlinear system.
|
||||||
@@ -361,32 +358,6 @@ namespace Opm {
|
|||||||
ebosSimulator_.model().linearizer().linearize();
|
ebosSimulator_.model().linearizer().linearize();
|
||||||
ebosSimulator_.problem().endIteration();
|
ebosSimulator_.problem().endIteration();
|
||||||
|
|
||||||
// -------- Current time step length ----------
|
|
||||||
const double dt = timer.currentStepLength();
|
|
||||||
|
|
||||||
// -------- Well equations ----------
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// assembles the well equations and applies the wells to
|
|
||||||
// the reservoir equations as a source term.
|
|
||||||
wellModel().assemble(iterationIdx, dt);
|
|
||||||
}
|
|
||||||
catch ( const Dune::FMatrixError& )
|
|
||||||
{
|
|
||||||
OPM_THROW(Opm::NumericalIssue,"Error encounted when solving well equations");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& ebosJac = ebosSimulator_.model().linearizer().matrix();
|
|
||||||
if (param_.matrix_add_well_contributions_) {
|
|
||||||
wellModel().addWellContributions(ebosJac);
|
|
||||||
}
|
|
||||||
if ( param_.preconditioner_add_well_contributions_ &&
|
|
||||||
! param_.matrix_add_well_contributions_ ) {
|
|
||||||
matrix_for_preconditioner_ .reset(new Mat(ebosJac));
|
|
||||||
wellModel().addWellContributions(*matrix_for_preconditioner_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return wellModel().lastReport();
|
return wellModel().lastReport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,9 +475,6 @@ namespace Opm {
|
|||||||
/// r is the residual.
|
/// r is the residual.
|
||||||
void solveJacobianSystem(BVector& x) const
|
void solveJacobianSystem(BVector& x) const
|
||||||
{
|
{
|
||||||
const auto& ebosJac = ebosSimulator_.model().linearizer().matrix();
|
|
||||||
auto& ebosResid = ebosSimulator_.model().linearizer().residual();
|
|
||||||
|
|
||||||
// J = [A, B; C, D], where A is the reservoir equations, B and C the interaction of well
|
// J = [A, B; C, D], where A is the reservoir equations, B and C the interaction of well
|
||||||
// with the reservoir and D is the wells itself.
|
// with the reservoir and D is the wells itself.
|
||||||
// The full system is reduced to a number of cells X number of cells system via Schur complement
|
// The full system is reduced to a number of cells X number of cells system via Schur complement
|
||||||
@@ -516,8 +484,8 @@ namespace Opm {
|
|||||||
// r = [r, r_well], where r is the residual and r_well the well residual.
|
// r = [r, r_well], where r is the residual and r_well the well residual.
|
||||||
// r -= B^T * D^-1 r_well
|
// r -= B^T * D^-1 r_well
|
||||||
|
|
||||||
// apply well residual to the residual.
|
auto& ebosJac = ebosSimulator_.model().linearizer().matrix();
|
||||||
wellModel().apply(ebosResid);
|
auto& ebosResid = ebosSimulator_.model().linearizer().residual();
|
||||||
|
|
||||||
// set initial guess
|
// set initial guess
|
||||||
x = 0.0;
|
x = 0.0;
|
||||||
@@ -1001,9 +969,9 @@ namespace Opm {
|
|||||||
const BlackoilWellModel<TypeTag>&
|
const BlackoilWellModel<TypeTag>&
|
||||||
wellModel() const { return well_model_; }
|
wellModel() const { return well_model_; }
|
||||||
|
|
||||||
void beginReportStep()
|
void beginReportStep(bool isRestart)
|
||||||
{
|
{
|
||||||
ebosSimulator_.problem().beginEpisode();
|
ebosSimulator_.problem().beginEpisode(isRestart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void endReportStep()
|
void endReportStep()
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#ifndef OPM_BLACKOILWELLMODEL_HEADER_INCLUDED
|
#ifndef OPM_BLACKOILWELLMODEL_HEADER_INCLUDED
|
||||||
#define OPM_BLACKOILWELLMODEL_HEADER_INCLUDED
|
#define OPM_BLACKOILWELLMODEL_HEADER_INCLUDED
|
||||||
|
|
||||||
|
#include <ebos/eclproblem.hh>
|
||||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||||
|
|
||||||
#include <opm/common/utility/platform_dependent/disable_warnings.h>
|
#include <opm/common/utility/platform_dependent/disable_warnings.h>
|
||||||
@@ -60,12 +61,18 @@
|
|||||||
|
|
||||||
#include <opm/simulators/WellSwitchingLogger.hpp>
|
#include <opm/simulators/WellSwitchingLogger.hpp>
|
||||||
|
|
||||||
|
BEGIN_PROPERTIES
|
||||||
|
|
||||||
|
NEW_PROP_TAG(EnableTerminalOutput);
|
||||||
|
|
||||||
|
END_PROPERTIES
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
/// Class for handling the blackoil well model.
|
/// Class for handling the blackoil well model.
|
||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
class BlackoilWellModel {
|
class BlackoilWellModel : public Ewoms::BaseAuxiliaryModule<TypeTag>
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
// --------- Types ---------
|
// --------- Types ---------
|
||||||
typedef WellStateFullyImplicitBlackoil WellState;
|
typedef WellStateFullyImplicitBlackoil WellState;
|
||||||
@@ -77,6 +84,11 @@ namespace Opm {
|
|||||||
typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
|
typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
|
||||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||||
|
typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
|
||||||
|
typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector;
|
||||||
|
typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix;
|
||||||
|
|
||||||
|
typedef typename Ewoms::BaseAuxiliaryModule<TypeTag>::NeighborSet NeighborSet;
|
||||||
|
|
||||||
static const int numEq = Indices::numEq;
|
static const int numEq = Indices::numEq;
|
||||||
static const int solventSaturationIdx = Indices::solventSaturationIdx;
|
static const int solventSaturationIdx = Indices::solventSaturationIdx;
|
||||||
@@ -101,51 +113,94 @@ namespace Opm {
|
|||||||
using RateConverterType = RateConverter::
|
using RateConverterType = RateConverter::
|
||||||
SurfaceToReservoirVoidage<FluidSystem, std::vector<int> >;
|
SurfaceToReservoirVoidage<FluidSystem, std::vector<int> >;
|
||||||
|
|
||||||
BlackoilWellModel(Simulator& ebosSimulator,
|
BlackoilWellModel(Simulator& ebosSimulator);
|
||||||
const ModelParameters& param,
|
|
||||||
const bool terminal_output);
|
|
||||||
|
|
||||||
void initFromRestartFile(const RestartValue& restartValues)
|
void init(const Opm::EclipseState& eclState, const Opm::Schedule& schedule);
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// <eWoms auxiliary module stuff>
|
||||||
|
/////////////
|
||||||
|
unsigned numDofs() const
|
||||||
|
// No extra dofs are inserted for wells. (we use a Schur complement.)
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
void addNeighbors(std::vector<NeighborSet>& neighbors) const;
|
||||||
|
|
||||||
|
void applyInitial()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void linearize(JacobianMatrix& mat , GlobalEqVector& res);
|
||||||
|
|
||||||
|
void postSolve(GlobalEqVector& deltaX)
|
||||||
{
|
{
|
||||||
// gives a dummy dynamic_list_econ_limited
|
recoverWellSolutionAndUpdateWellState(deltaX);
|
||||||
DynamicListEconLimited dummyListEconLimited;
|
|
||||||
const auto& defunctWellNames = ebosSimulator_.vanguard().defunctWellNames();
|
|
||||||
WellsManager wellsmanager(eclState(),
|
|
||||||
schedule(),
|
|
||||||
// The restart step value is used to identify wells present at the given
|
|
||||||
// time step. Wells that are added at the same time step as RESTART is initiated
|
|
||||||
// will not be present in a restart file. Use the previous time step to retrieve
|
|
||||||
// wells that have information written to the restart file.
|
|
||||||
std::max(eclState().getInitConfig().getRestartStep() - 1, 0),
|
|
||||||
Opm::UgGridHelpers::numCells(grid()),
|
|
||||||
Opm::UgGridHelpers::globalCell(grid()),
|
|
||||||
Opm::UgGridHelpers::cartDims(grid()),
|
|
||||||
Opm::UgGridHelpers::dimensions(grid()),
|
|
||||||
Opm::UgGridHelpers::cell2Faces(grid()),
|
|
||||||
Opm::UgGridHelpers::beginFaceCentroids(grid()),
|
|
||||||
dummyListEconLimited,
|
|
||||||
grid().comm().size() > 1,
|
|
||||||
defunctWellNames);
|
|
||||||
|
|
||||||
const Wells* wells = wellsmanager.c_wells();
|
|
||||||
|
|
||||||
const int nw = wells->number_of_wells;
|
|
||||||
if (nw > 0) {
|
|
||||||
auto phaseUsage = phaseUsageFromDeck(eclState());
|
|
||||||
size_t numCells = Opm::UgGridHelpers::numCells(grid());
|
|
||||||
well_state_.resize(wells, numCells, phaseUsage); //Resize for restart step
|
|
||||||
wellsToState(restartValues.wells, phaseUsage, well_state_);
|
|
||||||
previous_well_state_ = well_state_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute the well fluxes and assemble them in to the reservoir equations as source terms
|
/////////////
|
||||||
// and in the well equations.
|
// </ eWoms auxiliary module stuff>
|
||||||
void assemble(const int iterationIdx,
|
/////////////
|
||||||
const double dt);
|
|
||||||
|
|
||||||
// substract Binv(D)rw from r;
|
template <class Restarter>
|
||||||
void apply( BVector& r) const;
|
void deserialize(Restarter& res)
|
||||||
|
{
|
||||||
|
// TODO (?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief This method writes the complete state of the well
|
||||||
|
* to the harddisk.
|
||||||
|
*/
|
||||||
|
template <class Restarter>
|
||||||
|
void serialize(Restarter& res)
|
||||||
|
{
|
||||||
|
// TODO (?)
|
||||||
|
}
|
||||||
|
|
||||||
|
void beginEpisode(const Opm::EclipseState& eclState,
|
||||||
|
const Opm::Schedule& schedule,
|
||||||
|
bool isRestart)
|
||||||
|
{
|
||||||
|
size_t episodeIdx = ebosSimulator_.episodeIndex();
|
||||||
|
// beginEpisode in eclProblem advances the episode index
|
||||||
|
// we don't want this when we are at the beginning of an
|
||||||
|
// restart.
|
||||||
|
if (isRestart)
|
||||||
|
episodeIdx -= 1;
|
||||||
|
|
||||||
|
beginReportStep(episodeIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void beginTimeStep();
|
||||||
|
|
||||||
|
void beginIteration()
|
||||||
|
{
|
||||||
|
assemble(ebosSimulator_.model().newtonMethod().numIterations(),
|
||||||
|
ebosSimulator_.timeStepSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void endIteration()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void endTimeStep()
|
||||||
|
{
|
||||||
|
timeStepSucceeded(ebosSimulator_.time());
|
||||||
|
}
|
||||||
|
|
||||||
|
void endEpisode()
|
||||||
|
{
|
||||||
|
endReportStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Context>
|
||||||
|
void computeTotalRatesForDof(RateVector& rate,
|
||||||
|
const Context& context,
|
||||||
|
unsigned spaceIdx,
|
||||||
|
unsigned timeIdx) const;
|
||||||
|
|
||||||
|
void initFromRestartFile(const RestartValue& restartValues);
|
||||||
|
|
||||||
|
Opm::data::Wells wellData() const
|
||||||
|
{ return well_state_.report(phase_usage_, Opm::UgGridHelpers::globalCell(grid())); }
|
||||||
|
|
||||||
// subtract B*inv(D)*C * x from A*x
|
// subtract B*inv(D)*C * x from A*x
|
||||||
void apply(const BVector& x, BVector& Ax) const;
|
void apply(const BVector& x, BVector& Ax) const;
|
||||||
@@ -153,10 +208,6 @@ namespace Opm {
|
|||||||
// apply well model with scaling of alpha
|
// apply well model with scaling of alpha
|
||||||
void applyScaleAdd(const Scalar alpha, const BVector& x, BVector& Ax) const;
|
void applyScaleAdd(const Scalar alpha, const BVector& x, BVector& Ax) const;
|
||||||
|
|
||||||
// using the solution x to recover the solution xw for wells and applying
|
|
||||||
// xw to update Well State
|
|
||||||
void recoverWellSolutionAndUpdateWellState(const BVector& x);
|
|
||||||
|
|
||||||
// Check if well equations is converged.
|
// Check if well equations is converged.
|
||||||
bool getWellConvergence(const std::vector<Scalar>& B_avg) const;
|
bool getWellConvergence(const std::vector<Scalar>& B_avg) const;
|
||||||
|
|
||||||
@@ -172,31 +223,13 @@ namespace Opm {
|
|||||||
// return the internal well state
|
// return the internal well state
|
||||||
const WellState& wellState() const;
|
const WellState& wellState() const;
|
||||||
|
|
||||||
// only use this for restart.
|
const SimulatorReport& lastReport() const;
|
||||||
void setRestartWellState(const WellState& well_state);
|
|
||||||
|
|
||||||
// called at the beginning of a time step
|
|
||||||
void beginTimeStep(const int timeStepIdx,const double simulationTime);
|
|
||||||
// called at the end of a time step
|
|
||||||
void timeStepSucceeded(const double& simulationTime);
|
|
||||||
|
|
||||||
// called at the beginning of a report step
|
// called at the beginning of a report step
|
||||||
void beginReportStep(const int time_step);
|
void beginReportStep(const int time_step);
|
||||||
|
|
||||||
// called at the end of a report step
|
|
||||||
void endReportStep();
|
|
||||||
|
|
||||||
const SimulatorReport& lastReport() const;
|
|
||||||
|
|
||||||
|
|
||||||
void addWellContributions(Mat& mat)
|
|
||||||
{
|
|
||||||
for ( const auto& well: well_container_ ) {
|
|
||||||
well->addWellContributions(mat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void extractLegacyPressure_(std::vector<double>& cellPressure) const
|
void extractLegacyPressure_(std::vector<double>& cellPressure) const
|
||||||
{
|
{
|
||||||
size_t nc = number_of_cells_;
|
size_t nc = number_of_cells_;
|
||||||
@@ -234,6 +267,9 @@ namespace Opm {
|
|||||||
// a vector of all the wells.
|
// a vector of all the wells.
|
||||||
std::vector<WellInterfacePtr > well_container_;
|
std::vector<WellInterfacePtr > well_container_;
|
||||||
|
|
||||||
|
// map from logically cartesian cell indices to compressed ones
|
||||||
|
std::vector<int> cartesian_to_compressed_;
|
||||||
|
|
||||||
// create the well container
|
// create the well container
|
||||||
std::vector<WellInterfacePtr > createWellContainer(const int time_step);
|
std::vector<WellInterfacePtr > createWellContainer(const int time_step);
|
||||||
|
|
||||||
@@ -276,6 +312,21 @@ namespace Opm {
|
|||||||
const Schedule& schedule() const
|
const Schedule& schedule() const
|
||||||
{ return ebosSimulator_.vanguard().schedule(); }
|
{ return ebosSimulator_.vanguard().schedule(); }
|
||||||
|
|
||||||
|
// compute the well fluxes and assemble them in to the reservoir equations as source terms
|
||||||
|
// and in the well equations.
|
||||||
|
void assemble(const int iterationIdx,
|
||||||
|
const double dt);
|
||||||
|
|
||||||
|
// called at the end of a time step
|
||||||
|
void timeStepSucceeded(const double& simulationTime);
|
||||||
|
|
||||||
|
// called at the end of a report step
|
||||||
|
void endReportStep();
|
||||||
|
|
||||||
|
// using the solution x to recover the solution xw for wells and applying
|
||||||
|
// xw to update Well State
|
||||||
|
void recoverWellSolutionAndUpdateWellState(const BVector& x);
|
||||||
|
|
||||||
void updateWellControls();
|
void updateWellControls();
|
||||||
|
|
||||||
void updateGroupControls();
|
void updateGroupControls();
|
||||||
@@ -283,7 +334,7 @@ namespace Opm {
|
|||||||
// setting the well_solutions_ based on well_state.
|
// setting the well_solutions_ based on well_state.
|
||||||
void updatePrimaryVariables();
|
void updatePrimaryVariables();
|
||||||
|
|
||||||
void setupCompressedToCartesian(const int* global_cell, int number_of_cells, std::map<int,int>& cartesian_to_compressed ) const;
|
void setupCartesianToCompressed_(const int* global_cell, int number_of_cells);
|
||||||
|
|
||||||
void computeRepRadiusPerfLength(const Grid& grid);
|
void computeRepRadiusPerfLength(const Grid& grid);
|
||||||
|
|
||||||
@@ -322,8 +373,7 @@ namespace Opm {
|
|||||||
|
|
||||||
void resetWellControlFromState() const;
|
void resetWellControlFromState() const;
|
||||||
|
|
||||||
void assembleWellEq(const double dt,
|
void assembleWellEq(const double dt);
|
||||||
bool only_wells);
|
|
||||||
|
|
||||||
// some preparation work, mostly related to group control and RESV,
|
// some preparation work, mostly related to group control and RESV,
|
||||||
// at the beginning of each time step (Not report step)
|
// at the beginning of each time step (Not report step)
|
||||||
|
|||||||
@@ -4,16 +4,26 @@
|
|||||||
namespace Opm {
|
namespace Opm {
|
||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
BlackoilWellModel(Simulator& ebosSimulator,
|
BlackoilWellModel(Simulator& ebosSimulator)
|
||||||
const ModelParameters& param,
|
|
||||||
const bool terminal_output)
|
|
||||||
: ebosSimulator_(ebosSimulator)
|
: ebosSimulator_(ebosSimulator)
|
||||||
, param_(param)
|
|
||||||
, terminal_output_(terminal_output)
|
|
||||||
, has_solvent_(GET_PROP_VALUE(TypeTag, EnableSolvent))
|
, has_solvent_(GET_PROP_VALUE(TypeTag, EnableSolvent))
|
||||||
, has_polymer_(GET_PROP_VALUE(TypeTag, EnablePolymer))
|
, has_polymer_(GET_PROP_VALUE(TypeTag, EnablePolymer))
|
||||||
{
|
{
|
||||||
const auto& eclState = ebosSimulator_.vanguard().eclState();
|
terminal_output_ = false;
|
||||||
|
if (ebosSimulator.gridView().comm().rank() == 0)
|
||||||
|
terminal_output_ = EWOMS_GET_PARAM(TypeTag, bool, EnableTerminalOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeTag>
|
||||||
|
void
|
||||||
|
BlackoilWellModel<TypeTag>::
|
||||||
|
init(const Opm::EclipseState& eclState, const Opm::Schedule& schedule)
|
||||||
|
{
|
||||||
|
gravity_ = ebosSimulator_.problem().gravity()[2];
|
||||||
|
|
||||||
|
extractLegacyCellPvtRegionIndex_();
|
||||||
|
extractLegacyDepth_();
|
||||||
|
|
||||||
phase_usage_ = phaseUsageFromDeck(eclState);
|
phase_usage_ = phaseUsageFromDeck(eclState);
|
||||||
|
|
||||||
const auto& gridView = ebosSimulator_.gridView();
|
const auto& gridView = ebosSimulator_.gridView();
|
||||||
@@ -28,6 +38,75 @@ namespace Opm {
|
|||||||
extractLegacyCellPvtRegionIndex_();
|
extractLegacyCellPvtRegionIndex_();
|
||||||
extractLegacyDepth_();
|
extractLegacyDepth_();
|
||||||
initial_step_ = true;
|
initial_step_ = true;
|
||||||
|
|
||||||
|
const auto& grid = ebosSimulator_.vanguard().grid();
|
||||||
|
const auto& cartDims = Opm::UgGridHelpers::cartDims(grid);
|
||||||
|
setupCartesianToCompressed_(Opm::UgGridHelpers::globalCell(grid),
|
||||||
|
cartDims[0]*cartDims[1]*cartDims[2]);
|
||||||
|
|
||||||
|
// add the eWoms auxiliary module for the wells to the list
|
||||||
|
ebosSimulator_.model().addAuxiliaryModule(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeTag>
|
||||||
|
void
|
||||||
|
BlackoilWellModel<TypeTag>::
|
||||||
|
addNeighbors(std::vector<NeighborSet>& neighbors) const
|
||||||
|
{
|
||||||
|
if (!param_.matrix_add_well_contributions_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create cartesian to compressed mapping
|
||||||
|
int last_time_step = schedule().getTimeMap().size() - 1;
|
||||||
|
const auto& schedule_wells = schedule().getWells();
|
||||||
|
const auto& cartesianSize = Opm::UgGridHelpers::cartDims(grid());
|
||||||
|
|
||||||
|
// initialize the additional cell connections introduced by wells.
|
||||||
|
for (const auto well : schedule_wells)
|
||||||
|
{
|
||||||
|
std::vector<int> wellCells;
|
||||||
|
// All possible connections of the well
|
||||||
|
const auto& connectionSet = well->getConnections(last_time_step);
|
||||||
|
wellCells.reserve(connectionSet.size());
|
||||||
|
|
||||||
|
for ( size_t c=0; c < connectionSet.size(); c++ )
|
||||||
|
{
|
||||||
|
const auto& connection = connectionSet.get(c);
|
||||||
|
int i = connection.getI();
|
||||||
|
int j = connection.getJ();
|
||||||
|
int k = connection.getK();
|
||||||
|
int cart_grid_idx = i + cartesianSize[0]*(j + cartesianSize[1]*k);
|
||||||
|
int compressed_idx = cartesian_to_compressed_.at(cart_grid_idx);
|
||||||
|
|
||||||
|
if ( compressed_idx >= 0 ) { // Ignore connections in inactive/remote cells.
|
||||||
|
wellCells.push_back(compressed_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int cellIdx : wellCells) {
|
||||||
|
neighbors[cellIdx].insert(wellCells.begin(),
|
||||||
|
wellCells.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeTag>
|
||||||
|
void
|
||||||
|
BlackoilWellModel<TypeTag>::
|
||||||
|
linearize(JacobianMatrix& mat , GlobalEqVector& res)
|
||||||
|
{
|
||||||
|
if (!localWellsActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto& well: well_container_) {
|
||||||
|
if (param_.matrix_add_well_contributions_)
|
||||||
|
well->addWellContributions(mat);
|
||||||
|
|
||||||
|
// applying the well residual to reservoir residuals
|
||||||
|
// r = r - duneC_^T * invDuneD_ * resWell_
|
||||||
|
well->apply(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -126,15 +205,17 @@ namespace Opm {
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
beginTimeStep(const int timeStepIdx, const double simulationTime) {
|
beginTimeStep() {
|
||||||
well_state_ = previous_well_state_;
|
well_state_ = previous_well_state_;
|
||||||
|
|
||||||
|
const int reportStepIdx = ebosSimulator_.episodeIndex();
|
||||||
|
const double simulationTime = ebosSimulator_.time();
|
||||||
|
|
||||||
// test wells
|
// test wells
|
||||||
wellTesting(timeStepIdx, simulationTime);
|
wellTesting(reportStepIdx, simulationTime);
|
||||||
|
|
||||||
// create the well container
|
// create the well container
|
||||||
well_container_ = createWellContainer(timeStepIdx);
|
well_container_ = createWellContainer(reportStepIdx);
|
||||||
|
|
||||||
// do the initialization for all the wells
|
// do the initialization for all the wells
|
||||||
// TODO: to see whether we can postpone of the intialization of the well containers to
|
// TODO: to see whether we can postpone of the intialization of the well containers to
|
||||||
@@ -205,12 +286,6 @@ namespace Opm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// only use this for restart.
|
|
||||||
template<typename TypeTag>
|
|
||||||
void
|
|
||||||
BlackoilWellModel<TypeTag>::
|
|
||||||
setRestartWellState(const WellState& well_state) { previous_well_state_ = well_state; }
|
|
||||||
|
|
||||||
// called at the end of a report step
|
// called at the end of a report step
|
||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
@@ -238,6 +313,60 @@ namespace Opm {
|
|||||||
previous_well_state_ = well_state_;
|
previous_well_state_ = well_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename TypeTag>
|
||||||
|
template <class Context>
|
||||||
|
void
|
||||||
|
BlackoilWellModel<TypeTag>::
|
||||||
|
computeTotalRatesForDof(RateVector& rate,
|
||||||
|
const Context& context,
|
||||||
|
unsigned spaceIdx,
|
||||||
|
unsigned timeIdx) const
|
||||||
|
{
|
||||||
|
rate = 0;
|
||||||
|
int elemIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
|
||||||
|
for (const auto& well : well_container_)
|
||||||
|
well->addCellRates(rate, elemIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeTag>
|
||||||
|
void
|
||||||
|
BlackoilWellModel<TypeTag>::
|
||||||
|
initFromRestartFile(const RestartValue& restartValues)
|
||||||
|
{
|
||||||
|
// gives a dummy dynamic_list_econ_limited
|
||||||
|
DynamicListEconLimited dummyListEconLimited;
|
||||||
|
const auto& defunctWellNames = ebosSimulator_.vanguard().defunctWellNames();
|
||||||
|
WellsManager wellsmanager(eclState(),
|
||||||
|
schedule(),
|
||||||
|
// The restart step value is used to identify wells present at the given
|
||||||
|
// time step. Wells that are added at the same time step as RESTART is initiated
|
||||||
|
// will not be present in a restart file. Use the previous time step to retrieve
|
||||||
|
// wells that have information written to the restart file.
|
||||||
|
std::max(eclState().getInitConfig().getRestartStep() - 1, 0),
|
||||||
|
Opm::UgGridHelpers::numCells(grid()),
|
||||||
|
Opm::UgGridHelpers::globalCell(grid()),
|
||||||
|
Opm::UgGridHelpers::cartDims(grid()),
|
||||||
|
Opm::UgGridHelpers::dimensions(grid()),
|
||||||
|
Opm::UgGridHelpers::cell2Faces(grid()),
|
||||||
|
Opm::UgGridHelpers::beginFaceCentroids(grid()),
|
||||||
|
dummyListEconLimited,
|
||||||
|
grid().comm().size() > 1,
|
||||||
|
defunctWellNames);
|
||||||
|
|
||||||
|
const Wells* wells = wellsmanager.c_wells();
|
||||||
|
|
||||||
|
const int nw = wells->number_of_wells;
|
||||||
|
if (nw > 0) {
|
||||||
|
auto phaseUsage = phaseUsageFromDeck(eclState());
|
||||||
|
size_t numCells = Opm::UgGridHelpers::numCells(grid());
|
||||||
|
well_state_.resize(wells, numCells, phaseUsage); //Resize for restart step
|
||||||
|
wellsToState(restartValues.wells, phaseUsage, well_state_);
|
||||||
|
previous_well_state_ = well_state_;
|
||||||
|
}
|
||||||
|
initial_step_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
std::vector<typename BlackoilWellModel<TypeTag>::WellInterfacePtr >
|
std::vector<typename BlackoilWellModel<TypeTag>::WellInterfacePtr >
|
||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
@@ -401,7 +530,7 @@ namespace Opm {
|
|||||||
// basically, this is a more updated state from the solveWellEq based on fixed
|
// basically, this is a more updated state from the solveWellEq based on fixed
|
||||||
// reservoir state, will tihs be a better place to inialize the explict information?
|
// reservoir state, will tihs be a better place to inialize the explict information?
|
||||||
}
|
}
|
||||||
assembleWellEq(dt, false);
|
assembleWellEq(dt);
|
||||||
|
|
||||||
last_report_.converged = true;
|
last_report_.converged = true;
|
||||||
}
|
}
|
||||||
@@ -413,32 +542,13 @@ namespace Opm {
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
assembleWellEq(const double dt,
|
assembleWellEq(const double dt)
|
||||||
bool only_wells)
|
|
||||||
{
|
{
|
||||||
for (auto& well : well_container_) {
|
for (auto& well : well_container_) {
|
||||||
well->assembleWellEq(ebosSimulator_, dt, well_state_, only_wells);
|
well->assembleWellEq(ebosSimulator_, dt, well_state_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// applying the well residual to reservoir residuals
|
|
||||||
// r = r - duneC_^T * invDuneD_ * resWell_
|
|
||||||
template<typename TypeTag>
|
|
||||||
void
|
|
||||||
BlackoilWellModel<TypeTag>::
|
|
||||||
apply( BVector& r) const
|
|
||||||
{
|
|
||||||
if ( ! localWellsActive() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& well : well_container_) {
|
|
||||||
well->apply(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Ax = A x - C D^-1 B x
|
// Ax = A x - C D^-1 B x
|
||||||
@@ -584,7 +694,7 @@ namespace Opm {
|
|||||||
int it = 0;
|
int it = 0;
|
||||||
bool converged;
|
bool converged;
|
||||||
do {
|
do {
|
||||||
assembleWellEq(dt, true);
|
assembleWellEq(dt);
|
||||||
|
|
||||||
converged = getWellConvergence(B_avg);
|
converged = getWellConvergence(B_avg);
|
||||||
|
|
||||||
@@ -1071,16 +1181,17 @@ namespace Opm {
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
setupCompressedToCartesian(const int* global_cell, int number_of_cells, std::map<int,int>& cartesian_to_compressed ) const
|
setupCartesianToCompressed_(const int* global_cell, int number_of_cartesian_cells)
|
||||||
{
|
{
|
||||||
|
cartesian_to_compressed_.resize(number_of_cartesian_cells, -1);
|
||||||
if (global_cell) {
|
if (global_cell) {
|
||||||
for (int i = 0; i < number_of_cells; ++i) {
|
for (unsigned i = 0; i < number_of_cells_; ++i) {
|
||||||
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
|
cartesian_to_compressed_[global_cell[i]] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < number_of_cells; ++i) {
|
for (unsigned i = 0; i < number_of_cells_; ++i) {
|
||||||
cartesian_to_compressed.insert(std::make_pair(i, i));
|
cartesian_to_compressed_[i] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1091,16 +1202,8 @@ namespace Opm {
|
|||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
computeRepRadiusPerfLength(const Grid& grid)
|
computeRepRadiusPerfLength(const Grid& grid)
|
||||||
{
|
{
|
||||||
// TODO, the function does not work for parallel running
|
|
||||||
// to be fixed later.
|
|
||||||
const int* global_cell = Opm::UgGridHelpers::globalCell(grid);
|
|
||||||
|
|
||||||
std::map<int,int> cartesian_to_compressed;
|
|
||||||
setupCompressedToCartesian(global_cell, number_of_cells_,
|
|
||||||
cartesian_to_compressed);
|
|
||||||
|
|
||||||
for (const auto& well : well_container_) {
|
for (const auto& well : well_container_) {
|
||||||
well->computeRepRadiusPerfLength(grid, cartesian_to_compressed);
|
well->computeRepRadiusPerfLength(grid, cartesian_to_compressed_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef WellInterface<TypeTag> Base;
|
typedef WellInterface<TypeTag> Base;
|
||||||
|
typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
|
||||||
|
|
||||||
using typename Base::WellState;
|
using typename Base::WellState;
|
||||||
using typename Base::Simulator;
|
using typename Base::Simulator;
|
||||||
@@ -107,44 +108,43 @@ namespace Opm
|
|||||||
virtual void init(const PhaseUsage* phase_usage_arg,
|
virtual void init(const PhaseUsage* phase_usage_arg,
|
||||||
const std::vector<double>& depth_arg,
|
const std::vector<double>& depth_arg,
|
||||||
const double gravity_arg,
|
const double gravity_arg,
|
||||||
const int num_cells);
|
const int num_cells) override;
|
||||||
|
|
||||||
|
|
||||||
virtual void initPrimaryVariablesEvaluation() const;
|
virtual void initPrimaryVariablesEvaluation() const override;
|
||||||
|
|
||||||
virtual void assembleWellEq(Simulator& ebosSimulator,
|
virtual void assembleWellEq(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state,
|
WellState& well_state) override;
|
||||||
bool only_wells);
|
|
||||||
|
|
||||||
/// updating the well state based the control mode specified with current
|
/// updating the well state based the control mode specified with current
|
||||||
// TODO: later will check wheter we need current
|
// TODO: later will check wheter we need current
|
||||||
virtual void updateWellStateWithTarget(WellState& well_state) const;
|
virtual void updateWellStateWithTarget(WellState& well_state) const override;
|
||||||
|
|
||||||
/// check whether the well equations get converged for this well
|
/// check whether the well equations get converged for this well
|
||||||
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const;
|
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const override;
|
||||||
|
|
||||||
/// Ax = Ax - C D^-1 B x
|
/// Ax = Ax - C D^-1 B x
|
||||||
virtual void apply(const BVector& x, BVector& Ax) const;
|
virtual void apply(const BVector& x, BVector& Ax) const override;
|
||||||
/// r = r - C D^-1 Rw
|
/// r = r - C D^-1 Rw
|
||||||
virtual void apply(BVector& r) const;
|
virtual void apply(BVector& r) const override;
|
||||||
|
|
||||||
/// using the solution x to recover the solution xw for wells and applying
|
/// using the solution x to recover the solution xw for wells and applying
|
||||||
/// xw to update Well State
|
/// xw to update Well State
|
||||||
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
|
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
|
||||||
WellState& well_state) const;
|
WellState& well_state) const override;
|
||||||
|
|
||||||
/// computing the well potentials for group control
|
/// computing the well potentials for group control
|
||||||
virtual void computeWellPotentials(const Simulator& ebosSimulator,
|
virtual void computeWellPotentials(const Simulator& ebosSimulator,
|
||||||
const WellState& well_state,
|
const WellState& well_state,
|
||||||
std::vector<double>& well_potentials);
|
std::vector<double>& well_potentials) override;
|
||||||
|
|
||||||
virtual void updatePrimaryVariables(const WellState& well_state) const;
|
virtual void updatePrimaryVariables(const WellState& well_state) const override;
|
||||||
|
|
||||||
virtual void solveEqAndUpdateWellState(WellState& well_state); // const?
|
virtual void solveEqAndUpdateWellState(WellState& well_state) override; // const?
|
||||||
|
|
||||||
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
|
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
|
||||||
const WellState& well_state); // should be const?
|
const WellState& well_state) override; // should be const?
|
||||||
|
|
||||||
/// number of segments for this well
|
/// number of segments for this well
|
||||||
/// int number_of_segments_;
|
/// int number_of_segments_;
|
||||||
@@ -152,6 +152,17 @@ namespace Opm
|
|||||||
|
|
||||||
int numberOfPerforations() const;
|
int numberOfPerforations() const;
|
||||||
|
|
||||||
|
void addCellRates(RateVector& rates, int cellIdx) const override
|
||||||
|
{
|
||||||
|
for (int perfIdx = 0; perfIdx < number_of_perforations_; ++perfIdx) {
|
||||||
|
if (Base::cells()[perfIdx] == cellIdx) {
|
||||||
|
for (int i = 0; i < RateVector::dimension; ++i) {
|
||||||
|
rates[i] += connectionRates_[perfIdx][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int number_segments_;
|
int number_segments_;
|
||||||
|
|
||||||
@@ -253,6 +264,8 @@ namespace Opm
|
|||||||
|
|
||||||
std::vector<double> segment_depth_diffs_;
|
std::vector<double> segment_depth_diffs_;
|
||||||
|
|
||||||
|
std::vector<RateVector> connectionRates_;
|
||||||
|
|
||||||
void initMatrixAndVectors(const int num_cells) const;
|
void initMatrixAndVectors(const int num_cells) const;
|
||||||
|
|
||||||
// protected functions
|
// protected functions
|
||||||
@@ -337,14 +350,13 @@ namespace Opm
|
|||||||
bool accelerationalPressureLossConsidered() const;
|
bool accelerationalPressureLossConsidered() const;
|
||||||
|
|
||||||
// TODO: try to make ebosSimulator const, as it should be
|
// TODO: try to make ebosSimulator const, as it should be
|
||||||
void iterateWellEquations(Simulator& ebosSimulator,
|
void iterateWellEquations(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state);
|
WellState& well_state);
|
||||||
|
|
||||||
void assembleWellEqWithoutIteration(Simulator& ebosSimulator,
|
void assembleWellEqWithoutIteration(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state,
|
WellState& well_state);
|
||||||
bool only_wells);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ namespace Opm
|
|||||||
if (has_polymer) {
|
if (has_polymer) {
|
||||||
OPM_THROW(std::runtime_error, "polymer is not supported by multisegment well yet");
|
OPM_THROW(std::runtime_error, "polymer is not supported by multisegment well yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Base::has_energy) {
|
||||||
|
OPM_THROW(std::runtime_error, "energy is not supported by multisegment well yet");
|
||||||
|
}
|
||||||
// since we decide to use the WellSegments from the well parser. we can reuse a lot from it.
|
// since we decide to use the WellSegments from the well parser. we can reuse a lot from it.
|
||||||
// for other facilities needed but not available from parser, we need to process them here
|
// for other facilities needed but not available from parser, we need to process them here
|
||||||
|
|
||||||
@@ -110,6 +114,8 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
Base::init(phase_usage_arg, depth_arg, gravity_arg, num_cells);
|
Base::init(phase_usage_arg, depth_arg, gravity_arg, num_cells);
|
||||||
|
|
||||||
|
connectionRates_.resize(number_of_perforations_);
|
||||||
|
|
||||||
// TODO: for StandardWell, we need to update the perf depth here using depth_arg.
|
// TODO: for StandardWell, we need to update the perf depth here using depth_arg.
|
||||||
// for MultisegmentWell, it is much more complicated.
|
// for MultisegmentWell, it is much more complicated.
|
||||||
// It can be specified directly, it can be calculated from the segment depth,
|
// It can be specified directly, it can be calculated from the segment depth,
|
||||||
@@ -228,10 +234,9 @@ namespace Opm
|
|||||||
template <typename TypeTag>
|
template <typename TypeTag>
|
||||||
void
|
void
|
||||||
MultisegmentWell<TypeTag>::
|
MultisegmentWell<TypeTag>::
|
||||||
assembleWellEq(Simulator& ebosSimulator,
|
assembleWellEq(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state,
|
WellState& well_state)
|
||||||
bool only_wells)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
const bool use_inner_iterations = param_.use_inner_iterations_ms_wells_;
|
const bool use_inner_iterations = param_.use_inner_iterations_ms_wells_;
|
||||||
@@ -239,7 +244,7 @@ namespace Opm
|
|||||||
iterateWellEquations(ebosSimulator, dt, well_state);
|
iterateWellEquations(ebosSimulator, dt, well_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state, only_wells);
|
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1719,7 +1724,7 @@ namespace Opm
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
MultisegmentWell<TypeTag>::
|
MultisegmentWell<TypeTag>::
|
||||||
iterateWellEquations(Simulator& ebosSimulator,
|
iterateWellEquations(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state)
|
WellState& well_state)
|
||||||
{
|
{
|
||||||
@@ -1732,7 +1737,7 @@ namespace Opm
|
|||||||
int it = 0;
|
int it = 0;
|
||||||
for (; it < max_iter_number; ++it) {
|
for (; it < max_iter_number; ++it) {
|
||||||
|
|
||||||
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state, true);
|
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state);
|
||||||
|
|
||||||
const BVectorWell dx_well = mswellhelpers::invDXDirect(duneD_, resWell_);
|
const BVectorWell dx_well = mswellhelpers::invDXDirect(duneD_, resWell_);
|
||||||
|
|
||||||
@@ -1762,19 +1767,16 @@ namespace Opm
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
MultisegmentWell<TypeTag>::
|
MultisegmentWell<TypeTag>::
|
||||||
assembleWellEqWithoutIteration(Simulator& ebosSimulator,
|
assembleWellEqWithoutIteration(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state,
|
WellState& well_state)
|
||||||
bool only_wells)
|
|
||||||
{
|
{
|
||||||
// calculate the fluid properties needed.
|
// calculate the fluid properties needed.
|
||||||
computeSegmentFluidProperties(ebosSimulator);
|
computeSegmentFluidProperties(ebosSimulator);
|
||||||
|
|
||||||
// clear all entries
|
// clear all entries
|
||||||
if (!only_wells) {
|
duneB_ = 0.0;
|
||||||
duneB_ = 0.0;
|
duneC_ = 0.0;
|
||||||
duneC_ = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
duneD_ = 0.0;
|
duneD_ = 0.0;
|
||||||
resWell_ = 0.0;
|
resWell_ = 0.0;
|
||||||
@@ -1784,9 +1786,6 @@ namespace Opm
|
|||||||
//
|
//
|
||||||
// but for the top segment, the pressure equation will be the well control equation, and the other three will be the same.
|
// but for the top segment, the pressure equation will be the well control equation, and the other three will be the same.
|
||||||
|
|
||||||
auto& ebosJac = ebosSimulator.model().linearizer().matrix();
|
|
||||||
auto& ebosResid = ebosSimulator.model().linearizer().residual();
|
|
||||||
|
|
||||||
const bool allow_cf = getAllowCrossFlow();
|
const bool allow_cf = getAllowCrossFlow();
|
||||||
|
|
||||||
const int nseg = numberOfSegments();
|
const int nseg = numberOfSegments();
|
||||||
@@ -1835,31 +1834,24 @@ namespace Opm
|
|||||||
// the cq_s entering mass balance equations need to consider the efficiency factors.
|
// the cq_s entering mass balance equations need to consider the efficiency factors.
|
||||||
const EvalWell cq_s_effective = cq_s[comp_idx] * well_efficiency_factor_;
|
const EvalWell cq_s_effective = cq_s[comp_idx] * well_efficiency_factor_;
|
||||||
|
|
||||||
if (!only_wells) {
|
connectionRates_[perf][comp_idx] = Base::restrictEval(cq_s_effective);
|
||||||
// subtract sum of component fluxes in the reservoir equation.
|
|
||||||
// need to consider the efficiency factor
|
|
||||||
ebosResid[cell_idx][comp_idx] -= cq_s_effective.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// subtract sum of phase fluxes in the well equations.
|
// subtract sum of phase fluxes in the well equations.
|
||||||
resWell_[seg][comp_idx] -= cq_s_effective.value();
|
resWell_[seg][comp_idx] -= cq_s_effective.value();
|
||||||
|
|
||||||
// assemble the jacobians
|
// assemble the jacobians
|
||||||
for (int pv_idx = 0; pv_idx < numWellEq; ++pv_idx) {
|
for (int pv_idx = 0; pv_idx < numWellEq; ++pv_idx) {
|
||||||
if (!only_wells) {
|
|
||||||
// also need to consider the efficiency factor when manipulating the jacobians.
|
// also need to consider the efficiency factor when manipulating the jacobians.
|
||||||
duneC_[seg][cell_idx][pv_idx][comp_idx] -= cq_s_effective.derivative(pv_idx + numEq); // intput in transformed matrix
|
duneC_[seg][cell_idx][pv_idx][comp_idx] -= cq_s_effective.derivative(pv_idx + numEq); // intput in transformed matrix
|
||||||
}
|
|
||||||
// the index name for the D should be eq_idx / pv_idx
|
// the index name for the D should be eq_idx / pv_idx
|
||||||
duneD_[seg][seg][comp_idx][pv_idx] -= cq_s_effective.derivative(pv_idx + numEq);
|
duneD_[seg][seg][comp_idx][pv_idx] -= cq_s_effective.derivative(pv_idx + numEq);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int pv_idx = 0; pv_idx < numEq; ++pv_idx) {
|
for (int pv_idx = 0; pv_idx < numEq; ++pv_idx) {
|
||||||
if (!only_wells) {
|
// also need to consider the efficiency factor when manipulating the jacobians.
|
||||||
// also need to consider the efficiency factor when manipulating the jacobians.
|
duneB_[seg][cell_idx][comp_idx][pv_idx] -= cq_s_effective.derivative(pv_idx);
|
||||||
ebosJac[cell_idx][cell_idx][comp_idx][pv_idx] -= cq_s_effective.derivative(pv_idx);
|
|
||||||
duneB_[seg][cell_idx][comp_idx][pv_idx] -= cq_s_effective.derivative(pv_idx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: we should save the perforation pressure and preforation rates?
|
// TODO: we should save the perforation pressure and preforation rates?
|
||||||
|
|||||||
@@ -188,18 +188,13 @@ public:
|
|||||||
SimulatorReport report;
|
SimulatorReport report;
|
||||||
SimulatorReport stepReport;
|
SimulatorReport stepReport;
|
||||||
|
|
||||||
WellModel wellModel(ebosSimulator_, modelParam_, terminalOutput_);
|
|
||||||
if (isRestart()) {
|
if (isRestart()) {
|
||||||
wellModel.initFromRestartFile(*restartValues);
|
wellModel_().initFromRestartFile(*restartValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modelParam_.matrix_add_well_contributions_ ||
|
// beginReportStep(...) wants to know when we are at the
|
||||||
modelParam_.preconditioner_add_well_contributions_)
|
// beginning of a restart
|
||||||
{
|
bool firstRestartStep = isRestart();
|
||||||
ebosSimulator_.model().clearAuxiliaryModules();
|
|
||||||
wellAuxMod_.reset(new WellConnectionAuxiliaryModule<TypeTag>(schedule(), grid()));
|
|
||||||
ebosSimulator_.model().addAuxiliaryModule(wellAuxMod_.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main simulation loop.
|
// Main simulation loop.
|
||||||
while (!timer.done()) {
|
while (!timer.done()) {
|
||||||
@@ -210,30 +205,25 @@ public:
|
|||||||
OpmLog::debug(ss.str());
|
OpmLog::debug(ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a multiple steps of the solver depending on the time step control.
|
|
||||||
solverTimer.start();
|
|
||||||
//ebosSimulator_.setEpisodeIndex(timer.reportStepNum());
|
|
||||||
wellModel.beginReportStep(timer.currentStepNum());
|
|
||||||
|
|
||||||
auto solver = createSolver(wellModel);
|
|
||||||
|
|
||||||
// write the inital state at the report stage
|
// write the inital state at the report stage
|
||||||
if (timer.initialStep()) {
|
if (timer.initialStep()) {
|
||||||
Dune::Timer perfTimer;
|
Dune::Timer perfTimer;
|
||||||
perfTimer.start();
|
perfTimer.start();
|
||||||
|
|
||||||
// No per cell data is written for initial step, but will be
|
wellModel_().beginReportStep(timer.currentStepNum());
|
||||||
// for subsequent steps, when we have started simulating
|
ebosSimulator_.problem().writeOutput(false);
|
||||||
auto localWellData = wellModel.wellState().report(phaseUsage_, Opm::UgGridHelpers::globalCell(grid()));
|
|
||||||
ebosSimulator_.problem().writeOutput(localWellData,
|
|
||||||
timer.simulationTimeElapsed(),
|
|
||||||
/*isSubstep=*/false,
|
|
||||||
totalTimer.secsSinceStart(),
|
|
||||||
/*nextStepSize=*/-1.0);
|
|
||||||
|
|
||||||
report.output_write_time += perfTimer.stop();
|
report.output_write_time += perfTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run a multiple steps of the solver depending on the time step control.
|
||||||
|
solverTimer.start();
|
||||||
|
|
||||||
|
auto solver = createSolver(wellModel_());
|
||||||
|
|
||||||
|
solver->model().beginReportStep(firstRestartStep);
|
||||||
|
firstRestartStep = false;
|
||||||
|
|
||||||
if (terminalOutput_) {
|
if (terminalOutput_) {
|
||||||
std::ostringstream stepMsg;
|
std::ostringstream stepMsg;
|
||||||
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%d-%b-%Y");
|
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%d-%b-%Y");
|
||||||
@@ -246,8 +236,6 @@ public:
|
|||||||
OpmLog::info(stepMsg.str());
|
OpmLog::info(stepMsg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
solver->model().beginReportStep();
|
|
||||||
|
|
||||||
// If sub stepping is enabled allow the solver to sub cycle
|
// If sub stepping is enabled allow the solver to sub cycle
|
||||||
// in case the report steps are too large for the solver to converge
|
// in case the report steps are too large for the solver to converge
|
||||||
//
|
//
|
||||||
@@ -282,7 +270,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
solver->model().endReportStep();
|
solver->model().endReportStep();
|
||||||
wellModel.endReportStep();
|
|
||||||
|
|
||||||
// take time that was used to solve system for this reportStep
|
// take time that was used to solve system for this reportStep
|
||||||
solverTimer.stop();
|
solverTimer.stop();
|
||||||
@@ -305,13 +292,8 @@ public:
|
|||||||
Dune::Timer perfTimer;
|
Dune::Timer perfTimer;
|
||||||
perfTimer.start();
|
perfTimer.start();
|
||||||
const double nextstep = adaptiveTimeStepping ? adaptiveTimeStepping->suggestedNextStep() : -1.0;
|
const double nextstep = adaptiveTimeStepping ? adaptiveTimeStepping->suggestedNextStep() : -1.0;
|
||||||
|
ebosSimulator_.problem().setNextTimeStepSize(nextstep);
|
||||||
auto localWellData = wellModel.wellState().report(phaseUsage_, Opm::UgGridHelpers::globalCell(grid()));
|
ebosSimulator_.problem().writeOutput(false);
|
||||||
ebosSimulator_.problem().writeOutput(localWellData,
|
|
||||||
timer.simulationTimeElapsed(),
|
|
||||||
/*isSubstep=*/false,
|
|
||||||
totalTimer.secsSinceStart(),
|
|
||||||
nextstep);
|
|
||||||
report.output_write_time += perfTimer.stop();
|
report.output_write_time += perfTimer.stop();
|
||||||
|
|
||||||
if (terminalOutput_) {
|
if (terminalOutput_) {
|
||||||
@@ -379,6 +361,12 @@ protected:
|
|||||||
return initconfig.restartRequested();
|
return initconfig.restartRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WellModel& wellModel_()
|
||||||
|
{ return ebosSimulator_.problem().wellModel(); }
|
||||||
|
|
||||||
|
const WellModel& wellModel_() const
|
||||||
|
{ return ebosSimulator_.problem().wellModel(); }
|
||||||
|
|
||||||
// Data.
|
// Data.
|
||||||
Simulator& ebosSimulator_;
|
Simulator& ebosSimulator_;
|
||||||
std::unique_ptr<WellConnectionAuxiliaryModule<TypeTag>> wellAuxMod_;
|
std::unique_ptr<WellConnectionAuxiliaryModule<TypeTag>> wellAuxMod_;
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ namespace Opm
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
typedef WellInterface<TypeTag> Base;
|
typedef WellInterface<TypeTag> Base;
|
||||||
|
typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
|
||||||
|
|
||||||
// TODO: some functions working with AD variables handles only with values (double) without
|
// 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.
|
// 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.
|
// And also, it can also be beneficial to make these functions hanle different types of AD variables.
|
||||||
@@ -129,52 +131,63 @@ namespace Opm
|
|||||||
virtual void init(const PhaseUsage* phase_usage_arg,
|
virtual void init(const PhaseUsage* phase_usage_arg,
|
||||||
const std::vector<double>& depth_arg,
|
const std::vector<double>& depth_arg,
|
||||||
const double gravity_arg,
|
const double gravity_arg,
|
||||||
const int num_cells);
|
const int num_cells) override;
|
||||||
|
|
||||||
|
|
||||||
virtual void initPrimaryVariablesEvaluation() const;
|
virtual void initPrimaryVariablesEvaluation() const override;
|
||||||
|
|
||||||
virtual void assembleWellEq(Simulator& ebosSimulator,
|
virtual void assembleWellEq(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state,
|
WellState& well_state) override;
|
||||||
bool only_wells);
|
|
||||||
|
|
||||||
/// updating the well state based the control mode specified with current
|
/// updating the well state based the control mode specified with current
|
||||||
// TODO: later will check wheter we need current
|
// TODO: later will check wheter we need current
|
||||||
virtual void updateWellStateWithTarget(WellState& well_state) const;
|
virtual void updateWellStateWithTarget(WellState& well_state) const override;
|
||||||
|
|
||||||
/// check whether the well equations get converged for this well
|
/// check whether the well equations get converged for this well
|
||||||
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const;
|
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const override;
|
||||||
|
|
||||||
/// Ax = Ax - C D^-1 B x
|
/// Ax = Ax - C D^-1 B x
|
||||||
virtual void apply(const BVector& x, BVector& Ax) const;
|
virtual void apply(const BVector& x, BVector& Ax) const override;
|
||||||
/// r = r - C D^-1 Rw
|
/// r = r - C D^-1 Rw
|
||||||
virtual void apply(BVector& r) const;
|
virtual void apply(BVector& r) const override;
|
||||||
|
|
||||||
/// using the solution x to recover the solution xw for wells and applying
|
/// using the solution x to recover the solution xw for wells and applying
|
||||||
/// xw to update Well State
|
/// xw to update Well State
|
||||||
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
|
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
|
||||||
WellState& well_state) const;
|
WellState& well_state) const override;
|
||||||
|
|
||||||
/// computing the well potentials for group control
|
/// computing the well potentials for group control
|
||||||
virtual void computeWellPotentials(const Simulator& ebosSimulator,
|
virtual void computeWellPotentials(const Simulator& ebosSimulator,
|
||||||
const WellState& well_state,
|
const WellState& well_state,
|
||||||
std::vector<double>& well_potentials) /* const */;
|
std::vector<double>& well_potentials) /* const */ override;
|
||||||
|
|
||||||
virtual void updatePrimaryVariables(const WellState& well_state) const;
|
virtual void updatePrimaryVariables(const WellState& well_state) const override;
|
||||||
|
|
||||||
virtual void solveEqAndUpdateWellState(WellState& well_state);
|
virtual void solveEqAndUpdateWellState(WellState& well_state) override;
|
||||||
|
|
||||||
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
|
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
|
||||||
const WellState& well_state); // should be const?
|
const WellState& well_state) override; // should be const?
|
||||||
|
|
||||||
virtual void addWellContributions(Mat& mat) const;
|
virtual void addWellContributions(Mat& mat) const override;
|
||||||
|
|
||||||
/// \brief Wether the Jacobian will also have well contributions in it.
|
/// \brief Wether the Jacobian will also have well contributions in it.
|
||||||
virtual bool jacobianContainsWellContributions() const
|
virtual bool jacobianContainsWellContributions() const override
|
||||||
{
|
{
|
||||||
return param_.matrix_add_well_contributions_;
|
return param_.matrix_add_well_contributions_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addCellRates(RateVector& rates, int cellIdx) const override
|
||||||
|
{
|
||||||
|
for (int perfIdx = 0; perfIdx < number_of_perforations_; ++perfIdx) {
|
||||||
|
if (Base::cells()[perfIdx] == cellIdx) {
|
||||||
|
for (int i = 0; i < RateVector::dimension; ++i) {
|
||||||
|
rates[i] += connectionRates_[perfIdx][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// protected functions from the Base class
|
// protected functions from the Base class
|
||||||
@@ -228,6 +241,8 @@ namespace Opm
|
|||||||
// diagonal matrix for the well
|
// diagonal matrix for the well
|
||||||
DiagMatWell invDuneD_;
|
DiagMatWell invDuneD_;
|
||||||
|
|
||||||
|
std::vector<RateVector> connectionRates_;
|
||||||
|
|
||||||
// several vector used in the matrix calculation
|
// several vector used in the matrix calculation
|
||||||
mutable BVectorWell Bx_;
|
mutable BVectorWell Bx_;
|
||||||
mutable BVectorWell invDrw_;
|
mutable BVectorWell invDrw_;
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
Base::init(phase_usage_arg, depth_arg, gravity_arg, num_cells);
|
Base::init(phase_usage_arg, depth_arg, gravity_arg, num_cells);
|
||||||
|
|
||||||
|
connectionRates_.resize(number_of_perforations_);
|
||||||
|
|
||||||
perf_depth_.resize(number_of_perforations_, 0.);
|
perf_depth_.resize(number_of_perforations_, 0.);
|
||||||
for (int perf = 0; perf < number_of_perforations_; ++perf) {
|
for (int perf = 0; perf < number_of_perforations_; ++perf) {
|
||||||
const int cell_idx = well_cells_[perf];
|
const int cell_idx = well_cells_[perf];
|
||||||
@@ -241,6 +243,7 @@ namespace Opm
|
|||||||
StandardWell<TypeTag>::
|
StandardWell<TypeTag>::
|
||||||
wellSurfaceVolumeFraction(const int compIdx) const
|
wellSurfaceVolumeFraction(const int compIdx) const
|
||||||
{
|
{
|
||||||
|
|
||||||
EvalWell sum_volume_fraction_scaled = 0.;
|
EvalWell sum_volume_fraction_scaled = 0.;
|
||||||
for (int idx = 0; idx < num_components_; ++idx) {
|
for (int idx = 0; idx < num_components_; ++idx) {
|
||||||
sum_volume_fraction_scaled += wellVolumeFractionScaled(idx);
|
sum_volume_fraction_scaled += wellVolumeFractionScaled(idx);
|
||||||
@@ -432,24 +435,18 @@ namespace Opm
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
StandardWell<TypeTag>::
|
StandardWell<TypeTag>::
|
||||||
assembleWellEq(Simulator& ebosSimulator,
|
assembleWellEq(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state,
|
WellState& well_state)
|
||||||
bool only_wells)
|
|
||||||
{
|
{
|
||||||
const int np = number_of_phases_;
|
const int np = number_of_phases_;
|
||||||
|
|
||||||
// clear all entries
|
// clear all entries
|
||||||
if (!only_wells) {
|
duneB_ = 0.0;
|
||||||
duneB_ = 0.0;
|
duneC_ = 0.0;
|
||||||
duneC_ = 0.0;
|
|
||||||
}
|
|
||||||
invDuneD_ = 0.0;
|
invDuneD_ = 0.0;
|
||||||
resWell_ = 0.0;
|
resWell_ = 0.0;
|
||||||
|
|
||||||
auto& ebosJac = ebosSimulator.model().linearizer().matrix();
|
|
||||||
auto& ebosResid = ebosSimulator.model().linearizer().residual();
|
|
||||||
|
|
||||||
// TODO: it probably can be static member for StandardWell
|
// TODO: it probably can be static member for StandardWell
|
||||||
const double volume = 0.002831684659200; // 0.1 cu ft;
|
const double volume = 0.002831684659200; // 0.1 cu ft;
|
||||||
|
|
||||||
@@ -483,34 +480,28 @@ namespace Opm
|
|||||||
well_state.wellVaporizedOilRates()[index_of_well_] += perf_vap_oil_rate;
|
well_state.wellVaporizedOilRates()[index_of_well_] += perf_vap_oil_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_energy) {
|
||||||
|
connectionRates_[perf][contiEnergyEqIdx] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) {
|
for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) {
|
||||||
// the cq_s entering mass balance equations need to consider the efficiency factors.
|
// the cq_s entering mass balance equations need to consider the efficiency factors.
|
||||||
const EvalWell cq_s_effective = cq_s[componentIdx] * well_efficiency_factor_;
|
const EvalWell cq_s_effective = cq_s[componentIdx] * well_efficiency_factor_;
|
||||||
|
|
||||||
if (!only_wells) {
|
connectionRates_[perf][componentIdx] = Base::restrictEval(cq_s_effective);
|
||||||
// subtract sum of component fluxes in the reservoir equation.
|
|
||||||
// need to consider the efficiency factor
|
|
||||||
ebosResid[cell_idx][componentIdx] -= cq_s_effective.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// subtract sum of phase fluxes in the well equations.
|
// subtract sum of phase fluxes in the well equations.
|
||||||
resWell_[0][componentIdx] -= cq_s_effective.value();
|
resWell_[0][componentIdx] -= cq_s_effective.value();
|
||||||
|
|
||||||
// assemble the jacobians
|
// assemble the jacobians
|
||||||
for (int pvIdx = 0; pvIdx < numWellEq; ++pvIdx) {
|
for (int pvIdx = 0; pvIdx < numWellEq; ++pvIdx) {
|
||||||
if (!only_wells) {
|
// also need to consider the efficiency factor when manipulating the jacobians.
|
||||||
// also need to consider the efficiency factor when manipulating the jacobians.
|
duneC_[0][cell_idx][pvIdx][componentIdx] -= cq_s_effective.derivative(pvIdx+numEq); // intput in transformed matrix
|
||||||
duneC_[0][cell_idx][pvIdx][componentIdx] -= cq_s_effective.derivative(pvIdx+numEq); // intput in transformed matrix
|
|
||||||
}
|
|
||||||
invDuneD_[0][0][componentIdx][pvIdx] -= cq_s_effective.derivative(pvIdx+numEq);
|
invDuneD_[0][0][componentIdx][pvIdx] -= cq_s_effective.derivative(pvIdx+numEq);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int pvIdx = 0; pvIdx < numEq; ++pvIdx) {
|
for (int pvIdx = 0; pvIdx < numEq; ++pvIdx) {
|
||||||
if (!only_wells) {
|
duneB_[0][cell_idx][componentIdx][pvIdx] -= cq_s_effective.derivative(pvIdx);
|
||||||
// also need to consider the efficiency factor when manipulating the jacobians.
|
|
||||||
ebosJac[cell_idx][cell_idx][componentIdx][pvIdx] -= cq_s_effective.derivative(pvIdx);
|
|
||||||
duneB_[0][cell_idx][componentIdx][pvIdx] -= cq_s_effective.derivative(pvIdx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the perforation phase flux for later usage.
|
// Store the perforation phase flux for later usage.
|
||||||
@@ -574,15 +565,7 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
// compute the thermal flux
|
// compute the thermal flux
|
||||||
cq_r_thermal *= extendEval(fs.enthalpy(phaseIdx)) * extendEval(fs.density(phaseIdx));
|
cq_r_thermal *= extendEval(fs.enthalpy(phaseIdx)) * extendEval(fs.density(phaseIdx));
|
||||||
// scale the flux by the scaling factor for the energy equation
|
connectionRates_[perf][contiEnergyEqIdx] += Base::restrictEval(cq_r_thermal);
|
||||||
cq_r_thermal *= GET_PROP_VALUE(TypeTag, BlackOilEnergyScalingFactor);
|
|
||||||
|
|
||||||
if (!only_wells) {
|
|
||||||
for (int pvIdx = 0; pvIdx < numEq; ++pvIdx) {
|
|
||||||
ebosJac[cell_idx][cell_idx][contiEnergyEqIdx][pvIdx] -= cq_r_thermal.derivative(pvIdx);
|
|
||||||
}
|
|
||||||
ebosResid[cell_idx][contiEnergyEqIdx] -= cq_r_thermal.value();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,12 +578,7 @@ namespace Opm
|
|||||||
} else {
|
} else {
|
||||||
cq_s_poly *= extendEval(intQuants.polymerConcentration() * intQuants.polymerViscosityCorrection());
|
cq_s_poly *= extendEval(intQuants.polymerConcentration() * intQuants.polymerViscosityCorrection());
|
||||||
}
|
}
|
||||||
if (!only_wells) {
|
connectionRates_[perf][contiPolymerEqIdx] = Base::restrictEval(cq_s_poly);
|
||||||
for (int pvIdx = 0; pvIdx < numEq; ++pvIdx) {
|
|
||||||
ebosJac[cell_idx][cell_idx][contiPolymerEqIdx][pvIdx] -= cq_s_poly.derivative(pvIdx);
|
|
||||||
}
|
|
||||||
ebosResid[cell_idx][contiPolymerEqIdx] -= cq_s_poly.value();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the perforation pressure for later usage.
|
// Store the perforation pressure for later usage.
|
||||||
@@ -631,9 +609,16 @@ namespace Opm
|
|||||||
assembleControlEq();
|
assembleControlEq();
|
||||||
|
|
||||||
// do the local inversion of D.
|
// do the local inversion of D.
|
||||||
// we do this manually with invertMatrix to always get our
|
try
|
||||||
// specializations in for 3x3 and 4x4 matrices.
|
{
|
||||||
Dune::ISTLUtility::invertMatrix(invDuneD_[0][0]);
|
Dune::ISTLUtility::invertMatrix(invDuneD_[0][0]);
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
OPM_THROW(Opm::NumericalIssue,"Error when inverting local well equations for well " + name());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ namespace Opm
|
|||||||
typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
|
typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
|
||||||
typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) IntensiveQuantities;
|
typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) IntensiveQuantities;
|
||||||
typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
|
typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
|
||||||
|
typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
|
||||||
|
|
||||||
static const int numEq = Indices::numEq;
|
static const int numEq = Indices::numEq;
|
||||||
typedef double Scalar;
|
typedef double Scalar;
|
||||||
@@ -121,7 +122,7 @@ namespace Opm
|
|||||||
const int indexOfWell() const;
|
const int indexOfWell() const;
|
||||||
|
|
||||||
/// Well cells.
|
/// Well cells.
|
||||||
const std::vector<int>& cells() {return well_cells_; }
|
const std::vector<int>& cells() const {return well_cells_; }
|
||||||
|
|
||||||
/// Well type, INJECTOR or PRODUCER.
|
/// Well type, INJECTOR or PRODUCER.
|
||||||
WellType wellType() const;
|
WellType wellType() const;
|
||||||
@@ -142,20 +143,19 @@ namespace Opm
|
|||||||
|
|
||||||
virtual void solveEqAndUpdateWellState(WellState& well_state) = 0;
|
virtual void solveEqAndUpdateWellState(WellState& well_state) = 0;
|
||||||
|
|
||||||
virtual void assembleWellEq(Simulator& ebosSimulator,
|
virtual void assembleWellEq(const Simulator& ebosSimulator,
|
||||||
const double dt,
|
const double dt,
|
||||||
WellState& well_state,
|
WellState& well_state) = 0;
|
||||||
bool only_wells) = 0;
|
|
||||||
|
|
||||||
void updateWellTestState(const WellState& well_state,
|
void updateWellTestState(const WellState& well_state,
|
||||||
const double& simulationTime,
|
const double& simulationTime,
|
||||||
const bool& writeMessageToOPMLog,
|
const bool& writeMessageToOPMLog,
|
||||||
WellTestState& wellTestState) const;
|
WellTestState& wellTestState
|
||||||
|
) const;
|
||||||
|
|
||||||
void setWellEfficiencyFactor(const double efficiency_factor);
|
void setWellEfficiencyFactor(const double efficiency_factor);
|
||||||
|
|
||||||
void computeRepRadiusPerfLength(const Grid& grid, const std::map<int, int>& cartesian_to_compressed);
|
void computeRepRadiusPerfLength(const Grid& grid, const std::vector<int>& cartesian_to_compressed);
|
||||||
|
|
||||||
/// using the solution x to recover the solution xw for wells and applying
|
/// using the solution x to recover the solution xw for wells and applying
|
||||||
/// xw to update Well State
|
/// xw to update Well State
|
||||||
@@ -196,6 +196,20 @@ namespace Opm
|
|||||||
virtual void addWellContributions(Mat&) const
|
virtual void addWellContributions(Mat&) const
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
virtual void addCellRates(RateVector& rates, int cellIdx) const
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <class EvalWell>
|
||||||
|
Eval restrictEval(const EvalWell& in) const
|
||||||
|
{
|
||||||
|
Eval out = 0.0;
|
||||||
|
out.setValue(in.value());
|
||||||
|
for(int eqIdx = 0; eqIdx < numEq;++eqIdx) {
|
||||||
|
out.setDerivative(eqIdx, in.derivative(eqIdx));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
void closeCompletions(WellTestState& wellTestState);
|
void closeCompletions(WellTestState& wellTestState);
|
||||||
|
|
||||||
const Well* wellEcl() const;
|
const Well* wellEcl() const;
|
||||||
|
|||||||
@@ -875,7 +875,7 @@ namespace Opm
|
|||||||
void
|
void
|
||||||
WellInterface<TypeTag>::
|
WellInterface<TypeTag>::
|
||||||
computeRepRadiusPerfLength(const Grid& grid,
|
computeRepRadiusPerfLength(const Grid& grid,
|
||||||
const std::map<int, int>& cartesian_to_compressed)
|
const std::vector<int>& cartesian_to_compressed)
|
||||||
{
|
{
|
||||||
const int* cart_dims = Opm::UgGridHelpers::cartDims(grid);
|
const int* cart_dims = Opm::UgGridHelpers::cartDims(grid);
|
||||||
auto cell_to_faces = Opm::UgGridHelpers::cell2Faces(grid);
|
auto cell_to_faces = Opm::UgGridHelpers::cell2Faces(grid);
|
||||||
@@ -902,12 +902,12 @@ namespace Opm
|
|||||||
|
|
||||||
const int* cpgdim = cart_dims;
|
const int* cpgdim = cart_dims;
|
||||||
const int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
|
const int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
|
||||||
const std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
|
const int cell = cartesian_to_compressed[cart_grid_indx];
|
||||||
if (cgit == cartesian_to_compressed.end()) {
|
|
||||||
|
if (cell < 0) {
|
||||||
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
|
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
|
||||||
<< k << " not found in grid (well = " << name() << ')');
|
<< k << " not found in grid (well = " << name() << ')');
|
||||||
}
|
}
|
||||||
const int cell = cgit->second;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
double radius = connection.rw();
|
double radius = connection.rw();
|
||||||
@@ -1023,7 +1023,7 @@ namespace Opm
|
|||||||
bool converged;
|
bool converged;
|
||||||
WellState well_state0 = well_state;
|
WellState well_state0 = well_state;
|
||||||
do {
|
do {
|
||||||
assembleWellEq(ebosSimulator, dt, well_state, true);
|
assembleWellEq(ebosSimulator, dt, well_state);
|
||||||
|
|
||||||
auto report = getWellConvergence(B_avg);
|
auto report = getWellConvergence(B_avg);
|
||||||
converged = report.converged();
|
converged = report.converged();
|
||||||
@@ -1047,6 +1047,7 @@ namespace Opm
|
|||||||
if ( terminal_output ) {
|
if ( terminal_output ) {
|
||||||
OpmLog::debug("WellTest: Well equation for well" +name() + " solution failed in getting converged with " + std::to_string(it) + " iterations");
|
OpmLog::debug("WellTest: Well equation for well" +name() + " solution failed in getting converged with " + std::to_string(it) + " iterations");
|
||||||
}
|
}
|
||||||
|
well_state = well_state0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,7 +203,6 @@ namespace Opm {
|
|||||||
|
|
||||||
auto& ebosSimulator = solver.model().ebosSimulator();
|
auto& ebosSimulator = solver.model().ebosSimulator();
|
||||||
auto& ebosProblem = ebosSimulator.problem();
|
auto& ebosProblem = ebosSimulator.problem();
|
||||||
auto phaseUsage = Opm::phaseUsageFromDeck(ebosSimulator.vanguard().eclState());
|
|
||||||
|
|
||||||
// create adaptive step timer with previously used sub step size
|
// create adaptive step timer with previously used sub step size
|
||||||
AdaptiveSimulatorTimer substepTimer(simulatorTimer, suggestedNextTimestep_, maxTimeStep_);
|
AdaptiveSimulatorTimer substepTimer(simulatorTimer, suggestedNextTimestep_, maxTimeStep_);
|
||||||
@@ -316,13 +315,7 @@ namespace Opm {
|
|||||||
Opm::time::StopWatch perfTimer;
|
Opm::time::StopWatch perfTimer;
|
||||||
perfTimer.start();
|
perfTimer.start();
|
||||||
|
|
||||||
// The writeOutput expects a local data::solution vector and a local data::well vector.
|
ebosProblem.writeOutput(/*isSubStep=*/true);
|
||||||
auto localWellData = solver.model().wellModel().wellState().report(phaseUsage, Opm::UgGridHelpers::globalCell(ebosSimulator.vanguard().grid()));
|
|
||||||
ebosProblem.writeOutput(localWellData,
|
|
||||||
substepTimer.simulationTimeElapsed(),
|
|
||||||
/*isSubstep=*/true,
|
|
||||||
substepReport.total_time,
|
|
||||||
/*nextStepSize=*/-1.0);
|
|
||||||
|
|
||||||
report.output_write_time += perfTimer.secsSinceStart();
|
report.output_write_time += perfTimer.secsSinceStart();
|
||||||
}
|
}
|
||||||
@@ -361,6 +354,7 @@ namespace Opm {
|
|||||||
|
|
||||||
++restarts;
|
++restarts;
|
||||||
}
|
}
|
||||||
|
ebosProblem.setNextTimeStepSize(substepTimer.currentStepLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user