Files
opm-upscaling/opm/porsol/mimetic/MimeticIPAnisoRelpermEvaluator.hpp
T
Arne Morten Kvarving 41bcc182bb mark constructors explicit
quells static analyzer warnings
2024-08-16 14:18:24 +02:00

432 lines
17 KiB
C++

//===========================================================================
//
// File: MimeticIPAnisoRelpermEvaluator.hpp
//
// Created: Mon Oct 19 10:22:22 2009
//
// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
// Brd Skaflestad <bard.skaflestad@sintef.no>
//
// $Date$
//
// $Revision$
//
//===========================================================================
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 Statoil ASA.
This file is part of The Open Reservoir Simulator Project (OpenRS).
OpenRS 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.
OpenRS 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 OpenRS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPENRS_MIMETICIPANISORELPERMEVALUATOR_HEADER
#define OPENRS_MIMETICIPANISORELPERMEVALUATOR_HEADER
#include <algorithm>
#include <vector>
#include <opm/common/ErrorMacros.hpp>
#include <opm/grid/utility/SparseTable.hpp>
#include <opm/porsol/common/fortran.hpp>
#include <opm/porsol/common/blas_lapack.hpp>
#include <opm/porsol/common/Matrix.hpp>
namespace Opm {
/// @class MimeticIPAnisoRelpermEvaluator<CellIter,dim,computeInverseIP>
///
/// @brief
/// Defines a class template for computing a matrix
/// representation of the permeability-dependent inner product
/// @f$b(v,w) = (v, K^{-1}\,w)@f$ of the velocity vectors
/// @f$v@f$ and @f$w@f$. The matrix entries are defined
/// through the mimetic finite difference method of Brezzi
/// et. al.
///
/// @tparam GridInterface
/// Grid interface class expected to expose members such as
/// a @code CellIterator @endcode type with @code operator->()
/// @endcode exposing centroid, volume, and intersections.
///
/// @tparam RockInterface
/// Rock interface class expected to expose a @code
/// permeability() @endcode member.
///
/// @tparam computeInverseIP
/// NOTE: This template parameter no longer exists, but the
/// concept warrants enough attention to keep the doc.
/// Whether or not to compute the @em inverse of the mimetic
/// inner product matrix. Specifically, if @f$B@f$ is the
/// matrix representation of the mimetic inner product, then
/// setting @code computeInverseIP = true; @endcode means that
/// the @code evaluate() @endcode method computes @f$B^{-1}@f$
/// rather than @f$B@f$ itself. This parameter is a concession
/// to hybrid discretization methods based on Schur complement
/// reduction which only need access to @f$B^{-1}@f$. In the
/// mimetic case there is an explicit formula for said inverse.
template<class GridInterface, class RockInterface>
class MimeticIPAnisoRelpermEvaluator
{
public:
/// @brief
/// The number of space dimensions.
enum { dim = GridInterface::Dimension };
/// @brief
/// The iterator type for iterating over grid cells.
typedef typename GridInterface::CellIterator CellIter;
/// @brief
/// The element type of the matrix representation of the
/// mimetic inner product. Assumed to be a floating point
/// type, and usually, @code Scalar @endcode is an alias
/// for @code double @endcode.
typedef typename CellIter::Scalar Scalar;
/// @brief Default constructor.
MimeticIPAnisoRelpermEvaluator()
: max_nf_(-1),
prock_(0)
{}
/// @brief Constructor.
///
/// @param [in] max_nf
/// Maximum number of faces/connections of any single cell
/// in the model. Used to set the size of certain internal
/// working std::arrays. A cell with @f$n_f@f$ faces results in
/// an inner product matrix of size @f$n_f \times n_f@f$.
explicit MimeticIPAnisoRelpermEvaluator(const int max_nf)
: max_nf_ (max_nf ),
fa_ (max_nf * max_nf),
t1_ (max_nf * dim ),
t2_ (max_nf * dim ),
second_term_ ( ),
n_ ( ),
Kg_ ( ),
prock_ ( 0 )
{}
/// @brief Initialization routine.
///
/// @param [in] max_nf
/// Maximum number of faces/connections of any single cell
/// in the model. Used to set the size of certain internal
/// working std::arrays. A cell with @f$n_f@f$ faces results in
/// an inner product matrix of size @f$n_f \times n_f@f$.
void init(const int max_nf)
{
max_nf_ = max_nf;
std::vector<double>(max_nf * max_nf).swap(fa_);
std::vector<double>(max_nf * dim ).swap(t1_);
std::vector<double>(max_nf * dim ).swap(t2_);
}
/// @brief
/// Reserve internal space for storing values of (static)
/// IP contributions for given set of cells.
///
/// @tparam Vector
/// Vector type, often @code std::vector<int> @endcode,
/// representing a set of sizes.
///
/// @param [in] sz
/// Set of sizes. Assumed to contain @f$n@f$ positive
/// values, each representing the number of faces of a
/// specific cell. In other words @code sz[i] @endcode is
/// the number of faces of cell @code i @endcode.
template<class Vector>
void reserveMatrices(const Vector& sz)
{
typedef typename Vector::value_type vt;
Vector sz2(sz.size());
std::transform(sz.begin(), sz.end(), sz2.begin(),
[](const vt& input) { return input*input; });
second_term_.allocate(sz2.begin(), sz2.end());
int idim = int(dim);
std::transform(sz.begin(), sz.end(), sz2.begin(),
[idim](const vt& input) { return input*idim; });
n_.allocate(sz2.begin(), sz2.end());
std::fill(sz2.begin(), sz2.end(), vt(dim));
Kg_.allocate(sz2.begin(), sz2.end());
}
/// @brief
/// Main evaluation routine. Computes the inverse of the
/// matrix representation of the mimetic inner product in a
/// single cell with kown permeability @f$K@f$. Adds a
/// regularization term in order to guarantee a positive
/// definite matrix.
///
/// @tparam RockInterface
/// Type representing rock properties. Assumed to
/// expose a method @code permeability(i) @endcode which
/// retrieves the static permeability tensor of cell @code
/// i @endcode. The permeability tensor, @$K@$, is in
/// turn, assumed to expose a method @code operator()(int
/// i, int j) @endcode such that the call @code K(i,j)
/// @endcode retrieves the @f$ij@f$'th component of the
/// cell permeability @f$K@f$.
///
/// @param [in] c
/// Cell for which to evaluate the inverse of the mimetic
/// inner product.
///
/// @param [in] r
/// Specific reservoir properties. Only the permeability
/// is used in method @code buildMatrix() @endcode.
///
/// @param [in] nf
/// Number of faces (i.e., number of neighbours) of cell
/// @code *c @endcode.
void buildStaticContrib(const CellIter& c,
const RockInterface& r,
const typename CellIter::Vector& grav,
const int nf)
{
// Binv = (N*lambda*K*N' + t*diag(A)*(I - Q*Q')*diag(A))/vol
// ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
// precompute: n_ precompute: second_term_
// t = 6/dim * trace(lambda*K)
typedef typename CellIter::FaceIterator FI;
typedef typename CellIter::Vector CV;
typedef typename FI ::Vector FV;
// Now we need to remember the rocks, since we will need
// the permeability for dynamic assembly.
prock_ = &r;
const int ci = c->index();
static_assert (FV::dimension == int(dim), "");
assert (int(t1_.size()) >= nf * dim);
assert (int(t2_.size()) >= nf * dim);
assert (int(fa_.size()) >= nf * nf);
SharedFortranMatrix T2 (nf, dim, &t2_ [0]);
SharedFortranMatrix fa (nf, nf , &fa_ [0]);
SharedFortranMatrix second_term(nf, nf, &second_term_[ci][0]);
SharedFortranMatrix n(nf, dim, &n_[ci][0]);
// Clear matrices of any residual data.
zero(second_term); zero(n); zero(T2); zero(fa);
// Setup: second_term <- I, n <- N, T2 <- C
const CV cc = c->centroid();
int i = 0;
for (FI f = c->facebegin(); f != c->faceend(); ++f, ++i) {
second_term(i,i) = Scalar(1.0);
fa(i,i) = f->area();
FV fc = f->centroid(); fc -= cc; fc *= fa(i,i);
FV fn = f->normal (); fn *= fa(i,i);
for (int j = 0; j < dim; ++j) {
n (i,j) = fn[j];
T2(i,j) = fc[j];
}
}
assert (i == nf);
// T2 <- orth(T2)
if (orthogonalizeColumns(T2) != 0) {
assert (false);
}
// second_term <- second_term - T2*T2' == I - Q*Q'
symmetricUpdate(Scalar(-1.0), T2, Scalar(1.0), second_term);
// second_term <- diag(A) * second_term * diag(A)
symmetricUpdate(fa, second_term);
// Gravity term: Kg_ = K * grav
vecMulAdd_N(Scalar(1.0), r.permeability(ci), &grav[0],
Scalar(0.0), &Kg_[ci][0]);
}
/// @brief
/// Evaluate dynamic (saturation dependent) properties in
/// single cell.
///
/// @tparam FluidInterface
/// Type representing fluid properties. Assumed to
/// expose methods @code phaseDensities() @endcode and @code
/// phaseMobilities() @endcode for retrieving the phase
/// densities and (tensorial, anisotropic) phase mobilities,
/// respectively.
///
/// @tparam Sat
/// Type representing single-cell saturation values.
/// Typically, @code Sat @endcode is an alias for @code
/// double @endcode.
///
/// @param [in] c
/// Cell for which to evaluate the dynamic properties.
///
/// @param [in] fl
/// Specific reservoir properties.
///
/// @param [in] s
/// Vector of current fluid saturations.
template<class FluidInterface, class Sat>
void computeDynamicParams(const CellIter& c,
const FluidInterface& fl,
const std::vector<Sat>& s)
{
const int ci = c->index();
std::array<Scalar, dim * dim> lambda_t;
std::array<Scalar, dim * dim> pmob_data;
SharedFortranMatrix pmob(dim, dim, &pmob_data[0]);
SharedFortranMatrix Kg (dim, 1 , &Kg_[ci][0]);
std::array<Scalar, FluidInterface::NumberOfPhases> rho;
fl.phaseDensities(ci, rho);
std::fill(dyn_Kg_.begin(), dyn_Kg_.end(), Scalar(0.0));
std::fill(lambda_t.begin(), lambda_t.end(), 0.0);
for (int phase = 0; phase < FluidInterface::NumberOfPhases; ++phase) {
fl.phaseMobility(phase, ci, s[ci], pmob);
// dyn_Kg_ += (\rho_phase \lambda_phase) Kg
vecMulAdd_N(rho[phase], pmob, Kg.data(), Scalar(1.0), dyn_Kg_.data());
// \lambda_t += \lambda_phase
std::transform(lambda_t.begin(), lambda_t.end(), pmob_data.begin(),
lambda_t.begin(),
std::plus<Scalar>());
}
// lambdaK_ = (\sum_i \lambda_i) K
SharedFortranMatrix lambdaT(dim, dim, lambda_t.data());
SharedFortranMatrix lambdaK(dim, dim, lambdaK_.data());
prod(lambdaT, prock_->permeability(ci), lambdaK);
}
/// @brief
/// Retrieve the dynamic (mobility updated) inverse mimetic
/// inner product matrix for specific cell.
///
/// @tparam SP
/// Type representing the @code FullMatrix<T,SP,OP>
/// @endcode storage policy of the matrix into which the
/// inverse inner product matrix entries will be stored.
///
/// @param [in] c
/// Cell for which to evaluate the dynamic inverse mimetic
/// inner product.
///
/// @param [in] r
/// Specific reservoir properties. Only the phase
/// mobilities is used in method @code getInverseMatrix()
/// @endcode.
///
/// @param [in] s
/// Fluid saturations.
///
/// @param [out] Binv
/// Inverse of matrix representation of the mimetic inner
/// product for cell @code *c @endcode. A square, full
/// matrix with the number of rows equal to the number of
/// faces in cell @code *c @endcode.
template<template<typename> class SP>
void getInverseMatrix(const CellIter& c,
FullMatrix<Scalar,SP,FortranOrdering>& Binv) const
{
// Binv = (N*lambda*K*N' + t*diag(A)*(I - Q*Q')*diag(A))/vol
// ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
// precomputed: n_ precomputed: second_term_
// t = 6/dim * trace(lambda*K)
int ci = c->index();
int nf = Binv.numRows();
ImmutableFortranMatrix n(nf, dim, &n_[ci][0]);
ImmutableFortranMatrix t2(nf, nf, &second_term_[ci][0]);
Binv = t2;
ImmutableFortranMatrix lambdaK(dim, dim, lambdaK_.data());
SharedFortranMatrix T2(nf, dim, &t2_[0]);
// T2 <- N*lambda*K
matMulAdd_NN(Scalar(1.0), n, lambdaK, Scalar(0.0), T2);
// Binv <- (T2*N' + t*Binv) / vol(c)
// == (N*lambda*K*N' + t*(diag(A) * (I - Q*Q') * diag(A))) / vol(c)
//
// where t = 6/d * TRACE(lambda*K) (== 2*TRACE(lambda*K) for 3D).
//
Scalar t = Scalar(6.0) * trace(lambdaK) / dim;
matMulAdd_NT(Scalar(1.0) / c->volume(), T2, n,
t / c->volume(), Binv );
}
/// @brief Compute gravity flux for all faces of single cell.
///
/// @tparam Vector
/// Type representing a vector (or a linear std::array) for
/// which (a constant time) @code operator[] @endcode is
/// defined.
///
/// @param [in] c
/// Cell for which to evaluate the gravity flux.
///
/// @param [out] gflux
/// Gravity fluxes on all faces/intersections of cell c in
/// the order of the face iterator of the cell.
template<class Vector>
void gravityFlux(const CellIter& c,
Vector& gflux) const
{
const int ci = c->index();
const int nf = n_.rowSize(ci) / dim;
ImmutableFortranMatrix N(nf, dim, &n_[ci][0]);
// gflux = N (\sum_i \rho_i \lambda_i) Kg
vecMulAdd_N(Scalar(1.0), N, &dyn_Kg_[0],
Scalar(0.0), &gflux[0]);
}
private:
int max_nf_ ;
mutable std::vector<Scalar> fa_, t1_, t2_;
Opm::SparseTable<Scalar> second_term_ ;
Opm::SparseTable<Scalar> n_ ;
Opm::SparseTable<Scalar> Kg_ ;
std::array<Scalar, dim> dyn_Kg_ ;
std::array<double, dim*dim> lambdaK_ ;
const RockInterface* prock_ ;
};
} // namespace Opm
#endif // OPENRS_MIMETICIPANISORELPERMEVALUATOR_HEADER