mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Remove opm/autodiff/ files, fix header files.
This commit is contained in:
@@ -1,302 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2013 Statoil ASA.
|
||||
|
||||
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_AUTODIFF_HPP_HEADER
|
||||
#define OPM_AUTODIFF_HPP_HEADER
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// A simple class for forward-mode automatic differentiation.
|
||||
///
|
||||
/// The class represents a single value and a single derivative.
|
||||
/// Only basic arithmetic operators and a few functions are
|
||||
/// implemented for it, it is mostly intended for simple
|
||||
/// experimentation.
|
||||
template <typename Scalar>
|
||||
class AutoDiff
|
||||
{
|
||||
public:
|
||||
/// Create an AutoDiff object representing a constant, that
|
||||
/// is, its derivative is zero.
|
||||
static AutoDiff
|
||||
constant(const Scalar x)
|
||||
{
|
||||
return function(x, Scalar(0));
|
||||
}
|
||||
|
||||
/// Create an AutoDiff object representing a primary variable,
|
||||
/// that is, its derivative is one.
|
||||
static AutoDiff
|
||||
variable(const Scalar x)
|
||||
{
|
||||
return function(x, Scalar(1));
|
||||
}
|
||||
|
||||
/// Create an AutoDiff object representing a function value
|
||||
/// and its derivative.
|
||||
static AutoDiff
|
||||
function(const Scalar x, const Scalar dx)
|
||||
{
|
||||
return AutoDiff(x, dx);
|
||||
}
|
||||
|
||||
void
|
||||
operator +=(const Scalar& rhs)
|
||||
{
|
||||
val_ += rhs;
|
||||
}
|
||||
|
||||
void
|
||||
operator +=(const AutoDiff& rhs)
|
||||
{
|
||||
val_ += rhs.val_;
|
||||
der_ += rhs.der_;
|
||||
}
|
||||
|
||||
void
|
||||
operator -=(const Scalar& rhs)
|
||||
{
|
||||
val_ -= rhs;
|
||||
}
|
||||
|
||||
void
|
||||
operator -=(const AutoDiff& rhs)
|
||||
{
|
||||
val_ -= rhs.val_;
|
||||
der_ -= rhs.der_;
|
||||
}
|
||||
|
||||
void
|
||||
operator *=(const Scalar& rhs)
|
||||
{
|
||||
val_ *= rhs;
|
||||
der_ *= rhs;
|
||||
}
|
||||
|
||||
void
|
||||
operator *=(const AutoDiff& rhs)
|
||||
{
|
||||
der_ = der_*rhs.val_ + val_*rhs.der_;
|
||||
val_ *= rhs.val_;
|
||||
}
|
||||
|
||||
void
|
||||
operator /=(const Scalar& rhs)
|
||||
{
|
||||
val_ /= rhs;
|
||||
der_ /= rhs;
|
||||
}
|
||||
|
||||
void
|
||||
operator /=(const AutoDiff& rhs)
|
||||
{
|
||||
der_ = (der_*rhs.val_ - val_*rhs.der_) / (rhs.val_ * rhs.val_);
|
||||
val_ /= rhs.val_;
|
||||
}
|
||||
|
||||
template <class Ostream>
|
||||
Ostream&
|
||||
print(Ostream& os) const
|
||||
{
|
||||
os << "(x,dx) = (" << val_ << ',' << der_ << ")";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
const Scalar val() const { return val_; }
|
||||
const Scalar der() const { return der_; }
|
||||
|
||||
private:
|
||||
AutoDiff(const Scalar x, const Scalar dx)
|
||||
: val_(x), der_(dx)
|
||||
{}
|
||||
|
||||
Scalar val_;
|
||||
Scalar der_;
|
||||
};
|
||||
|
||||
|
||||
template <class Ostream, typename Scalar>
|
||||
Ostream&
|
||||
operator<<(Ostream& os, const AutoDiff<Scalar>& fw)
|
||||
{
|
||||
return fw.print(os);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
AutoDiff<Scalar>
|
||||
operator +(const AutoDiff<Scalar>& lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = lhs;
|
||||
ret += rhs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator +(const T lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = rhs;
|
||||
ret += Scalar(lhs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator +(const AutoDiff<Scalar>& lhs,
|
||||
const T rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = lhs;
|
||||
ret += Scalar(rhs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
AutoDiff<Scalar>
|
||||
operator -(const AutoDiff<Scalar>& lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = lhs;
|
||||
ret -= rhs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator -(const T lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
return AutoDiff<Scalar>::function(Scalar(lhs) - rhs.val(), -rhs.der());
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator -(const AutoDiff<Scalar>& lhs,
|
||||
const T rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = lhs;
|
||||
ret -= Scalar(rhs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
AutoDiff<Scalar>
|
||||
operator *(const AutoDiff<Scalar>& lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = lhs;
|
||||
ret *= rhs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator *(const T lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = rhs;
|
||||
ret *= Scalar(lhs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator *(const AutoDiff<Scalar>& lhs,
|
||||
const T rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = lhs;
|
||||
ret *= Scalar(rhs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
AutoDiff<Scalar>
|
||||
operator /(const AutoDiff<Scalar>& lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
AutoDiff<Scalar> ret = lhs;
|
||||
ret /= rhs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator /(const T lhs,
|
||||
const AutoDiff<Scalar>& rhs)
|
||||
{
|
||||
Scalar a = Scalar(lhs) / rhs.val();
|
||||
Scalar b = -Scalar(lhs) / (rhs.val() * rhs.val());
|
||||
|
||||
return AutoDiff<Scalar>::function(a, b);
|
||||
}
|
||||
|
||||
template <typename Scalar, typename T>
|
||||
AutoDiff<Scalar>
|
||||
operator /(const AutoDiff<Scalar>& lhs,
|
||||
const T rhs)
|
||||
{
|
||||
Scalar a = lhs.val() / Scalar(rhs);
|
||||
Scalar b = lhs.der() / Scalar(rhs);
|
||||
|
||||
return AutoDiff<Scalar>::function(a, b);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
AutoDiff<Scalar>
|
||||
cos(const AutoDiff<Scalar>& x)
|
||||
{
|
||||
Scalar a = std::cos(x.val());
|
||||
Scalar b = -std::sin(x.val()) * x.der();
|
||||
|
||||
return AutoDiff<Scalar>::function(a, b);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
AutoDiff<Scalar>
|
||||
sqrt(const AutoDiff<Scalar>& x)
|
||||
{
|
||||
Scalar a = std::sqrt(x.val());
|
||||
Scalar b = (Scalar(1.0) / (Scalar(2.0) * a)) * x.der();
|
||||
|
||||
return AutoDiff<Scalar>::function(a, b);
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
namespace std {
|
||||
using Opm::cos;
|
||||
using Opm::sqrt;
|
||||
}
|
||||
|
||||
#endif /* OPM_AUTODIFF_HPP_HEADER */
|
||||
@@ -1,506 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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_AUTODIFFBLOCK_HEADER_INCLUDED
|
||||
#define OPM_AUTODIFFBLOCK_HEADER_INCLUDED
|
||||
|
||||
#include <Eigen/Eigen>
|
||||
#include <Eigen/Sparse>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// A class for forward-mode automatic differentiation with vector
|
||||
/// values and sparse jacobian matrices.
|
||||
///
|
||||
/// The class contains a (column) vector of values and multiple
|
||||
/// sparse matrices representing its partial derivatives. Each
|
||||
/// such matrix has a number of rows equal to the number of rows
|
||||
/// in the value vector, and a number of columns equal to the
|
||||
/// number of discrete variables we want to compute the
|
||||
/// derivatives with respect to. The reason to have multiple such
|
||||
/// jacobians instead of just one is to allow simpler grouping of
|
||||
/// variables, making it easier to implement various
|
||||
/// preconditioning schemes. Only basic arithmetic operators are
|
||||
/// implemented for this class, reflecting our needs so far.
|
||||
///
|
||||
/// The class is built on the Eigen library, using an Eigen array
|
||||
/// type to contain the values and Eigen sparse matrices for the
|
||||
/// jacobians. The overloaded operators are intended to behave in
|
||||
/// a similar way to Eigen arrays, meaning for example that the *
|
||||
/// operator is elementwise multiplication. The only exception is
|
||||
/// multiplication with a sparse matrix from the left, which is
|
||||
/// treated as an Eigen matrix operation.
|
||||
///
|
||||
/// There are no public constructors, instead we use the Named
|
||||
/// Constructor pattern. In general, one needs to know which
|
||||
/// variables one wants to compute the derivatives with respect to
|
||||
/// before constructing an AutoDiffBlock. Some of the constructors
|
||||
/// require you to pass a block pattern. This should be a vector
|
||||
/// containing the number of columns you want for each jacobian
|
||||
/// matrix.
|
||||
///
|
||||
/// For example: you want the derivatives with respect to three
|
||||
/// different variables p, r and s. Assuming that there are 10
|
||||
/// elements in p, and 20 in each of r and s, the block pattern is
|
||||
/// { 10, 20, 20 }. When creating the variables p, r and s in your
|
||||
/// program you have two options:
|
||||
/// - Use the variable() constructor three times, passing the
|
||||
/// index (0 for p, 1 for r and 2 for s), initial value of
|
||||
/// each variable and the block pattern.
|
||||
/// - Use the variables() constructor passing only the initial
|
||||
/// values of each variable. The block pattern will be
|
||||
/// inferred from the size of the initial value vectors.
|
||||
/// This is usually the simplest option if you have multiple
|
||||
/// variables. Note that this constructor returns a vector
|
||||
/// of all three variables, so you need to use index access
|
||||
/// (operator[]) to get the individual variables (that is p,
|
||||
/// r and s).
|
||||
///
|
||||
/// After this, the r variable for example will have a size() of
|
||||
/// 20 and three jacobian matrices. The first is a 20 by 10 zero
|
||||
/// matrix, the second is a 20 by 20 identity matrix, and the
|
||||
/// third is a 20 by 20 zero matrix.
|
||||
template <typename Scalar>
|
||||
class AutoDiffBlock
|
||||
{
|
||||
public:
|
||||
/// Underlying type for values.
|
||||
typedef Eigen::Array<Scalar, Eigen::Dynamic, 1> V;
|
||||
/// Underlying type for jacobians.
|
||||
typedef Eigen::SparseMatrix<Scalar> M;
|
||||
|
||||
/// Construct an empty AutoDiffBlock.
|
||||
static AutoDiffBlock null()
|
||||
{
|
||||
V val;
|
||||
std::vector<M> jac;
|
||||
return AutoDiffBlock(val, jac);
|
||||
}
|
||||
|
||||
/// Create an AutoDiffBlock representing a constant.
|
||||
/// \param[in] val values
|
||||
static AutoDiffBlock constant(const V& val)
|
||||
{
|
||||
return AutoDiffBlock(val);
|
||||
}
|
||||
|
||||
/// Create an AutoDiffBlock representing a constant.
|
||||
/// This variant requires specifying the block sizes used
|
||||
/// for the Jacobians even though the Jacobian matrices
|
||||
/// themselves will be zero.
|
||||
/// \param[in] val values
|
||||
/// \param[in] blocksizes block pattern
|
||||
static AutoDiffBlock constant(const V& val, const std::vector<int>& blocksizes)
|
||||
{
|
||||
std::vector<M> jac;
|
||||
const int num_elem = val.size();
|
||||
const int num_blocks = blocksizes.size();
|
||||
// For constants, all jacobian blocks are zero.
|
||||
jac.resize(num_blocks);
|
||||
for (int i = 0; i < num_blocks; ++i) {
|
||||
jac[i] = M(num_elem, blocksizes[i]);
|
||||
}
|
||||
return AutoDiffBlock(val, jac);
|
||||
}
|
||||
|
||||
/// Create an AutoDiffBlock representing a single variable block.
|
||||
/// \param[in] index index of the variable you are constructing
|
||||
/// \param[in] val values
|
||||
/// \param[in] blocksizes block pattern
|
||||
/// The resulting object will have size() equal to block_pattern[index].
|
||||
/// Its jacobians will all be zero, except for derivative()[index], which
|
||||
/// will be an identity matrix.
|
||||
static AutoDiffBlock variable(const int index, const V& val, const std::vector<int>& blocksizes)
|
||||
{
|
||||
std::vector<M> jac;
|
||||
const int num_elem = val.size();
|
||||
const int num_blocks = blocksizes.size();
|
||||
// First, set all jacobian blocks to zero...
|
||||
jac.resize(num_blocks);
|
||||
for (int i = 0; i < num_blocks; ++i) {
|
||||
jac[i] = M(num_elem, blocksizes[i]);
|
||||
}
|
||||
// ... then set the one corrresponding to this variable to identity.
|
||||
assert(blocksizes[index] == num_elem);
|
||||
jac[index].reserve(Eigen::VectorXi::Constant(val.size(), 1));
|
||||
for (typename M::Index row = 0; row < val.size(); ++row) {
|
||||
jac[index].insert(row, row) = Scalar(1.0);
|
||||
}
|
||||
return AutoDiffBlock(val, jac);
|
||||
}
|
||||
|
||||
/// Create an AutoDiffBlock by directly specifying values and jacobians.
|
||||
/// \param[in] val values
|
||||
/// \param[in] jac vector of jacobians
|
||||
static AutoDiffBlock function(const V& val, const std::vector<M>& jac)
|
||||
{
|
||||
return AutoDiffBlock(val, jac);
|
||||
}
|
||||
|
||||
/// Construct a set of primary variables, each initialized to
|
||||
/// a given vector.
|
||||
static std::vector<AutoDiffBlock> variables(const std::vector<V>& initial_values)
|
||||
{
|
||||
const int num_vars = initial_values.size();
|
||||
std::vector<int> bpat;
|
||||
for (int v = 0; v < num_vars; ++v) {
|
||||
bpat.push_back(initial_values[v].size());
|
||||
}
|
||||
std::vector<AutoDiffBlock> vars;
|
||||
for (int v = 0; v < num_vars; ++v) {
|
||||
vars.emplace_back(variable(v, initial_values[v], bpat));
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
/// Elementwise operator +=
|
||||
AutoDiffBlock& operator+=(const AutoDiffBlock& rhs)
|
||||
{
|
||||
if (jac_.empty()) {
|
||||
jac_ = rhs.jac_;
|
||||
} else if (!rhs.jac_.empty()) {
|
||||
assert (numBlocks() == rhs.numBlocks());
|
||||
assert (value().size() == rhs.value().size());
|
||||
|
||||
const int num_blocks = numBlocks();
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
assert(jac_[block].rows() == rhs.jac_[block].rows());
|
||||
assert(jac_[block].cols() == rhs.jac_[block].cols());
|
||||
jac_[block] += rhs.jac_[block];
|
||||
}
|
||||
}
|
||||
|
||||
val_ += rhs.val_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Elementwise operator +
|
||||
AutoDiffBlock operator+(const AutoDiffBlock& rhs) const
|
||||
{
|
||||
if (jac_.empty() && rhs.jac_.empty()) {
|
||||
return constant(val_ + rhs.val_);
|
||||
}
|
||||
if (jac_.empty()) {
|
||||
return val_ + rhs;
|
||||
}
|
||||
if (rhs.jac_.empty()) {
|
||||
return *this + rhs.val_;
|
||||
}
|
||||
std::vector<M> jac = jac_;
|
||||
assert(numBlocks() == rhs.numBlocks());
|
||||
int num_blocks = numBlocks();
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
assert(jac[block].rows() == rhs.jac_[block].rows());
|
||||
assert(jac[block].cols() == rhs.jac_[block].cols());
|
||||
jac[block] += rhs.jac_[block];
|
||||
}
|
||||
return function(val_ + rhs.val_, jac);
|
||||
}
|
||||
|
||||
/// Elementwise operator -
|
||||
AutoDiffBlock operator-(const AutoDiffBlock& rhs) const
|
||||
{
|
||||
if (jac_.empty() && rhs.jac_.empty()) {
|
||||
return constant(val_ - rhs.val_);
|
||||
}
|
||||
if (jac_.empty()) {
|
||||
return val_ - rhs;
|
||||
}
|
||||
if (rhs.jac_.empty()) {
|
||||
return *this - rhs.val_;
|
||||
}
|
||||
std::vector<M> jac = jac_;
|
||||
assert(numBlocks() == rhs.numBlocks());
|
||||
int num_blocks = numBlocks();
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
assert(jac[block].rows() == rhs.jac_[block].rows());
|
||||
assert(jac[block].cols() == rhs.jac_[block].cols());
|
||||
jac[block] -= rhs.jac_[block];
|
||||
}
|
||||
return function(val_ - rhs.val_, jac);
|
||||
}
|
||||
|
||||
/// Elementwise operator *
|
||||
AutoDiffBlock operator*(const AutoDiffBlock& rhs) const
|
||||
{
|
||||
if (jac_.empty() && rhs.jac_.empty()) {
|
||||
return constant(val_ * rhs.val_);
|
||||
}
|
||||
if (jac_.empty()) {
|
||||
return val_ * rhs;
|
||||
}
|
||||
if (rhs.jac_.empty()) {
|
||||
return *this * rhs.val_;
|
||||
}
|
||||
int num_blocks = numBlocks();
|
||||
std::vector<M> jac(num_blocks);
|
||||
assert(numBlocks() == rhs.numBlocks());
|
||||
typedef Eigen::DiagonalMatrix<Scalar, Eigen::Dynamic> D;
|
||||
D D1 = val_.matrix().asDiagonal();
|
||||
D D2 = rhs.val_.matrix().asDiagonal();
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
assert(jac_[block].rows() == rhs.jac_[block].rows());
|
||||
assert(jac_[block].cols() == rhs.jac_[block].cols());
|
||||
jac[block] = D2*jac_[block] + D1*rhs.jac_[block];
|
||||
}
|
||||
return function(val_ * rhs.val_, jac);
|
||||
}
|
||||
|
||||
/// Elementwise operator /
|
||||
AutoDiffBlock operator/(const AutoDiffBlock& rhs) const
|
||||
{
|
||||
if (jac_.empty() && rhs.jac_.empty()) {
|
||||
return constant(val_ / rhs.val_);
|
||||
}
|
||||
if (jac_.empty()) {
|
||||
return val_ / rhs;
|
||||
}
|
||||
if (rhs.jac_.empty()) {
|
||||
return *this / rhs.val_;
|
||||
}
|
||||
int num_blocks = numBlocks();
|
||||
std::vector<M> jac(num_blocks);
|
||||
assert(numBlocks() == rhs.numBlocks());
|
||||
typedef Eigen::DiagonalMatrix<Scalar, Eigen::Dynamic> D;
|
||||
D D1 = val_.matrix().asDiagonal();
|
||||
D D2 = rhs.val_.matrix().asDiagonal();
|
||||
D D3 = (1.0/(rhs.val_*rhs.val_)).matrix().asDiagonal();
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
assert(jac_[block].rows() == rhs.jac_[block].rows());
|
||||
assert(jac_[block].cols() == rhs.jac_[block].cols());
|
||||
jac[block] = D3 * (D2*jac_[block] - D1*rhs.jac_[block]);
|
||||
}
|
||||
return function(val_ / rhs.val_, jac);
|
||||
}
|
||||
|
||||
/// I/O.
|
||||
template <class Ostream>
|
||||
Ostream&
|
||||
print(Ostream& os) const
|
||||
{
|
||||
int num_blocks = jac_.size();
|
||||
os << "Value =\n" << val_ << "\n\nJacobian =\n";
|
||||
for (int i = 0; i < num_blocks; ++i) {
|
||||
os << "Sub Jacobian #" << i << '\n' << jac_[i] << "\n";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
/// Number of elements
|
||||
int size() const
|
||||
{
|
||||
return val_.size();
|
||||
}
|
||||
|
||||
/// Number of Jacobian blocks.
|
||||
int numBlocks() const
|
||||
{
|
||||
return jac_.size();
|
||||
}
|
||||
|
||||
/// Sizes (number of columns) of Jacobian blocks.
|
||||
std::vector<int> blockPattern() const
|
||||
{
|
||||
const int nb = numBlocks();
|
||||
std::vector<int> bp(nb);
|
||||
for (int block = 0; block < nb; ++block) {
|
||||
bp[block] = jac_[block].cols();
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
|
||||
/// Function value.
|
||||
const V& value() const
|
||||
{
|
||||
return val_;
|
||||
}
|
||||
|
||||
/// Function derivatives.
|
||||
const std::vector<M>& derivative() const
|
||||
{
|
||||
return jac_;
|
||||
}
|
||||
|
||||
private:
|
||||
AutoDiffBlock(const V& val)
|
||||
: val_(val)
|
||||
{
|
||||
}
|
||||
|
||||
AutoDiffBlock(const V& val,
|
||||
const std::vector<M>& jac)
|
||||
: val_(val), jac_(jac)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
const int num_elem = val_.size();
|
||||
const int num_blocks = jac_.size();
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
assert(num_elem == jac_[block].rows());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
V val_;
|
||||
std::vector<M> jac_;
|
||||
};
|
||||
|
||||
|
||||
// --------- Free functions and operators for AutoDiffBlock ---------
|
||||
|
||||
/// Stream output.
|
||||
template <class Ostream, typename Scalar>
|
||||
Ostream&
|
||||
operator<<(Ostream& os, const AutoDiffBlock<Scalar>& fw)
|
||||
{
|
||||
return fw.print(os);
|
||||
}
|
||||
|
||||
|
||||
/// Multiply with sparse matrix from the left.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator*(const typename AutoDiffBlock<Scalar>::M& lhs,
|
||||
const AutoDiffBlock<Scalar>& rhs)
|
||||
{
|
||||
int num_blocks = rhs.numBlocks();
|
||||
std::vector<typename AutoDiffBlock<Scalar>::M> jac(num_blocks);
|
||||
assert(lhs.cols() == rhs.value().rows());
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jac[block] = lhs*rhs.derivative()[block];
|
||||
}
|
||||
typename AutoDiffBlock<Scalar>::V val = lhs*rhs.value().matrix();
|
||||
return AutoDiffBlock<Scalar>::function(val, jac);
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise multiplication with constant on the left.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator*(const typename AutoDiffBlock<Scalar>::V& lhs,
|
||||
const AutoDiffBlock<Scalar>& rhs)
|
||||
{
|
||||
return AutoDiffBlock<Scalar>::constant(lhs, rhs.blockPattern()) * rhs;
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise multiplication with constant on the right.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator*(const AutoDiffBlock<Scalar>& lhs,
|
||||
const typename AutoDiffBlock<Scalar>::V& rhs)
|
||||
{
|
||||
return rhs * lhs; // Commutative operation.
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise addition with constant on the left.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator+(const typename AutoDiffBlock<Scalar>::V& lhs,
|
||||
const AutoDiffBlock<Scalar>& rhs)
|
||||
{
|
||||
return AutoDiffBlock<Scalar>::constant(lhs, rhs.blockPattern()) + rhs;
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise addition with constant on the right.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator+(const AutoDiffBlock<Scalar>& lhs,
|
||||
const typename AutoDiffBlock<Scalar>::V& rhs)
|
||||
{
|
||||
return rhs + lhs; // Commutative operation.
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise subtraction with constant on the left.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator-(const typename AutoDiffBlock<Scalar>::V& lhs,
|
||||
const AutoDiffBlock<Scalar>& rhs)
|
||||
{
|
||||
return AutoDiffBlock<Scalar>::constant(lhs, rhs.blockPattern()) - rhs;
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise subtraction with constant on the right.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator-(const AutoDiffBlock<Scalar>& lhs,
|
||||
const typename AutoDiffBlock<Scalar>::V& rhs)
|
||||
{
|
||||
return lhs - AutoDiffBlock<Scalar>::constant(rhs, lhs.blockPattern());
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise division with constant on the left.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator/(const typename AutoDiffBlock<Scalar>::V& lhs,
|
||||
const AutoDiffBlock<Scalar>& rhs)
|
||||
{
|
||||
return AutoDiffBlock<Scalar>::constant(lhs, rhs.blockPattern()) / rhs;
|
||||
}
|
||||
|
||||
|
||||
/// Elementwise division with constant on the right.
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator/(const AutoDiffBlock<Scalar>& lhs,
|
||||
const typename AutoDiffBlock<Scalar>::V& rhs)
|
||||
{
|
||||
return lhs / AutoDiffBlock<Scalar>::constant(rhs, lhs.blockPattern());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Operator for multiplication with a scalar on the right-hand side
|
||||
*
|
||||
* @param lhs The left-hand side AD forward block
|
||||
* @param rhs The scalar to multiply with
|
||||
* @return The product
|
||||
*/
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator*(const AutoDiffBlock<Scalar>& lhs,
|
||||
const Scalar& rhs)
|
||||
{
|
||||
std::vector< typename AutoDiffBlock<Scalar>::M > jac;
|
||||
jac.reserve( lhs.numBlocks() );
|
||||
for (int block=0; block<lhs.numBlocks(); block++) {
|
||||
jac.emplace_back( lhs.derivative()[block] * rhs );
|
||||
}
|
||||
return AutoDiffBlock<Scalar>::function( lhs.value() * rhs, jac );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Operator for multiplication with a scalar on the left-hand side
|
||||
*
|
||||
* @param lhs The scalar to multiply with
|
||||
* @param rhs The right-hand side AD forward block
|
||||
* @return The product
|
||||
*/
|
||||
template <typename Scalar>
|
||||
AutoDiffBlock<Scalar> operator*(const Scalar& lhs,
|
||||
const AutoDiffBlock<Scalar>& rhs)
|
||||
{
|
||||
return rhs * lhs; // Commutative operation.
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
|
||||
#endif // OPM_AUTODIFFBLOCK_HEADER_INCLUDED
|
||||
@@ -1,513 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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_AUTODIFFHELPERS_HEADER_INCLUDED
|
||||
#define OPM_AUTODIFFHELPERS_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
// -------------------- class HelperOps --------------------
|
||||
|
||||
/// Contains vectors and sparse matrices that represent subsets or
|
||||
/// operations on (AD or regular) vectors of data.
|
||||
struct HelperOps
|
||||
{
|
||||
typedef AutoDiffBlock<double>::M M;
|
||||
typedef AutoDiffBlock<double>::V V;
|
||||
|
||||
/// A list of internal faces.
|
||||
typedef Eigen::Array<int, Eigen::Dynamic, 1> IFaces;
|
||||
IFaces internal_faces;
|
||||
|
||||
/// Extract for each internal face the difference of its adjacent cells' values (first - second).
|
||||
M ngrad;
|
||||
/// Extract for each face the difference of its adjacent cells' values (second - first).
|
||||
M grad;
|
||||
/// Extract for each face the average of its adjacent cells' values.
|
||||
M caver;
|
||||
/// Extract for each cell the sum of its adjacent interior faces' (signed) values.
|
||||
M div;
|
||||
/// Extract for each face the difference of its adjacent cells' values (first - second).
|
||||
/// For boundary faces, one of the entries per row (corresponding to the outside) is zero.
|
||||
M fullngrad;
|
||||
/// Extract for each cell the sum of all its adjacent faces' (signed) values.
|
||||
M fulldiv;
|
||||
|
||||
/// Constructs all helper vectors and matrices.
|
||||
HelperOps(const UnstructuredGrid& grid)
|
||||
{
|
||||
const int nc = grid.number_of_cells;
|
||||
const int nf = grid.number_of_faces;
|
||||
// Define some neighbourhood-derived helper arrays.
|
||||
typedef Eigen::Array<bool, Eigen::Dynamic, 1> OneColBool;
|
||||
typedef Eigen::Array<int, Eigen::Dynamic, 2, Eigen::RowMajor> TwoColInt;
|
||||
typedef Eigen::Array<bool, Eigen::Dynamic, 2, Eigen::RowMajor> TwoColBool;
|
||||
TwoColInt nb = Eigen::Map<TwoColInt>(grid.face_cells, nf, 2);
|
||||
// std::cout << "nb = \n" << nb << std::endl;
|
||||
TwoColBool nbib = nb >= 0;
|
||||
OneColBool ifaces = nbib.rowwise().all();
|
||||
const int num_internal = ifaces.cast<int>().sum();
|
||||
// std::cout << num_internal << " internal faces." << std::endl;
|
||||
TwoColInt nbi(num_internal, 2);
|
||||
internal_faces.resize(num_internal);
|
||||
int fi = 0;
|
||||
for (int f = 0; f < nf; ++f) {
|
||||
if (ifaces[f]) {
|
||||
internal_faces[fi] = f;
|
||||
nbi.row(fi) = nb.row(f);
|
||||
++fi;
|
||||
}
|
||||
}
|
||||
// std::cout << "nbi = \n" << nbi << std::endl;
|
||||
// Create matrices.
|
||||
ngrad.resize(num_internal, nc);
|
||||
caver.resize(num_internal, nc);
|
||||
typedef Eigen::Triplet<double> Tri;
|
||||
std::vector<Tri> ngrad_tri;
|
||||
std::vector<Tri> caver_tri;
|
||||
ngrad_tri.reserve(2*num_internal);
|
||||
caver_tri.reserve(2*num_internal);
|
||||
for (int i = 0; i < num_internal; ++i) {
|
||||
ngrad_tri.emplace_back(i, nbi(i,0), 1.0);
|
||||
ngrad_tri.emplace_back(i, nbi(i,1), -1.0);
|
||||
caver_tri.emplace_back(i, nbi(i,0), 0.5);
|
||||
caver_tri.emplace_back(i, nbi(i,1), 0.5);
|
||||
}
|
||||
ngrad.setFromTriplets(ngrad_tri.begin(), ngrad_tri.end());
|
||||
caver.setFromTriplets(caver_tri.begin(), caver_tri.end());
|
||||
grad = -ngrad;
|
||||
div = ngrad.transpose();
|
||||
std::vector<Tri> fullngrad_tri;
|
||||
fullngrad_tri.reserve(2*nf);
|
||||
for (int i = 0; i < nf; ++i) {
|
||||
if (nb(i,0) >= 0) {
|
||||
fullngrad_tri.emplace_back(i, nb(i,0), 1.0);
|
||||
}
|
||||
if (nb(i,1) >= 0) {
|
||||
fullngrad_tri.emplace_back(i, nb(i,1), -1.0);
|
||||
}
|
||||
}
|
||||
fullngrad.resize(nf, nc);
|
||||
fullngrad.setFromTriplets(fullngrad_tri.begin(), fullngrad_tri.end());
|
||||
fulldiv = fullngrad.transpose();
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------- upwinding helper class --------------------
|
||||
|
||||
|
||||
/// Upwind selection in absence of counter-current flow (i.e.,
|
||||
/// without effects of gravity and/or capillary pressure).
|
||||
template <typename Scalar>
|
||||
class UpwindSelector {
|
||||
public:
|
||||
typedef AutoDiffBlock<Scalar> ADB;
|
||||
|
||||
UpwindSelector(const UnstructuredGrid& g,
|
||||
const HelperOps& h,
|
||||
const typename ADB::V& ifaceflux)
|
||||
{
|
||||
typedef HelperOps::IFaces::Index IFIndex;
|
||||
const IFIndex nif = h.internal_faces.size();
|
||||
assert(nif == ifaceflux.size());
|
||||
|
||||
// Define selector structure.
|
||||
typedef typename Eigen::Triplet<Scalar> Triplet;
|
||||
std::vector<Triplet> s; s.reserve(nif);
|
||||
for (IFIndex iface = 0; iface < nif; ++iface) {
|
||||
const int f = h.internal_faces[iface];
|
||||
const int c1 = g.face_cells[2*f + 0];
|
||||
const int c2 = g.face_cells[2*f + 1];
|
||||
|
||||
assert ((c1 >= 0) && (c2 >= 0));
|
||||
|
||||
// Select upwind cell.
|
||||
const int c = (ifaceflux[iface] >= 0) ? c1 : c2;
|
||||
|
||||
s.push_back(Triplet(iface, c, Scalar(1)));
|
||||
}
|
||||
|
||||
// Assemble explicit selector operator.
|
||||
select_.resize(nif, g.number_of_cells);
|
||||
select_.setFromTriplets(s.begin(), s.end());
|
||||
}
|
||||
|
||||
/// Apply selector to multiple per-cell quantities.
|
||||
std::vector<ADB>
|
||||
select(const std::vector<ADB>& xc) const
|
||||
{
|
||||
// Absence of counter-current flow means that the same
|
||||
// selector applies to all quantities, 'x', defined per
|
||||
// cell.
|
||||
std::vector<ADB> xf; xf.reserve(xc.size());
|
||||
for (typename std::vector<ADB>::const_iterator
|
||||
b = xc.begin(), e = xc.end(); b != e; ++b)
|
||||
{
|
||||
xf.push_back(select_ * (*b));
|
||||
}
|
||||
|
||||
return xf;
|
||||
}
|
||||
|
||||
/// Apply selector to single per-cell ADB quantity.
|
||||
ADB select(const ADB& xc) const
|
||||
{
|
||||
return select_*xc;
|
||||
}
|
||||
|
||||
/// Apply selector to single per-cell constant quantity.
|
||||
typename ADB::V select(const typename ADB::V& xc) const
|
||||
{
|
||||
return (select_*xc.matrix()).array();
|
||||
}
|
||||
|
||||
private:
|
||||
typename ADB::M select_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Scalar, class IntVec>
|
||||
Eigen::SparseMatrix<Scalar>
|
||||
constructSubsetSparseMatrix(const int full_size, const IntVec& indices)
|
||||
{
|
||||
typedef Eigen::Triplet<Scalar> Tri;
|
||||
const int subset_size = indices.size();
|
||||
std::vector<Tri> triplets(subset_size);
|
||||
for (int i = 0; i < subset_size; ++i) {
|
||||
triplets[i] = Tri(i, indices[i], 1);
|
||||
}
|
||||
Eigen::SparseMatrix<Scalar> sub(subset_size, full_size);
|
||||
sub.setFromTriplets(triplets.begin(), triplets.end());
|
||||
return sub;
|
||||
}
|
||||
|
||||
template <typename Scalar, class IntVec>
|
||||
Eigen::SparseMatrix<Scalar>
|
||||
constructSupersetSparseMatrix(const int full_size, const IntVec& indices)
|
||||
{
|
||||
return constructSubsetSparseMatrix<Scalar>(full_size, indices).transpose();
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
|
||||
/// Returns x(indices).
|
||||
template <typename Scalar, class IntVec>
|
||||
AutoDiffBlock<Scalar>
|
||||
subset(const AutoDiffBlock<Scalar>& x,
|
||||
const IntVec& indices)
|
||||
{
|
||||
return constructSubsetSparseMatrix<Scalar>(x.value().size(), indices) * x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Returns x(indices).
|
||||
template <typename Scalar, class IntVec>
|
||||
Eigen::Array<Scalar, Eigen::Dynamic, 1>
|
||||
subset(const Eigen::Array<Scalar, Eigen::Dynamic, 1>& x,
|
||||
const IntVec& indices)
|
||||
{
|
||||
return (constructSubsetSparseMatrix<Scalar>(x.size(), indices) * x.matrix()).array();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Returns v where v(indices) == x, v(!indices) == 0 and v.size() == n.
|
||||
template <typename Scalar, class IntVec>
|
||||
AutoDiffBlock<Scalar>
|
||||
superset(const AutoDiffBlock<Scalar>& x,
|
||||
const IntVec& indices,
|
||||
const int n)
|
||||
{
|
||||
return constructSupersetSparseMatrix<Scalar>(n, indices) * x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Returns v where v(indices) == x, v(!indices) == 0 and v.size() == n.
|
||||
template <typename Scalar, class IntVec>
|
||||
Eigen::Array<Scalar, Eigen::Dynamic, 1>
|
||||
superset(const Eigen::Array<Scalar, Eigen::Dynamic, 1>& x,
|
||||
const IntVec& indices,
|
||||
const int n)
|
||||
{
|
||||
return constructSupersetSparseMatrix<Scalar>(n, indices) * x.matrix();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Construct square sparse matrix with the
|
||||
/// elements of d on the diagonal.
|
||||
/// Need to mark this as inline since it is defined in a header and not a template.
|
||||
inline
|
||||
AutoDiffBlock<double>::M
|
||||
spdiag(const AutoDiffBlock<double>::V& d)
|
||||
{
|
||||
typedef AutoDiffBlock<double>::M M;
|
||||
|
||||
const int n = d.size();
|
||||
M mat(n, n);
|
||||
mat.reserve(Eigen::ArrayXi::Ones(n, 1));
|
||||
for (M::Index i = 0; i < n; ++i) {
|
||||
mat.insert(i, i) = d[i];
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Selection. Choose first of two elements if selection basis element is nonnegative.
|
||||
template <typename Scalar>
|
||||
class Selector {
|
||||
public:
|
||||
typedef AutoDiffBlock<Scalar> ADB;
|
||||
|
||||
Selector(const typename ADB::V& selection_basis)
|
||||
{
|
||||
// Define selector structure.
|
||||
const int n = selection_basis.size();
|
||||
// Over-reserving so we do not have to count.
|
||||
left_elems_.reserve(n);
|
||||
right_elems_.reserve(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (selection_basis[i] < 0.0) {
|
||||
right_elems_.push_back(i);
|
||||
} else {
|
||||
left_elems_.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply selector to ADB quantities.
|
||||
ADB select(const ADB& x1, const ADB& x2) const
|
||||
{
|
||||
if (right_elems_.empty()) {
|
||||
return x1;
|
||||
} else if (left_elems_.empty()) {
|
||||
return x2;
|
||||
} else {
|
||||
return superset(subset(x1, left_elems_), left_elems_, x1.size())
|
||||
+ superset(subset(x2, right_elems_), right_elems_, x2.size());
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply selector to ADB quantities.
|
||||
typename ADB::V select(const typename ADB::V& x1, const typename ADB::V& x2) const
|
||||
{
|
||||
if (right_elems_.empty()) {
|
||||
return x1;
|
||||
} else if (left_elems_.empty()) {
|
||||
return x2;
|
||||
} else {
|
||||
return superset(subset(x1, left_elems_), left_elems_, x1.size())
|
||||
+ superset(subset(x2, right_elems_), right_elems_, x2.size());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<int> left_elems_;
|
||||
std::vector<int> right_elems_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/// Returns the input expression, but with all Jacobians collapsed to one.
|
||||
inline
|
||||
AutoDiffBlock<double>
|
||||
collapseJacs(const AutoDiffBlock<double>& x)
|
||||
{
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
const int nb = x.numBlocks();
|
||||
typedef Eigen::Triplet<double> Tri;
|
||||
int nnz = 0;
|
||||
for (int block = 0; block < nb; ++block) {
|
||||
nnz += x.derivative()[block].nonZeros();
|
||||
}
|
||||
std::vector<Tri> t;
|
||||
t.reserve(nnz);
|
||||
int block_col_start = 0;
|
||||
for (int block = 0; block < nb; ++block) {
|
||||
const ADB::M& jac = x.derivative()[block];
|
||||
for (ADB::M::Index k = 0; k < jac.outerSize(); ++k) {
|
||||
for (ADB::M::InnerIterator i(jac, k); i ; ++i) {
|
||||
t.push_back(Tri(i.row(),
|
||||
i.col() + block_col_start,
|
||||
i.value()));
|
||||
}
|
||||
}
|
||||
block_col_start += jac.cols();
|
||||
}
|
||||
// Build final jacobian.
|
||||
std::vector<ADB::M> jacs(1);
|
||||
jacs[0].resize(x.size(), block_col_start);
|
||||
jacs[0].setFromTriplets(t.begin(), t.end());
|
||||
return ADB::function(x.value(), jacs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Returns the vertical concatenation [ x; y ] of the inputs.
|
||||
inline
|
||||
AutoDiffBlock<double>
|
||||
vertcat(const AutoDiffBlock<double>& x,
|
||||
const AutoDiffBlock<double>& y)
|
||||
{
|
||||
const int nx = x.size();
|
||||
const int ny = y.size();
|
||||
const int n = nx + ny;
|
||||
std::vector<int> xind(nx);
|
||||
for (int i = 0; i < nx; ++i) {
|
||||
xind[i] = i;
|
||||
}
|
||||
std::vector<int> yind(ny);
|
||||
for (int i = 0; i < ny; ++i) {
|
||||
yind[i] = nx + i;
|
||||
}
|
||||
return superset(x, xind, n) + superset(y, yind, n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Span
|
||||
{
|
||||
public:
|
||||
explicit Span(const int num)
|
||||
: num_(num),
|
||||
stride_(1),
|
||||
start_(0)
|
||||
{
|
||||
}
|
||||
Span(const int num, const int stride, const int start)
|
||||
: num_(num),
|
||||
stride_(stride),
|
||||
start_(start)
|
||||
{
|
||||
}
|
||||
int operator[](const int i) const
|
||||
{
|
||||
assert(i >= 0 && i < num_);
|
||||
return start_ + i*stride_;
|
||||
}
|
||||
int size() const
|
||||
{
|
||||
return num_;
|
||||
}
|
||||
|
||||
|
||||
class SpanIterator
|
||||
{
|
||||
public:
|
||||
SpanIterator(const Span* span, const int index)
|
||||
: span_(span),
|
||||
index_(index)
|
||||
{
|
||||
}
|
||||
SpanIterator operator++()
|
||||
{
|
||||
++index_;
|
||||
return *this;
|
||||
}
|
||||
SpanIterator operator++(int)
|
||||
{
|
||||
SpanIterator before_increment(*this);
|
||||
++index_;
|
||||
return before_increment;
|
||||
}
|
||||
bool operator<(const SpanIterator& rhs) const
|
||||
{
|
||||
assert(span_ == rhs.span_);
|
||||
return index_ < rhs.index_;
|
||||
}
|
||||
bool operator==(const SpanIterator& rhs) const
|
||||
{
|
||||
assert(span_ == rhs.span_);
|
||||
return index_ == rhs.index_;
|
||||
}
|
||||
bool operator!=(const SpanIterator& rhs) const
|
||||
{
|
||||
assert(span_ == rhs.span_);
|
||||
return index_ != rhs.index_;
|
||||
}
|
||||
int operator*()
|
||||
{
|
||||
return (*span_)[index_];
|
||||
}
|
||||
private:
|
||||
const Span* span_;
|
||||
int index_;
|
||||
};
|
||||
|
||||
typedef SpanIterator iterator;
|
||||
typedef SpanIterator const_iterator;
|
||||
|
||||
SpanIterator begin() const
|
||||
{
|
||||
return SpanIterator(this, 0);
|
||||
}
|
||||
|
||||
SpanIterator end() const
|
||||
{
|
||||
return SpanIterator(this, num_);
|
||||
}
|
||||
|
||||
bool operator==(const Span& rhs)
|
||||
{
|
||||
return num_ == rhs.num_ && start_ == rhs.start_ && stride_ == rhs.stride_;
|
||||
}
|
||||
|
||||
private:
|
||||
const int num_;
|
||||
const int stride_;
|
||||
const int start_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Return a vector of (-1.0, 0.0 or 1.0), depending on sign per element.
|
||||
inline Eigen::ArrayXd sign (const Eigen::ArrayXd& x)
|
||||
{
|
||||
const int n = x.size();
|
||||
Eigen::ArrayXd retval(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
retval[i] = x[i] < 0.0 ? -1.0 : (x[i] > 0.0 ? 1.0 : 0.0);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_AUTODIFFHELPERS_HEADER_INCLUDED
|
||||
@@ -1,647 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAd.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/core/props/BlackoilPropertiesInterface.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
// Making these typedef to make the code more readable.
|
||||
typedef BlackoilPropsAd::ADB ADB;
|
||||
typedef BlackoilPropsAd::V V;
|
||||
typedef Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Block;
|
||||
|
||||
/// Constructor wrapping an opm-core black oil interface.
|
||||
BlackoilPropsAd::BlackoilPropsAd(const BlackoilPropertiesInterface& props)
|
||||
: props_(props),
|
||||
pu_(props.phaseUsage())
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int BlackoilPropsAd::numDimensions() const
|
||||
{
|
||||
return props_.numDimensions();
|
||||
}
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int BlackoilPropsAd::numCells() const
|
||||
{
|
||||
return props_.numCells();
|
||||
}
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* BlackoilPropsAd::porosity() const
|
||||
{
|
||||
return props_.porosity();
|
||||
}
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* BlackoilPropsAd::permeability() const
|
||||
{
|
||||
return props_.permeability();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
int BlackoilPropsAd::numPhases() const
|
||||
{
|
||||
return props_.numPhases();
|
||||
}
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
PhaseUsage BlackoilPropsAd::phaseUsage() const
|
||||
{
|
||||
return props_.phaseUsage();
|
||||
}
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of 3 density values.
|
||||
const double* BlackoilPropsAd::surfaceDensity() const
|
||||
{
|
||||
return props_.surfaceDensity();
|
||||
}
|
||||
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAd::muWat(const V& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block mu(n, np);
|
||||
props_.viscosity(n, pw.data(), z.data(), cells.data(), mu.data(), 0);
|
||||
return mu.col(pu_.phase_pos[Water]);
|
||||
}
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAd::muOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
if (pu_.phase_used[Gas]) {
|
||||
// Faking a z with the right ratio:
|
||||
// rs = zg/zo
|
||||
z.col(pu_.phase_pos[Oil]) = V::Ones(n, 1);
|
||||
z.col(pu_.phase_pos[Gas]) = rs;
|
||||
}
|
||||
Block mu(n, np);
|
||||
props_.viscosity(n, po.data(), z.data(), cells.data(), mu.data(), 0);
|
||||
return mu.col(pu_.phase_pos[Oil]);
|
||||
}
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAd::muGas(const V& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block mu(n, np);
|
||||
props_.viscosity(n, pg.data(), z.data(), cells.data(), mu.data(), 0);
|
||||
return mu.col(pu_.phase_pos[Gas]);
|
||||
}
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAd::muWat(const ADB& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
#if 1
|
||||
return ADB::constant(muWat(pw.value(), cells), pw.blockPattern());
|
||||
#else
|
||||
if (!pu_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.value().size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block mu(n, np);
|
||||
Block dmu(n, np);
|
||||
props_.viscosity(n, pw.value().data(), z.data(), cells.data(), mu.data(), dmu.data());
|
||||
ADB::M dmu_diag = spdiag(dmu.col(pu_.phase_pos[Water]));
|
||||
const int num_blocks = pw.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmu_diag * pw.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu.col(pu_.phase_pos[Water]), jacs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAd::muOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
#if 1
|
||||
return ADB::constant(muOil(po.value(), rs.value(), cells), po.blockPattern());
|
||||
#else
|
||||
if (!pu_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.value().size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
if (pu_.phase_used[Gas]) {
|
||||
// Faking a z with the right ratio:
|
||||
// rs = zg/zo
|
||||
z.col(pu_.phase_pos[Oil]) = V::Ones(n, 1);
|
||||
z.col(pu_.phase_pos[Gas]) = rs.value();
|
||||
}
|
||||
Block mu(n, np);
|
||||
Block dmu(n, np);
|
||||
props_.viscosity(n, po.value().data(), z.data(), cells.data(), mu.data(), dmu.data());
|
||||
ADB::M dmu_diag = spdiag(dmu.col(pu_.phase_pos[Oil]));
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
// For now, we deliberately ignore the derivative with respect to rs,
|
||||
// since the BlackoilPropertiesInterface class does not evaluate it.
|
||||
// We would add to the next line: + dmu_drs_diag * rs.derivative()[block]
|
||||
jacs[block] = dmu_diag * po.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu.col(pu_.phase_pos[Oil]), jacs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAd::muGas(const ADB& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
#if 1
|
||||
return ADB::constant(muGas(pg.value(), cells), pg.blockPattern());
|
||||
#else
|
||||
if (!pu_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.value().size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block mu(n, np);
|
||||
Block dmu(n, np);
|
||||
props_.viscosity(n, pg.value().data(), z.data(), cells.data(), mu.data(), dmu.data());
|
||||
ADB::M dmu_diag = spdiag(dmu.col(pu_.phase_pos[Gas]));
|
||||
const int num_blocks = pg.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmu_diag * pg.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu.col(pu_.phase_pos[Gas]), jacs);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ------ Formation volume factor (b) ------
|
||||
|
||||
// These methods all call the matrix() method, after which the variable
|
||||
// (also) called 'matrix' contains, in each row, the A = RB^{-1} matrix for
|
||||
// a cell. For three-phase black oil:
|
||||
// A = [ bw 0 0
|
||||
// 0 bo 0
|
||||
// 0 b0*rs bw ]
|
||||
// Where b = B^{-1}.
|
||||
// Therefore, we extract the correct diagonal element, and are done.
|
||||
// When we need the derivatives (w.r.t. p, since we don't do w.r.t. rs),
|
||||
// we also get the following derivative matrix:
|
||||
// A = [ dbw 0 0
|
||||
// 0 dbo 0
|
||||
// 0 db0*rs dbw ]
|
||||
// Again, we just extract a diagonal element.
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAd::bWat(const V& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call bWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block matrix(n, np*np);
|
||||
props_.matrix(n, pw.data(), z.data(), cells.data(), matrix.data(), 0);
|
||||
const int wi = pu_.phase_pos[Water];
|
||||
return matrix.col(wi*np + wi);
|
||||
}
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAd::bOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call bOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
if (pu_.phase_used[Gas]) {
|
||||
// Faking a z with the right ratio:
|
||||
// rs = zg/zo
|
||||
z.col(pu_.phase_pos[Oil]) = V::Ones(n, 1);
|
||||
z.col(pu_.phase_pos[Gas]) = rs;
|
||||
}
|
||||
Block matrix(n, np*np);
|
||||
props_.matrix(n, po.data(), z.data(), cells.data(), matrix.data(), 0);
|
||||
const int oi = pu_.phase_pos[Oil];
|
||||
return matrix.col(oi*np + oi);
|
||||
}
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAd::bGas(const V& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call bGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block matrix(n, np*np);
|
||||
props_.matrix(n, pg.data(), z.data(), cells.data(), matrix.data(), 0);
|
||||
const int gi = pu_.phase_pos[Gas];
|
||||
return matrix.col(gi*np + gi);
|
||||
}
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAd::bWat(const ADB& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.value().size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block matrix(n, np*np);
|
||||
Block dmatrix(n, np*np);
|
||||
props_.matrix(n, pw.value().data(), z.data(), cells.data(), matrix.data(), dmatrix.data());
|
||||
const int phase_ind = pu_.phase_pos[Water];
|
||||
const int column = phase_ind*np + phase_ind; // Index of our sought diagonal column.
|
||||
ADB::M db_diag = spdiag(dmatrix.col(column));
|
||||
const int num_blocks = pw.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = db_diag * pw.derivative()[block];
|
||||
}
|
||||
return ADB::function(matrix.col(column), jacs);
|
||||
}
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAd::bOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.value().size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
if (pu_.phase_used[Gas]) {
|
||||
// Faking a z with the right ratio:
|
||||
// rs = zg/zo
|
||||
z.col(pu_.phase_pos[Oil]) = V::Ones(n, 1);
|
||||
z.col(pu_.phase_pos[Gas]) = rs.value();
|
||||
}
|
||||
Block matrix(n, np*np);
|
||||
Block dmatrix(n, np*np);
|
||||
props_.matrix(n, po.value().data(), z.data(), cells.data(), matrix.data(), dmatrix.data());
|
||||
const int phase_ind = pu_.phase_pos[Oil];
|
||||
const int column = phase_ind*np + phase_ind; // Index of our sought diagonal column.
|
||||
ADB::M db_diag = spdiag(dmatrix.col(column));
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
// For now, we deliberately ignore the derivative with respect to rs,
|
||||
// since the BlackoilPropertiesInterface class does not evaluate it.
|
||||
// We would add to the next line: + db_drs_diag * rs.derivative()[block]
|
||||
jacs[block] = db_diag * po.derivative()[block];
|
||||
}
|
||||
return ADB::function(matrix.col(column), jacs);
|
||||
}
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAd::bGas(const ADB& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!pu_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.value().size() == n);
|
||||
const int np = props_.numPhases();
|
||||
Block z = Block::Zero(n, np);
|
||||
Block matrix(n, np*np);
|
||||
Block dmatrix(n, np*np);
|
||||
props_.matrix(n, pg.value().data(), z.data(), cells.data(), matrix.data(), dmatrix.data());
|
||||
const int phase_ind = pu_.phase_pos[Gas];
|
||||
const int column = phase_ind*np + phase_ind; // Index of our sought diagonal column.
|
||||
ADB::M db_diag = spdiag(dmatrix.col(column));
|
||||
const int num_blocks = pg.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = db_diag * pg.derivative()[block];
|
||||
}
|
||||
return ADB::function(matrix.col(column), jacs);
|
||||
}
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
V BlackoilPropsAd::rsMax(const V& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
// Suppress warning about "unused parameters".
|
||||
static_cast<void>(po);
|
||||
static_cast<void>(cells);
|
||||
|
||||
OPM_THROW(std::runtime_error, "Method rsMax() not implemented.");
|
||||
}
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
ADB BlackoilPropsAd::rsMax(const ADB& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
// Suppress warning about "unused parameters".
|
||||
static_cast<void>(po);
|
||||
static_cast<void>(cells);
|
||||
|
||||
OPM_THROW(std::runtime_error, "Method rsMax() not implemented.");
|
||||
}
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<V> BlackoilPropsAd::relperm(const V& sw,
|
||||
const V& so,
|
||||
const V& sg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = props_.numPhases();
|
||||
Block s_all(n, np);
|
||||
if (pu_.phase_used[Water]) {
|
||||
assert(sw.size() == n);
|
||||
s_all.col(pu_.phase_pos[Water]) = sw;
|
||||
}
|
||||
if (pu_.phase_used[Oil]) {
|
||||
assert(so.size() == n);
|
||||
s_all.col(pu_.phase_pos[Oil]) = so;
|
||||
}
|
||||
if (pu_.phase_used[Gas]) {
|
||||
assert(sg.size() == n);
|
||||
s_all.col(pu_.phase_pos[Gas]) = sg;
|
||||
}
|
||||
Block kr(n, np);
|
||||
props_.relperm(n, s_all.data(), cells.data(), kr.data(), 0);
|
||||
std::vector<V> relperms;
|
||||
relperms.reserve(3);
|
||||
for (int phase = 0; phase < 3; ++phase) {
|
||||
if (pu_.phase_used[phase]) {
|
||||
relperms.emplace_back(kr.col(pu_.phase_pos[phase]));
|
||||
} else {
|
||||
relperms.emplace_back();
|
||||
}
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<ADB> BlackoilPropsAd::relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = props_.numPhases();
|
||||
Block s_all(n, np);
|
||||
if (pu_.phase_used[Water]) {
|
||||
assert(sw.value().size() == n);
|
||||
s_all.col(pu_.phase_pos[Water]) = sw.value();
|
||||
}
|
||||
if (pu_.phase_used[Oil]) {
|
||||
assert(so.value().size() == n);
|
||||
s_all.col(pu_.phase_pos[Oil]) = so.value();
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropsAd::relperm() assumes oil phase is active.");
|
||||
}
|
||||
if (pu_.phase_used[Gas]) {
|
||||
assert(sg.value().size() == n);
|
||||
s_all.col(pu_.phase_pos[Gas]) = sg.value();
|
||||
}
|
||||
Block kr(n, np);
|
||||
Block dkr(n, np*np);
|
||||
props_.relperm(n, s_all.data(), cells.data(), kr.data(), dkr.data());
|
||||
const int num_blocks = so.numBlocks();
|
||||
std::vector<ADB> relperms;
|
||||
relperms.reserve(3);
|
||||
typedef const ADB* ADBPtr;
|
||||
ADBPtr s[3] = { &sw, &so, &sg };
|
||||
for (int phase1 = 0; phase1 < 3; ++phase1) {
|
||||
if (pu_.phase_used[phase1]) {
|
||||
const int phase1_pos = pu_.phase_pos[phase1];
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = ADB::M(n, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < 3; ++phase2) {
|
||||
if (!pu_.phase_used[phase2]) {
|
||||
continue;
|
||||
}
|
||||
const int phase2_pos = pu_.phase_pos[phase2];
|
||||
// Assemble dkr1/ds2.
|
||||
const int column = phase1_pos + np*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dkr1_ds2_diag = spdiag(dkr.col(column));
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] += dkr1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
relperms.emplace_back(ADB::function(kr.col(phase1_pos), jacs));
|
||||
} else {
|
||||
relperms.emplace_back(ADB::null());
|
||||
}
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
std::vector<ADB> BlackoilPropsAd::capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const
|
||||
|
||||
{
|
||||
const int numCells = cells.size();
|
||||
const int numActivePhases = numPhases();
|
||||
const int numBlocks = so.numBlocks();
|
||||
|
||||
Block activeSat(numCells, numActivePhases);
|
||||
if (pu_.phase_used[Water]) {
|
||||
assert(sw.value().size() == numCells);
|
||||
activeSat.col(pu_.phase_pos[Water]) = sw.value();
|
||||
}
|
||||
if (pu_.phase_used[Oil]) {
|
||||
assert(so.value().size() == numCells);
|
||||
activeSat.col(pu_.phase_pos[Oil]) = so.value();
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::relperm() assumes oil phase is active.");
|
||||
}
|
||||
if (pu_.phase_used[Gas]) {
|
||||
assert(sg.value().size() == numCells);
|
||||
activeSat.col(pu_.phase_pos[Gas]) = sg.value();
|
||||
}
|
||||
|
||||
Block pc(numCells, numActivePhases);
|
||||
Block dpc(numCells, numActivePhases*numActivePhases);
|
||||
props_.capPress(numCells, activeSat.data(), cells.data(), pc.data(), dpc.data());
|
||||
|
||||
std::vector<ADB> adbCapPressures;
|
||||
adbCapPressures.reserve(3);
|
||||
const ADB* s[3] = { &sw, &so, &sg };
|
||||
for (int phase1 = 0; phase1 < 3; ++phase1) {
|
||||
if (pu_.phase_used[phase1]) {
|
||||
const int phase1_pos = pu_.phase_pos[phase1];
|
||||
std::vector<ADB::M> jacs(numBlocks);
|
||||
for (int block = 0; block < numBlocks; ++block) {
|
||||
jacs[block] = ADB::M(numCells, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < 3; ++phase2) {
|
||||
if (!pu_.phase_used[phase2])
|
||||
continue;
|
||||
const int phase2_pos = pu_.phase_pos[phase2];
|
||||
// Assemble dpc1/ds2.
|
||||
const int column = phase1_pos + numActivePhases*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dpc1_ds2_diag = spdiag(dpc.col(column));
|
||||
for (int block = 0; block < numBlocks; ++block) {
|
||||
jacs[block] += dpc1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
adbCapPressures.emplace_back(ADB::function(pc.col(phase1_pos), jacs));
|
||||
} else {
|
||||
adbCapPressures.emplace_back(ADB::null());
|
||||
}
|
||||
}
|
||||
return adbCapPressures;
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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_BLACKOILPROPSAD_HEADER_INCLUDED
|
||||
#define OPM_BLACKOILPROPSAD_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
class BlackoilPropertiesInterface;
|
||||
|
||||
/// This class implements the AD-adapted fluid interface for
|
||||
/// three-phase black-oil.
|
||||
///
|
||||
/// It is implemented by wrapping a BlackoilPropertiesInterface
|
||||
/// object (the interface class defined in opm-core) and calling
|
||||
/// its methods. This class does not implement rsMax() because the
|
||||
/// required information is not available when wrapping a
|
||||
/// BlackoilPropertiesInterface. Consequently, class
|
||||
/// BlackoilPropsAd cannot be used to simulate problems involving
|
||||
/// miscibility.
|
||||
///
|
||||
/// Most methods are available in two overloaded versions, one
|
||||
/// taking a constant vector and returning the same, and one
|
||||
/// taking an AD type and returning the same. Derivatives are not
|
||||
/// returned separately by any method, only implicitly with the AD
|
||||
/// version of the methods.
|
||||
class BlackoilPropsAd : public BlackoilPropsAdInterface
|
||||
{
|
||||
public:
|
||||
/// Constructor wrapping an opm-core black oil interface.
|
||||
explicit BlackoilPropsAd(const BlackoilPropertiesInterface& props);
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int numDimensions() const;
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int numCells() const;
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* porosity() const;
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* permeability() const;
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
virtual int numPhases() const;
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
virtual PhaseUsage phaseUsage() const;
|
||||
|
||||
// ------ Canonical named indices for each phase ------
|
||||
|
||||
/// Canonical named indices for each phase.
|
||||
enum PhaseIndex { Water = 0, Oil = 1, Gas = 2 };
|
||||
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of 3 density values.
|
||||
const double* surfaceDensity() const;
|
||||
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muWat(const V& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muGas(const V& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muWat(const ADB& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muGas(const ADB& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Formation volume factor (b) ------
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bWat(const V& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bGas(const V& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bWat(const ADB& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bGas(const ADB& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
V rsMax(const V& po,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
ADB rsMax(const ADB& po,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<V> relperm(const V& sw,
|
||||
const V& so,
|
||||
const V& sg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<ADB> relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const;
|
||||
/// Capillary pressure for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n capillary pressure values,
|
||||
/// containing the offsets for each p_g, p_o, p_w. The capillary pressure between
|
||||
/// two arbitrary phases alpha and beta is then given as p_alpha - p_beta.
|
||||
std::vector<ADB> capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const;
|
||||
|
||||
private:
|
||||
const BlackoilPropertiesInterface& props_;
|
||||
PhaseUsage pu_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_BLACKOILPROPSAD_HEADER_INCLUDED
|
||||
@@ -1,740 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdFromDeck.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/core/props/BlackoilPropertiesInterface.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtInterface.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtConstCompr.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtDead.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtDeadSpline.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtLiveOil.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
// Making these typedef to make the code more readable.
|
||||
typedef BlackoilPropsAdFromDeck::ADB ADB;
|
||||
typedef BlackoilPropsAdFromDeck::V V;
|
||||
typedef Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Block;
|
||||
enum { Aqua = BlackoilPhases::Aqua,
|
||||
Liquid = BlackoilPhases::Liquid,
|
||||
Vapour = BlackoilPhases::Vapour };
|
||||
|
||||
/// Constructor wrapping an opm-core black oil interface.
|
||||
BlackoilPropsAdFromDeck::BlackoilPropsAdFromDeck(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
const bool init_rock)
|
||||
{
|
||||
if (init_rock){
|
||||
rock_.init(deck, grid);
|
||||
}
|
||||
const int samples = 0;
|
||||
const int region_number = 0;
|
||||
|
||||
phase_usage_ = phaseUsageFromDeck(deck);
|
||||
|
||||
// Surface densities. Accounting for different orders in eclipse and our code.
|
||||
if (deck.hasField("DENSITY")) {
|
||||
const std::vector<double>& d = deck.getDENSITY().densities_[region_number];
|
||||
enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 };
|
||||
if (phase_usage_.phase_used[Aqua]) {
|
||||
densities_[phase_usage_.phase_pos[Aqua]] = d[ECL_water];
|
||||
}
|
||||
if (phase_usage_.phase_used[Vapour]) {
|
||||
densities_[phase_usage_.phase_pos[Vapour]] = d[ECL_gas];
|
||||
}
|
||||
if (phase_usage_.phase_used[Liquid]) {
|
||||
densities_[phase_usage_.phase_pos[Liquid]] = d[ECL_oil];
|
||||
}
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Input is missing DENSITY\n");
|
||||
}
|
||||
|
||||
// Set the properties.
|
||||
props_.resize(phase_usage_.num_phases);
|
||||
// Water PVT
|
||||
if (phase_usage_.phase_used[Aqua]) {
|
||||
if (deck.hasField("PVTW")) {
|
||||
props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(deck.getPVTW().pvtw_));
|
||||
} else {
|
||||
// Eclipse 100 default.
|
||||
props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(0.5*Opm::prefix::centi*Opm::unit::Poise));
|
||||
}
|
||||
}
|
||||
// Oil PVT
|
||||
if (phase_usage_.phase_used[Liquid]) {
|
||||
if (deck.hasField("PVDO")) {
|
||||
if (samples > 0) {
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDeadSpline(deck.getPVDO().pvdo_, samples));
|
||||
} else {
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDead(deck.getPVDO().pvdo_));
|
||||
}
|
||||
} else if (deck.hasField("PVTO")) {
|
||||
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtLiveOil(deck.getPVTO().pvto_));
|
||||
} else if (deck.hasField("PVCDO")) {
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtConstCompr(deck.getPVCDO().pvcdo_));
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Input is missing PVDO or PVTO\n");
|
||||
}
|
||||
}
|
||||
// Gas PVT
|
||||
if (phase_usage_.phase_used[Vapour]) {
|
||||
if (deck.hasField("PVDG")) {
|
||||
if (samples > 0) {
|
||||
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDeadSpline(deck.getPVDG().pvdg_, samples));
|
||||
} else {
|
||||
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDead(deck.getPVDG().pvdg_));
|
||||
}
|
||||
// } else if (deck.hasField("PVTG")) {
|
||||
// props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_));
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Input is missing PVDG or PVTG\n");
|
||||
}
|
||||
}
|
||||
|
||||
SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, -1);
|
||||
|
||||
if (phase_usage_.num_phases != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::BlackoilPropsAdFromDeck() - "
|
||||
"Inconsistent number of phases in pvt data (" << phase_usage_.num_phases
|
||||
<< ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int BlackoilPropsAdFromDeck::numDimensions() const
|
||||
{
|
||||
return rock_.numDimensions();
|
||||
}
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int BlackoilPropsAdFromDeck::numCells() const
|
||||
{
|
||||
return rock_.numCells();
|
||||
}
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* BlackoilPropsAdFromDeck::porosity() const
|
||||
{
|
||||
return rock_.porosity();
|
||||
}
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* BlackoilPropsAdFromDeck::permeability() const
|
||||
{
|
||||
return rock_.permeability();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
int BlackoilPropsAdFromDeck::numPhases() const
|
||||
{
|
||||
return phase_usage_.num_phases;
|
||||
}
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
PhaseUsage BlackoilPropsAdFromDeck::phaseUsage() const
|
||||
{
|
||||
return phase_usage_;
|
||||
}
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of 3 density values.
|
||||
const double* BlackoilPropsAdFromDeck::surfaceDensity() const
|
||||
{
|
||||
return densities_;
|
||||
}
|
||||
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAdFromDeck::muWat(const V& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->mu(n, pw.data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
return mu;
|
||||
}
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAdFromDeck::muOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->mu(n, po.data(), rs.data(),
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
return mu;
|
||||
}
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAdFromDeck::muGas(const V& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
return mu;
|
||||
}
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAdFromDeck::muWat(const ADB& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->mu(n, pw.value().data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
ADB::M dmudp_diag = spdiag(dmudp);
|
||||
const int num_blocks = pw.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmudp_diag * pw.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu, jacs);
|
||||
}
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAdFromDeck::muOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->mu(n, po.value().data(), rs.value().data(),
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
|
||||
ADB::M dmudp_diag = spdiag(dmudp);
|
||||
ADB::M dmudr_diag = spdiag(dmudr);
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmudp_diag * po.derivative()[block] + dmudr_diag * rs.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu, jacs);
|
||||
}
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAdFromDeck::muGas(const ADB& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.value().size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.value().data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
|
||||
ADB::M dmudp_diag = spdiag(dmudp);
|
||||
const int num_blocks = pg.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmudp_diag * pg.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu, jacs);
|
||||
}
|
||||
|
||||
|
||||
// ------ Formation volume factor (b) ------
|
||||
|
||||
// These methods all call the matrix() method, after which the variable
|
||||
// (also) called 'matrix' contains, in each row, the A = RB^{-1} matrix for
|
||||
// a cell. For three-phase black oil:
|
||||
// A = [ bw 0 0
|
||||
// 0 bo 0
|
||||
// 0 b0*rs bw ]
|
||||
// Where b = B^{-1}.
|
||||
// Therefore, we extract the correct diagonal element, and are done.
|
||||
// When we need the derivatives (w.r.t. p, since we don't do w.r.t. rs),
|
||||
// we also get the following derivative matrix:
|
||||
// A = [ dbw 0 0
|
||||
// 0 dbo 0
|
||||
// 0 db0*rs dbw ]
|
||||
// Again, we just extract a diagonal element.
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAdFromDeck::bWat(const V& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call bWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->b(n, pw.data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAdFromDeck::bOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call bOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->b(n, po.data(), rs.data(),
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAdFromDeck::bGas(const V& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call bGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->b(n, pg.data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAdFromDeck::bWat(const ADB& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pw.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->b(n, pw.value().data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
ADB::M dbdp_diag = spdiag(dbdp);
|
||||
const int num_blocks = pw.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dbdp_diag * pw.derivative()[block];
|
||||
}
|
||||
return ADB::function(b, jacs);
|
||||
}
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAdFromDeck::bOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->b(n, po.value().data(), rs.value().data(),
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
ADB::M dbdp_diag = spdiag(dbdp);
|
||||
ADB::M dbdr_diag = spdiag(dbdr);
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dbdp_diag * po.derivative()[block] + dbdr_diag * rs.derivative()[block];
|
||||
}
|
||||
return ADB::function(b, jacs);
|
||||
}
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAdFromDeck::bGas(const ADB& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(pg.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->b(n, pg.value().data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
ADB::M dbdp_diag = spdiag(dbdp);
|
||||
const int num_blocks = pg.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dbdp_diag * pg.derivative()[block];
|
||||
}
|
||||
return ADB::function(b, jacs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
V BlackoilPropsAdFromDeck::rsMax(const V& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call rsMax(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
V rbub(n);
|
||||
V drbubdp(n);
|
||||
props_[Oil]->rsSat(n, po.data(), rbub.data(), drbubdp.data());
|
||||
return rbub;
|
||||
}
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
ADB BlackoilPropsAdFromDeck::rsMax(const ADB& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
OPM_THROW(std::runtime_error, "Cannot call rsMax(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
assert(po.size() == n);
|
||||
V rbub(n);
|
||||
V drbubdp(n);
|
||||
props_[Oil]->rsSat(n, po.value().data(), rbub.data(), drbubdp.data());
|
||||
ADB::M drbubdp_diag = spdiag(drbubdp);
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = drbubdp_diag * po.derivative()[block];
|
||||
}
|
||||
return ADB::function(rbub, jacs);
|
||||
}
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<V> BlackoilPropsAdFromDeck::relperm(const V& sw,
|
||||
const V& so,
|
||||
const V& sg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
if (phase_usage_.phase_used[Water]) {
|
||||
assert(sw.size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Water]) = sw;
|
||||
}
|
||||
if (phase_usage_.phase_used[Oil]) {
|
||||
assert(so.size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Oil]) = so;
|
||||
}
|
||||
if (phase_usage_.phase_used[Gas]) {
|
||||
assert(sg.size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Gas]) = sg;
|
||||
}
|
||||
Block kr(n, np);
|
||||
satprops_->relperm(n, s_all.data(), cells.data(), kr.data(), 0);
|
||||
std::vector<V> relperms;
|
||||
relperms.reserve(3);
|
||||
for (int phase = 0; phase < 3; ++phase) {
|
||||
if (phase_usage_.phase_used[phase]) {
|
||||
relperms.emplace_back(kr.col(phase_usage_.phase_pos[phase]));
|
||||
} else {
|
||||
relperms.emplace_back();
|
||||
}
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<ADB> BlackoilPropsAdFromDeck::relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
if (phase_usage_.phase_used[Water]) {
|
||||
assert(sw.value().size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Water]) = sw.value();
|
||||
}
|
||||
if (phase_usage_.phase_used[Oil]) {
|
||||
assert(so.value().size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Oil]) = so.value();
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::relperm() assumes oil phase is active.");
|
||||
}
|
||||
if (phase_usage_.phase_used[Gas]) {
|
||||
assert(sg.value().size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Gas]) = sg.value();
|
||||
}
|
||||
Block kr(n, np);
|
||||
Block dkr(n, np*np);
|
||||
satprops_->relperm(n, s_all.data(), cells.data(), kr.data(), dkr.data());
|
||||
const int num_blocks = so.numBlocks();
|
||||
std::vector<ADB> relperms;
|
||||
relperms.reserve(3);
|
||||
typedef const ADB* ADBPtr;
|
||||
ADBPtr s[3] = { &sw, &so, &sg };
|
||||
for (int phase1 = 0; phase1 < 3; ++phase1) {
|
||||
if (phase_usage_.phase_used[phase1]) {
|
||||
const int phase1_pos = phase_usage_.phase_pos[phase1];
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = ADB::M(n, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < 3; ++phase2) {
|
||||
if (!phase_usage_.phase_used[phase2]) {
|
||||
continue;
|
||||
}
|
||||
const int phase2_pos = phase_usage_.phase_pos[phase2];
|
||||
// Assemble dkr1/ds2.
|
||||
const int column = phase1_pos + np*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dkr1_ds2_diag = spdiag(dkr.col(column));
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] += dkr1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
relperms.emplace_back(ADB::function(kr.col(phase1_pos), jacs));
|
||||
} else {
|
||||
relperms.emplace_back(ADB::null());
|
||||
}
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
std::vector<ADB> BlackoilPropsAdFromDeck::capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int numCells = cells.size();
|
||||
const int numActivePhases = numPhases();
|
||||
const int numBlocks = so.numBlocks();
|
||||
|
||||
Block activeSat(numCells, numActivePhases);
|
||||
if (phase_usage_.phase_used[Water]) {
|
||||
assert(sw.value().size() == numCells);
|
||||
activeSat.col(phase_usage_.phase_pos[Water]) = sw.value();
|
||||
}
|
||||
if (phase_usage_.phase_used[Oil]) {
|
||||
assert(so.value().size() == numCells);
|
||||
activeSat.col(phase_usage_.phase_pos[Oil]) = so.value();
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::relperm() assumes oil phase is active.");
|
||||
}
|
||||
if (phase_usage_.phase_used[Gas]) {
|
||||
assert(sg.value().size() == numCells);
|
||||
activeSat.col(phase_usage_.phase_pos[Gas]) = sg.value();
|
||||
}
|
||||
|
||||
Block pc(numCells, numActivePhases);
|
||||
Block dpc(numCells, numActivePhases*numActivePhases);
|
||||
satprops_->capPress(numCells, activeSat.data(), cells.data(), pc.data(), dpc.data());
|
||||
|
||||
std::vector<ADB> adbCapPressures;
|
||||
adbCapPressures.reserve(3);
|
||||
const ADB* s[3] = { &sw, &so, &sg };
|
||||
for (int phase1 = 0; phase1 < 3; ++phase1) {
|
||||
if (phase_usage_.phase_used[phase1]) {
|
||||
const int phase1_pos = phase_usage_.phase_pos[phase1];
|
||||
std::vector<ADB::M> jacs(numBlocks);
|
||||
for (int block = 0; block < numBlocks; ++block) {
|
||||
jacs[block] = ADB::M(numCells, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < 3; ++phase2) {
|
||||
if (!phase_usage_.phase_used[phase2])
|
||||
continue;
|
||||
const int phase2_pos = phase_usage_.phase_pos[phase2];
|
||||
// Assemble dpc1/ds2.
|
||||
const int column = phase1_pos + numActivePhases*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dpc1_ds2_diag = spdiag(dpc.col(column));
|
||||
for (int block = 0; block < numBlocks; ++block) {
|
||||
jacs[block] += dpc1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
adbCapPressures.emplace_back(ADB::function(pc.col(phase1_pos), jacs));
|
||||
} else {
|
||||
adbCapPressures.emplace_back(ADB::null());
|
||||
}
|
||||
}
|
||||
return adbCapPressures;
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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_BLACKOILPROPSADFROMDECK_HEADER_INCLUDED
|
||||
#define OPM_BLACKOILPROPSADFROMDECK_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/core/props/satfunc/SaturationPropsFromDeck.hpp>
|
||||
#include <opm/core/io/eclipse/EclipseGridParser.hpp>
|
||||
#include <opm/core/props/rock/RockFromDeck.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
class SinglePvtInterface;
|
||||
|
||||
/// This class implements the AD-adapted fluid interface for
|
||||
/// three-phase black-oil. It requires an input deck from which it
|
||||
/// reads all relevant property data.
|
||||
///
|
||||
/// Most methods are available in two overloaded versions, one
|
||||
/// taking a constant vector and returning the same, and one
|
||||
/// taking an AD type and returning the same. Derivatives are not
|
||||
/// returned separately by any method, only implicitly with the AD
|
||||
/// version of the methods.
|
||||
class BlackoilPropsAdFromDeck : public BlackoilPropsAdInterface
|
||||
{
|
||||
public:
|
||||
/// Constructor wrapping an opm-core black oil interface.
|
||||
BlackoilPropsAdFromDeck(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
const bool init_rock = true );
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int numDimensions() const;
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int numCells() const;
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* porosity() const;
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* permeability() const;
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
int numPhases() const;
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
PhaseUsage phaseUsage() const;
|
||||
|
||||
// ------ Canonical named indices for each phase ------
|
||||
|
||||
/// Canonical named indices for each phase.
|
||||
enum PhaseIndex { Water = 0, Oil = 1, Gas = 2 };
|
||||
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of 3 density values.
|
||||
const double* surfaceDensity() const;
|
||||
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muWat(const V& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muGas(const V& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muWat(const ADB& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muGas(const ADB& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Formation volume factor (b) ------
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bWat(const V& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bGas(const V& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bWat(const ADB& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bGas(const ADB& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
V rsMax(const V& po,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
ADB rsMax(const ADB& po,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<V> relperm(const V& sw,
|
||||
const V& so,
|
||||
const V& sg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<ADB> relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const;
|
||||
/// Capillary pressure for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n capillary pressure values,
|
||||
/// containing the offsets for each p_g, p_o, p_w. The capillary pressure between
|
||||
/// two arbitrary phases alpha and beta is then given as p_alpha - p_beta.
|
||||
std::vector<ADB> capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
private:
|
||||
RockFromDeck rock_;
|
||||
boost::scoped_ptr<SaturationPropsInterface> satprops_;
|
||||
PhaseUsage phase_usage_;
|
||||
std::vector<boost::shared_ptr<SinglePvtInterface> > props_;
|
||||
double densities_[BlackoilPhases::MaxNumPhases];
|
||||
};
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_BLACKOILPROPSADFROMDECK_HEADER_INCLUDED
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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/>.
|
||||
*/
|
||||
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
|
||||
Opm::BlackoilPropsAdInterface::~BlackoilPropsAdInterface()
|
||||
{
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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_BLACKOILPROPSADINTERFACE_HEADER_INCLUDED
|
||||
#define OPM_BLACKOILPROPSADINTERFACE_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// This class is intended to present a fluid interface for
|
||||
/// three-phase black-oil that is easy to use with the AD-using
|
||||
/// simulators.
|
||||
///
|
||||
/// Most methods are available in two overloaded versions, one
|
||||
/// taking a constant vector and returning the same, and one
|
||||
/// taking an AD type and returning the same. Derivatives are not
|
||||
/// returned separately by any method, only implicitly with the AD
|
||||
/// version of the methods.
|
||||
class BlackoilPropsAdInterface
|
||||
{
|
||||
public:
|
||||
/// Virtual destructor for inheritance.
|
||||
virtual ~BlackoilPropsAdInterface();
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
virtual int numDimensions() const = 0;
|
||||
|
||||
/// \return N, the number of cells.
|
||||
virtual int numCells() const = 0;
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
virtual const double* porosity() const = 0;
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
virtual const double* permeability() const = 0;
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef ADB::M M;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
virtual int numPhases() const = 0;
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
virtual PhaseUsage phaseUsage() const = 0;
|
||||
|
||||
// ------ Canonical named indices for each phase ------
|
||||
|
||||
/// Canonical named indices for each phase.
|
||||
enum PhaseIndex { Water = 0, Oil = 1, Gas = 2 };
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of 3 density values.
|
||||
virtual const double* surfaceDensity() const = 0;
|
||||
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
virtual
|
||||
V muWat(const V& pw,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
virtual
|
||||
V muOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
virtual
|
||||
V muGas(const V& pg,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
virtual
|
||||
ADB muWat(const ADB& pw,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
virtual
|
||||
ADB muOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
virtual
|
||||
ADB muGas(const ADB& pg,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
|
||||
// ------ Formation volume factor (b) ------
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
virtual
|
||||
V bWat(const V& pw,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
virtual
|
||||
V bOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
virtual
|
||||
V bGas(const V& pg,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
virtual
|
||||
ADB bWat(const ADB& pw,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
virtual
|
||||
ADB bOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
virtual
|
||||
ADB bGas(const ADB& pg,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
virtual
|
||||
V rsMax(const V& po,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
virtual
|
||||
ADB rsMax(const ADB& po,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
virtual
|
||||
std::vector<V> relperm(const V& sw,
|
||||
const V& so,
|
||||
const V& sg,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
virtual
|
||||
std::vector<ADB> relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
|
||||
/// Capillary pressure for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n capillary pressure values,
|
||||
/// containing the offsets for each p_g, p_o, p_w. The capillary pressure between
|
||||
/// two arbitrary phases alpha and beta is then given as p_alpha - p_beta.
|
||||
virtual
|
||||
std::vector<ADB> capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_BLACKOILPROPSADINTERFACE_HEADER_INCLUDED
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2013 STATOIL.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
@@ -20,10 +21,10 @@
|
||||
#include <opm/polymer/fullyimplicit/FullyImplicitCompressiblePolymerSolver.hpp>
|
||||
|
||||
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/GeoProps.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/GeoProps.hpp>
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/linalg/LinearSolverInterface.hpp>
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#ifndef OPM_FULLYIMPLICITBLACKOILSOLVER_HEADER_INCLUDED
|
||||
#define OPM_FULLYIMPLICITBLACKOILSOLVER_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/PolymerProperties.hpp>
|
||||
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#include <opm/polymer/fullyimplicit/FullyImplicitTwophasePolymerSolver.hpp>
|
||||
|
||||
#include <opm/core/pressure/tpfa/trans_tpfa.h>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/IncompPropsAdInterface.hpp>
|
||||
#include <opm/polymer/PolymerProperties.hpp>
|
||||
#include <opm/polymer/PolymerState.hpp>
|
||||
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#ifndef OPM_FULLYIMPLICITTWOPHASEPOLYMERSOLVER_HEADER_INCLUDED
|
||||
#define OPM_FULLYIMPLICITTWOPHASEPOLYMERSOLVER_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer//fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/IncompPropsAdInterface.hpp>
|
||||
#include <opm/polymer/PolymerProperties.hpp>
|
||||
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
||||
#include <opm/core/pressure/tpfa/trans_tpfa.h>
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
Copyright 2013 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_GEOPROPS_HEADER_INCLUDED
|
||||
#define OPM_GEOPROPS_HEADER_INCLUDED
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/pressure/tpfa/trans_tpfa.h>
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// Class containing static geological properties that are
|
||||
/// derived from grid and petrophysical properties:
|
||||
/// - pore volume
|
||||
/// - transmissibilities
|
||||
/// - gravity potentials
|
||||
class DerivedGeology
|
||||
{
|
||||
public:
|
||||
typedef Eigen::ArrayXd Vector;
|
||||
|
||||
/// Construct contained derived geological properties
|
||||
/// from grid and property information.
|
||||
template <class Props>
|
||||
DerivedGeology(const UnstructuredGrid& grid,
|
||||
const Props& props ,
|
||||
const double* grav = 0)
|
||||
: pvol_ (grid.number_of_cells)
|
||||
, trans_(grid.number_of_faces)
|
||||
, gpot_ (Vector::Zero(grid.cell_facepos[ grid.number_of_cells ], 1))
|
||||
, z_(grid.number_of_cells)
|
||||
{
|
||||
// Pore volume
|
||||
const typename Vector::Index nc = grid.number_of_cells;
|
||||
std::transform(grid.cell_volumes, grid.cell_volumes + nc,
|
||||
props.porosity(), pvol_.data(),
|
||||
std::multiplies<double>());
|
||||
|
||||
// Transmissibility
|
||||
Vector htrans(grid.cell_facepos[nc]);
|
||||
UnstructuredGrid* ug = const_cast<UnstructuredGrid*>(& grid);
|
||||
tpfa_htrans_compute(ug, props.permeability(), htrans.data());
|
||||
tpfa_trans_compute (ug, htrans.data() , trans_.data());
|
||||
|
||||
// Compute z coordinates
|
||||
for (int c = 0; c<nc; ++c){
|
||||
z_[c] = grid.cell_centroids[c*3 + 2];
|
||||
}
|
||||
|
||||
|
||||
// Gravity potential
|
||||
std::fill(gravity_, gravity_ + 3, 0.0);
|
||||
if (grav != 0) {
|
||||
const typename Vector::Index nd = grid.dimensions;
|
||||
|
||||
for (typename Vector::Index c = 0; c < nc; ++c) {
|
||||
const double* const cc = & grid.cell_centroids[c*nd + 0];
|
||||
|
||||
const int* const p = grid.cell_facepos;
|
||||
for (int i = p[c]; i < p[c + 1]; ++i) {
|
||||
const int f = grid.cell_faces[i];
|
||||
|
||||
const double* const fc = & grid.face_centroids[f*nd + 0];
|
||||
|
||||
for (typename Vector::Index d = 0; d < nd; ++d) {
|
||||
gpot_[i] += grav[d] * (fc[d] - cc[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::copy(grav, grav + nd, gravity_);
|
||||
}
|
||||
}
|
||||
|
||||
const Vector& poreVolume() const { return pvol_ ;}
|
||||
const Vector& transmissibility() const { return trans_ ;}
|
||||
const Vector& gravityPotential() const { return gpot_ ;}
|
||||
const Vector& z() const { return z_ ;}
|
||||
const double* gravity() const { return gravity_;}
|
||||
|
||||
private:
|
||||
Vector pvol_ ;
|
||||
Vector trans_;
|
||||
Vector gpot_ ;
|
||||
Vector z_;
|
||||
double gravity_[3]; // Size 3 even if grid is 2-dim.
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // OPM_GEOPROPS_HEADER_INCLUDED
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdBasic.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// Constructor.
|
||||
IncompPropsAdBasic::IncompPropsAdBasic(const parameter::ParameterGroup& param,
|
||||
const int dim,
|
||||
const int num_cells)
|
||||
{
|
||||
double poro = param.getDefault("porosity", 1.0);
|
||||
using namespace Opm::unit;
|
||||
using namespace Opm::prefix;
|
||||
double perm = param.getDefault("permeability", 100) * milli * darcy;
|
||||
rock_.init(dim, num_cells, poro, perm);
|
||||
pvt_.init(param);
|
||||
satprops_.init(param);
|
||||
if (pvt_.numPhases() != satprops_.numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "IncompPropsAdBasic::IncompPropsAdBasic() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
|
||||
}
|
||||
viscosity_.resize(pvt_.numPhases());
|
||||
pvt_.mu(1, 0, 0, &viscosity_[0]);
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
IncompPropsAdBasic::IncompPropsAdBasic(const int num_phases,
|
||||
const SaturationPropsBasic::RelPermFunc& relpermfunc,
|
||||
const std::vector<double>& rho,
|
||||
const std::vector<double>& mu,
|
||||
const double por, //porosity
|
||||
const double perm,
|
||||
const int dim,
|
||||
const int num_cells)
|
||||
{
|
||||
rock_.init(dim, num_cells, por, perm);
|
||||
pvt_.init(num_phases, rho, mu);
|
||||
satprops_.init(num_phases, relpermfunc);
|
||||
if (pvt_.numPhases() != satprops_.numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "IncompPropsAdBasic::IncompPropsAdBasic() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
|
||||
}
|
||||
viscosity_.resize(pvt_.numPhases());
|
||||
pvt_.mu(1, 0, 0, &viscosity_[0]);
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
IncompPropsAdBasic::~IncompPropsAdBasic()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int IncompPropsAdBasic::numDimensions() const
|
||||
{
|
||||
return rock_.numDimensions();
|
||||
}
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int IncompPropsAdBasic::numCells() const
|
||||
{
|
||||
return rock_.numCells();
|
||||
}
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* IncompPropsAdBasic::porosity() const
|
||||
{
|
||||
return rock_.porosity();
|
||||
}
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* IncompPropsAdBasic::permeability() const
|
||||
{
|
||||
return rock_.permeability();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return P, the number of phases (also the number of components).
|
||||
int IncompPropsAdBasic::numPhases() const
|
||||
{
|
||||
return pvt_.numPhases();
|
||||
}
|
||||
|
||||
/// \return Array of P viscosity values.
|
||||
const double* IncompPropsAdBasic::viscosity() const
|
||||
{
|
||||
return &viscosity_[0];
|
||||
}
|
||||
|
||||
/// Densities of fluid phases at reservoir conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* IncompPropsAdBasic::density() const
|
||||
{
|
||||
return pvt_.surfaceDensities();
|
||||
}
|
||||
|
||||
/// Densities of fluid phases at surface conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* IncompPropsAdBasic::surfaceDensity() const
|
||||
{
|
||||
return pvt_.surfaceDensities();
|
||||
}
|
||||
|
||||
typedef IncompPropsAdBasic::ADB ADB;
|
||||
typedef IncompPropsAdBasic::V V;
|
||||
typedef Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Block;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<V>
|
||||
IncompPropsAdBasic::relperm(const V& sw,
|
||||
const V& so,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
assert(sw.size() == n && so.size() == n);
|
||||
s_all.col(0) = sw;
|
||||
s_all.col(1) = so;
|
||||
Block kr(n, np);
|
||||
// satprops_.relperm(n, s_all.data(), cells.data(), kr.data(), 0);
|
||||
satprops_.relperm(n, s_all.data(), kr.data(), 0);
|
||||
|
||||
std::vector<V> relperms;
|
||||
relperms.reserve(2);
|
||||
for (int phase = 0; phase < 2; ++phase) {
|
||||
relperms.emplace_back(kr.col(phase));
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<ADB>
|
||||
IncompPropsAdBasic::relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
assert(sw.size() == n && so.size() == n);
|
||||
s_all.col(0) = sw.value();
|
||||
s_all.col(1) = so.value();
|
||||
Block kr(n, np);
|
||||
Block dkr(n, np*np);
|
||||
// satprops_.relperm(n, s_all.data(), cells.data(), kr.data(), dkr.data());
|
||||
satprops_.relperm(n, s_all.data(), kr.data(), dkr.data());
|
||||
const int num_blocks = so.numBlocks();
|
||||
std::vector<ADB> relperms;
|
||||
relperms.reserve(2);
|
||||
typedef const ADB* ADBPtr;
|
||||
ADBPtr s[2] = { &sw, &so };
|
||||
for (int phase1 = 0; phase1 < 2; ++phase1) {
|
||||
const int phase1_pos = phase1;
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = ADB::M(n, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < 2; ++phase2) {
|
||||
const int phase2_pos = phase2;
|
||||
// Assemble dkr1/ds2.
|
||||
const int column = phase1_pos + np*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dkr1_ds2_diag = spdiag(dkr.col(column));
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] += dkr1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
relperms.emplace_back(ADB::function(kr.col(phase1_pos), jacs));
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
} //namespace Opm
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL
|
||||
|
||||
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_INCOMPPROPSADBASIC_HEADER_INCLUDED
|
||||
#define OPM_INCOMPPROPSADBASIC_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
#include <opm/core/props/rock/RockBasic.hpp>
|
||||
#include <opm/core/props/pvt/PvtPropertiesBasic.hpp>
|
||||
#include <opm/core/props/satfunc/SaturationPropsBasic.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// This class implements the AD-adapted fluid interface for
|
||||
/// two-phase oil-water. It requires an input deck from which it
|
||||
/// reads all relevant property data.
|
||||
///
|
||||
/// Most methods are available in two overloaded versions, one
|
||||
/// taking a constant vector and returning the same, and one
|
||||
/// taking an AD type and returning the same. Derivatives are not
|
||||
/// returned separately by any method, only implicitly with the AD
|
||||
/// version of the methods.
|
||||
class IncompPropsAdBasic : public IncompPropsAdInterface
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
IncompPropsAdBasic(const parameter::ParameterGroup& param,
|
||||
const int dim,
|
||||
const int num_cells);
|
||||
|
||||
/// Constructor.
|
||||
IncompPropsAdBasic(const int num_phases,
|
||||
const SaturationPropsBasic::RelPermFunc& relpermfunc,
|
||||
const std::vector<double>& rho,
|
||||
const std::vector<double>& mu,
|
||||
const double porosity,
|
||||
const double permeability,
|
||||
const int dim,
|
||||
const int num_cells);
|
||||
/// Destructor.
|
||||
~IncompPropsAdBasic();
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int numDimensions() const;
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int numCells() const;
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* porosity() const;
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* permeability() const;
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
|
||||
/// \return P, Number of active phases (also the number of components).
|
||||
int numPhases() const;
|
||||
|
||||
/// \return Array of P viscosity values.
|
||||
const double* viscosity() const;
|
||||
|
||||
/// Densities of fluid phases at reservoir conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* density() const;
|
||||
|
||||
/// Densities of fluid phases at surface conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* surfaceDensity() const;
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<V> relperm(const V& sw,
|
||||
const V& so,
|
||||
const std::vector<int>& cells) const;
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<ADB> relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const std::vector<int>& cells) const;
|
||||
private:
|
||||
RockBasic rock_;
|
||||
PvtPropertiesBasic pvt_;
|
||||
SaturationPropsBasic satprops_;
|
||||
std::vector<double> viscosity_;
|
||||
};
|
||||
} //namespace Opm
|
||||
|
||||
#endif // OPM_INCOMPPROPSADBASIC_HEADER_INCLUDED
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdFromDeck.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// Constructor wrapping an opm-core two-phase interface.
|
||||
IncompPropsAdFromDeck::IncompPropsAdFromDeck(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid)
|
||||
{
|
||||
rock_.init(deck, grid);
|
||||
pvt_.init(deck);
|
||||
satprops_.init(deck, grid, 200);
|
||||
if (pvt_.numPhases() != satprops_.numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::BlackoilPropsAdFromDeck() - "
|
||||
"Inconsistent number of phases in pvt data (" << pvt_.numPhases()
|
||||
<< ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
|
||||
}
|
||||
}
|
||||
IncompPropsAdFromDeck::~IncompPropsAdFromDeck()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int IncompPropsAdFromDeck::numDimensions() const
|
||||
{
|
||||
return rock_.numDimensions();
|
||||
}
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int IncompPropsAdFromDeck::numCells() const
|
||||
{
|
||||
return rock_.numCells();
|
||||
}
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* IncompPropsAdFromDeck::porosity() const
|
||||
{
|
||||
return rock_.porosity();
|
||||
}
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* IncompPropsAdFromDeck::permeability() const
|
||||
{
|
||||
return rock_.permeability();
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return P, Number of active phases (also the number of components).
|
||||
int IncompPropsAdFromDeck::numPhases() const
|
||||
{
|
||||
return pvt_.numPhases();
|
||||
}
|
||||
|
||||
/// \return Array of P viscosity values.
|
||||
const double* IncompPropsAdFromDeck::viscosity() const
|
||||
{
|
||||
return pvt_.viscosity();
|
||||
}
|
||||
|
||||
///Densities of fluid phases at reservoir conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* IncompPropsAdFromDeck::density() const
|
||||
{
|
||||
return pvt_.reservoirDensities();
|
||||
}
|
||||
|
||||
/// Densities of fluid phases at surface conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* IncompPropsAdFromDeck::surfaceDensity() const
|
||||
{
|
||||
return pvt_.surfaceDensities();
|
||||
}
|
||||
|
||||
|
||||
typedef IncompPropsAdFromDeck::ADB ADB;
|
||||
typedef IncompPropsAdFromDeck::V V;
|
||||
typedef Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Block;
|
||||
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<V>
|
||||
IncompPropsAdFromDeck::relperm(const V& sw,
|
||||
const V& so,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
assert(sw.size() == n && so.size() == n);
|
||||
s_all.col(0) = sw;
|
||||
s_all.col(1) = so;
|
||||
Block kr(n, np);
|
||||
satprops_.relperm(n, s_all.data(), cells.data(), kr.data(), 0);
|
||||
std::vector<V> relperms;
|
||||
relperms.reserve(np);
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
relperms.emplace_back(kr.col(phase));
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<ADB>
|
||||
IncompPropsAdFromDeck::relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
assert(sw.size() == n && so.size() == n);
|
||||
s_all.col(0) = sw.value();
|
||||
s_all.col(1) = so.value();
|
||||
Block kr(n, np);
|
||||
Block dkr(n, np*np);
|
||||
satprops_.relperm(n, s_all.data(), cells.data(), kr.data(), dkr.data());
|
||||
const int num_blocks = so.numBlocks();
|
||||
std::vector<ADB> relperms;
|
||||
relperms.reserve(np);
|
||||
typedef const ADB* ADBPtr;
|
||||
ADBPtr s[2] = { &sw, &so };
|
||||
for (int phase1 = 0; phase1 < np; ++phase1) {
|
||||
const int phase1_pos = phase1;
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = ADB::M(n, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < np; ++phase2) {
|
||||
const int phase2_pos = phase2;
|
||||
// Assemble dkr1/ds2.
|
||||
const int column = phase1_pos + np*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dkr1_ds2_diag = spdiag(dkr.col(column));
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] += dkr1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
relperms.emplace_back(ADB::function(kr.col(phase1_pos), jacs));
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
/// Capillary pressure for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n capillary pressure values,
|
||||
/// containing the offsets for each p_o, p_w. The capillary pressure between
|
||||
/// two arbitrary phases alpha and beta is then given as p_alpha - p_beta.
|
||||
std::vector<ADB>
|
||||
IncompPropsAdFromDeck::capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int numCells = cells.size();
|
||||
const int numActivePhases = numPhases();
|
||||
const int numBlocks = so.numBlocks();
|
||||
assert(sw.value().size() == numCells);
|
||||
assert(so.value().size() == numCells);
|
||||
Block s_all(numCells, numActivePhases);
|
||||
s_all.col(0) = sw.value();
|
||||
s_all.col(1) = so.value();
|
||||
|
||||
Block pc(numCells, numActivePhases);
|
||||
Block dpc(numCells, numActivePhases*numActivePhases);
|
||||
satprops_.capPress(numCells, s_all.data(), cells.data(), pc.data(), dpc.data());
|
||||
|
||||
std::vector<ADB> adbCapPressures;
|
||||
adbCapPressures.reserve(2);
|
||||
const ADB* s[2] = { &sw, &so};
|
||||
for (int phase1 = 0; phase1 < 2; ++phase1) {
|
||||
const int phase1_pos = phase1;
|
||||
std::vector<ADB::M> jacs(numBlocks);
|
||||
for (int block = 0; block < numBlocks; ++block) {
|
||||
jacs[block] = ADB::M(numCells, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < 2; ++phase2) {
|
||||
const int phase2_pos = phase2;
|
||||
// Assemble dpc1/ds2.
|
||||
const int column = phase1_pos + numActivePhases*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dpc1_ds2_diag = spdiag(dpc.col(column));
|
||||
for (int block = 0; block < numBlocks; ++block) {
|
||||
jacs[block] += dpc1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
adbCapPressures.emplace_back(ADB::function(pc.col(phase1_pos), jacs));
|
||||
}
|
||||
return adbCapPressures;
|
||||
}
|
||||
|
||||
|
||||
} //namespace Opm
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL
|
||||
|
||||
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_INCOMPPROPSADFROMDECK_HEADER_INCLUDED
|
||||
#define OPM_INCOMPPROPSADFROMDECK_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/core/props/rock/RockFromDeck.hpp>
|
||||
#include <opm/core/props/pvt/PvtPropertiesIncompFromDeck.hpp>
|
||||
#include <opm/core/props/satfunc/SaturationPropsFromDeck.hpp>
|
||||
#include <opm/core/io/eclipse/EclipseGridParser.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
namespace Opm
|
||||
{
|
||||
/// This class implements the AD-adapted fluid interface for
|
||||
/// two-phase oil-water. It requires an input deck from which it
|
||||
/// reads all relevant property data.
|
||||
///
|
||||
/// Most methods are available in two overloaded versions, one
|
||||
/// taking a constant vector and returning the same, and one
|
||||
/// taking an AD type and returning the same. Derivatives are not
|
||||
/// returned separately by any method, only implicitly with the AD
|
||||
/// version of the methods.
|
||||
class IncompPropsAdFromDeck : public IncompPropsAdInterface
|
||||
{
|
||||
public:
|
||||
/// Constructor wrapping an opm-core two-phase interface.
|
||||
IncompPropsAdFromDeck(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid);
|
||||
|
||||
/// Destructor.
|
||||
~IncompPropsAdFromDeck();
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int numDimensions() const;
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int numCells() const;
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* porosity() const;
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* permeability() const;
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return P, Number of active phases (also the number of components).
|
||||
int numPhases() const;
|
||||
|
||||
/// \return Array of P viscosity values.
|
||||
const double* viscosity() const;
|
||||
|
||||
/// Densities of fluid phases at reservoir conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* density() const;
|
||||
|
||||
/// Densities of fluid phases at surface conditions.
|
||||
/// \return Array of P density values.
|
||||
const double* surfaceDensity() const;
|
||||
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<V> relperm(const V& sw,
|
||||
const V& so,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
std::vector<ADB> relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Capillary pressure for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n capillary pressure values,
|
||||
/// containing the offsets for each p_o, p_w. The capillary pressure between
|
||||
/// two arbitrary phases alpha and beta is then given as p_alpha - p_beta.
|
||||
std::vector<ADB> capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const Cells& cells) const;
|
||||
|
||||
private:
|
||||
RockFromDeck rock_;
|
||||
PvtPropertiesIncompFromDeck pvt_;
|
||||
SaturationPropsFromDeck<SatFuncStone2Uniform> satprops_;
|
||||
};
|
||||
|
||||
} //namespace Opm
|
||||
|
||||
#endif// OPM_INCOMPPROPSADFROMDECK_HEADER_INCLUDED
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
|
||||
Opm::IncompPropsAdInterface::~IncompPropsAdInterface()
|
||||
{
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
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_INCOMPPROPSADINTERFACE_HEADER_INCLUDED
|
||||
#define OPM_INCOMPPROPSADINTERFACE_HEADER_INCLUDED
|
||||
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
class IncompPropsAdInterface
|
||||
{
|
||||
public:
|
||||
/// Virtual destructor for inheritance.
|
||||
virtual ~IncompPropsAdInterface();
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
virtual int numDimensions() const = 0;
|
||||
|
||||
/// \return N, the number of cells.
|
||||
virtual int numCells() const = 0;
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
virtual const double* porosity() const = 0;
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
virtual const double* permeability() const = 0;
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef ADB::M M;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return P, Number of active phases (also the number of components).
|
||||
virtual int numPhases() const = 0;
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of P density values.
|
||||
virtual const double* surfaceDensity() const = 0;
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Viscosity of stock components at surface conditions.
|
||||
/// \return Array of P viscosity values.
|
||||
virtual const double* viscosity() const = 0;
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
virtual
|
||||
std::vector<V> relperm(const V& sw,
|
||||
const V& so,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n relperm values,
|
||||
/// containing krw, kro.
|
||||
virtual
|
||||
std::vector<ADB> relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
/// Capillary pressure for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 2 elements, each an array of n capillary pressure values,
|
||||
/// containing the offsets for each p_o, p_w. The capillary pressure between
|
||||
/// two arbitrary phases alpha and beta is then given as p_alpha - p_beta.
|
||||
virtual
|
||||
std::vector<ADB> capPress(const ADB& sw,
|
||||
const ADB& so,
|
||||
const Cells& cells) const = 0;
|
||||
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
#endif// OPM_INCOMPPROPSADINTERFACE_HEADER_INCLUDED
|
||||
@@ -1,15 +1,31 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef PolymerPropsAd::ADB ADB;
|
||||
typedef PolymerPropsAd::V V;
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/polymer/PolymerProperties.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_WELLSTATE_HEADER_INCLUDED
|
||||
#define OPM_WELLSTATE_HEADER_INCLUDED
|
||||
|
||||
#include <opm/core/wells.h>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// The state of a set of wells.
|
||||
class WellState
|
||||
{
|
||||
public:
|
||||
/// Allocate and initialize if wells is non-null.
|
||||
/// Also tries to give useful initial values to the bhp() and
|
||||
/// wellRates() fields, depending on controls. The
|
||||
/// perfRates() field is filled with zero, and perfPress()
|
||||
/// with -1e100.
|
||||
template <class State>
|
||||
void init(const Wells* wells, const State& state)
|
||||
{
|
||||
if (wells) {
|
||||
const int nw = wells->number_of_wells;
|
||||
const int np = wells->number_of_phases + 1;
|
||||
bhp_.resize(nw);
|
||||
wellrates_.resize(nw * np, 0.0);
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const WellControls* ctrl = wells->ctrls[w];
|
||||
// Initialize bhp to be target pressure if
|
||||
// bhp-controlled well, otherwise set to a little
|
||||
// above or below (depending on if the well is an
|
||||
// injector or producer) pressure in first perforation
|
||||
// cell.
|
||||
if ((ctrl->current < 0) || // SHUT
|
||||
(ctrl->type[ctrl->current] != BHP)) {
|
||||
const int first_cell = wells->well_cells[wells->well_connpos[w]];
|
||||
const double safety_factor = (wells->type[w] == INJECTOR) ? 1.01 : 0.99;
|
||||
bhp_[w] = safety_factor*state.pressure()[first_cell];
|
||||
} else {
|
||||
bhp_[w] = ctrl->target[ctrl->current];
|
||||
}
|
||||
// Initialize well rates to match controls if type is SURFACE_RATE
|
||||
if ((ctrl->current >= 0) && // open well
|
||||
(ctrl->type[ctrl->current] == SURFACE_RATE)) {
|
||||
const double rate_target = ctrl->target[ctrl->current];
|
||||
for (int p = 0; p < np; ++p) {
|
||||
const double phase_distr = ctrl->distr[np * ctrl->current + p];
|
||||
wellrates_[np*w + p] = rate_target * phase_distr;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The perforation rates and perforation pressures are
|
||||
// not expected to be consistent with bhp_ and wellrates_
|
||||
// after init().
|
||||
perfrates_.resize(wells->well_connpos[nw], 0.0);
|
||||
perfpress_.resize(wells->well_connpos[nw], -1e100);
|
||||
}
|
||||
}
|
||||
|
||||
/// One bhp pressure per well.
|
||||
std::vector<double>& bhp() { return bhp_; }
|
||||
const std::vector<double>& bhp() const { return bhp_; }
|
||||
|
||||
/// One rate per well and phase.
|
||||
std::vector<double>& wellRates() { return wellrates_; }
|
||||
const std::vector<double>& wellRates() const { return wellrates_; }
|
||||
|
||||
/// One rate per well connection.
|
||||
std::vector<double>& perfRates() { return perfrates_; }
|
||||
const std::vector<double>& perfRates() const { return perfrates_; }
|
||||
|
||||
/// One pressure per well connection.
|
||||
std::vector<double>& perfPress() { return perfpress_; }
|
||||
const std::vector<double>& perfPress() const { return perfpress_; }
|
||||
|
||||
private:
|
||||
std::vector<double> bhp_;
|
||||
std::vector<double> wellrates_;
|
||||
std::vector<double> perfrates_;
|
||||
std::vector<double> perfpress_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_WELLSTATE_HEADER_INCLUDED
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
@@ -26,9 +27,9 @@
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <opm/polymer/fullyimplicit/GeoProps.hpp>
|
||||
#include <opm/autodiff/GeoProps.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/FullyImplicitCompressiblePolymerSolver.hpp>
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/utilities.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/wells.h>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
@@ -22,7 +23,7 @@
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <opm/polymer/fullyimplicit/FullyImplicitTwophasePolymerSolver.hpp>
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/IncompPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
||||
#include <opm/polymer/fullyimplicit/utilities.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
@@ -22,16 +22,16 @@
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/linalg/blas_lapack.h>
|
||||
#include <opm/core/props/BlackoilPropertiesInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/IncompPropsAdInterface.hpp>
|
||||
#include <opm/polymer/PolymerBlackoilState.hpp>
|
||||
#include <opm/polymer/PolymerState.hpp>
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffBlock.hpp>
|
||||
#include <opm/polymer/fullyimplicit/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/polymer/fullyimplicit/PolymerPropsAd.hpp>
|
||||
#include <opm/polymer/fullyimplicit/utilities.hpp>
|
||||
#include <algorithm>
|
||||
@@ -45,13 +45,13 @@
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef ADB::M M;
|
||||
typedef Eigen::Array<double,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
Eigen::RowMajor> DataBlock;
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef ADB::M M;
|
||||
typedef Eigen::Array<double,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
Eigen::RowMajor> DataBlock;
|
||||
/// Compute two-phase transport source terms from well terms.
|
||||
/// Note: Unlike the incompressible version of this function,
|
||||
/// this version computes surface volume injection rates,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2014 STATOIL
|
||||
Copyright 2014 STATOIL.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/props/BlackoilPropertiesInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/polymer/fullyimplicit/IncompPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/IncompPropsAdInterface.hpp>
|
||||
#include <opm/polymer/PolymerBlackoilState.hpp>
|
||||
#include <opm/polymer/PolymerState.hpp>
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
@@ -46,13 +46,13 @@
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef ADB::M M;
|
||||
typedef Eigen::Array<double,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
Eigen::RowMajor> DataBlock;
|
||||
typedef AutoDiffBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef ADB::M M;
|
||||
typedef Eigen::Array<double,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
Eigen::RowMajor> DataBlock;
|
||||
/// Compute two-phase transport source terms from well terms.
|
||||
/// Note: Unlike the incompressible version of this function,
|
||||
/// this version computes surface volume injection rates,
|
||||
@@ -97,7 +97,6 @@ namespace Opm
|
||||
double& polyinj,
|
||||
double& polyprod);
|
||||
|
||||
|
||||
/// @brief Computes injected and produced volumes of all phases,
|
||||
/// and injected and produced polymer mass - in the compressible case.
|
||||
/// Note 1: assumes that only the first phase is injected.
|
||||
|
||||
Reference in New Issue
Block a user