25#ifndef DUMUX_POROUSMEDIUMFLOW_VELOCITY_HH
26#define DUMUX_POROUSMEDIUMFLOW_VELOCITY_HH
31#include <dune/common/fvector.hh>
32#include <dune/common/float_cmp.hh>
33#include <dune/geometry/type.hh>
46template <
typename T,
typename ...Ts>
47using MoleFractionDetector =
decltype(std::declval<T>().moleFraction(std::declval<Ts>()...));
49template<
class T,
typename ...Args>
50static constexpr bool hasMoleFraction()
51{
return Dune::Std::is_detected<MoleFractionDetector, T, Args...>::value; }
53template <
typename T,
typename ...Ts>
54using MassFractionDetector =
decltype(std::declval<T>().massFraction(std::declval<Ts>()...));
56template<
class T,
typename ...Args>
57static constexpr bool hasMassFraction()
58{
return Dune::Std::is_detected<MassFractionDetector, T, Args...>::value; }
67template<
class Gr
idVariables,
class FluxVariables>
70 using GridGeometry =
typename GridVariables::GridGeometry;
71 using FVElementGeometry =
typename GridGeometry::LocalView;
72 using SubControlVolume =
typename GridGeometry::SubControlVolume;
73 using SubControlVolumeFace =
typename GridGeometry::SubControlVolumeFace;
74 using GridView =
typename GridGeometry::GridView;
75 using Element =
typename GridView::template Codim<0>::Entity;
76 using GridVolumeVariables =
typename GridVariables::GridVolumeVariables;
77 using ElementFluxVarsCache =
typename GridVariables::GridFluxVariablesCache::LocalView;
78 using VolumeVariables =
typename GridVariables::VolumeVariables;
79 using ElementVolumeVariables =
typename GridVolumeVariables::LocalView;
80 using FluidSystem =
typename VolumeVariables::FluidSystem;
81 using Scalar =
typename GridVariables::Scalar;
83 using AdvectionType =
typename FluxVariables::AdvectionType;
85 static constexpr int dim = GridView::dimension;
86 static constexpr int dimWorld = GridView::dimensionworld;
88 static constexpr int dofCodim = isBox ? dim : 0;
91 using GlobalPosition =
typename Element::Geometry::GlobalCoordinate;
93 using Problem =
typename GridVolumeVariables::Problem;
95 static constexpr bool modelIsCompositional = Detail::hasMoleFraction<typename GridVolumeVariables::VolumeVariables, int, int>() ||
96 Detail::hasMassFraction<typename GridVolumeVariables::VolumeVariables, int, int>();
98 static_assert(VolumeVariables::numFluidPhases() >= 1,
"Velocity output only makes sense for models with fluid phases.");
110 : problem_(gridVariables.curGridVolVars().problem())
111 , gridGeometry_(gridVariables.gridGeometry())
112 , gridVariables_(gridVariables)
115 if constexpr (isBox && dim > 1)
118 cellNum_.assign(gridGeometry_.gridView().size(dim), 0);
120 for (
const auto& element : elements(gridGeometry_.gridView()))
121 for (
unsigned int vIdx = 0; vIdx < element.subEntities(dim); ++vIdx)
122 ++cellNum_[gridGeometry_.vertexMapper().subIndex(element, vIdx, dim)];
129 const Element& element,
130 const FVElementGeometry& fvGeometry,
131 const ElementVolumeVariables& elemVolVars,
132 const ElementFluxVarsCache& elemFluxVarsCache,
135 using Velocity =
typename VelocityVector::value_type;
137 const auto geometry = element.geometry();
138 const Dune::GeometryType geomType = geometry.type();
141 auto upwindTerm = [phaseIdx](
const auto& volVars) {
return volVars.mobility(phaseIdx); };
143 if constexpr (isBox && dim == 1)
145 Velocity tmpVelocity(0.0);
146 tmpVelocity = (geometry.corner(1) - geometry.corner(0));
147 tmpVelocity /= tmpVelocity.two_norm();
149 for (
auto&& scvf : scvfs(fvGeometry))
155 FluxVariables fluxVars;
156 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
160 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
161 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
162 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
163 flux /= insideVolVars.extrusionFactor();
166 const int eIdxGlobal = gridGeometry_.elementMapper().index(element);
167 velocity[eIdxGlobal] = tmpVelocity;
173 const auto refElement = Dune::referenceElement(geometry);
174 const auto& localPos = refElement.position(0, 0);
175 const auto jacobianT2 = geometry.jacobianTransposed(localPos);
179 using ScvVelocities = Dune::BlockVector<Velocity>;
180 ScvVelocities scvVelocities(fvGeometry.numScv());
183 for (
auto&& scvf : scvfs(fvGeometry))
189 const auto localPosIP = geometry.local(scvf.ipGlobal());
192 const auto jacobianT1 = geometry.jacobianTransposed(localPosIP);
193 const auto globalNormal = scvf.unitOuterNormal();
194 GlobalPosition localNormal(0);
195 jacobianT1.mv(globalNormal, localNormal);
196 localNormal /= localNormal.two_norm();
199 FluxVariables fluxVars;
200 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
204 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
205 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
206 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
207 flux /= insideVolVars.extrusionFactor();
210 Velocity tmpVelocity = localNormal;
213 scvVelocities[scvf.insideScvIdx()] += tmpVelocity;
214 scvVelocities[scvf.outsideScvIdx()] += tmpVelocity;
218 for (
auto&& scv : scvs(fvGeometry))
220 int vIdxGlobal = scv.dofIndex();
223 Velocity scvVelocity(0);
225 jacobianT2.mtv(scvVelocities[scv.indexInElement()], scvVelocity);
226 scvVelocity /= geometry.integrationElement(localPos)*cellNum_[vIdxGlobal];
228 velocity[vIdxGlobal] += scvVelocity;
237 const int numScvfsPerFace = isMpfa ? element.template subEntity<1>(0).geometry().corners() : 1;
239 if (fvGeometry.numScvf() != element.subEntities(1)*numScvfsPerFace)
240 DUNE_THROW(Dune::NotImplemented,
"Velocity output for non-conforming grids");
242 if (!geomType.isCube() && !geomType.isSimplex())
243 DUNE_THROW(Dune::NotImplemented,
"Velocity output for other geometry types than cube and simplex");
249 std::vector<bool> handledScvf;
251 handledScvf.resize(element.subEntities(1),
false);
254 std::vector<unsigned int> scvfIndexInInside(fvGeometry.numScvf());
255 int localScvfIdx = 0;
256 for (
const auto& intersection : intersections(gridGeometry_.gridView(), element))
259 if (handledScvf[intersection.indexInInside()])
262 if (intersection.neighbor() || intersection.boundary())
264 for (
int i = 0; i < numScvfsPerFace; ++i)
265 scvfIndexInInside[localScvfIdx++] = intersection.indexInInside();
269 handledScvf[intersection.indexInInside()] =
true;
273 std::vector<Scalar> scvfFluxes(element.subEntities(1), 0.0);
275 for (
auto&& scvf : scvfs(fvGeometry))
277 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
278 if (!scvf.boundary())
280 FluxVariables fluxVars;
281 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
282 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
286 auto bcTypes = problem_.boundaryTypes(element, scvf);
287 if (bcTypes.hasOnlyDirichlet())
289 FluxVariables fluxVars;
290 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
291 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
306 for (
auto&& scvf : scvfs(fvGeometry))
310 auto bcTypes = problem_.boundaryTypes(element, scvf);
311 if (bcTypes.hasNeumann())
317 if (stationaryVelocityField)
319 const auto flux = AdvectionType::flux(problem_, element, fvGeometry, elemVolVars,
320 scvf, phaseIdx, elemFluxVarsCache);
322 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
323 scvfFluxes[scvfIndexInInside[localScvfIdx]] += flux / insideVolVars.extrusionFactor();
328 const auto neumannFlux = problem_.neumann(element, fvGeometry, elemVolVars, elemFluxVarsCache, scvf);
329 using NumEqVector = std::decay_t<
decltype(neumannFlux)>;
330 if (Dune::FloatCmp::eq<NumEqVector, Dune::FloatCmp::CmpStyle::absolute>(neumannFlux, NumEqVector(0.0), 1e-30))
331 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
335 else if (dim == 1 || geomType.isCube())
337 const auto fIdx = scvfIndexInInside[localScvfIdx];
339 if constexpr (!modelIsCompositional)
342 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
343 const auto eqIdx = VolumeVariables::Indices::conti0EqIdx + phaseIdx;
344 scvfFluxes[fIdx] += neumannFlux[eqIdx] / insideVolVars.density(phaseIdx) * scvf.area() * insideVolVars.extrusionFactor();
350 const auto fIdxOpposite = fIdx%2 ? fIdx-1 : fIdx+1;
351 scvfFluxes[fIdx] = -scvfFluxes[fIdxOpposite];
356 else if (geomType.isSimplex())
357 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
360 DUNE_THROW(Dune::NotImplemented,
"Velocity computation at Neumann boundaries for cell-centered and prism/pyramid");
370 Velocity refVelocity;
373 if (dim == 1 || geomType.isCube())
375 for (
int i = 0; i < dim; i++)
376 refVelocity[i] = 0.5 * (scvfFluxes[2*i + 1] - scvfFluxes[2*i]);
379 else if (geomType.isSimplex())
381 for (
int dimIdx = 0; dimIdx < dim; dimIdx++)
383 refVelocity[dimIdx] = -scvfFluxes[dim - 1 - dimIdx];
384 for (
int fIdx = 0; fIdx < dim + 1; fIdx++)
385 refVelocity[dimIdx] += scvfFluxes[fIdx]/(dim + 1);
390 DUNE_THROW(Dune::NotImplemented,
"Velocity computation for cell-centered and prism/pyramid");
392 Velocity scvVelocity(0);
393 jacobianT2.mtv(refVelocity, scvVelocity);
395 scvVelocity /= geometry.integrationElement(localPos);
397 int eIdxGlobal = gridGeometry_.elementMapper().index(element);
399 velocity[eIdxGlobal] = scvVelocity;
408 static Scalar scvfReferenceArea_(Dune::GeometryType geomType,
int fIdx)
410 if (dim == 1 || geomType.isCube())
412 return 1.0/(1 << (dim-1));
414 else if (geomType.isTriangle())
416 static const Scalar faceToArea[] = {0.372677996249965,
419 return faceToArea[fIdx];
421 else if (geomType.isTetrahedron())
423 static const Scalar faceToArea[] = {0.102062072615966,
429 return faceToArea[fIdx];
431 else if (geomType.isPyramid())
433 static const Scalar faceToArea[] = {0.130437298687488,
441 return faceToArea[fIdx];
443 else if (geomType.isPrism())
445 static const Scalar faceToArea[] = {0.166666666666667,
454 return faceToArea[fIdx];
457 DUNE_THROW(Dune::NotImplemented,
"scvf area for unknown GeometryType");
462 const Problem& problem_;
463 const GridGeometry& gridGeometry_;
464 const GridVariables& gridVariables_;
466 std::vector<int> cellNum_;
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Element solution classes and factory functions.
The available discretization methods in Dumux.
Traits of a flux variables type.
Definition: flux/traits.hh:44
static constexpr bool hasStationaryVelocityField()
Definition: flux/traits.hh:45
Velocity computation for implicit (porous media) models.
Definition: velocity.hh:69
void calculateVelocity(VelocityVector &velocity, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFluxVarsCache &elemFluxVarsCache, int phaseIdx) const
Definition: velocity.hh:128
PorousMediumFlowVelocity(const GridVariables &gridVariables)
Constructor initializes the static data with the initial solution.
Definition: velocity.hh:109
std::vector< Dune::FieldVector< Scalar, dimWorld > > VelocityVector
Definition: velocity.hh:102
static constexpr int numFluidPhases
Definition: velocity.hh:101