2013-12-06 22:13:29 +08:00
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
|
|
|
|
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
|
|
|
|
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
|
|
|
|
|
|
|
|
|
namespace Opm {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef PolymerPropsAd::ADB ADB;
|
|
|
|
|
typedef PolymerPropsAd::V V;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
PolymerPropsAd::PolymerPropsAd()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PolymerPropsAd::PolymerPropsAd(const int num_cells,
|
|
|
|
|
const double c_max,
|
|
|
|
|
const double mix_param,
|
|
|
|
|
const double std::vector<double>& c_vals_visc,
|
|
|
|
|
const double std::vector<double>& visc_mult_vals)
|
|
|
|
|
: num_cells_ (num_cells)
|
|
|
|
|
, c_max_ (c_max)
|
|
|
|
|
, mix_param_(mix_param)
|
|
|
|
|
, c_vals_visc_ (c_vals_visc)
|
|
|
|
|
, visc_mult_vals_ (visc_mult_vals)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-12-11 22:52:11 +08:00
|
|
|
double PolymerPropsAd::num_cells() const
|
2013-12-06 22:13:29 +08:00
|
|
|
{
|
|
|
|
|
return num__cells_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double PolymerPropsAd::cMax() const
|
|
|
|
|
{
|
|
|
|
|
return c_max_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double PolymerPropsAd::mixParam() const
|
|
|
|
|
{
|
|
|
|
|
return mix_param_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V PolymerPropsAd::muM(const V& c,
|
|
|
|
|
const double* visc) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = num_cells();
|
|
|
|
|
assert(nc == c.size());
|
|
|
|
|
std::vector<double> mu(nc);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
mu[i] = Opm::linearInterpolation(c_vals_visc_, visc_mult_vals_, c(i));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const V muM = Eigen::Map<const V>(&mu[0], nc);
|
|
|
|
|
|
|
|
|
|
const double mu_w = visc[0];
|
|
|
|
|
|
|
|
|
|
return muM * mu_w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADB PolymerPropsAd::muM(const ADB& c,
|
|
|
|
|
const double* visc) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = num_cells();
|
|
|
|
|
assert(nc == c.size());
|
|
|
|
|
|
|
|
|
|
V mu_m = muM(c.value());
|
|
|
|
|
|
|
|
|
|
std::vector<double> dmu_dc(nc);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
dmu_dc[i] = Opm::linearInterpolationDerivative(c_vals_visc_, visc_mult_vals_, c.value()(i));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const V dmu = Eigen::Map<const V>(&dmu_dc[0], nc);
|
|
|
|
|
|
|
|
|
|
ADB::M dmu_diag = spdiag(dmu);
|
|
|
|
|
const int num_blocks = c.numBlocks();
|
|
|
|
|
std::vector<ADB::M> jacs(num_blocks);
|
|
|
|
|
|
|
|
|
|
for (int block = 0; block < num_blocks; ++block) {
|
|
|
|
|
jacs[block] = dmu_diag * c.derivative()[block];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const double mu_w = visc[0]
|
|
|
|
|
|
|
|
|
|
return ADB::function(mu_m, jacs) * mu_w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V PolymerPropsAd::ToddLongstaff(const double mix_param,
|
|
|
|
|
const V& muM,
|
|
|
|
|
const V& mu) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = num_cells();
|
|
|
|
|
assert(nc == muM.size());
|
|
|
|
|
|
|
|
|
|
std::vector<double> mueff(nc);
|
|
|
|
|
const double omega = mix_param;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
mueff[i] = std::pow(muM(i),omega) * std::pow(mu(i), 1. - omega);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const V muEff = Eigen::Map<const V>(&mueff[0], nc);
|
|
|
|
|
|
|
|
|
|
return muEff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADB PolymerPropsAd::ToddLongstaff(const double mix_param,
|
|
|
|
|
const ADB& muM,
|
|
|
|
|
const ADB& mu) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = num_cells();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V PolymerPropsAd::muPolyEff(const double mix_param,
|
|
|
|
|
const V& muM,
|
|
|
|
|
const V& muPoly) const
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
return ToddLongstaff(mix_param, muM, muPoly);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
V PolymerPropsAd::muWatEff(const double mix_param,
|
|
|
|
|
const std::vecotr<double>& c_max,
|
|
|
|
|
const V& c,
|
|
|
|
|
const V& muM,
|
|
|
|
|
const V& muWat,
|
|
|
|
|
const V& muPolyEff) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = num_cells();
|
|
|
|
|
assert(nc == c.size());
|
|
|
|
|
V muWate = ToddLongstaff(mix_param, muM, muWat);
|
|
|
|
|
|
|
|
|
|
// V cmax = V::Constant(nc, 1, c_max);
|
|
|
|
|
const V cmax = Eigen::Map<const V>(&c_max[0], nc);
|
|
|
|
|
const V one = V::Ones(nc, 1);
|
|
|
|
|
V inv_muWatEff = (one - c / cmax) / muWate + c / cmax / muPolyEff;
|
|
|
|
|
|
|
|
|
|
V muWatEff = one / inv_muWatEff;
|
|
|
|
|
|
|
|
|
|
return muWatEff;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
*/
|
2013-12-12 20:29:40 +08:00
|
|
|
double
|
|
|
|
|
PolymerPropsAd::rockDensity() const
|
|
|
|
|
{
|
|
|
|
|
return polymer_props_.rockDensity();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-12-06 23:35:13 +08:00
|
|
|
PolymerPropsAd::PolymerPropsAd(const PolymerProperties& polymer_props)
|
|
|
|
|
: polymer_props_ (polymer_props)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PolymerPropsAd::~PolymerPropsAd()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-12-06 22:13:29 +08:00
|
|
|
V PolymerPropsAd::effectiveInvWaterVisc(const V& c,
|
|
|
|
|
const double* visc) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = c.size();
|
2013-12-09 20:33:05 +08:00
|
|
|
V inv_mu_w_eff(nc);
|
2013-12-06 22:13:29 +08:00
|
|
|
for (int i = 0; i < nc; ++i) {
|
2013-12-06 23:35:13 +08:00
|
|
|
double im = 0;
|
2013-12-06 22:13:29 +08:00
|
|
|
polymer_props_.effectiveInvVisc(c(i), visc, im);
|
|
|
|
|
inv_mu_w_eff(i) = im;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return inv_mu_w_eff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADB PolymerPropsAd::effectiveInvWaterVisc(const ADB& c,
|
2013-12-09 20:33:05 +08:00
|
|
|
const double* visc) const
|
2013-12-06 22:13:29 +08:00
|
|
|
{
|
2013-12-06 23:35:13 +08:00
|
|
|
const int nc = c.size();
|
2013-12-09 20:33:05 +08:00
|
|
|
V inv_mu_w_eff(nc);
|
|
|
|
|
V dinv_mu_w_eff(nc);
|
2013-12-06 23:35:13 +08:00
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
double im = 0, dim = 0;
|
2013-12-06 22:13:29 +08:00
|
|
|
polymer_props_.effectiveInvViscWithDer(c.value()(i), visc, im, dim);
|
|
|
|
|
inv_mu_w_eff(i) = im;
|
|
|
|
|
dinv_mu_w_eff(i) = dim;
|
|
|
|
|
}
|
2013-12-06 23:35:13 +08:00
|
|
|
ADB::M dim_diag = spdiag(dinv_mu_w_eff);
|
|
|
|
|
const int num_blocks = c.numBlocks();
|
|
|
|
|
std::vector<ADB::M> jacs(num_blocks);
|
|
|
|
|
for (int block = 0; block < num_blocks; ++block) {
|
|
|
|
|
jacs[block] = dim_diag * c.derivative()[block];
|
|
|
|
|
}
|
2013-12-06 22:13:29 +08:00
|
|
|
return ADB::function(inv_mu_w_eff, jacs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V PolymerPropsAd::polymerWaterVelocityRatio(const V& c) const
|
|
|
|
|
{
|
2013-12-06 23:35:13 +08:00
|
|
|
const int nc = c.size();
|
2013-12-09 20:33:05 +08:00
|
|
|
V mc(nc);
|
2013-12-06 23:35:13 +08:00
|
|
|
|
|
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
double m = 0;
|
|
|
|
|
polymer_props_.computeMc(c(i), m);
|
|
|
|
|
mc(i) = m;
|
|
|
|
|
}
|
2013-12-06 22:13:29 +08:00
|
|
|
|
2013-12-06 23:35:13 +08:00
|
|
|
return mc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADB PolymerPropsAd::polymerWaterVelocityRatio(const ADB& c) const
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
const int nc = c.size();
|
2013-12-09 20:33:05 +08:00
|
|
|
V mc(nc);
|
|
|
|
|
V dmc(nc);
|
2013-12-06 23:35:13 +08:00
|
|
|
|
|
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
double m = 0;
|
|
|
|
|
double dm = 0;
|
2013-12-09 20:33:05 +08:00
|
|
|
polymer_props_.computeMcWithDer(c.value()(i), m, dm);
|
2013-12-06 23:35:13 +08:00
|
|
|
|
|
|
|
|
mc(i) = m;
|
|
|
|
|
dmc(i) = dm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ADB::M dmc_diag = spdiag(dmc);
|
|
|
|
|
const int num_blocks = c.numBlocks();
|
|
|
|
|
std::vector<ADB::M> jacs(num_blocks);
|
|
|
|
|
for (int block = 0; block < num_blocks; ++block) {
|
|
|
|
|
jacs[block] = dmc_diag * c.derivative()[block];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ADB::function(mc, jacs);
|
2013-12-06 22:13:29 +08:00
|
|
|
}
|
|
|
|
|
|
2013-12-11 22:52:11 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
V PolymerPropsAd::adsorption(const V& c, const V& cmax_cells) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = c.size();
|
|
|
|
|
V ads(nc);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
double c_ads = 0;
|
|
|
|
|
polymer_props_.adsorption(c(i), cmax_cells(i), c_ads);
|
|
|
|
|
|
|
|
|
|
ads(i) = c_ads;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ads;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ADB PolymerPropsAd::adsorption(const ADB& c, const ADB& cmax_cells) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = c.value().size();
|
|
|
|
|
|
|
|
|
|
V ads(nc);
|
|
|
|
|
V dads(nc);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < nc; ++i) {
|
|
|
|
|
double c_ads = 0;
|
|
|
|
|
double dc_ads = 0;
|
|
|
|
|
polymer_props_.adsorptionWithDer(c.value()(i), cmax_cells.value()(i), c_ads, dc_ads);
|
|
|
|
|
ads(i) = c_ads;
|
|
|
|
|
dads(i) = dc_ads;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ADB::M dads_diag = spdiag(dads);
|
|
|
|
|
int num_blocks = c.numBlocks();
|
|
|
|
|
std::vector<ADB::M> jacs(num_blocks);
|
|
|
|
|
for (int block = 0; block < num_blocks; ++block) {
|
|
|
|
|
jacs[block] = dads_diag * c.derivative()[block];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ADB::function(ads, jacs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V
|
|
|
|
|
PolymerPropsAd::effectiveRelPerm(const V& c,
|
|
|
|
|
const V& cmax_cells,
|
|
|
|
|
const V& krw) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = c.size();
|
|
|
|
|
|
|
|
|
|
V one = V::Ones(nc);
|
2013-12-12 21:58:25 +08:00
|
|
|
V ads = adsorption(c, cmax_cells);
|
2013-12-11 22:52:11 +08:00
|
|
|
double max_ads = polymer_props_.cMaxAds();
|
|
|
|
|
double res_factor = polymer_props_.resFactor();
|
|
|
|
|
double factor = (res_factor -1.) / max_ads;
|
|
|
|
|
V rk = one + factor * ads;
|
|
|
|
|
V krw_eff = krw / rk;
|
|
|
|
|
|
2013-12-12 21:58:25 +08:00
|
|
|
return krw_eff;
|
2013-12-11 22:52:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADB
|
|
|
|
|
PolymerPropsAd::effectiveRelPerm(const ADB& c,
|
|
|
|
|
const ADB& cmax_cells,
|
|
|
|
|
const ADB& krw,
|
|
|
|
|
const ADB& sw) const
|
|
|
|
|
{
|
|
|
|
|
const int nc = c.value().size();
|
|
|
|
|
|
|
|
|
|
V one = V::Ones(nc);
|
|
|
|
|
|
2013-12-12 21:58:25 +08:00
|
|
|
ADB ads = adsorption(c, cmax_cells);
|
2013-12-11 22:52:11 +08:00
|
|
|
V krw_eff = effectiveRelPerm(c.value(), cmax_cells.value(), krw.value());
|
|
|
|
|
|
|
|
|
|
double max_ads = polymer_props_.cMaxAds();
|
|
|
|
|
double res_factor = polymer_props_.resFactor();
|
|
|
|
|
double factor = (res_factor - 1.) / max_ads;
|
|
|
|
|
ADB rk = one + ads * factor;
|
2013-12-12 21:58:25 +08:00
|
|
|
ADB dkrw_ds = krw / rk.value();
|
|
|
|
|
ADB dkrw_dc = -krw.value() / (rk.value() * rk.value()) * ads * factor;
|
2013-12-11 22:52:11 +08:00
|
|
|
|
|
|
|
|
const int num_blocks = c.numBlocks();
|
|
|
|
|
std::vector<ADB::M> jacs(num_blocks);
|
|
|
|
|
for (int block = 0; block < num_blocks; ++block) {
|
2013-12-12 21:58:25 +08:00
|
|
|
jacs[block] = dkrw_ds.derivative()[block] * sw.derivative()[block] + dkrw_dc.derivative()[block] * c.derivative()[block];
|
2013-12-11 22:52:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ADB::function(krw_eff, jacs);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-06 23:35:13 +08:00
|
|
|
}// namespace Opm
|