Remove opm/autodiff/ files, fix header files.

This commit is contained in:
Liu Ming
2014-03-14 14:12:26 +08:00
parent 010676ad30
commit 84fab85860
28 changed files with 70 additions and 4652 deletions

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()
{
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()
{
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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).

View File

@@ -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,

View File

@@ -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.