mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge branch 'Adding_PLYSHLOG_RELATED' into Adding_SHRATE_RELATED
Conflicts: opm/polymer/PolymerProperties.hpp
This commit is contained in:
commit
d2602cc73f
102
opm/polymer/Point2D.hpp
Normal file
102
opm/polymer/Point2D.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_POINT2D_HEADER_INCLUDED
|
||||
#define OPM_POINT2D_HEADER_INCLUDED
|
||||
|
||||
namespace Opm {
|
||||
|
||||
namespace detail {
|
||||
class Point2D
|
||||
{
|
||||
public:
|
||||
Point2D(const double xi, const double yi)
|
||||
: x_(xi),
|
||||
y_(yi) {
|
||||
|
||||
}
|
||||
|
||||
Point2D()
|
||||
{
|
||||
}
|
||||
|
||||
const double getX() const
|
||||
{
|
||||
return x_;
|
||||
}
|
||||
|
||||
const double getY() const
|
||||
{
|
||||
return y_;
|
||||
}
|
||||
|
||||
void setX(const double x)
|
||||
{
|
||||
x_ = x;
|
||||
}
|
||||
|
||||
void setY(const double y){
|
||||
y_ = y;
|
||||
}
|
||||
|
||||
/// Finding the intersection point of a line segment and a line.
|
||||
/// return true, if found.
|
||||
static bool findIntersection(Point2D line_segment1[2], Point2D line2[2], Point2D& intersection_point)
|
||||
{
|
||||
|
||||
const double x1 = line_segment1[0].getX();
|
||||
const double y1 = line_segment1[0].getY();
|
||||
const double x2 = line_segment1[1].getX();
|
||||
const double y2 = line_segment1[1].getY();
|
||||
|
||||
const double x3 = line2[0].getX();
|
||||
const double y3 = line2[0].getY();
|
||||
const double x4 = line2[1].getX();
|
||||
const double y4 = line2[1].getY();
|
||||
|
||||
const double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
|
||||
|
||||
if (d == 0.) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const double x = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
|
||||
const double y = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
|
||||
|
||||
if (x >= std::min(x1,x2) && x <= std::max(x1,x2)) {
|
||||
intersection_point.setX(x);
|
||||
intersection_point.setY(y);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
double x_;
|
||||
double y_;
|
||||
|
||||
}; // class Point2D
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_POINT2D_HEADER_INCLUDED
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <opm/polymer/PolymerProperties.hpp>
|
||||
#include <opm/polymer/Point2D.hpp>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <opm/core/utility/linearInterpolation.hpp>
|
||||
@ -424,4 +425,98 @@ namespace Opm
|
||||
dmc_dc = 0.;
|
||||
}
|
||||
}
|
||||
|
||||
bool PolymerProperties::computeShearMultLog(std::vector<double>& water_vel, std::vector<double>& visc_mult, std::vector<double>& shear_mult) const
|
||||
{
|
||||
|
||||
double refConcentration = plyshlogRefConc();
|
||||
double refViscMult = viscMult(refConcentration);
|
||||
|
||||
std::vector<double> shear_water_vel = shearWaterVelocity();
|
||||
std::vector<double> shear_vrf = shearViscosityReductionFactor();
|
||||
|
||||
std::vector<double> logShearWaterVel;
|
||||
std::vector<double> 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<double>::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 {
|
||||
if (std::abs(water_vel[i]) < maxShearVel) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -190,14 +190,14 @@ namespace Opm
|
||||
|
||||
plyshlog_ref_conc_ = plyshlogTable.getRefPolymerConcentration();
|
||||
|
||||
if(plyshlogTable.hasRefSalinity()) {
|
||||
if (plyshlogTable.hasRefSalinity()) {
|
||||
has_plyshlog_ref_salinity_ = true;
|
||||
plyshlog_ref_salinity_ = plyshlogTable.getRefSalinity();
|
||||
} else {
|
||||
has_plyshlog_ref_salinity_ = false;
|
||||
}
|
||||
|
||||
if(plyshlogTable.hasRefTemperature()) {
|
||||
if (plyshlogTable.hasRefTemperature()) {
|
||||
has_plyshlog_ref_temp_ = true;
|
||||
plyshlog_ref_temp_ = plyshlogTable.getRefTemperature();
|
||||
} else {
|
||||
@ -351,6 +351,9 @@ namespace Opm
|
||||
void computeMcBoth(const double& c, double& mc,
|
||||
double& dmc_dc, bool if_with_der) const;
|
||||
|
||||
/// Computing the shear multiplier based on the water velocity/shear rate with PLYSHLOG keyword
|
||||
bool computeShearMultLog(std::vector<double>& water_vel, std::vector<double>& visc_mult, std::vector<double>& shear_mult) const;
|
||||
|
||||
private:
|
||||
double c_max_;
|
||||
double mix_param_;
|
||||
@ -396,6 +399,7 @@ namespace Opm
|
||||
double& deff_relperm_wat_ds,
|
||||
double& deff_relperm_wat_dc,
|
||||
bool if_with_der) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
@ -203,7 +203,6 @@ namespace Opm {
|
||||
using Base::drMaxRel;
|
||||
using Base::maxResidualAllowed;
|
||||
|
||||
// using Base::addWellEq;
|
||||
using Base::updateWellControls;
|
||||
using Base::computeWellConnectionPressures;
|
||||
using Base::addWellControlEq;
|
||||
@ -233,17 +232,9 @@ namespace Opm {
|
||||
assembleMassBalanceEq(const SolutionState& state);
|
||||
|
||||
void
|
||||
addWellEq(const SolutionState& state,
|
||||
WellState& xw,
|
||||
V& aliveWells);
|
||||
|
||||
void
|
||||
extraAddWellEq(const SolutionState& state,
|
||||
const WellState& xw,
|
||||
const std::vector<ADB>& cq_ps,
|
||||
const std::vector<ADB>& cmix_s,
|
||||
const ADB& cqt_is,
|
||||
const std::vector<int>& well_cells);
|
||||
addWellContributionToMassBalanceEq(const std::vector<ADB>& cq_s,
|
||||
const SolutionState& state,
|
||||
WellState& xw);
|
||||
|
||||
void
|
||||
computeMassFlux(const int actph ,
|
||||
@ -291,28 +282,16 @@ namespace Opm {
|
||||
int nc,
|
||||
int nw) const;
|
||||
|
||||
|
||||
struct Point2D {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
/// Finding the intersection point of a line segment and a line.
|
||||
/// return true, if found.
|
||||
bool findIntersection (Point2D line_segment1[2], Point2D line2[2], Point2D& intersection_point);
|
||||
|
||||
/// Computing the shear multiplier based on the water velocity/shear rate with PLYSHLOG keyword
|
||||
bool computeShearMultLog( std::vector<double>& water_vel, std::vector<double>& visc_mult, std::vector<double>& shear_mult);
|
||||
|
||||
/// Computing the water velocity without shear-thinning for the cell faces.
|
||||
/// The water velocity will be used for shear-thinning calculation.
|
||||
void computeWaterShearVelocityFaces(const V& transi, const std::vector<ADB>& kr,
|
||||
const std::vector<ADB>& phasePressure, const SolutionState& state,
|
||||
std::vector<double>& water_vel, std::vector<double>& visc_mult);
|
||||
|
||||
void computeWaterShearVelocityWells(const SolutionState& state, WellState& well_state,
|
||||
V& aliveWells, std::vector<double>& water_vel_wells, std::vector<double>& visc_mult_wells);
|
||||
|
||||
/// Computing the water velocity without shear-thinning for the well perforations based on the water flux rate.
|
||||
/// The water velocity will be used for shear-thinning calculation.
|
||||
void computeWaterShearVelocityWells(const SolutionState& state, WellState& xw, const ADB& cq_sw,
|
||||
std::vector<double>& water_vel_wells, std::vector<double>& visc_mult_wells);
|
||||
|
||||
};
|
||||
|
||||
|
@ -291,7 +291,7 @@ namespace Opm {
|
||||
std::vector<double> visc_mult;
|
||||
|
||||
computeWaterShearVelocityFaces(transi, kr, state.canonical_phase_pressures, state, water_vel, visc_mult);
|
||||
if(!computeShearMultLog(water_vel, visc_mult, shear_mult_faces_)) {
|
||||
if ( !polymer_props_ad_.computeShearMultLog(water_vel, visc_mult, shear_mult_faces_) ) {
|
||||
// std::cerr << " failed in calculating the shear-multiplier " << std::endl;
|
||||
OPM_THROW(std::runtime_error, " failed in calculating the shear-multiplier. ");
|
||||
}
|
||||
@ -341,23 +341,26 @@ namespace Opm {
|
||||
|
||||
|
||||
template <class Grid>
|
||||
void BlackoilPolymerModel<Grid>::extraAddWellEq(const SolutionState& state,
|
||||
const WellState& xw,
|
||||
const std::vector<ADB>& cq_ps,
|
||||
const std::vector<ADB>& cmix_s,
|
||||
const ADB& cqt_is,
|
||||
const std::vector<int>& well_cells)
|
||||
void BlackoilPolymerModel<Grid>::addWellContributionToMassBalanceEq(const std::vector<ADB>& cq_s,
|
||||
const SolutionState& state,
|
||||
WellState& xw)
|
||||
|
||||
{
|
||||
Base::addWellContributionToMassBalanceEq(cq_s, state, xw);
|
||||
|
||||
// Add well contributions to polymer mass balance equation
|
||||
if (has_polymer_) {
|
||||
const ADB mc = computeMc(state);
|
||||
const int nc = xw.polymerInflow().size();
|
||||
const V polyin = Eigen::Map<const V>(xw.polymerInflow().data(), nc);
|
||||
const int nperf = wells().well_connpos[wells().number_of_wells];
|
||||
const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
|
||||
const V poly_in_perf = subset(polyin, well_cells);
|
||||
const V poly_mc_perf = subset(mc, well_cells).value();
|
||||
const PhaseUsage& pu = fluid_.phaseUsage();
|
||||
const ADB cq_s_poly = cq_ps[pu.phase_pos[Water]] * poly_mc_perf
|
||||
+ cmix_s[pu.phase_pos[Water]] * cqt_is * poly_in_perf;
|
||||
const V poly_mc_perf = subset(mc.value(), well_cells);
|
||||
const ADB& cq_s_water = cq_s[fluid_.phaseUsage().phase_pos[Water]];
|
||||
Selector<double> injector_selector(cq_s_water.value());
|
||||
const V poly_perf = injector_selector.select(poly_in_perf, poly_mc_perf);
|
||||
const ADB cq_s_poly = cq_s_water * poly_perf;
|
||||
residual_.material_balance_eq[poly_pos_] -= superset(cq_s_poly, well_cells, nc);
|
||||
}
|
||||
}
|
||||
@ -573,30 +576,53 @@ namespace Opm {
|
||||
assembleMassBalanceEq(state);
|
||||
|
||||
// -------- Well equations ----------
|
||||
if ( ! wellsActive() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
V aliveWells;
|
||||
|
||||
const int np = wells().number_of_phases;
|
||||
std::vector<ADB> cq_s(np, ADB::null());
|
||||
|
||||
const int nw = wells().number_of_wells;
|
||||
const int nperf = wells().well_connpos[nw];
|
||||
const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
|
||||
|
||||
std::vector<ADB> mob_perfcells(np, ADB::null());
|
||||
std::vector<ADB> b_perfcells(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
mob_perfcells[phase] = subset(rq_[phase].mob, well_cells);
|
||||
b_perfcells[phase] = subset(rq_[phase].b, well_cells);
|
||||
}
|
||||
if (param_.solve_welleq_initially_ && initial_assembly) {
|
||||
// solve the well equations as a pre-processing step
|
||||
Base::solveWellEq(mob_perfcells, b_perfcells, state, well_state);
|
||||
}
|
||||
|
||||
Base::computeWellFlux(state, mob_perfcells, b_perfcells, aliveWells, cq_s);
|
||||
|
||||
if (has_plyshlog_) {
|
||||
std::vector<double> water_vel_wells;
|
||||
std::vector<double> visc_mult_wells;
|
||||
|
||||
computeWaterShearVelocityWells(state, well_state, aliveWells, water_vel_wells, visc_mult_wells);
|
||||
const int water_pos = fluid_.phaseUsage().phase_pos[Water];
|
||||
computeWaterShearVelocityWells(state, well_state, cq_s[water_pos], water_vel_wells, visc_mult_wells);
|
||||
|
||||
if (!computeShearMultLog(water_vel_wells, visc_mult_wells, shear_mult_wells_)) {
|
||||
// std::cout << " failed in calculating the shear factors for wells " << std::endl;
|
||||
if ( !polymer_props_ad_.computeShearMultLog(water_vel_wells, visc_mult_wells, shear_mult_wells_) ) {
|
||||
OPM_THROW(std::runtime_error, " failed in calculating the shear factors for wells ");
|
||||
}
|
||||
|
||||
/* const int nw = wells().number_of_wells;
|
||||
const int nperf = wells().well_connpos[nw];
|
||||
|
||||
const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
|
||||
|
||||
// assuming the water phase is the first phase
|
||||
const int nw = wells().number_of_wells;
|
||||
mob_perfcells = subset(rq_[0].mob,well_cells); */
|
||||
// applying the shear-thinning to the water phase
|
||||
V shear_mult_wells_v = Eigen::Map<V>(shear_mult_wells_.data(), shear_mult_wells_.size());
|
||||
ADB shear_mult_wells_adb = ADB::constant(shear_mult_wells_v);
|
||||
mob_perfcells[water_pos] = mob_perfcells[water_pos] / shear_mult_wells_adb;
|
||||
}
|
||||
|
||||
addWellEq(state, well_state, aliveWells);
|
||||
Base::computeWellFlux(state, mob_perfcells, b_perfcells, aliveWells, cq_s);
|
||||
Base::updatePerfPhaseRatesAndPressures(cq_s, state, well_state);
|
||||
Base::addWellFluxEq(cq_s, state);
|
||||
addWellContributionToMassBalanceEq(cq_s, state, well_state);
|
||||
addWellControlEq(state, well_state, aliveWells);
|
||||
}
|
||||
|
||||
@ -723,307 +749,6 @@ namespace Opm {
|
||||
return polymer_props_ad_.polymerWaterVelocityRatio(state.concentration);
|
||||
}
|
||||
|
||||
|
||||
template <class Grid>
|
||||
void
|
||||
BlackoilPolymerModel<Grid>::addWellEq(const SolutionState& state,
|
||||
WellState& xw,
|
||||
V& aliveWells)
|
||||
{
|
||||
if( ! wellsActive() ) return ;
|
||||
|
||||
const int nc = Opm::AutoDiffGrid::numCells(grid_);
|
||||
const int np = wells().number_of_phases;
|
||||
const int nw = wells().number_of_wells;
|
||||
const int nperf = wells().well_connpos[nw];
|
||||
const Opm::PhaseUsage& pu = fluid_.phaseUsage();
|
||||
V Tw = Eigen::Map<const V>(wells().WI, nperf);
|
||||
const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
|
||||
|
||||
// pressure diffs computed already (once per step, not changing per iteration)
|
||||
const V& cdp = well_perforation_pressure_diffs_;
|
||||
|
||||
// Extract needed quantities for the perforation cells
|
||||
const ADB& p_perfcells = subset(state.pressure, well_cells);
|
||||
const ADB& rv_perfcells = subset(state.rv,well_cells);
|
||||
const ADB& rs_perfcells = subset(state.rs,well_cells);
|
||||
std::vector<ADB> mob_perfcells(np, ADB::null());
|
||||
std::vector<ADB> b_perfcells(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
mob_perfcells[phase] = subset(rq_[phase].mob,well_cells);
|
||||
b_perfcells[phase] = subset(rq_[phase].b,well_cells);
|
||||
}
|
||||
|
||||
// applying the shear-thinning to the water face
|
||||
if (has_plyshlog_) {
|
||||
V shear_mult_wells_v = Eigen::Map<V>(shear_mult_wells_.data(), shear_mult_wells_.size());
|
||||
ADB shear_mult_wells_adb = ADB::constant(shear_mult_wells_v);
|
||||
mob_perfcells[0] = mob_perfcells[0] / shear_mult_wells_adb;
|
||||
}
|
||||
|
||||
|
||||
// Perforation pressure
|
||||
const ADB perfpressure = (wops_.w2p * state.bhp) + cdp;
|
||||
std::vector<double> perfpressure_d(perfpressure.value().data(), perfpressure.value().data() + nperf);
|
||||
xw.perfPress() = perfpressure_d;
|
||||
|
||||
// Pressure drawdown (also used to determine direction of flow)
|
||||
const ADB drawdown = p_perfcells - perfpressure;
|
||||
|
||||
// Compute vectors with zero and ones that
|
||||
// selects the wanted quantities.
|
||||
|
||||
// selects injection perforations
|
||||
V selectInjectingPerforations = V::Zero(nperf);
|
||||
// selects producing perforations
|
||||
V selectProducingPerforations = V::Zero(nperf);
|
||||
for (int c = 0; c < nperf; ++c){
|
||||
if (drawdown.value()[c] < 0)
|
||||
selectInjectingPerforations[c] = 1;
|
||||
else
|
||||
selectProducingPerforations[c] = 1;
|
||||
}
|
||||
|
||||
// HANDLE FLOW INTO WELLBORE
|
||||
|
||||
// compute phase volumetric rates at standard conditions
|
||||
std::vector<ADB> cq_ps(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
const ADB cq_p = -(selectProducingPerforations * Tw) * (mob_perfcells[phase] * drawdown);
|
||||
cq_ps[phase] = b_perfcells[phase] * cq_p;
|
||||
}
|
||||
if (active_[Oil] && active_[Gas]) {
|
||||
const int oilpos = pu.phase_pos[Oil];
|
||||
const int gaspos = pu.phase_pos[Gas];
|
||||
const ADB cq_psOil = cq_ps[oilpos];
|
||||
const ADB cq_psGas = cq_ps[gaspos];
|
||||
cq_ps[gaspos] += rs_perfcells * cq_psOil;
|
||||
cq_ps[oilpos] += rv_perfcells * cq_psGas;
|
||||
}
|
||||
|
||||
// HANDLE FLOW OUT FROM WELLBORE
|
||||
|
||||
// Using total mobilities
|
||||
ADB total_mob = mob_perfcells[0];
|
||||
for (int phase = 1; phase < np; ++phase) {
|
||||
total_mob += mob_perfcells[phase];
|
||||
}
|
||||
// injection perforations total volume rates
|
||||
const ADB cqt_i = -(selectInjectingPerforations * Tw) * (total_mob * drawdown);
|
||||
|
||||
// compute wellbore mixture for injecting perforations
|
||||
// The wellbore mixture depends on the inflow from the reservoar
|
||||
// and the well injection rates.
|
||||
|
||||
// compute avg. and total wellbore phase volumetric rates at standard conds
|
||||
const DataBlock compi = Eigen::Map<const DataBlock>(wells().comp_frac, nw, np);
|
||||
std::vector<ADB> wbq(np, ADB::null());
|
||||
ADB wbqt = ADB::constant(V::Zero(nw));
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
const ADB& q_ps = wops_.p2w * cq_ps[phase];
|
||||
const ADB& q_s = subset(state.qs, Span(nw, 1, phase*nw));
|
||||
Selector<double> injectingPhase_selector(q_s.value(), Selector<double>::GreaterZero);
|
||||
const int pos = pu.phase_pos[phase];
|
||||
wbq[phase] = (compi.col(pos) * injectingPhase_selector.select(q_s,ADB::constant(V::Zero(nw)))) - q_ps;
|
||||
wbqt += wbq[phase];
|
||||
}
|
||||
|
||||
// compute wellbore mixture at standard conditions.
|
||||
Selector<double> notDeadWells_selector(wbqt.value(), Selector<double>::Zero);
|
||||
std::vector<ADB> cmix_s(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
const int pos = pu.phase_pos[phase];
|
||||
cmix_s[phase] = wops_.w2p * notDeadWells_selector.select(ADB::constant(compi.col(pos)), wbq[phase]/wbqt);
|
||||
}
|
||||
|
||||
// compute volume ratio between connection at standard conditions
|
||||
ADB volumeRatio = ADB::constant(V::Zero(nperf));
|
||||
const ADB d = V::Constant(nperf,1.0) - rv_perfcells * rs_perfcells;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
ADB tmp = cmix_s[phase];
|
||||
|
||||
if (phase == Oil && active_[Gas]) {
|
||||
const int gaspos = pu.phase_pos[Gas];
|
||||
tmp = tmp - rv_perfcells * cmix_s[gaspos] / d;
|
||||
}
|
||||
if (phase == Gas && active_[Oil]) {
|
||||
const int oilpos = pu.phase_pos[Oil];
|
||||
tmp = tmp - rs_perfcells * cmix_s[oilpos] / d;
|
||||
}
|
||||
volumeRatio += tmp / b_perfcells[phase];
|
||||
}
|
||||
|
||||
// injecting connections total volumerates at standard conditions
|
||||
ADB cqt_is = cqt_i/volumeRatio;
|
||||
|
||||
// connection phase volumerates at standard conditions
|
||||
std::vector<ADB> cq_s(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
cq_s[phase] = cq_ps[phase] + cmix_s[phase]*cqt_is;
|
||||
}
|
||||
|
||||
// Add well contributions to mass balance equations
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
residual_.material_balance_eq[phase] -= superset(cq_s[phase],well_cells,nc);
|
||||
}
|
||||
|
||||
// WELL EQUATIONS
|
||||
ADB qs = state.qs;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
qs -= superset(wops_.p2w * cq_s[phase], Span(nw, 1, phase*nw), nw*np);
|
||||
|
||||
}
|
||||
|
||||
// check for dead wells (used in the well controll equations)
|
||||
aliveWells = V::Constant(nw, 1.0);
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
if (wbqt.value()[w] == 0) {
|
||||
aliveWells[w] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the perforation phase rates (used to calculate the pressure drop in the wellbore)
|
||||
V cq = superset(cq_s[0].value(), Span(nperf, np, 0), nperf*np);
|
||||
for (int phase = 1; phase < np; ++phase) {
|
||||
cq += superset(cq_s[phase].value(), Span(nperf, np, phase), nperf*np);
|
||||
}
|
||||
|
||||
std::vector<double> cq_d(cq.data(), cq.data() + nperf*np);
|
||||
xw.perfPhaseRates() = cq_d;
|
||||
|
||||
residual_.well_flux_eq = qs;
|
||||
|
||||
extraAddWellEq(state, xw, cq_ps, cmix_s, cqt_is, well_cells);
|
||||
}
|
||||
|
||||
|
||||
template<class Grid>
|
||||
bool
|
||||
BlackoilPolymerModel<Grid>::findIntersection (Point2D line_segment1[2], Point2D line2[2], Point2D& intersection_point)
|
||||
{
|
||||
|
||||
const double x1 = line_segment1[0].x;
|
||||
const double y1 = line_segment1[0].y;
|
||||
const double x2 = line_segment1[1].x;
|
||||
const double y2 = line_segment1[1].y;
|
||||
|
||||
const double x3 = line2[0].x;
|
||||
const double y3 = line2[0].y;
|
||||
const double x4 = line2[1].x;
|
||||
const double y4 = line2[1].y;
|
||||
|
||||
const double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
|
||||
|
||||
if (d == 0.) { return false; }
|
||||
|
||||
const double x = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
|
||||
const double y = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
|
||||
|
||||
if( x >= std::min(x1,x2) && x <= std::max(x1,x2) ){
|
||||
intersection_point.x = x;
|
||||
intersection_point.y = y;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Grid>
|
||||
bool
|
||||
BlackoilPolymerModel<Grid>::computeShearMultLog( std::vector<double>& water_vel, std::vector<double>& visc_mult, std::vector<double>& shear_mult)
|
||||
{
|
||||
|
||||
double refConcentration = polymer_props_ad_.plyshlogRefConc();
|
||||
double refViscMult = polymer_props_ad_.viscMult(refConcentration);
|
||||
|
||||
std::vector<double> shear_water_vel = polymer_props_ad_.shearWaterVelocity();
|
||||
std::vector<double> shear_vrf = polymer_props_ad_.shearViscosityReductionFactor();
|
||||
|
||||
std::vector<double> logShearWaterVel;
|
||||
std::vector<double> logShearVRF;
|
||||
|
||||
logShearWaterVel.resize(shear_water_vel.size());
|
||||
logShearVRF.resize(shear_water_vel.size());
|
||||
|
||||
// converting the table using the reference condition
|
||||
for(int 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<double>::epsilon());
|
||||
|
||||
for(int 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(int 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]));
|
||||
|
||||
int 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){
|
||||
Point2D lineSegment[2];
|
||||
lineSegment[0] = Point2D{logShearWaterVel[iIntersection], logShearVRF[iIntersection]};
|
||||
lineSegment[1] = Point2D{logShearWaterVel[iIntersection + 1], logShearVRF[iIntersection + 1]};
|
||||
|
||||
Point2D line[2];
|
||||
line[0] = Point2D{0, logWaterVelO};
|
||||
line[1] = Point2D{logWaterVelO, 0};
|
||||
|
||||
Point2D intersectionPoint;
|
||||
|
||||
bool foundIntersection = findIntersection(lineSegment, line, intersectionPoint);
|
||||
|
||||
if(foundIntersection){
|
||||
shear_mult[i] = std::exp(intersectionPoint.y);
|
||||
}else{
|
||||
std::cerr << " failed in finding the solution for shear-thinning multiplier " << std::endl;
|
||||
return false; // failed in finding the solution.
|
||||
}
|
||||
}else{
|
||||
if (std::abs(water_vel[i]) < maxShearVel) {
|
||||
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;
|
||||
}
|
||||
|
||||
template<class Grid>
|
||||
void
|
||||
BlackoilPolymerModel<Grid>::computeWaterShearVelocityFaces(const V& transi, const std::vector<ADB>& kr,
|
||||
@ -1033,7 +758,7 @@ namespace Opm {
|
||||
|
||||
std::vector<double> b_faces;
|
||||
|
||||
const int phase = fluid_.phaseUsage().phase_pos[BlackoilPhases::Aqua]; // water position
|
||||
const int phase = fluid_.phaseUsage().phase_pos[Water]; // water position
|
||||
|
||||
const int canonicalPhaseIdx = canph_[phase];
|
||||
|
||||
@ -1074,9 +799,9 @@ namespace Opm {
|
||||
|
||||
rq_[ phase ].mflux = upwind.select(b * mob) * (transi * dh);
|
||||
|
||||
const auto& tempb_faces = upwind.select(b);
|
||||
b_faces.resize(tempb_faces.size());
|
||||
std::copy(&(tempb_faces.value()[0]), &(tempb_faces.value()[0]) + tempb_faces.size(), b_faces.begin());
|
||||
const auto& b_faces_adb = upwind.select(b);
|
||||
b_faces.resize(b_faces_adb.size());
|
||||
std::copy(&(b_faces_adb.value()[0]), &(b_faces_adb.value()[0]) + b_faces_adb.size(), b_faces.begin());
|
||||
|
||||
const auto& internal_faces = ops_.internal_faces;
|
||||
|
||||
@ -1088,11 +813,11 @@ namespace Opm {
|
||||
}
|
||||
|
||||
const ADB phi = Opm::AutoDiffBlock<double>::constant(Eigen::Map<const V>(& fluid_.porosity()[0], AutoDiffGrid::numCells(grid_), 1));
|
||||
const ADB temp_phiavg = ops_.caver * phi;
|
||||
const ADB phiavg_adb = ops_.caver * phi;
|
||||
|
||||
std::vector<double> phiavg;
|
||||
phiavg.resize(temp_phiavg.size());
|
||||
std::copy(&(temp_phiavg.value()[0]), &(temp_phiavg.value()[0]) + temp_phiavg.size(), phiavg.begin());
|
||||
phiavg.resize(phiavg_adb.size());
|
||||
std::copy(&(phiavg_adb.value()[0]), &(phiavg_adb.value()[0]) + phiavg_adb.size(), phiavg.begin());
|
||||
|
||||
water_vel.resize(nface);
|
||||
std::copy(&(rq_[0].mflux.value()[0]), &(rq_[0].mflux.value()[0]) + nface, water_vel.begin());
|
||||
@ -1149,145 +874,42 @@ namespace Opm {
|
||||
|
||||
template<class Grid>
|
||||
void
|
||||
BlackoilPolymerModel<Grid>::computeWaterShearVelocityWells(const SolutionState& state, WellState& xw,
|
||||
V& aliveWells, std::vector<double>& water_vel_wells, std::vector<double>& visc_mult_wells)
|
||||
BlackoilPolymerModel<Grid>::computeWaterShearVelocityWells(const SolutionState& state, WellState& xw, const ADB& cq_sw,
|
||||
std::vector<double>& water_vel_wells, std::vector<double>& visc_mult_wells)
|
||||
{
|
||||
if( ! wellsActive() ) return ;
|
||||
|
||||
// const int nc = Opm::AutoDiffGrid::numCells(grid_);
|
||||
const int np = wells().number_of_phases;
|
||||
const int nw = wells().number_of_wells;
|
||||
const int nperf = wells().well_connpos[nw];
|
||||
const Opm::PhaseUsage& pu = fluid_.phaseUsage();
|
||||
V Tw = Eigen::Map<const V>(wells().WI, nperf);
|
||||
const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
|
||||
|
||||
// pressure diffs computed already (once per step, not changing per iteration)
|
||||
const V& cdp = well_perforation_pressure_diffs_;
|
||||
|
||||
// Extract needed quantities for the perforation cells
|
||||
const ADB& p_perfcells = subset(state.pressure, well_cells);
|
||||
const ADB& rv_perfcells = subset(state.rv,well_cells);
|
||||
const ADB& rs_perfcells = subset(state.rs,well_cells);
|
||||
std::vector<ADB> mob_perfcells(np, ADB::null());
|
||||
std::vector<ADB> b_perfcells(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
mob_perfcells[phase] = subset(rq_[phase].mob,well_cells);
|
||||
b_perfcells[phase] = subset(rq_[phase].b,well_cells);
|
||||
}
|
||||
|
||||
// Perforation pressure
|
||||
const ADB perfpressure = (wops_.w2p * state.bhp) + cdp;
|
||||
std::vector<double> perfpressure_d(perfpressure.value().data(), perfpressure.value().data() + nperf);
|
||||
xw.perfPress() = perfpressure_d;
|
||||
|
||||
// Pressure drawdown (also used to determine direction of flow)
|
||||
const ADB drawdown = p_perfcells - perfpressure;
|
||||
|
||||
// Compute vectors with zero and ones that
|
||||
// selects the wanted quantities.
|
||||
|
||||
// selects injection perforations
|
||||
V selectInjectingPerforations = V::Zero(nperf);
|
||||
// selects producing perforations
|
||||
V selectProducingPerforations = V::Zero(nperf);
|
||||
for (int c = 0; c < nperf; ++c) {
|
||||
if (drawdown.value()[c] < 0)
|
||||
selectInjectingPerforations[c] = 1;
|
||||
else
|
||||
selectProducingPerforations[c] = 1;
|
||||
}
|
||||
|
||||
// HANDLE FLOW INTO WELLBORE
|
||||
|
||||
// compute phase volumetric rates at standard conditions
|
||||
std::vector<ADB> cq_ps(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
const ADB cq_p = -(selectProducingPerforations * Tw) * (mob_perfcells[phase] * drawdown);
|
||||
cq_ps[phase] = b_perfcells[phase] * cq_p;
|
||||
}
|
||||
if (active_[Oil] && active_[Gas]) {
|
||||
const int oilpos = pu.phase_pos[Oil];
|
||||
const int gaspos = pu.phase_pos[Gas];
|
||||
const ADB cq_psOil = cq_ps[oilpos];
|
||||
const ADB cq_psGas = cq_ps[gaspos];
|
||||
cq_ps[gaspos] += rs_perfcells * cq_psOil;
|
||||
cq_ps[oilpos] += rv_perfcells * cq_psGas;
|
||||
}
|
||||
|
||||
// HANDLE FLOW OUT FROM WELLBORE
|
||||
|
||||
// Using total mobilities
|
||||
ADB total_mob = mob_perfcells[0];
|
||||
for (int phase = 1; phase < np; ++phase) {
|
||||
total_mob += mob_perfcells[phase];
|
||||
}
|
||||
// injection perforations total volume rates
|
||||
const ADB cqt_i = -(selectInjectingPerforations * Tw) * (total_mob * drawdown);
|
||||
|
||||
// compute wellbore mixture for injecting perforations
|
||||
// The wellbore mixture depends on the inflow from the reservoar
|
||||
// and the well injection rates.
|
||||
|
||||
// compute avg. and total wellbore phase volumetric rates at standard conds
|
||||
const DataBlock compi = Eigen::Map<const DataBlock>(wells().comp_frac, nw, np);
|
||||
std::vector<ADB> wbq(np, ADB::null());
|
||||
ADB wbqt = ADB::constant(V::Zero(nw));
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
const ADB& q_ps = wops_.p2w * cq_ps[phase];
|
||||
const ADB& q_s = subset(state.qs, Span(nw, 1, phase*nw));
|
||||
Selector<double> injectingPhase_selector(q_s.value(), Selector<double>::GreaterZero);
|
||||
const int pos = pu.phase_pos[phase];
|
||||
wbq[phase] = (compi.col(pos) * injectingPhase_selector.select(q_s,ADB::constant(V::Zero(nw)))) - q_ps;
|
||||
wbqt += wbq[phase];
|
||||
}
|
||||
|
||||
// compute wellbore mixture at standard conditions.
|
||||
Selector<double> notDeadWells_selector(wbqt.value(), Selector<double>::Zero);
|
||||
std::vector<ADB> cmix_s(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
const int pos = pu.phase_pos[phase];
|
||||
cmix_s[phase] = wops_.w2p * notDeadWells_selector.select(ADB::constant(compi.col(pos)), wbq[phase]/wbqt);
|
||||
}
|
||||
|
||||
// compute volume ratio between connection at standard conditions
|
||||
ADB volumeRatio = ADB::constant(V::Zero(nperf));
|
||||
const ADB d = V::Constant(nperf,1.0) - rv_perfcells * rs_perfcells;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
ADB tmp = cmix_s[phase];
|
||||
|
||||
if (phase == Oil && active_[Gas]) {
|
||||
const int gaspos = pu.phase_pos[Gas];
|
||||
tmp = tmp - rv_perfcells * cmix_s[gaspos] / d;
|
||||
}
|
||||
if (phase == Gas && active_[Oil]) {
|
||||
const int oilpos = pu.phase_pos[Oil];
|
||||
tmp = tmp - rs_perfcells * cmix_s[oilpos] / d;
|
||||
}
|
||||
volumeRatio += tmp / b_perfcells[phase];
|
||||
}
|
||||
|
||||
// injecting connections total volumerates at standard conditions
|
||||
ADB cqt_is = cqt_i/volumeRatio;
|
||||
|
||||
// connection phase volumerates at standard conditions
|
||||
std::vector<ADB> cq_s(np, ADB::null());
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
cq_s[phase] = cq_ps[phase] + cmix_s[phase]*cqt_is;
|
||||
}
|
||||
|
||||
water_vel_wells.resize(cq_s[0].size());
|
||||
std::copy(&(cq_s[0].value()[0]), &(cq_s[0].value()[0]) + cq_s[0].size(), water_vel_wells.begin());
|
||||
|
||||
water_vel_wells.resize(cq_sw.size());
|
||||
std::copy(&(cq_sw.value()[0]), &(cq_sw.value()[0]) + cq_sw.size(), water_vel_wells.begin());
|
||||
|
||||
const V& polymer_conc = state.concentration.value();
|
||||
|
||||
V visc_mult_cells = polymer_props_ad_.viscMult(polymer_conc);
|
||||
V visc_mult_wells_v = subset(visc_mult_cells, well_cells);
|
||||
|
||||
V temp_visc_mult_wells = subset(visc_mult_cells, well_cells);
|
||||
visc_mult_wells.resize(visc_mult_wells_v.size());
|
||||
std::copy(&(visc_mult_wells_v[0]), &(visc_mult_wells_v[0]) + visc_mult_wells_v.size(), visc_mult_wells.begin());
|
||||
|
||||
visc_mult_wells.resize(temp_visc_mult_wells.size());
|
||||
std::copy(&(temp_visc_mult_wells[0]), &(temp_visc_mult_wells[0]) + temp_visc_mult_wells.size(), visc_mult_wells.begin());
|
||||
const int water_pos = fluid_.phaseUsage().phase_pos[Water];
|
||||
ADB b_perfcells = subset(rq_[water_pos].b, well_cells);
|
||||
|
||||
const ADB& p_perfcells = subset(state.pressure, well_cells);
|
||||
const V& cdp = well_perforation_pressure_diffs_;
|
||||
const ADB perfpressure = (wops_.w2p * state.bhp) + cdp;
|
||||
// Pressure drawdown (also used to determine direction of flow)
|
||||
const ADB drawdown = p_perfcells - perfpressure;
|
||||
|
||||
// selects injection perforations
|
||||
V selectInjectingPerforations = V::Zero(nperf);
|
||||
for (int c = 0; c < nperf; ++c) {
|
||||
if (drawdown.value()[c] < 0) {
|
||||
selectInjectingPerforations[c] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// for the injection wells
|
||||
for (int i = 0; i < well_cells.size(); ++i) {
|
||||
@ -1297,18 +919,15 @@ namespace Opm {
|
||||
}
|
||||
|
||||
const ADB phi = Opm::AutoDiffBlock<double>::constant(Eigen::Map<const V>(& fluid_.porosity()[0], AutoDiffGrid::numCells(grid_), 1));
|
||||
|
||||
const ADB temp_phi_wells = subset(phi, well_cells);
|
||||
const ADB phi_wells_adb = subset(phi, well_cells);
|
||||
|
||||
std::vector<double> phi_wells;
|
||||
phi_wells.resize(temp_phi_wells.size());
|
||||
|
||||
std::copy(&(temp_phi_wells.value()[0]), &(temp_phi_wells.value()[0]) + temp_phi_wells.size(), phi_wells.begin());
|
||||
phi_wells.resize(phi_wells_adb.size());
|
||||
std::copy(&(phi_wells_adb.value()[0]), &(phi_wells_adb.value()[0]) + phi_wells_adb.size(), phi_wells.begin());
|
||||
|
||||
std::vector<double> b_wells;
|
||||
|
||||
b_wells.resize(b_perfcells[0].size());
|
||||
std::copy(&(b_perfcells[0].value()[0]), &(b_perfcells[0].value()[0]) + b_perfcells[0].size(), b_wells.begin());
|
||||
b_wells.resize(b_perfcells.size());
|
||||
std::copy(&(b_perfcells.value()[0]), &(b_perfcells.value()[0]) + b_perfcells.size(), b_wells.begin());
|
||||
|
||||
for (int i = 0; i < water_vel_wells.size(); ++i) {
|
||||
water_vel_wells[i] = b_wells[i] * water_vel_wells[i] / (phi_wells[i] * 2. * M_PI * wells_rep_radius_[i] * wells_perf_length_[i]);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <opm/polymer/PolymerProperties.hpp>
|
||||
#include <opm/polymer/fullyimplicit/WellStateFullyImplicitBlackoilPolymer.hpp>
|
||||
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
struct Wells;
|
||||
@ -88,6 +89,9 @@ namespace Opm {
|
||||
int newtonIterations() const;
|
||||
int linearIterations() const;
|
||||
|
||||
/// Not used by this class except to satisfy interface requirements.
|
||||
typedef parameter::ParameterGroup SolverParameters;
|
||||
|
||||
private:
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
|
@ -327,4 +327,12 @@ namespace Opm {
|
||||
return krw / rk;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PolymerPropsAd::computeShearMultLog(std::vector<double>& water_vel, std::vector<double>& visc_mult, std::vector<double>& shear_mult) const
|
||||
{
|
||||
return polymer_props_.computeShearMultLog(water_vel, visc_mult, shear_mult);
|
||||
}
|
||||
|
||||
|
||||
}// namespace Opm
|
||||
|
@ -133,6 +133,14 @@ namespace Opm {
|
||||
ADB
|
||||
effectiveRelPerm(const ADB& c, const ADB& cmax_cells, const ADB& krw) const;
|
||||
|
||||
/// \param[in] water_vel Array of the n values of water velocity or shear rate.
|
||||
/// \param[in] visc_mult Array of the n values of the viscosity multiplier from PLYVISC table.
|
||||
/// \parma[out] shear_mult Array of the n values of calculated shear multiplier with PLYSHLOG keyword.
|
||||
/// \return TRUE if the calculation of shear multiplier is sucessful,
|
||||
/// FALSE if the calculation of shear multplier is failed.
|
||||
bool computeShearMultLog(std::vector<double>& water_vel, std::vector<double>& visc_mult, std::vector<double>& shear_mult) const;
|
||||
|
||||
|
||||
private:
|
||||
const PolymerProperties& polymer_props_;
|
||||
};
|
||||
|
@ -66,12 +66,9 @@ namespace Opm
|
||||
-> std::unique_ptr<Solver>
|
||||
{
|
||||
typedef typename Traits::Model Model;
|
||||
typedef typename Model::ModelParameters ModelParams;
|
||||
ModelParams modelParams( BaseType::param_ );
|
||||
typedef NewtonSolver<Model> Solver;
|
||||
|
||||
|
||||
auto model = std::unique_ptr<Model>(new Model(modelParams,
|
||||
auto model = std::unique_ptr<Model>(new Model(BaseType::model_param_,
|
||||
BaseType::grid_,
|
||||
BaseType::props_,
|
||||
BaseType::geo_,
|
||||
@ -93,9 +90,7 @@ namespace Opm
|
||||
model->setThresholdPressures(BaseType::threshold_pressures_by_face_);
|
||||
}
|
||||
|
||||
typedef typename Solver::SolverParameters SolverParams;
|
||||
SolverParams solverParams( BaseType::param_ );
|
||||
return std::unique_ptr<Solver>(new Solver(solverParams, std::move(model)));
|
||||
return std::unique_ptr<Solver>(new Solver(BaseType::solver_param_, std::move(model)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,6 +79,11 @@ namespace Opm
|
||||
typedef BlackoilOutputWriter OutputWriter;
|
||||
typedef GridT Grid;
|
||||
typedef FullyImplicitCompressiblePolymerSolver Solver;
|
||||
/// Dummy class, this Solver does not use a Model.
|
||||
struct Model
|
||||
{
|
||||
typedef parameter::ParameterGroup ModelParameters;
|
||||
};
|
||||
};
|
||||
|
||||
/// Class collecting all necessary components for a two-phase simulation.
|
||||
|
Loading…
Reference in New Issue
Block a user