/*
Copyright 2012 SINTEF ICT, Applied Mathematics.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace Opm
{
double PolymerProperties::cMax() const
{
return c_max_;
}
double PolymerProperties::mixParam() const
{
return mix_param_;
}
double PolymerProperties::rockDensity() const
{
return rock_density_;
}
double PolymerProperties::deadPoreVol() const
{
return dead_pore_vol_;
}
double PolymerProperties::resFactor() const
{
return res_factor_;
}
double PolymerProperties::cMaxAds() const
{
return c_max_ads_;
}
int PolymerProperties::adsIndex() const
{
return ads_index_;
}
const std::vector&
PolymerProperties::shearWaterVelocity() const
{
return water_vel_vals_;
}
const std::vector&
PolymerProperties::shearViscosityReductionFactor() const
{
return shear_vrf_vals_;
}
double PolymerProperties:: plyshlogRefConc() const
{
return plyshlog_ref_conc_;
}
bool PolymerProperties::hasPlyshlogRefSalinity() const
{
return has_plyshlog_ref_salinity_;
}
bool PolymerProperties::hasPlyshlogRefTemp() const
{
return has_plyshlog_ref_temp_;
}
double PolymerProperties::plyshlogRefSalinity() const
{
return plyshlog_ref_salinity_;
}
double PolymerProperties::plyshlogRefTemp() const
{
return plyshlog_ref_temp_;
}
bool PolymerProperties::hasPlyshlog() const
{
return has_plyshlog_;
}
bool PolymerProperties::hasShrate() const
{
return has_shrate_;
}
double PolymerProperties::shrate() const
{
return shrate_;
}
double
PolymerProperties::shearVrf(const double velocity) const
{
return Opm::linearInterpolation(water_vel_vals_, shear_vrf_vals_, velocity);
}
double
PolymerProperties::shearVrfWithDer(const double velocity, double& der) const
{
der = Opm::linearInterpolationDerivative(water_vel_vals_, shear_vrf_vals_, velocity);
return Opm::linearInterpolation(water_vel_vals_, shear_vrf_vals_, velocity);
}
double PolymerProperties::viscMult(double c) const
{
return Opm::linearInterpolation(c_vals_visc_, visc_mult_vals_, c);
}
double PolymerProperties::viscMultWithDer(double c, double* der) const
{
*der = Opm::linearInterpolationDerivative(c_vals_visc_, visc_mult_vals_, c);
return Opm::linearInterpolation(c_vals_visc_, visc_mult_vals_, c);
}
void PolymerProperties::simpleAdsorption(double c, double& c_ads) const
{
double dummy;
simpleAdsorptionBoth(c, c_ads, dummy, false);
}
void PolymerProperties::simpleAdsorptionWithDer(double c, double& c_ads,
double& dc_ads_dc) const
{
simpleAdsorptionBoth(c, c_ads, dc_ads_dc, true);
}
void PolymerProperties::simpleAdsorptionBoth(double c, double& c_ads,
double& dc_ads_dc, bool if_with_der) const
{
c_ads = Opm::linearInterpolation(c_vals_ads_, ads_vals_, c);;
if (if_with_der) {
dc_ads_dc = Opm::linearInterpolationDerivative(c_vals_ads_, ads_vals_, c);
} else {
dc_ads_dc = 0.;
}
}
void PolymerProperties::adsorption(double c, double cmax, double& c_ads) const
{
double dummy;
adsorptionBoth(c, cmax, c_ads, dummy, false);
}
void PolymerProperties::adsorptionWithDer(double c, double cmax,
double& c_ads, double& dc_ads_dc) const
{
adsorptionBoth(c, cmax, c_ads, dc_ads_dc, true);
}
void PolymerProperties::adsorptionBoth(double c, double cmax,
double& c_ads, double& dc_ads_dc,
bool if_with_der) const
{
if (ads_index_ == Desorption) {
simpleAdsorptionBoth(c, c_ads, dc_ads_dc, if_with_der);
} else if (ads_index_ == NoDesorption) {
simpleAdsorptionBoth(std::max(c, cmax), c_ads, dc_ads_dc, if_with_der);
} else {
OPM_THROW(std::runtime_error, "Invalid Adsoption index");
}
}
void PolymerProperties::effectiveVisc(const double c, const double mu_w, double& mu_w_eff) const {
effectiveInvVisc(c, mu_w, mu_w_eff);
mu_w_eff = 1./mu_w_eff;
}
void PolymerProperties::effectiveViscWithDer(const double c, const double mu_w, double& mu_w_eff, double dmu_w_eff_dc) const {
effectiveInvViscWithDer(c, mu_w, mu_w_eff, dmu_w_eff_dc);
mu_w_eff = 1./mu_w_eff;
dmu_w_eff_dc = -dmu_w_eff_dc*mu_w_eff*mu_w_eff;
}
void PolymerProperties::effectiveInvVisc(const double c, const double mu_w, double& inv_mu_w_eff) const
{
double dummy;
effectiveInvViscBoth(c, mu_w, inv_mu_w_eff, dummy, false);
}
void PolymerProperties::effectiveInvViscWithDer(const double c, const double mu_w,
double& inv_mu_w_eff,
double& dinv_mu_w_eff_dc) const {
effectiveInvViscBoth(c, mu_w, inv_mu_w_eff, dinv_mu_w_eff_dc, true);
}
void PolymerProperties::effectiveInvViscBoth(const double c, const double mu_w,
double& inv_mu_w_eff,
double& dinv_mu_w_eff_dc,
bool if_with_der) const {
const double cbar = c/c_max_;
double mu_m;
const double omega = mix_param_;
double dmu_m_dc;
if (if_with_der) {
mu_m = viscMultWithDer(c, &dmu_m_dc)*mu_w;
dmu_m_dc *= mu_w;
} else {
mu_m = viscMult(c)*mu_w;
}
double mu_p = viscMult(c_max_)*mu_w;
double inv_mu_m_omega = std::pow(mu_m, -omega);
double inv_mu_w_e = inv_mu_m_omega*std::pow(mu_w, omega - 1.);
double inv_mu_p_eff = inv_mu_m_omega*std::pow(mu_p, omega - 1.);
inv_mu_w_eff = (1.0 - cbar)*inv_mu_w_e + cbar*inv_mu_p_eff;
if (if_with_der) {
double dinv_mu_w_e_dc = -omega*dmu_m_dc*std::pow(mu_m, -omega - 1)*std::pow(mu_w, omega - 1);
double dinv_mu_p_eff_dc = -omega*dmu_m_dc*std::pow(mu_m, -omega - 1)*std::pow(mu_p, omega - 1);
dinv_mu_w_eff_dc = (1 - cbar)*dinv_mu_w_e_dc + cbar*dinv_mu_p_eff_dc +
1/c_max_*(inv_mu_p_eff - inv_mu_w_e);
}
}
void PolymerProperties::effectiveInvPolyVisc(const double c,
const double mu_w,
double& inv_mu_p_eff) const
{
double dummy;
effectiveInvPolyViscBoth(c, mu_w, inv_mu_p_eff, dummy, false);
}
void PolymerProperties::effectiveInvPolyViscWithDer(const double c,
const double mu_w,
double& inv_mu_p_eff,
double& d_inv_mu_p_eff_dc) const
{
effectiveInvPolyViscBoth(c, mu_w, inv_mu_p_eff, d_inv_mu_p_eff_dc, true);
}
void PolymerProperties::effectiveInvPolyViscBoth(const double c,
const double mu_w,
double& inv_mu_p_eff,
double& dinv_mu_p_eff_dc,
const bool if_with_der) const
{
const double omega = mix_param_;
double mu_m = 0.0;
double dmu_m_dc = 0.0;
if (if_with_der) {
mu_m = viscMultWithDer(c, &dmu_m_dc)*mu_w;
dmu_m_dc *= mu_w;
} else {
mu_m = viscMult(c)*mu_w;
}
const double inv_mu_m_omega = std::pow(mu_m, -omega);
const double mu_p = viscMult(c_max_) * mu_w;
inv_mu_p_eff = inv_mu_m_omega * std::pow(mu_p, omega - 1.);
if (if_with_der) {
dinv_mu_p_eff_dc = -omega * dmu_m_dc * std::pow(mu_m, -omega - 1) * std::pow(mu_p, omega - 1);
}
}
void PolymerProperties::effectiveRelperm(const double c,
const double cmax,
const double* relperm,
double& eff_relperm_wat) const {
double dummy;
effectiveRelpermBoth(c, cmax, relperm, 0, eff_relperm_wat,
dummy, dummy, false);
}
void PolymerProperties::effectiveRelpermWithDer (const double c,
const double cmax,
const double* relperm,
const double* drelperm_ds,
double& eff_relperm_wat,
double& deff_relperm_wat_ds,
double& deff_relperm_wat_dc) const {
effectiveRelpermBoth(c, cmax, relperm,
drelperm_ds, eff_relperm_wat,
deff_relperm_wat_ds, deff_relperm_wat_dc,
true);
}
void PolymerProperties::effectiveRelpermBoth(const double c,
const double cmax,
const double* relperm,
const double* drelperm_ds,
double& eff_relperm_wat,
double& deff_relperm_wat_ds,
double& deff_relperm_wat_dc,
bool if_with_der) const {
double c_ads;
double dc_ads_dc;
adsorptionBoth(c, cmax, c_ads, dc_ads_dc, if_with_der);
double rk = 1 + (res_factor_ - 1)*c_ads/c_max_ads_;
eff_relperm_wat = relperm[0]/rk;
if (if_with_der) {
deff_relperm_wat_ds = (drelperm_ds[0]-drelperm_ds[2])/rk; //derivative with respect to sw
//\frac{\partial k_{rw_eff}}{\parital c} = -\frac{krw}{rk^2}\frac{(RRF-1)}{c^a_{max}}\frac{\partial c^a}{\partial c}.
deff_relperm_wat_dc = -(res_factor_ - 1)*dc_ads_dc*relperm[0]/(rk*rk*c_max_ads_);
} else {
deff_relperm_wat_ds = -1.0;
deff_relperm_wat_dc = -1.0;
}
}
void PolymerProperties::effectiveMobilities(const double c,
const double cmax,
const double* visc,
const double* relperm,
double* mob) const
{
double dummy;
double dummy_pointer[4];
effectiveMobilitiesBoth(c, cmax, visc, relperm,
dummy_pointer, mob, dummy_pointer, dummy, false);
}
void PolymerProperties::effectiveMobilitiesWithDer(const double c,
const double cmax,
const double* visc,
const double* relperm,
const double* drelpermds,
double* mob,
double* dmobds,
double& dmobwatdc) const
{
effectiveMobilitiesBoth(c, cmax, visc,
relperm, drelpermds, mob, dmobds,
dmobwatdc, true);
}
void PolymerProperties::effectiveMobilitiesBoth(const double c,
const double cmax,
const double* visc,
const double* relperm,
const double* drelperm_ds,
double* mob,
double* dmob_ds,
double& dmobwat_dc,
bool if_with_der) const
{
double inv_mu_w_eff;
double dinv_mu_w_eff_dc;
effectiveInvViscBoth(c, visc[0], inv_mu_w_eff, dinv_mu_w_eff_dc, if_with_der);
double eff_relperm_wat;
double deff_relperm_wat_ds;
double deff_relperm_wat_dc;
effectiveRelpermBoth(c, cmax, relperm,
drelperm_ds, eff_relperm_wat,
deff_relperm_wat_ds, deff_relperm_wat_dc,
if_with_der);
// The "function" eff_relperm_wat is defined as a function of only sw (so that its
// partial derivative with respect to so is zero).
mob[0] = eff_relperm_wat*inv_mu_w_eff;
mob[1] = relperm[1]/visc[1];
if (if_with_der) {
dmobwat_dc = eff_relperm_wat*dinv_mu_w_eff_dc
+ deff_relperm_wat_dc*inv_mu_w_eff;
dmob_ds[0*2 + 0] = deff_relperm_wat_ds*inv_mu_w_eff;
// one have to deside which variables to derive
// here the full derivative is written out
dmob_ds[0*2 + 1] = 0.0*(drelperm_ds[0*2 + 1] - drelperm_ds[1*2 + 1])/visc[1];
dmob_ds[1*2 + 0] = -0.0*deff_relperm_wat_ds*inv_mu_w_eff;
dmob_ds[1*2 + 1] = (drelperm_ds[1*2 + 1] - drelperm_ds[0*2 + 1])/visc[1];
}
}
void PolymerProperties::effectiveTotalMobility(const double c,
const double cmax,
const double* visc,
const double* relperm,
double& totmob) const
{
double dummy1[4];
double dummy2[2];
effectiveTotalMobilityBoth(c, cmax, visc, relperm, dummy1,
totmob, dummy2, false);
}
void PolymerProperties::effectiveTotalMobilityWithDer(const double c,
const double cmax,
const double* visc,
const double* relperm,
const double* drelperm_ds,
double& totmob,
double* dtotmob_dsdc) const
{
effectiveTotalMobilityBoth(c, cmax, visc, relperm, drelperm_ds,
totmob, dtotmob_dsdc, true);
}
void PolymerProperties::effectiveTotalMobilityBoth(const double c,
const double cmax,
const double* visc,
const double* relperm,
const double* drelperm_ds,
double& totmob,
double* dtotmob_dsdc,
bool if_with_der) const
{
double mob[2];
double dmob_ds[4];
double dmobwat_dc;
effectiveMobilitiesBoth(c, cmax, visc, relperm, drelperm_ds,
mob, dmob_ds, dmobwat_dc, if_with_der);
totmob = mob[0] + mob[1];
if (if_with_der) {
dtotmob_dsdc[0] = dmob_ds[0*2 + 0] - dmob_ds[1*2 + 0]
+ dmob_ds[0*2 + 1] - dmob_ds[1*2 + 1]; //derivative with respect to sw
dtotmob_dsdc[1] = dmobwat_dc; //derivative with respect to c
}
}
void PolymerProperties::computeMc(const double& c, double& mc) const
{
double dummy;
computeMcBoth(c, mc, dummy, false);
}
void PolymerProperties::computeMcWithDer(const double& c, double& mc,
double& dmc_dc) const
{
computeMcBoth(c, mc, dmc_dc, true);
}
void PolymerProperties::computeMcBoth(const double& c, double& mc,
double& dmc_dc, bool if_with_der) const
{
double cbar = c/c_max_;
double omega = mix_param_;
double r = std::pow(viscMult(c_max_), 1 - omega); // viscMult(c_max_)=mu_p/mu_w
mc = c/(cbar + (1 - cbar)*r);
if (if_with_der) {
dmc_dc = r/std::pow(cbar + (1 - cbar)*r, 2);
} else {
dmc_dc = 0.;
}
}
bool PolymerProperties::computeShearMultLog(std::vector& water_vel, std::vector& visc_mult, std::vector& shear_mult) const
{
double refConcentration = plyshlogRefConc();
double refViscMult = viscMult(refConcentration);
std::vector shear_water_vel = shearWaterVelocity();
std::vector shear_vrf = shearViscosityReductionFactor();
std::vector logShearWaterVel;
std::vector logShearVRF;
logShearWaterVel.resize(shear_water_vel.size());
logShearVRF.resize(shear_water_vel.size());
// converting the table using the reference condition
for (size_t i = 0; i < shear_vrf.size(); ++i) {
shear_vrf[i] = (refViscMult * shear_vrf[i] - 1.) / (refViscMult - 1);
logShearWaterVel[i] = std::log(shear_water_vel[i]);
}
shear_mult.resize(water_vel.size());
// the mimum velocity to apply the shear-thinning
const double minShearVel = shear_water_vel[0];
const double maxShearVel = shear_water_vel.back();
const double epsilon = std::sqrt(std::numeric_limits::epsilon());
for (size_t i = 0; i < water_vel.size(); ++i) {
if (visc_mult[i] - 1. < epsilon || std::abs(water_vel[i]) < minShearVel) {
shear_mult[i] = 1.0;
continue;
}
for (size_t j = 0; j < shear_vrf.size(); ++j) {
logShearVRF[j] = (1 + (visc_mult[i] - 1.0) * shear_vrf[j]) / visc_mult[i];
logShearVRF[j] = std::log(logShearVRF[j]);
}
// const double logWaterVelO = std::log(water_vel[i]);
const double logWaterVelO = std::log(std::abs(water_vel[i]));
size_t iIntersection; // finding the intersection on the iIntersectionth table segment
bool foundSegment = false;
for (iIntersection = 0; iIntersection < shear_vrf.size() - 1; ++iIntersection) {
double temp1 = logShearVRF[iIntersection] + logShearWaterVel[iIntersection] - logWaterVelO;
double temp2 = logShearVRF[iIntersection + 1] + logShearWaterVel[iIntersection + 1] - logWaterVelO;
// ignore the cases the temp1 or temp2 is zero first for simplicity.
// several more complicated cases remain to be implemented.
if( temp1 * temp2 < 0.){
foundSegment = true;
break;
}
}
if (foundSegment == true) {
detail::Point2D lineSegment[2];
lineSegment[0] = detail::Point2D{logShearWaterVel[iIntersection], logShearVRF[iIntersection]};
lineSegment[1] = detail::Point2D{logShearWaterVel[iIntersection + 1], logShearVRF[iIntersection + 1]};
detail::Point2D line[2];
line[0] = detail::Point2D{0, logWaterVelO};
line[1] = detail::Point2D{logWaterVelO, 0};
detail::Point2D intersectionPoint;
bool foundIntersection = detail::Point2D::findIntersection(lineSegment, line, intersectionPoint);
if (foundIntersection) {
shear_mult[i] = std::exp(intersectionPoint.getY());
} else {
std::cerr << " failed in finding the solution for shear-thinning multiplier " << std::endl;
return false; // failed in finding the solution.
}
} else {
// check if the failure in finding the shear multiplier is due to too big water velocity.
if ((logWaterVelO - logShearVRF.back()) < logShearWaterVel.back()) {
std::cout << " the veclocity is " << water_vel[i] << std::endl;
std::cout << " max shear velocity is " << maxShearVel << std::endl;
std::cerr << " something wrong happend in finding segment" << std::endl;
return false;
} else {
shear_mult[i] = std::exp(logShearVRF.back());
}
}
}
return true;
}
}