make the constraint solvers usable with local-AD
This commit is contained in:
parent
8aaf2bfdab
commit
662531fee8
@ -24,6 +24,8 @@
|
||||
#ifndef OPM_COMPOSITION_FROM_FUGACITIES_HPP
|
||||
#define OPM_COMPOSITION_FROM_FUGACITIES_HPP
|
||||
|
||||
#include <opm/material/common/MathToolbox.hpp>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/fmatrix.hh>
|
||||
|
||||
@ -39,7 +41,7 @@ namespace Opm {
|
||||
* \brief Calculates the chemical equilibrium from the component
|
||||
* fugacities in a phase.
|
||||
*/
|
||||
template <class Scalar, class FluidSystem>
|
||||
template <class Scalar, class FluidSystem, class Evaluation = Scalar>
|
||||
class CompositionFromFugacities
|
||||
{
|
||||
enum { numComponents = FluidSystem::numComponents };
|
||||
@ -47,7 +49,7 @@ class CompositionFromFugacities
|
||||
typedef typename FluidSystem::ParameterCache ParameterCache;
|
||||
|
||||
public:
|
||||
typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
|
||||
typedef Dune::FieldVector<Evaluation, numComponents> ComponentVector;
|
||||
|
||||
/*!
|
||||
* \brief Guess an initial value for the composition of the phase.
|
||||
@ -65,8 +67,8 @@ public:
|
||||
for (int i = 0; i < numComponents; ++ i) {
|
||||
//std::cout << f << " -> " << mutParams.fugacity(phaseIdx, i)/f << "\n";
|
||||
fluidState.setMoleFraction(phaseIdx,
|
||||
i,
|
||||
1.0/numComponents);
|
||||
i,
|
||||
1.0/numComponents);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +84,8 @@ public:
|
||||
int phaseIdx,
|
||||
const ComponentVector &targetFug)
|
||||
{
|
||||
typedef MathToolbox<Evaluation> Toolbox;
|
||||
|
||||
// use a much more efficient method in case the phase is an
|
||||
// ideal mixture
|
||||
if (FluidSystem::isIdealMixture(phaseIdx)) {
|
||||
@ -89,10 +93,10 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
Dune::FMatrixPrecision<Scalar>::set_singular_limit(1e-25);
|
||||
//Dune::FMatrixPrecision<Scalar>::set_singular_limit(1e-25);
|
||||
|
||||
// save initial composition in case something goes wrong
|
||||
Dune::FieldVector<Scalar, numComponents> xInit;
|
||||
Dune::FieldVector<Evaluation, numComponents> xInit;
|
||||
for (int i = 0; i < numComponents; ++i) {
|
||||
xInit[i] = fluidState.moleFraction(phaseIdx, i);
|
||||
}
|
||||
@ -102,11 +106,11 @@ public:
|
||||
/////////////////////////
|
||||
|
||||
// Jacobian matrix
|
||||
Dune::FieldMatrix<Scalar, numComponents, numComponents> J;
|
||||
Dune::FieldMatrix<Evaluation, numComponents, numComponents> J;
|
||||
// solution, i.e. phase composition
|
||||
Dune::FieldVector<Scalar, numComponents> x;
|
||||
Dune::FieldVector<Evaluation, numComponents> x;
|
||||
// right hand side
|
||||
Dune::FieldVector<Scalar, numComponents> b;
|
||||
Dune::FieldVector<Evaluation, numComponents> b;
|
||||
|
||||
paramCache.updatePhase(fluidState, phaseIdx);
|
||||
|
||||
@ -130,7 +134,7 @@ public:
|
||||
*/
|
||||
|
||||
// Solve J*x = b
|
||||
x = 0;
|
||||
x = Toolbox::createConstant(0.0);
|
||||
try { J.solve(x, b); }
|
||||
catch (Dune::FMatrixError e)
|
||||
{ throw Opm::NumericalIssue(e.what()); }
|
||||
@ -159,7 +163,7 @@ public:
|
||||
Scalar relError = update_(fluidState, paramCache, x, b, phaseIdx, targetFug);
|
||||
|
||||
if (relError < 1e-9) {
|
||||
Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
const Evaluation& rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setDensity(phaseIdx, rho);
|
||||
|
||||
//std::cout << "num iterations: " << nIdx << "\n";
|
||||
@ -187,11 +191,11 @@ protected:
|
||||
const ComponentVector &fugacities)
|
||||
{
|
||||
for (int i = 0; i < numComponents; ++ i) {
|
||||
Scalar phi = FluidSystem::fugacityCoefficient(fluidState,
|
||||
paramCache,
|
||||
phaseIdx,
|
||||
i);
|
||||
Scalar gamma = phi * fluidState.pressure(phaseIdx);
|
||||
const Evaluation& phi = FluidSystem::fugacityCoefficient(fluidState,
|
||||
paramCache,
|
||||
phaseIdx,
|
||||
i);
|
||||
const Evaluation& gamma = phi * fluidState.pressure(phaseIdx);
|
||||
Valgrind::CheckDefined(phi);
|
||||
Valgrind::CheckDefined(gamma);
|
||||
Valgrind::CheckDefined(fugacities[i]);
|
||||
@ -201,19 +205,21 @@ protected:
|
||||
|
||||
paramCache.updatePhase(fluidState, phaseIdx);
|
||||
|
||||
Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
const Evaluation& rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setDensity(phaseIdx, rho);
|
||||
return;
|
||||
}
|
||||
|
||||
template <class FluidState>
|
||||
static Scalar linearize_(Dune::FieldMatrix<Scalar, numComponents, numComponents> &J,
|
||||
Dune::FieldVector<Scalar, numComponents> &defect,
|
||||
static Scalar linearize_(Dune::FieldMatrix<Evaluation, numComponents, numComponents> &J,
|
||||
Dune::FieldVector<Evaluation, numComponents> &defect,
|
||||
FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
int phaseIdx,
|
||||
const ComponentVector &targetFug)
|
||||
{
|
||||
typedef MathToolbox<Evaluation> Toolbox;
|
||||
|
||||
// reset jacobian
|
||||
J = 0;
|
||||
|
||||
@ -221,15 +227,15 @@ protected:
|
||||
// calculate the defect (deviation of the current fugacities
|
||||
// from the target fugacities)
|
||||
for (int i = 0; i < numComponents; ++ i) {
|
||||
Scalar phi = FluidSystem::fugacityCoefficient(fluidState,
|
||||
const Evaluation& phi = FluidSystem::fugacityCoefficient(fluidState,
|
||||
paramCache,
|
||||
phaseIdx,
|
||||
i);
|
||||
Scalar f = phi*fluidState.pressure(phaseIdx)*fluidState.moleFraction(phaseIdx, i);
|
||||
const Evaluation& f = phi*fluidState.pressure(phaseIdx)*fluidState.moleFraction(phaseIdx, i);
|
||||
fluidState.setFugacityCoefficient(phaseIdx, i, phi);
|
||||
|
||||
defect[i] = targetFug[i] - f;
|
||||
absError = std::max(absError, std::abs(defect[i]));
|
||||
absError = std::max(absError, std::abs(Toolbox::value(defect[i])));
|
||||
}
|
||||
|
||||
// assemble jacobian matrix of the constraints for the composition
|
||||
@ -242,7 +248,7 @@ protected:
|
||||
// forward differences
|
||||
|
||||
// deviate the mole fraction of the i-th component
|
||||
Scalar xI = fluidState.moleFraction(phaseIdx, i);
|
||||
Evaluation xI = fluidState.moleFraction(phaseIdx, i);
|
||||
fluidState.setMoleFraction(phaseIdx, i, xI + eps);
|
||||
paramCache.updateSingleMoleFraction(fluidState, phaseIdx, i);
|
||||
|
||||
@ -250,17 +256,17 @@ protected:
|
||||
// fugacities
|
||||
for (int j = 0; j < numComponents; ++j) {
|
||||
// compute the j-th component's fugacity coefficient ...
|
||||
Scalar phi = FluidSystem::fugacityCoefficient(fluidState,
|
||||
paramCache,
|
||||
phaseIdx,
|
||||
j);
|
||||
const Evaluation& phi = FluidSystem::fugacityCoefficient(fluidState,
|
||||
paramCache,
|
||||
phaseIdx,
|
||||
j);
|
||||
// ... and its fugacity ...
|
||||
Scalar f =
|
||||
const Evaluation& f =
|
||||
phi *
|
||||
fluidState.pressure(phaseIdx) *
|
||||
fluidState.moleFraction(phaseIdx, j);
|
||||
// as well as the defect for this fugacity
|
||||
Scalar defJPlusEps = targetFug[j] - f;
|
||||
const Evaluation& defJPlusEps = targetFug[j] - f;
|
||||
|
||||
// use forward differences to calculate the defect's
|
||||
// derivative
|
||||
@ -281,86 +287,48 @@ protected:
|
||||
template <class FluidState>
|
||||
static Scalar update_(FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
Dune::FieldVector<Scalar, numComponents> &x,
|
||||
Dune::FieldVector<Scalar, numComponents> &b,
|
||||
Dune::FieldVector<Evaluation, numComponents> &x,
|
||||
Dune::FieldVector<Evaluation, numComponents> &b,
|
||||
int phaseIdx,
|
||||
const Dune::FieldVector<Scalar, numComponents> &targetFug)
|
||||
const Dune::FieldVector<Evaluation, numComponents> &targetFug)
|
||||
{
|
||||
typedef MathToolbox<Evaluation> Toolbox;
|
||||
|
||||
// store original composition and calculate relative error
|
||||
Dune::FieldVector<Scalar, numComponents> origComp;
|
||||
Dune::FieldVector<Evaluation, numComponents> origComp;
|
||||
Scalar relError = 0;
|
||||
Scalar sumDelta = 0;
|
||||
Scalar sumx = 0;
|
||||
Evaluation sumDelta = Toolbox::createConstant(0.0);
|
||||
Evaluation sumx = Toolbox::createConstant(0.0);
|
||||
for (int i = 0; i < numComponents; ++i) {
|
||||
origComp[i] = fluidState.moleFraction(phaseIdx, i);
|
||||
relError = std::max(relError, std::abs(x[i]));
|
||||
relError = std::max(relError, std::abs(Toolbox::value(x[i])));
|
||||
|
||||
sumx += std::abs(fluidState.moleFraction(phaseIdx, i));
|
||||
sumDelta += std::abs(x[i]);
|
||||
sumx += Toolbox::abs(fluidState.moleFraction(phaseIdx, i));
|
||||
sumDelta += Toolbox::abs(x[i]);
|
||||
}
|
||||
|
||||
#if 1
|
||||
// chop update to at most 20% change in composition
|
||||
const Scalar maxDelta = 0.2;
|
||||
if (sumDelta > maxDelta)
|
||||
x /= (sumDelta/maxDelta);
|
||||
#endif
|
||||
|
||||
//Scalar curDefect = calculateDefect_(fluidState, phaseIdx, targetFug);
|
||||
//Scalar nextDefect;
|
||||
//Scalar sumMoleFrac = 0.0;
|
||||
//ComponentVector newB(1e100);
|
||||
//for (int numTries = 0; numTries < 1; ++numTries) {
|
||||
// change composition
|
||||
for (int i = 0; i < numComponents; ++i) {
|
||||
Scalar newx = origComp[i] - x[i];
|
||||
#if 1
|
||||
// only allow negative mole fractions if the target fugacity is negative
|
||||
if (targetFug[i] > 0)
|
||||
newx = std::max(0.0, newx);
|
||||
// only allow positive mole fractions if the target fugacity is positive
|
||||
else if (targetFug[i] < 0)
|
||||
newx = std::min(0.0, newx);
|
||||
// if the target fugacity is zero, the mole fraction must also be zero
|
||||
else
|
||||
newx = 0;
|
||||
#endif
|
||||
fluidState.setMoleFraction(phaseIdx, i, newx);
|
||||
//sumMoleFrac += std::abs(newx);
|
||||
}
|
||||
// change composition
|
||||
for (int i = 0; i < numComponents; ++i) {
|
||||
Evaluation newx = origComp[i] - x[i];
|
||||
// only allow negative mole fractions if the target fugacity is negative
|
||||
if (targetFug[i] > 0)
|
||||
newx = Toolbox::max(0.0, newx);
|
||||
// only allow positive mole fractions if the target fugacity is positive
|
||||
else if (targetFug[i] < 0)
|
||||
newx = Toolbox::min(0.0, newx);
|
||||
// if the target fugacity is zero, the mole fraction must also be zero
|
||||
else
|
||||
newx = 0;
|
||||
|
||||
paramCache.updateComposition(fluidState, phaseIdx);
|
||||
|
||||
/*
|
||||
// if the sum of the mole fractions gets 0, we take the
|
||||
// original composition divided by 100
|
||||
if (sumMoleFrac < 1e-10) {
|
||||
for (int i = 0; i < numComponents; ++i) {
|
||||
fluidState.setMoleFraction(phaseIdx, i, origComp[i]/100);
|
||||
}
|
||||
return relError;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// calculate new residual
|
||||
for (int i = 0; i < numComponents; ++i) {
|
||||
Scalar phi = FluidSystem::computeFugacityCoeff(fluidState,
|
||||
phaseIdx,
|
||||
i);
|
||||
fluidState.setFugacityCoeff(phaseIdx, i, phi);
|
||||
}
|
||||
|
||||
nextDefect = calculateDefect_(fluidState, phaseIdx, targetFug);
|
||||
//std::cout << "try delta: " << x << "\n";
|
||||
//std::cout << "defect: old=" << curDefect << " new=" << nextDefect << "\n";
|
||||
if (nextDefect <= curDefect)
|
||||
break;
|
||||
|
||||
// divide delta vector
|
||||
x /= 2;
|
||||
fluidState.setMoleFraction(phaseIdx, i, newx);
|
||||
}
|
||||
*/
|
||||
|
||||
paramCache.updateComposition(fluidState, phaseIdx);
|
||||
|
||||
return relError;
|
||||
}
|
||||
|
@ -58,13 +58,13 @@ namespace Opm {
|
||||
* - if the setViscosity parameter is true, also dynamic viscosities of *all* phases
|
||||
* - if the setEnthalpy parameter is true, also specific enthalpies and internal energies of *all* phases
|
||||
*/
|
||||
template <class Scalar, class FluidSystem>
|
||||
template <class Scalar, class FluidSystem, class Evaluation = Scalar>
|
||||
class ComputeFromReferencePhase
|
||||
{
|
||||
enum { numPhases = FluidSystem::numPhases };
|
||||
enum { numComponents = FluidSystem::numComponents };
|
||||
typedef Opm::CompositionFromFugacities<Scalar, FluidSystem> CompositionFromFugacities;
|
||||
typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
|
||||
typedef Opm::CompositionFromFugacities<Scalar, FluidSystem, Evaluation> CompositionFromFugacities;
|
||||
typedef Dune::FieldVector<Evaluation, numComponents> ComponentVector;
|
||||
|
||||
public:
|
||||
/*!
|
||||
@ -108,6 +108,7 @@ public:
|
||||
bool setViscosity,
|
||||
bool setEnthalpy)
|
||||
{
|
||||
typedef MathToolbox<typename FluidState::Scalar> FsToolbox;
|
||||
|
||||
// compute the density and enthalpy of the
|
||||
// reference phase
|
||||
@ -145,8 +146,10 @@ public:
|
||||
continue; // reference phase is already calculated
|
||||
|
||||
ComponentVector fugVec;
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx)
|
||||
fugVec[compIdx] = fluidState.fugacity(refPhaseIdx, compIdx);
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
const auto& fug = fluidState.fugacity(refPhaseIdx, compIdx);
|
||||
fugVec[compIdx] = FsToolbox::template toLhs<Evaluation>(fug);
|
||||
}
|
||||
|
||||
CompositionFromFugacities::solve(fluidState, paramCache, phaseIdx, fugVec);
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
#ifndef OPM_MISCIBLE_MULTIPHASE_COMPOSITION_HPP
|
||||
#define OPM_MISCIBLE_MULTIPHASE_COMPOSITION_HPP
|
||||
|
||||
#include <opm/material/common/MathToolbox.hpp>
|
||||
|
||||
#include <dune/common/fvector.hh>
|
||||
#include <dune/common/fmatrix.hh>
|
||||
|
||||
@ -114,12 +116,14 @@ private:
|
||||
* - if the setViscosity parameter is true, also dynamic viscosities of *all* phases
|
||||
* - if the setInternalEnergy parameter is true, also specific enthalpies and internal energies of *all* phases
|
||||
*/
|
||||
template <class Scalar, class FluidSystem>
|
||||
template <class Scalar, class FluidSystem, class Evaluation = Scalar>
|
||||
class MiscibleMultiPhaseComposition
|
||||
{
|
||||
static const int numPhases = FluidSystem::numPhases;
|
||||
static const int numComponents = FluidSystem::numComponents;
|
||||
|
||||
typedef MathToolbox<Evaluation> Toolbox;
|
||||
|
||||
static_assert(numPhases <= numComponents,
|
||||
"This solver requires that the number fluid phases is smaller or equal "
|
||||
"to the number of components");
|
||||
@ -153,11 +157,15 @@ public:
|
||||
static void solve(FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
int phasePresence,
|
||||
const MMPCAuxConstraint<Scalar> *auxConstraints,
|
||||
const MMPCAuxConstraint<Evaluation> *auxConstraints,
|
||||
int numAuxConstraints,
|
||||
bool setViscosity,
|
||||
bool setInternalEnergy)
|
||||
{
|
||||
typedef MathToolbox<typename FluidState::Scalar> FsToolbox;
|
||||
static_assert(std::is_same<typename FluidState::Scalar, Evaluation>::value,
|
||||
"The scalar type of the fluid state must be 'Evaluation'");
|
||||
|
||||
#ifndef NDEBUG
|
||||
// currently this solver can only handle fluid systems which
|
||||
// assume ideal mixtures of all fluids. TODO: relax this
|
||||
@ -176,7 +184,8 @@ public:
|
||||
// coefficients of the components cannot depend on
|
||||
// composition, i.e. the parameters in the cache are valid
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
Scalar fugCoeff = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
Evaluation fugCoeff = FsToolbox::template toLhs<Evaluation>(
|
||||
FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx));
|
||||
fluidState.setFugacityCoefficient(phaseIdx, compIdx, fugCoeff);
|
||||
}
|
||||
}
|
||||
@ -184,25 +193,25 @@ public:
|
||||
// create the linear system of equations which defines the
|
||||
// mole fractions
|
||||
static const int numEq = numComponents*numPhases;
|
||||
Dune::FieldMatrix<Scalar, numEq, numEq> M(0.0);
|
||||
Dune::FieldVector<Scalar, numEq> x(0.0);
|
||||
Dune::FieldVector<Scalar, numEq> b(0.0);
|
||||
Dune::FieldMatrix<Evaluation, numEq, numEq> M(Toolbox::createConstant(0.0));
|
||||
Dune::FieldVector<Evaluation, numEq> x(Toolbox::createConstant(0.0));
|
||||
Dune::FieldVector<Evaluation, numEq> b(Toolbox::createConstant(0.0));
|
||||
|
||||
// assemble the equations expressing the fact that the
|
||||
// fugacities of each component are equal in all phases
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
Scalar entryCol1 =
|
||||
const Evaluation& entryCol1 =
|
||||
fluidState.fugacityCoefficient(/*phaseIdx=*/0, compIdx)
|
||||
* fluidState.pressure(/*phaseIdx=*/0);
|
||||
*fluidState.pressure(/*phaseIdx=*/0);
|
||||
int col1Idx = compIdx;
|
||||
|
||||
for (int phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) {
|
||||
int rowIdx = (phaseIdx - 1)*numComponents + compIdx;
|
||||
int col2Idx = phaseIdx*numComponents + compIdx;
|
||||
|
||||
Scalar entryCol2 =
|
||||
const Evaluation& entryCol2 =
|
||||
fluidState.fugacityCoefficient(phaseIdx, compIdx)
|
||||
* fluidState.pressure(phaseIdx);
|
||||
*fluidState.pressure(phaseIdx);
|
||||
|
||||
M[rowIdx][col1Idx] = entryCol1;
|
||||
M[rowIdx][col2Idx] = -entryCol2;
|
||||
@ -220,11 +229,11 @@ public:
|
||||
int rowIdx = numComponents*(numPhases - 1) + presentPhases;
|
||||
presentPhases += 1;
|
||||
|
||||
b[rowIdx] = 1.0;
|
||||
b[rowIdx] = Toolbox::createConstant(1.0);
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
int colIdx = phaseIdx*numComponents + compIdx;
|
||||
|
||||
M[rowIdx][colIdx] = 1.0;
|
||||
M[rowIdx][colIdx] = Toolbox::createConstant(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,17 +271,17 @@ public:
|
||||
}
|
||||
paramCache.updateComposition(fluidState, phaseIdx);
|
||||
|
||||
Scalar value = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setDensity(phaseIdx, value);
|
||||
const Evaluation& rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setDensity(phaseIdx, rho);
|
||||
|
||||
if (setViscosity) {
|
||||
value = FluidSystem::viscosity(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setViscosity(phaseIdx, value);
|
||||
const Evaluation& mu = FluidSystem::viscosity(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setViscosity(phaseIdx, mu);
|
||||
}
|
||||
|
||||
if (setInternalEnergy) {
|
||||
value = FluidSystem::enthalpy(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setEnthalpy(phaseIdx, value);
|
||||
const Evaluation& h = FluidSystem::enthalpy(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setEnthalpy(phaseIdx, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include <opm/material/fluidmatrixinteractions/NullMaterial.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
|
||||
#include <opm/material/common/MathToolbox.hpp>
|
||||
#include <opm/material/common/ErrorMacros.hpp>
|
||||
#include <opm/material/common/Exceptions.hpp>
|
||||
#include <opm/material/common/Means.hpp>
|
||||
@ -87,22 +88,17 @@ class NcpFlash
|
||||
|
||||
static const int numEq = numPhases*(numComponents + 1);
|
||||
|
||||
typedef Dune::FieldMatrix<Scalar, numEq, numEq> Matrix;
|
||||
typedef Dune::FieldVector<Scalar, numEq> Vector;
|
||||
|
||||
public:
|
||||
typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
|
||||
|
||||
/*!
|
||||
* \brief Guess initial values for all quantities.
|
||||
*/
|
||||
template <class FluidState>
|
||||
template <class FluidState, class Evaluation = typename FluidState::Scalar>
|
||||
static void guessInitial(FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
const ComponentVector &globalMolarities)
|
||||
const Dune::FieldVector<Evaluation, numComponents>& globalMolarities)
|
||||
{
|
||||
// the sum of all molarities
|
||||
Scalar sumMoles = 0;
|
||||
Evaluation sumMoles = 0;
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx)
|
||||
sumMoles += globalMolarities[compIdx];
|
||||
|
||||
@ -124,7 +120,8 @@ public:
|
||||
paramCache.updateAll(fluidState);
|
||||
for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
|
||||
for (int compIdx = 0; compIdx < numComponents; ++ compIdx) {
|
||||
Scalar phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
const typename FluidState::Scalar phi =
|
||||
FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi);
|
||||
}
|
||||
}
|
||||
@ -140,15 +137,19 @@ public:
|
||||
static void solve(FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
const typename MaterialLaw::Params &matParams,
|
||||
const ComponentVector &globalMolarities,
|
||||
const Dune::FieldVector<typename FluidState::Scalar, numComponents>& globalMolarities,
|
||||
Scalar tolerance = 0.0)
|
||||
{
|
||||
typedef typename FluidState::Scalar Evaluation;
|
||||
typedef Dune::FieldMatrix<Evaluation, numEq, numEq> Matrix;
|
||||
typedef Dune::FieldVector<Evaluation, numEq> Vector;
|
||||
|
||||
Dune::FMatrixPrecision<Scalar>::set_singular_limit(1e-35);
|
||||
|
||||
if (tolerance <= 0.0) {
|
||||
tolerance = std::min(1e-10,
|
||||
Opm::geometricMean(Scalar(1.0),
|
||||
std::numeric_limits<Scalar>::epsilon()));
|
||||
tolerance = std::min<Scalar>(1e-10,
|
||||
Opm::geometricMean(Scalar(1.0),
|
||||
std::numeric_limits<Scalar>::epsilon()));
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
@ -257,7 +258,7 @@ public:
|
||||
* This is a convenience method which assumes that the capillary pressure is
|
||||
* zero...
|
||||
*/
|
||||
template <class FluidState>
|
||||
template <class FluidState, class ComponentVector>
|
||||
static void solve(FluidState &fluidState,
|
||||
const ComponentVector &globalMolarities,
|
||||
Scalar tolerance = 0.0)
|
||||
@ -320,14 +321,20 @@ protected:
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
template <class MaterialLaw, class FluidState>
|
||||
static Scalar linearize_(Matrix &J,
|
||||
Vector &b,
|
||||
FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
const typename MaterialLaw::Params &matParams,
|
||||
const ComponentVector &globalMolarities)
|
||||
template <class MaterialLaw,
|
||||
class FluidState,
|
||||
class Matrix,
|
||||
class Vector,
|
||||
class ComponentVector>
|
||||
static void linearize_(Matrix &J,
|
||||
Vector &b,
|
||||
FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
const typename MaterialLaw::Params &matParams,
|
||||
const ComponentVector &globalMolarities)
|
||||
{
|
||||
typedef typename FluidState::Scalar Evaluation;
|
||||
|
||||
FluidState origFluidState(fluidState);
|
||||
ParameterCache origParamCache(paramCache);
|
||||
|
||||
@ -340,28 +347,6 @@ protected:
|
||||
calculateDefect_(b, fluidState, fluidState, globalMolarities);
|
||||
Valgrind::CheckDefined(b);
|
||||
|
||||
///////
|
||||
// calculate the absolute error
|
||||
///////
|
||||
Scalar absError = 0;
|
||||
|
||||
#if 0
|
||||
// fugacities are equal
|
||||
int eqIdx = 0;
|
||||
for (int compIdx = 0; compIdx < numComponents; ++ compIdx)
|
||||
absError = std::max(std::abs(b[eqIdx + compIdx]), absError);
|
||||
eqIdx += numComponents;
|
||||
|
||||
// sum of concentrations are given
|
||||
for (int compIdx = 0; compIdx < numComponents; ++ compIdx)
|
||||
absError = std::max(std::abs(b[eqIdx + compIdx]), absError);
|
||||
eqIdx += numComponents;
|
||||
|
||||
// NCP model assumptions
|
||||
for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
|
||||
absError = std::max(std::abs(b[eqIdx + phaseIdx]), absError);
|
||||
eqIdx += numPhases;
|
||||
#endif
|
||||
///////
|
||||
// assemble jacobian matrix
|
||||
///////
|
||||
@ -373,17 +358,16 @@ protected:
|
||||
// forward differences
|
||||
|
||||
// deviate the mole fraction of the i-th component
|
||||
Scalar x_i = getQuantity_(fluidState, pvIdx);
|
||||
const Evaluation& x_i = getQuantity_(fluidState, pvIdx);
|
||||
const Scalar eps = std::numeric_limits<Scalar>::epsilon()*1e7/(quantityWeight_(fluidState, pvIdx));
|
||||
|
||||
setQuantity_<MaterialLaw>(fluidState, paramCache, matParams, pvIdx, x_i + eps);
|
||||
assert(std::abs(getQuantity_(fluidState, pvIdx) - (x_i + eps))
|
||||
<= std::max(1.0, std::abs(x_i))*std::numeric_limits<Scalar>::epsilon()*100);
|
||||
|
||||
// compute derivative of the defect
|
||||
calculateDefect_(tmp, origFluidState, fluidState, globalMolarities);
|
||||
tmp -= b;
|
||||
tmp /= eps;
|
||||
for (int i = 0; i < numEq; ++ i)
|
||||
tmp[i] /= eps;
|
||||
|
||||
// store derivative in jacobian matrix
|
||||
for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
|
||||
@ -396,16 +380,16 @@ protected:
|
||||
// end forward differences
|
||||
////////
|
||||
}
|
||||
|
||||
return absError;
|
||||
}
|
||||
|
||||
template <class FluidState>
|
||||
template <class FluidState, class Vector, class ComponentVector>
|
||||
static void calculateDefect_(Vector &b,
|
||||
const FluidState &fluidStateEval,
|
||||
const FluidState &fluidState,
|
||||
const ComponentVector &globalMolarities)
|
||||
{
|
||||
typedef typename FluidState::Scalar Evaluation;
|
||||
|
||||
int eqIdx = 0;
|
||||
|
||||
// fugacity of any component must be equal in all phases
|
||||
@ -420,9 +404,8 @@ protected:
|
||||
|
||||
assert(eqIdx == numComponents*(numPhases - 1));
|
||||
|
||||
// the fact saturations must sum up to 1 is included explicitly!
|
||||
|
||||
// capillary pressures are explicitly included!
|
||||
// the fact saturations must sum up to 1 is included implicitly and also,
|
||||
// capillary pressures are treated implicitly!
|
||||
|
||||
// global molarities are given
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
@ -437,10 +420,9 @@ protected:
|
||||
++eqIdx;
|
||||
}
|
||||
|
||||
// model assumptions (-> non-linear complementarity functions)
|
||||
// must be adhered
|
||||
// model assumptions (-> non-linear complementarity functions) must be adhered
|
||||
for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
||||
Scalar sumMoleFracEval = 0.0;
|
||||
Evaluation sumMoleFracEval = 0.0;
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx)
|
||||
sumMoleFracEval += fluidStateEval.moleFraction(phaseIdx, compIdx);
|
||||
|
||||
@ -448,7 +430,7 @@ protected:
|
||||
b[eqIdx] = fluidState.saturation(phaseIdx);
|
||||
}
|
||||
else {
|
||||
Scalar sumMoleFrac = 0.0;
|
||||
Evaluation sumMoleFrac = 0.0;
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx)
|
||||
sumMoleFrac += fluidState.moleFraction(phaseIdx, compIdx);
|
||||
b[eqIdx] = 1.0 - sumMoleFrac;
|
||||
@ -458,36 +440,43 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
template <class MaterialLaw, class FluidState>
|
||||
template <class MaterialLaw, class FluidState, class Vector>
|
||||
static Scalar update_(FluidState &fluidState,
|
||||
ParameterCache ¶mCache,
|
||||
const typename MaterialLaw::Params &matParams,
|
||||
const Vector &deltaX)
|
||||
{
|
||||
typedef typename FluidState::Scalar Evaluation;
|
||||
typedef Opm::MathToolbox<Evaluation> Toolbox;
|
||||
|
||||
// make sure we don't swallow non-finite update vectors
|
||||
assert(std::isfinite(deltaX.two_norm()));
|
||||
#ifndef NDEBUG
|
||||
assert(deltaX.dimension == numEq);
|
||||
for (int i = 0; i < numEq; ++i)
|
||||
assert(std::isfinite(Toolbox::value(deltaX[i])));
|
||||
#endif
|
||||
|
||||
Scalar relError = 0;
|
||||
for (int pvIdx = 0; pvIdx < numEq; ++ pvIdx) {
|
||||
Scalar tmp = getQuantity_(fluidState, pvIdx);
|
||||
Scalar delta = deltaX[pvIdx];
|
||||
const Evaluation& tmp = getQuantity_(fluidState, pvIdx);
|
||||
Evaluation delta = deltaX[pvIdx];
|
||||
|
||||
relError = std::max(relError, std::abs(delta)*quantityWeight_(fluidState, pvIdx));
|
||||
relError = std::max<Scalar>(relError,
|
||||
std::abs(Toolbox::value(delta))
|
||||
* quantityWeight_(fluidState, pvIdx));
|
||||
|
||||
if (isSaturationIdx_(pvIdx)) {
|
||||
// dampen to at most 25% change in saturation per
|
||||
// iteration
|
||||
delta = std::min(0.25, std::max(-0.25, delta));
|
||||
// dampen to at most 25% change in saturation per iteration
|
||||
delta = Toolbox::min(0.25, Toolbox::max(-0.25, delta));
|
||||
}
|
||||
else if (isMoleFracIdx_(pvIdx)) {
|
||||
// dampen to at most 20% change in mole fraction per
|
||||
// iteration
|
||||
delta = std::min(0.20, std::max(-0.20, delta));
|
||||
// dampen to at most 20% change in mole fraction per iteration
|
||||
delta = Toolbox::min(0.20, Toolbox::max(-0.20, delta));
|
||||
}
|
||||
else if (isPressureIdx_(pvIdx)) {
|
||||
// dampen to at most 50% change in pressure per
|
||||
// iteration
|
||||
delta = std::min(0.5*fluidState.pressure(0), std::max(-0.5*fluidState.pressure(0), delta));
|
||||
// dampen to at most 50% change in pressure per iteration
|
||||
delta = Toolbox::min(0.5*fluidState.pressure(0),
|
||||
Toolbox::max(-0.5*fluidState.pressure(0), delta));
|
||||
}
|
||||
|
||||
setQuantityRaw_(fluidState, pvIdx, tmp - delta);
|
||||
@ -534,9 +523,11 @@ protected:
|
||||
ParameterCache ¶mCache,
|
||||
const typename MaterialLaw::Params &matParams)
|
||||
{
|
||||
typedef typename FluidState::Scalar Evaluation;
|
||||
|
||||
// calculate the saturation of the last phase as a function of
|
||||
// the other saturations
|
||||
Scalar sumSat = 0.0;
|
||||
Evaluation sumSat = 0.0;
|
||||
for (int phaseIdx = 0; phaseIdx < numPhases - 1; ++phaseIdx)
|
||||
sumSat += fluidState.saturation(phaseIdx);
|
||||
fluidState.setSaturation(/*phaseIdx=*/numPhases - 1, 1.0 - sumSat);
|
||||
@ -544,7 +535,7 @@ protected:
|
||||
// update the pressures using the material law (saturations
|
||||
// and first pressure are already set because it is implicitly
|
||||
// solved for.)
|
||||
ComponentVector pC;
|
||||
Dune::FieldVector<Scalar, numPhases> pC;
|
||||
MaterialLaw::capillaryPressures(pC, matParams, fluidState);
|
||||
for (int phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx)
|
||||
fluidState.setPressure(phaseIdx,
|
||||
@ -556,11 +547,11 @@ protected:
|
||||
|
||||
// update all densities and fugacity coefficients
|
||||
for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
|
||||
Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
const Evaluation& rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
fluidState.setDensity(phaseIdx, rho);
|
||||
|
||||
for (int compIdx = 0; compIdx < numComponents; ++ compIdx) {
|
||||
Scalar phi = FluidSystem::fugacityCoefficient( fluidState, paramCache, phaseIdx, compIdx);
|
||||
const Evaluation& phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi);
|
||||
}
|
||||
}
|
||||
@ -577,7 +568,7 @@ protected:
|
||||
|
||||
// retrieves a quantity from the fluid state
|
||||
template <class FluidState>
|
||||
static Scalar getQuantity_(const FluidState &fluidState, int pvIdx)
|
||||
static const typename FluidState::Scalar& getQuantity_(const FluidState &fluidState, int pvIdx)
|
||||
{
|
||||
assert(pvIdx < numEq);
|
||||
|
||||
@ -606,12 +597,14 @@ protected:
|
||||
ParameterCache ¶mCache,
|
||||
const typename MaterialLaw::Params &matParams,
|
||||
int pvIdx,
|
||||
Scalar value)
|
||||
const typename FluidState::Scalar& value)
|
||||
{
|
||||
typedef typename FluidState::Scalar Evaluation;
|
||||
|
||||
assert(0 <= pvIdx && pvIdx < numEq);
|
||||
|
||||
if (pvIdx < 1) { // <- first pressure
|
||||
Scalar delta = value - fluidState.pressure(0);
|
||||
Evaluation delta = value - fluidState.pressure(0);
|
||||
|
||||
// set all pressures. here we assume that the capillary
|
||||
// pressure does not depend on absolute pressure.
|
||||
@ -621,41 +614,46 @@ protected:
|
||||
|
||||
// update all densities and fugacity coefficients
|
||||
for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
||||
Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
const Evaluation& rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
Valgrind::CheckDefined(rho);
|
||||
fluidState.setDensity(phaseIdx, rho);
|
||||
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
Scalar phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
const Evaluation& phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
Valgrind::CheckDefined(phi);
|
||||
fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pvIdx < numPhases) { // <- first M - 1 saturations
|
||||
Scalar delta = value - fluidState.saturation(/*phaseIdx=*/pvIdx - 1);
|
||||
const Evaluation& delta = value - fluidState.saturation(/*phaseIdx=*/pvIdx - 1);
|
||||
Valgrind::CheckDefined(delta);
|
||||
fluidState.setSaturation(/*phaseIdx=*/pvIdx - 1, value);
|
||||
|
||||
// set last saturation (-> minus the change of the
|
||||
// satuation of the other phase)
|
||||
// set last saturation (-> minus the change of the saturation of the other
|
||||
// phase)
|
||||
fluidState.setSaturation(/*phaseIdx=*/numPhases - 1,
|
||||
fluidState.saturation(numPhases - 1) - delta);
|
||||
|
||||
// update all fluid pressures using the capillary pressure
|
||||
// law
|
||||
ComponentVector pC;
|
||||
// update all fluid pressures using the capillary pressure law
|
||||
Dune::FieldVector<Evaluation, numPhases> pC;
|
||||
MaterialLaw::capillaryPressures(pC, matParams, fluidState);
|
||||
Valgrind::CheckDefined(pC);
|
||||
for (int phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx)
|
||||
fluidState.setPressure(phaseIdx,
|
||||
fluidState.pressure(0)
|
||||
+ (pC[phaseIdx] - pC[0]));
|
||||
fluidState.pressure(0)
|
||||
+ (pC[phaseIdx] - pC[0]));
|
||||
paramCache.updateAllPressures(fluidState);
|
||||
|
||||
// update all densities and fugacity coefficients
|
||||
for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
||||
Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
const Evaluation& rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
Valgrind::CheckDefined(rho);
|
||||
fluidState.setDensity(phaseIdx, rho);
|
||||
|
||||
for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
Scalar phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
const Evaluation& phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
|
||||
Valgrind::CheckDefined(phi);
|
||||
fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi);
|
||||
}
|
||||
}
|
||||
@ -665,18 +663,21 @@ protected:
|
||||
int phaseIdx = (pvIdx - numPhases)/numComponents;
|
||||
int compIdx = (pvIdx - numPhases)%numComponents;
|
||||
|
||||
Valgrind::CheckDefined(value);
|
||||
fluidState.setMoleFraction(phaseIdx, compIdx, value);
|
||||
paramCache.updateSingleMoleFraction(fluidState, phaseIdx, compIdx);
|
||||
|
||||
// update the density of the phase
|
||||
Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
const Evaluation& rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
|
||||
Valgrind::CheckDefined(rho);
|
||||
fluidState.setDensity(phaseIdx, rho);
|
||||
|
||||
// if the phase's fugacity coefficients are composition
|
||||
// dependent, update them as well.
|
||||
if (!FluidSystem::isIdealMixture(phaseIdx)) {
|
||||
for (int fugCompIdx = 0; fugCompIdx < numComponents; ++fugCompIdx) {
|
||||
Scalar phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, fugCompIdx);
|
||||
const Evaluation& phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, fugCompIdx);
|
||||
Valgrind::CheckDefined(phi);
|
||||
fluidState.setFugacityCoefficient(phaseIdx, fugCompIdx, phi);
|
||||
}
|
||||
}
|
||||
@ -688,10 +689,13 @@ protected:
|
||||
|
||||
// set a quantity in the fluid state
|
||||
template <class FluidState>
|
||||
static void setQuantityRaw_(FluidState &fluidState, int pvIdx, Scalar value)
|
||||
static void setQuantityRaw_(FluidState &fluidState,
|
||||
int pvIdx,
|
||||
const typename FluidState::Scalar& value)
|
||||
{
|
||||
assert(pvIdx < numEq);
|
||||
|
||||
Valgrind::CheckDefined(value);
|
||||
// first pressure
|
||||
if (pvIdx < 1) {
|
||||
int phaseIdx = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user