45 const FVElementGeometry& fvGeometry,
46 const typename FVElementGeometry::SubControlVolumeFace& scvf,
47 const ElementVolumeVariables& elemVolVars,
48 const ElementFluxVariablesCache& elemFluxVarsCache,
49 const Scalar pressure,
50 const bool zeroNormalVelocityGradient =
true)
54 using MomentumFlux =
typename Problem::MomentumFluxType;
55 constexpr std::size_t dim =
static_cast<std::size_t
>(FVElementGeometry::GridGeometry::GridView::dimension);
57 MomentumFlux::size() == dim,
58 "Expects momentum flux to have as many entries as dimensions."
61 const auto& element = fvGeometry.element();
64 std::decay_t<
decltype(problem.dirichlet(element, scvf))>::size() == dim,
65 "Expects problem.dirichlet to return an array with as many entries as dimensions."
70 MomentumFlux flux(0.0);
73 flux[scvf.normalAxis()] = (pressure - problem.referencePressure(element, fvGeometry, scvf)) * scvf.directionSign();
76 if (problem.enableInertiaTerms())
78 const auto v = elemVolVars[scvf.insideScvIdx()].velocity();
79 flux[scvf.normalAxis()] += v*v * problem.density(element, fvGeometry, scvf) * scvf.directionSign();
84 else if (scvf.isLateral())
87 if (!zeroNormalVelocityGradient)
88 return MomentumFlux(0.0);
93 const auto& scv = fvGeometry.scv(scvf.insideScvIdx());
94 if (scv.boundary() && problem.onSlipBoundary(fvGeometry, fvGeometry.frontalScvfOnBoundary(scv)))
98 MomentumFlux flux(0.0);
99 const Scalar mu = problem.effectiveViscosity(element, fvGeometry, scvf);
104 * scvf.directionSign();
106 else if (scvf.boundary())
108 * scvf.directionSign();
111 if (problem.enableInertiaTerms())
113 const auto transportingVelocity = [&]()
115 const auto& orthogonalScvf = fvGeometry.lateralOrthogonalScvf(scvf);
116 const auto innerTransportingVelocity = elemVolVars[orthogonalScvf.insideScvIdx()].velocity();
118 static const bool useOldScheme = getParam<bool>(
"FreeFlow.UseOldTransportingVelocity",
true);
124 if (problem.boundaryTypes(element, scvf).isDirichlet(scvf.normalAxis()))
125 return problem.dirichlet(element, scvf)[scvf.normalAxis()];
128 return innerTransportingVelocity;
134 if (problem.boundaryTypes(element, scvf).isDirichlet(scvf.normalAxis()))
135 return 0.5*(problem.dirichlet(element, scvf)[scvf.normalAxis()] + innerTransportingVelocity);
138 if (orthogonalScvf.boundary())
140 if (problem.boundaryTypes(element, orthogonalScvf).isDirichlet(scvf.normalAxis()))
141 return 0.5*(problem.dirichlet(element, scvf)[scvf.normalAxis()] + innerTransportingVelocity);
143 return innerTransportingVelocity;
147 const auto insideVolume = fvGeometry.scv(orthogonalScvf.insideScvIdx()).
volume();
148 const auto outsideVolume = fvGeometry.scv(orthogonalScvf.outsideScvIdx()).
volume();
149 const auto outerTransportingVelocity = elemVolVars[orthogonalScvf.outsideScvIdx()].velocity();
150 return (insideVolume*innerTransportingVelocity + outsideVolume*outerTransportingVelocity) / (insideVolume + outsideVolume);
156 const auto innerVelocity = elemVolVars[scvf.insideScvIdx()].velocity();
157 const auto outerVelocity = elemVolVars[scvf.outsideScvIdx()].velocity();
159 const auto rho = problem.insideAndOutsideDensity(element, fvGeometry, scvf);
160 const bool selfIsUpstream = scvf.directionSign() ==
sign(transportingVelocity);
162 const auto insideMomentum = innerVelocity * rho.first;
163 const auto outsideMomentum = outerVelocity * rho.second;
165 static const auto upwindWeight = getParamFromGroup<Scalar>(problem.paramGroup(),
"Flux.UpwindWeight");
167 const auto transportedMomentum = selfIsUpstream ? (upwindWeight * insideMomentum + (1.0 - upwindWeight) * outsideMomentum)
168 : (upwindWeight * outsideMomentum + (1.0 - upwindWeight) * insideMomentum);
170 flux[scv.dofAxis()] += transportingVelocity * transportedMomentum * scvf.directionSign();
174 else if (scvf.boundary())
176 const auto insideDensity = problem.density(element, fvGeometry.scv(scvf.insideScvIdx()));
177 const auto innerVelocity = elemVolVars[scvf.insideScvIdx()].velocity();
178 flux[scv.dofAxis()] += innerVelocity * transportingVelocity * insideDensity * scvf.directionSign();
185 DUNE_THROW(Dune::InvalidStateException,
"Face is neither lateral nor frontal.");
200 const FVElementGeometry& fvGeometry,
201 const typename FVElementGeometry::SubControlVolumeFace& scvf,
202 const ElementVolumeVariables& elemVolVars,
203 const ElementFluxVariablesCache& elemFluxVarsCache,
204 const TangentialVelocityGradient& tangentialVelocityGradient = TangentialVelocityGradient(0.0))
207 using MomentumFlux =
typename Problem::MomentumFluxType;
208 constexpr std::size_t dim =
static_cast<std::size_t
>(FVElementGeometry::GridGeometry::GridView::dimension);
210 MomentumFlux::size() == dim,
211 "Expects momentum flux to have as many entries as dimensions."
214 MomentumFlux flux(0.0);
217 if (scvf.isFrontal())
220 using Scalar = std::decay_t<
decltype(flux[0])>;
221 const auto& scv = fvGeometry.scv(scvf.insideScvIdx());
222 const auto& orthogonalScvf = fvGeometry.lateralOrthogonalScvf(scvf);
223 const auto& orthogonalScv = fvGeometry.scv(orthogonalScvf.insideScvIdx());
225 if (scvf.boundary() && problem.onSlipBoundary(fvGeometry, fvGeometry.frontalScvfOnBoundary(orthogonalScv)))
242 const Scalar velI = elemVolVars[scvf.insideScvIdx()].velocity();
245 const Scalar mu = problem.effectiveViscosity(fvGeometry.element(), fvGeometry, scvf);
246 const Scalar
distance = (scv.dofPosition()- scvf.ipGlobal()).two_norm();
247 const Scalar velGradJI = [&]
249 if (elemVolVars.hasVolVars(orthogonalScvf.outsideScvIdx()))
252 return tangentialVelocityGradient;
255 const Scalar slipVelocity = problem.beaversJosephVelocity(fvGeometry, scvf, elemVolVars, velGradJI)[scv.dofAxis()];
256 const Scalar velGradIJ = (slipVelocity - velI) /
distance * scvf.directionSign();
258 flux[scv.dofAxis()] -= (mu * (velGradIJ + velGradJI))*scvf.directionSign();
261 if (problem.enableInertiaTerms())
264 const auto transportingVelocity = [&]()
266 const auto innerTransportingVelocity = elemVolVars[orthogonalScvf.insideScvIdx()].velocity();
268 if (!elemVolVars.hasVolVars(orthogonalScvf.outsideScvIdx()))
269 return innerTransportingVelocity;
271 const auto outerTransportingVelocity = elemVolVars[orthogonalScvf.outsideScvIdx()].velocity();
274 if (orthogonalScvf.boundary())
275 return outerTransportingVelocity;
277 static const bool useOldScheme = getParam<bool>(
"FreeFlow.UseOldTransportingVelocity",
true);
279 return innerTransportingVelocity;
283 const auto insideVolume = fvGeometry.scv(orthogonalScvf.insideScvIdx()).volume();
284 const auto outsideVolume = fvGeometry.scv(orthogonalScvf.outsideScvIdx()).volume();
285 const auto outerTransportingVelocity = elemVolVars[orthogonalScvf.outsideScvIdx()].velocity();
286 return (insideVolume*innerTransportingVelocity + outsideVolume*outerTransportingVelocity) / (insideVolume + outsideVolume);
292 const auto rho = problem.insideAndOutsideDensity(fvGeometry.element(), fvGeometry, scvf);
293 const auto transportedMomentum = slipVelocity * rho.second;
295 flux[scv.dofAxis()] += transportingVelocity * transportedMomentum * scvf.directionSign();
298 else if (scv.boundary() && problem.onSlipBoundary(fvGeometry, fvGeometry.frontalScvfOnBoundary(scv)))
320 const Scalar velJ = elemVolVars[orthogonalScvf.insideScvIdx()].velocity();
323 const Scalar mu = problem.effectiveViscosity(fvGeometry.element(), fvGeometry, scvf);
324 const Scalar
distance = (fvGeometry.scv(orthogonalScvf.insideScvIdx()).dofPosition()- scvf.ipGlobal()).two_norm();
326 const Scalar velGradIJ = [&]
328 if (elemVolVars.hasVolVars(scvf.outsideScvIdx()))
331 return tangentialVelocityGradient;
334 const Scalar slipVelocity = problem.beaversJosephVelocity(fvGeometry, orthogonalScvf, elemVolVars, velGradIJ)[scvf.normalAxis()];
335 const Scalar velGradJI = (slipVelocity - velJ) /
distance * orthogonalScvf.directionSign();
337 flux[scv.dofAxis()] -= (mu * (velGradIJ + velGradJI))*scvf.directionSign();
340 if (problem.enableInertiaTerms())
343 const auto transportingVelocity = slipVelocity;
346 if (scvf.boundary() && elemVolVars.hasVolVars(scvf.outsideScvIdx()))
348 flux[scv.dofAxis()] += problem.density(fvGeometry.element(), scv)
349 * elemVolVars[scvf.outsideScvIdx()].velocity() * transportingVelocity * scvf.directionSign();
353 const auto innerVelocity = elemVolVars[scvf.insideScvIdx()].velocity();
354 const auto outerVelocity = [&]
356 if (!elemVolVars.hasVolVars(scvf.outsideScvIdx()))
357 return innerVelocity;
359 return elemVolVars[scvf.outsideScvIdx()].velocity();
362 const auto rho = problem.insideAndOutsideDensity(fvGeometry.element(), fvGeometry, scvf);
363 const bool selfIsUpstream = scvf.directionSign() ==
sign(transportingVelocity);
365 const auto insideMomentum = innerVelocity * rho.first;
366 const auto outsideMomentum = outerVelocity * rho.second;
368 static const auto upwindWeight = getParamFromGroup<Scalar>(problem.paramGroup(),
"Flux.UpwindWeight");
370 const auto transportedMomentum = selfIsUpstream ? (upwindWeight * insideMomentum + (1.0 - upwindWeight) * outsideMomentum)
371 : (upwindWeight * outsideMomentum + (1.0 - upwindWeight) * insideMomentum);
373 flux[scv.dofAxis()] += transportingVelocity * transportedMomentum * scvf.directionSign();