move relaxationFactorFractionsForProducer to StandardWellPrimaryVariables

This commit is contained in:
Arne Morten Kvarving
2022-11-08 07:09:51 +01:00
parent cd3388f7c0
commit 7b8e88bdd5
6 changed files with 60 additions and 74 deletions

View File

@@ -122,7 +122,6 @@ namespace Opm
using Eval = typename StdWellEval::Eval; using Eval = typename StdWellEval::Eval;
using EvalWell = typename StdWellEval::EvalWell; using EvalWell = typename StdWellEval::EvalWell;
using BVectorWell = typename StdWellEval::BVectorWell; using BVectorWell = typename StdWellEval::BVectorWell;
using DiagMatrixBlockWellType = typename StdWellEval::DiagMatrixBlockWellType;
StandardWell(const Well& well, StandardWell(const Well& well,
const ParallelWellInfo& pw_info, const ParallelWellInfo& pw_info,

View File

@@ -69,53 +69,6 @@ extendEval(const Eval& in) const
return out; return out;
} }
template<class FluidSystem, class Indices, class Scalar>
double
StandardWellEval<FluidSystem,Indices,Scalar>::
relaxationFactorFractionsProducer(const std::vector<double>& primary_variables,
const BVectorWell& dwells)
{
// TODO: not considering solvent yet
// 0.95 is a experimental value, which remains to be optimized
double relaxation_factor = 1.0;
if (FluidSystem::numActivePhases() > 1) {
if constexpr (has_wfrac_variable) {
const double relaxation_factor_w = StandardWellGeneric<Scalar>::
relaxationFactorFraction(primary_variables[WFrac], dwells[0][WFrac]);
relaxation_factor = std::min(relaxation_factor, relaxation_factor_w);
}
if constexpr (has_gfrac_variable) {
const double relaxation_factor_g = StandardWellGeneric<Scalar>::
relaxationFactorFraction(primary_variables[GFrac], dwells[0][GFrac]);
relaxation_factor = std::min(relaxation_factor, relaxation_factor_g);
}
if constexpr (has_wfrac_variable && has_gfrac_variable) {
// We need to make sure the even with the relaxation_factor, the sum of F_w and F_g is below one, so there will
// not be negative oil fraction later
const double original_sum = primary_variables[WFrac] + primary_variables[GFrac];
const double relaxed_update = (dwells[0][WFrac] + dwells[0][GFrac]) * relaxation_factor;
const double possible_updated_sum = original_sum - relaxed_update;
// We only relax if fraction is above 1.
// The newton solver should handle the rest
const double epsilon = 0.001;
if (possible_updated_sum > 1.0 + epsilon) {
// since the orignal sum <= 1.0 the epsilon asserts that
// the relaxed_update is non trivial.
assert(relaxed_update != 0.);
const double further_relaxation_factor = std::abs((1. - original_sum) / relaxed_update) * 0.95;
relaxation_factor *= further_relaxation_factor;
}
}
assert(relaxation_factor >= 0.0 && relaxation_factor <= 1.0);
}
return relaxation_factor;
}
template<class FluidSystem, class Indices, class Scalar> template<class FluidSystem, class Indices, class Scalar>
void void
StandardWellEval<FluidSystem,Indices,Scalar>:: StandardWellEval<FluidSystem,Indices,Scalar>::
@@ -166,7 +119,7 @@ updatePrimaryVariablesNewton(const BVectorWell& dwells,
// for injectors, very typical one of the fractions will be one, and it is easy to get zero value // for injectors, very typical one of the fractions will be one, and it is easy to get zero value
// fractions. not sure what is the best way to handle it yet, so we just use 1.0 here // fractions. not sure what is the best way to handle it yet, so we just use 1.0 here
[[maybe_unused]] const double relaxation_factor_fractions = [[maybe_unused]] const double relaxation_factor_fractions =
(baseif_.isProducer()) ? relaxationFactorFractionsProducer(old_primary_variables, dwells) (baseif_.isProducer()) ? this->primary_variables_.relaxationFactorFractionsProducer(old_primary_variables, dwells)
: 1.0; : 1.0;
// update the second and third well variable (The flux fractions) // update the second and third well variable (The flux fractions)

View File

@@ -62,7 +62,7 @@ protected:
public: public:
using EvalWell = typename PrimaryVariables::EvalWell; using EvalWell = typename PrimaryVariables::EvalWell;
using Eval = DenseAd::Evaluation<Scalar, Indices::numEq>; using Eval = DenseAd::Evaluation<Scalar, Indices::numEq>;
using BVectorWell = typename StandardWellGeneric<Scalar>::BVectorWell; using BVectorWell = typename StandardWellEquations<Scalar,Indices::numEq>::BVectorWell;
//! \brief Returns a const reference to equation system. //! \brief Returns a const reference to equation system.
const StandardWellEquations<Scalar,Indices::numEq>& linSys() const const StandardWellEquations<Scalar,Indices::numEq>& linSys() const
@@ -85,11 +85,6 @@ protected:
EvalWell extendEval(const Eval& in) const; EvalWell extendEval(const Eval& in) const;
// calculate a relaxation factor to avoid overshoot of the fractions for producers
// which might result in negative rates
static double relaxationFactorFractionsProducer(const std::vector<double>& primary_variables,
const BVectorWell& dwells);
// computing the accumulation term for later use in well mass equations // computing the accumulation term for later use in well mass equations
void computeAccumWell(); void computeAccumWell();

View File

@@ -48,25 +48,7 @@ class WellState;
template<class Scalar> template<class Scalar>
class StandardWellGeneric class StandardWellGeneric
{ {
protected: public:
// sparsity pattern for the matrices
//[A C^T [x = [ res
// B D ] x_well] res_well]
// the vector type for the res_well and x_well
using VectorBlockWellType = Dune::DynamicVector<Scalar>;
using BVectorWell = Dune::BlockVector<VectorBlockWellType>;
// the matrix type for the diagonal matrix D
using DiagMatrixBlockWellType = Dune::DynamicMatrix<Scalar>;
using DiagMatWell = Dune::BCRSMatrix<DiagMatrixBlockWellType>;
// the matrix type for the non-diagonal matrix B and C^T
using OffDiagMatrixBlockWellType = Dune::DynamicMatrix<Scalar>;
using OffDiagMatWell = Dune::BCRSMatrix<OffDiagMatrixBlockWellType>;
StandardWellGeneric(const WellInterfaceGeneric& baseif);
// calculate a relaxation factor to avoid overshoot of total rates // calculate a relaxation factor to avoid overshoot of total rates
static double relaxationFactorRate(const std::vector<double>& primary_variables, static double relaxationFactorRate(const std::vector<double>& primary_variables,
const double newton_update); const double newton_update);
@@ -75,6 +57,9 @@ protected:
static double relaxationFactorFraction(const double old_value, static double relaxationFactorFraction(const double old_value,
const double dx); const double dx);
protected:
StandardWellGeneric(const WellInterfaceGeneric& baseif);
void computeConnectionPressureDelta(); void computeConnectionPressureDelta();
// Base interface reference // Base interface reference

View File

@@ -34,9 +34,12 @@
#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp> #include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
#include <opm/simulators/wells/StandardWellGeneric.hpp>
#include <opm/simulators/wells/WellInterfaceIndices.hpp> #include <opm/simulators/wells/WellInterfaceIndices.hpp>
#include <opm/simulators/wells/WellState.hpp> #include <opm/simulators/wells/WellState.hpp>
#include <algorithm>
namespace Opm { namespace Opm {
template<class FluidSystem, class Indices, class Scalar> template<class FluidSystem, class Indices, class Scalar>
@@ -524,6 +527,52 @@ processFractions()
} }
} }
template<class FluidSystem, class Indices, class Scalar>
double StandardWellPrimaryVariables<FluidSystem,Indices,Scalar>::
relaxationFactorFractionsProducer(const std::vector<double>& primary_variables,
const BVectorWell& dwells) const
{
// TODO: not considering solvent yet
// 0.95 is a experimental value, which remains to be optimized
double relaxation_factor = 1.0;
if (FluidSystem::numActivePhases() > 1) {
if constexpr (has_wfrac_variable) {
const double relaxation_factor_w = StandardWellGeneric<Scalar>::
relaxationFactorFraction(primary_variables[WFrac], dwells[0][WFrac]);
relaxation_factor = std::min(relaxation_factor, relaxation_factor_w);
}
if constexpr (has_gfrac_variable) {
const double relaxation_factor_g = StandardWellGeneric<Scalar>::
relaxationFactorFraction(primary_variables[GFrac], dwells[0][GFrac]);
relaxation_factor = std::min(relaxation_factor, relaxation_factor_g);
}
if constexpr (has_wfrac_variable && has_gfrac_variable) {
// We need to make sure the even with the relaxation_factor, the sum of F_w and F_g is below one, so there will
// not be negative oil fraction later
const double original_sum = primary_variables[WFrac] + primary_variables[GFrac];
const double relaxed_update = (dwells[0][WFrac] + dwells[0][GFrac]) * relaxation_factor;
const double possible_updated_sum = original_sum - relaxed_update;
// We only relax if fraction is above 1.
// The newton solver should handle the rest
const double epsilon = 0.001;
if (possible_updated_sum > 1.0 + epsilon) {
// since the orignal sum <= 1.0 the epsilon asserts that
// the relaxed_update is non trivial.
assert(relaxed_update != 0.);
const double further_relaxation_factor = std::abs((1. - original_sum) / relaxed_update) * 0.95;
relaxation_factor *= further_relaxation_factor;
}
}
assert(relaxation_factor >= 0.0 && relaxation_factor <= 1.0);
}
return relaxation_factor;
}
#define INSTANCE(...) \ #define INSTANCE(...) \
template class StandardWellPrimaryVariables<BlackOilFluidSystem<double,BlackOilDefaultIndexTraits>,__VA_ARGS__,double>; template class StandardWellPrimaryVariables<BlackOilFluidSystem<double,BlackOilDefaultIndexTraits>,__VA_ARGS__,double>;

View File

@@ -132,6 +132,11 @@ public:
//! \brief Handle non-reasonable fractions due to numerical overshoot. //! \brief Handle non-reasonable fractions due to numerical overshoot.
void processFractions(); void processFractions();
//! \brief Calculate a relaxation factor for producers.
//! \details To avoid overshoot of the fractions which might result in negative rates.
double relaxationFactorFractionsProducer(const std::vector<double>& primary_variables,
const BVectorWell& dwells) const;
private: private:
//! \brief Returns volume fraction for a component. //! \brief Returns volume fraction for a component.
EvalWell volumeFraction(const unsigned compIdx) const; EvalWell volumeFraction(const unsigned compIdx) const;