mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #4119 from atgeirr/refactor-boundary-flux
Refactor boundary flux
This commit is contained in:
commit
3bb35b223c
@ -43,6 +43,8 @@
|
|||||||
#include <dune/common/fmatrix.hh>
|
#include <dune/common/fmatrix.hh>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
template <class TypeTag>
|
template <class TypeTag>
|
||||||
@ -212,8 +214,8 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static void volumeAndPhasePressureDifferences(short (&upIdx)[numPhases],
|
static void volumeAndPhasePressureDifferences(std::array<short, numPhases>& upIdx,
|
||||||
short (&dnIdx)[numPhases],
|
std::array<short, numPhases>& dnIdx,
|
||||||
Evaluation (&volumeFlux)[numPhases],
|
Evaluation (&volumeFlux)[numPhases],
|
||||||
Evaluation (&pressureDifferences)[numPhases],
|
Evaluation (&pressureDifferences)[numPhases],
|
||||||
const ElementContext& elemCtx,
|
const ElementContext& elemCtx,
|
||||||
@ -418,34 +420,75 @@ protected:
|
|||||||
unsigned timeIdx,
|
unsigned timeIdx,
|
||||||
const FluidState& exFluidState)
|
const FluidState& exFluidState)
|
||||||
{
|
{
|
||||||
|
const auto& scvf = elemCtx.stencil(timeIdx).boundaryFace(scvfIdx);
|
||||||
|
const Scalar faceArea = scvf.area();
|
||||||
|
const Scalar zEx = scvf.integrationPos()[dimWorld - 1];
|
||||||
const auto& problem = elemCtx.problem();
|
const auto& problem = elemCtx.problem();
|
||||||
|
const unsigned globalSpaceIdx = elemCtx.globalSpaceIndex(0, timeIdx);
|
||||||
|
const auto& intQuantsIn = elemCtx.intensiveQuantities(0, timeIdx);
|
||||||
|
|
||||||
|
calculateBoundaryGradients_(problem,
|
||||||
|
globalSpaceIdx,
|
||||||
|
intQuantsIn,
|
||||||
|
scvfIdx,
|
||||||
|
faceArea,
|
||||||
|
zEx,
|
||||||
|
exFluidState,
|
||||||
|
upIdx_,
|
||||||
|
dnIdx_,
|
||||||
|
volumeFlux_,
|
||||||
|
pressureDifference_);
|
||||||
|
|
||||||
|
// Treating solvent here and not in the static method, since that would require more
|
||||||
|
// extensive refactoring. It means that the TpfaLinearizer will not support bcs for solvent until this is
|
||||||
|
// addressed.
|
||||||
|
if constexpr (enableSolvent) {
|
||||||
|
if (upIdx_[gasPhaseIdx] == 0) {
|
||||||
|
const Scalar trans = problem.transmissibilityBoundary(globalSpaceIdx, scvfIdx);
|
||||||
|
const Scalar transModified = trans * Toolbox::value(intQuantsIn.rockCompTransMultiplier());
|
||||||
|
const auto solventFlux = pressureDifference_[gasPhaseIdx] * intQuantsIn.mobility(gasPhaseIdx) * (-transModified/faceArea);
|
||||||
|
asImp_().setSolventVolumeFlux(solventFlux);
|
||||||
|
} else {
|
||||||
|
asImp_().setSolventVolumeFlux(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* \brief Update the required gradients for boundary faces
|
||||||
|
*/
|
||||||
|
template <class Problem, class FluidState, class EvaluationContainer>
|
||||||
|
static void calculateBoundaryGradients_(const Problem& problem,
|
||||||
|
const unsigned globalSpaceIdx,
|
||||||
|
const IntensiveQuantities& intQuantsIn,
|
||||||
|
const unsigned bfIdx,
|
||||||
|
const double faceArea,
|
||||||
|
const double zEx,
|
||||||
|
const FluidState& exFluidState,
|
||||||
|
std::array<short, numPhases>& upIdx,
|
||||||
|
std::array<short, numPhases>& dnIdx,
|
||||||
|
EvaluationContainer& volumeFlux,
|
||||||
|
EvaluationContainer& pressureDifference)
|
||||||
|
{
|
||||||
|
|
||||||
bool enableBoundaryMassFlux = problem.nonTrivialBoundaryConditions();
|
bool enableBoundaryMassFlux = problem.nonTrivialBoundaryConditions();
|
||||||
if (!enableBoundaryMassFlux)
|
if (!enableBoundaryMassFlux)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto& stencil = elemCtx.stencil(timeIdx);
|
Scalar trans = problem.transmissibilityBoundary(globalSpaceIdx, bfIdx);
|
||||||
const auto& scvf = stencil.boundaryFace(scvfIdx);
|
|
||||||
|
|
||||||
unsigned interiorDofIdx = scvf.interiorIndex();
|
|
||||||
|
|
||||||
Scalar trans = problem.transmissibilityBoundary(elemCtx, scvfIdx);
|
|
||||||
Scalar faceArea = scvf.area();
|
|
||||||
|
|
||||||
// estimate the gravity correction: for performance reasons we use a simplified
|
// estimate the gravity correction: for performance reasons we use a simplified
|
||||||
// approach for this flux module that assumes that gravity is constant and always
|
// approach for this flux module that assumes that gravity is constant and always
|
||||||
// acts into the downwards direction. (i.e., no centrifuge experiments, sorry.)
|
// acts into the downwards direction. (i.e., no centrifuge experiments, sorry.)
|
||||||
Scalar g = elemCtx.problem().gravity()[dimWorld - 1];
|
Scalar g = problem.gravity()[dimWorld - 1];
|
||||||
|
|
||||||
const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx, timeIdx);
|
|
||||||
|
|
||||||
// this is quite hacky because the dune grid interface does not provide a
|
// this is quite hacky because the dune grid interface does not provide a
|
||||||
// cellCenterDepth() method (so we ask the problem to provide it). The "good"
|
// cellCenterDepth() method (so we ask the problem to provide it). The "good"
|
||||||
// solution would be to take the Z coordinate of the element centroids, but since
|
// solution would be to take the Z coordinate of the element centroids, but since
|
||||||
// ECL seems to like to be inconsistent on that front, it needs to be done like
|
// ECL seems to like to be inconsistent on that front, it needs to be done like
|
||||||
// here...
|
// here...
|
||||||
Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx, timeIdx);
|
Scalar zIn = problem.dofCenterDepth(globalSpaceIdx);
|
||||||
Scalar zEx = scvf.integrationPos()[dimWorld - 1];
|
|
||||||
|
|
||||||
// the distances from the DOF's depths. (i.e., the additional depth of the
|
// the distances from the DOF's depths. (i.e., the additional depth of the
|
||||||
// exterior DOF)
|
// exterior DOF)
|
||||||
@ -465,62 +508,54 @@ protected:
|
|||||||
Evaluation pressureExterior = exFluidState.pressure(phaseIdx);
|
Evaluation pressureExterior = exFluidState.pressure(phaseIdx);
|
||||||
pressureExterior += rhoAvg*(distZ*g);
|
pressureExterior += rhoAvg*(distZ*g);
|
||||||
|
|
||||||
pressureDifference_[phaseIdx] = pressureExterior - pressureInterior;
|
pressureDifference[phaseIdx] = pressureExterior - pressureInterior;
|
||||||
|
|
||||||
// decide the upstream index for the phase. for this we make sure that the
|
// decide the upstream index for the phase. for this we make sure that the
|
||||||
// degree of freedom which is regarded upstream if both pressures are equal
|
// degree of freedom which is regarded upstream if both pressures are equal
|
||||||
// is always the same: if the pressure is equal, the DOF with the lower
|
// is always the same: if the pressure is equal, the DOF with the lower
|
||||||
// global index is regarded to be the upstream one.
|
// global index is regarded to be the upstream one.
|
||||||
if (pressureDifference_[phaseIdx] > 0.0) {
|
const unsigned interiorDofIdx = 0; // Valid only for cell-centered FV.
|
||||||
upIdx_[phaseIdx] = -1;
|
if (pressureDifference[phaseIdx] > 0.0) {
|
||||||
dnIdx_[phaseIdx] = interiorDofIdx;
|
upIdx[phaseIdx] = -1;
|
||||||
|
dnIdx[phaseIdx] = interiorDofIdx;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
upIdx_[phaseIdx] = interiorDofIdx;
|
upIdx[phaseIdx] = interiorDofIdx;
|
||||||
dnIdx_[phaseIdx] = -1;
|
dnIdx[phaseIdx] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Evaluation transModified = trans;
|
Evaluation transModified = trans;
|
||||||
|
|
||||||
unsigned upstreamIdx = upstreamIndex_(phaseIdx);
|
if (upIdx[phaseIdx] == interiorDofIdx) {
|
||||||
if (upstreamIdx == interiorDofIdx) {
|
|
||||||
|
|
||||||
// this is slightly hacky because in the automatic differentiation case, it
|
// this is slightly hacky because in the automatic differentiation case, it
|
||||||
// only works for the element centered finite volume method. for ebos this
|
// only works for the element centered finite volume method. for ebos this
|
||||||
// does not matter, though.
|
// does not matter, though.
|
||||||
const auto& up = elemCtx.intensiveQuantities(upstreamIdx, timeIdx);
|
const auto& up = intQuantsIn;
|
||||||
|
|
||||||
// deal with water induced rock compaction
|
// deal with water induced rock compaction
|
||||||
const double transMult = Toolbox::value(up.rockCompTransMultiplier());
|
const Scalar transMult = Toolbox::value(up.rockCompTransMultiplier());
|
||||||
transModified *= transMult;
|
transModified *= transMult;
|
||||||
|
|
||||||
volumeFlux_[phaseIdx] =
|
volumeFlux[phaseIdx] =
|
||||||
pressureDifference_[phaseIdx]*up.mobility(phaseIdx)*(-transModified/faceArea);
|
pressureDifference[phaseIdx]*up.mobility(phaseIdx)*(-transModified/faceArea);
|
||||||
|
|
||||||
if (enableSolvent && phaseIdx == gasPhaseIdx)
|
|
||||||
asImp_().setSolventVolumeFlux( pressureDifference_[phaseIdx]*up.solventMobility()*(-transModified/faceArea));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// compute the phase mobility using the material law parameters of the
|
// compute the phase mobility using the material law parameters of the
|
||||||
// interior element. TODO: this could probably be done more efficiently
|
// interior element. TODO: this could probably be done more efficiently
|
||||||
const auto& matParams =
|
const auto& matParams = problem.materialLawParams(globalSpaceIdx);
|
||||||
elemCtx.problem().materialLawParams(elemCtx,
|
|
||||||
interiorDofIdx,
|
|
||||||
/*timeIdx=*/0);
|
|
||||||
std::array<typename FluidState::Scalar,numPhases> kr;
|
std::array<typename FluidState::Scalar,numPhases> kr;
|
||||||
MaterialLaw::relativePermeabilities(kr, matParams, exFluidState);
|
MaterialLaw::relativePermeabilities(kr, matParams, exFluidState);
|
||||||
|
|
||||||
const auto& mob = kr[phaseIdx]/exFluidState.viscosity(phaseIdx);
|
const auto& mob = kr[phaseIdx]/exFluidState.viscosity(phaseIdx);
|
||||||
volumeFlux_[phaseIdx] =
|
volumeFlux[phaseIdx] =
|
||||||
pressureDifference_[phaseIdx]*mob*(-transModified/faceArea);
|
pressureDifference[phaseIdx]*mob*(-transModified/faceArea);
|
||||||
|
|
||||||
// Solvent inflow is not yet supported
|
|
||||||
if (enableSolvent && phaseIdx == gasPhaseIdx)
|
|
||||||
asImp_().setSolventVolumeFlux(0.0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Update the volumetric fluxes for all fluid phases on the interior faces of the context
|
* \brief Update the volumetric fluxes for all fluid phases on the interior faces of the context
|
||||||
*/
|
*/
|
||||||
@ -545,9 +580,9 @@ private:
|
|||||||
Evaluation pressureDifference_[numPhases];
|
Evaluation pressureDifference_[numPhases];
|
||||||
|
|
||||||
// the local indices of the interior and exterior degrees of freedom
|
// the local indices of the interior and exterior degrees of freedom
|
||||||
short upIdx_[numPhases];
|
std::array<short, numPhases> upIdx_;
|
||||||
short dnIdx_[numPhases];
|
std::array<short, numPhases> dnIdx_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
|
||||||
|
@ -1340,6 +1340,15 @@ public:
|
|||||||
return transmissibilities_.transmissibilityBoundary(elemIdx, boundaryFaceIdx);
|
return transmissibilities_.transmissibilityBoundary(elemIdx, boundaryFaceIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Direct access to a boundary transmissibility.
|
||||||
|
*/
|
||||||
|
Scalar transmissibilityBoundary(const unsigned globalSpaceIdx,
|
||||||
|
const unsigned boundaryFaceIdx) const
|
||||||
|
{
|
||||||
|
return transmissibilities_.transmissibilityBoundary(globalSpaceIdx, boundaryFaceIdx);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \copydoc EclTransmissiblity::thermalHalfTransmissibility
|
* \copydoc EclTransmissiblity::thermalHalfTransmissibility
|
||||||
*/
|
*/
|
||||||
@ -2048,6 +2057,29 @@ public:
|
|||||||
return this->rockCompTransMultWc_[tableIdx].eval(effectiveOilPressure, SwDeltaMax, /*extrapolation=*/true);
|
return this->rockCompTransMultWc_[tableIdx].eval(effectiveOilPressure, SwDeltaMax, /*extrapolation=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<bool, RateVector> boundaryCondition(const unsigned int globalSpaceIdx, const int directionId)
|
||||||
|
{
|
||||||
|
if (!nonTrivialBoundaryConditions_) {
|
||||||
|
return { false, RateVector(0.0) };
|
||||||
|
}
|
||||||
|
switch (directionId) {
|
||||||
|
case 0:
|
||||||
|
return { freebcXMinus_[globalSpaceIdx], massratebcXMinus_[globalSpaceIdx] };
|
||||||
|
case 1:
|
||||||
|
return { freebcX_[globalSpaceIdx], massratebcX_[globalSpaceIdx] };
|
||||||
|
case 2:
|
||||||
|
return { freebcYMinus_[globalSpaceIdx], massratebcYMinus_[globalSpaceIdx] };
|
||||||
|
case 3:
|
||||||
|
return { freebcY_[globalSpaceIdx], massratebcY_[globalSpaceIdx] };
|
||||||
|
case 4:
|
||||||
|
return { freebcZMinus_[globalSpaceIdx], massratebcZMinus_[globalSpaceIdx] };
|
||||||
|
case 5:
|
||||||
|
return { freebcZ_[globalSpaceIdx], massratebcZ_[globalSpaceIdx] };
|
||||||
|
default:
|
||||||
|
return { false, RateVector(0.0) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// update the parameters needed for DRSDT and DRVDT
|
// update the parameters needed for DRSDT and DRVDT
|
||||||
void updateCompositionChangeLimits_()
|
void updateCompositionChangeLimits_()
|
||||||
|
Loading…
Reference in New Issue
Block a user