58 template<std::
size_t id>
using SubDomainTypeTag =
typename Traits::template SubDomain<id>::TypeTag;
61 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
62 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
63 template<std::
size_t id>
using ElementSeed =
typename GridView<id>::Grid::template Codim<0>::EntitySeed;
64 template<std::
size_t id>
using FVElementGeometry =
typename GridGeometry<id>::LocalView;
65 template<std::
size_t id>
using SubControlVolume =
typename FVElementGeometry<id>::SubControlVolume;
66 template<std::
size_t id>
using SubControlVolumeFace =
typename FVElementGeometry<id>::SubControlVolumeFace;
67 template<std::
size_t id>
using GridVariables =
typename Traits::template SubDomain<id>::GridVariables;
68 template<std::
size_t id>
using ElementVolumeVariables =
typename GridVariables<id>::GridVolumeVariables::LocalView;
69 template<std::
size_t id>
using GridFluxVariablesCache =
typename GridVariables<id>::GridFluxVariablesCache;
73 using Scalar =
typename Traits::Scalar;
74 using SolutionVector =
typename Traits::SolutionVector;
76 template<std::
size_t id>
77 using SubSolutionVector
78 = std::decay_t<decltype(std::declval<SolutionVector>()[Dune::index_constant<id>()])>;
80 template<std::
size_t id>
81 using ConstSubSolutionVectorPtr =
const SubSolutionVector<id>*;
83 using PrevSolutionVectorStorage =
typename Traits::template Tuple<ConstSubSolutionVectorPtr>;
85 using CouplingStencilType = std::vector<std::size_t>;
87 using GridVariablesTuple =
typename Traits::template TupleOfSharedPtr<GridVariables>;
89 using FluidSystem =
typename VolumeVariables<freeFlowMassIndex>::FluidSystem;
91 using VelocityVector =
typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition;
92 static_assert(std::is_same_v<VelocityVector, typename SubControlVolumeFace<freeFlowMomentumIndex>::GlobalPosition>);
94 struct MomentumCouplingContext
96 FVElementGeometry<freeFlowMassIndex> fvGeometry;
97 ElementVolumeVariables<freeFlowMassIndex> curElemVolVars;
98 ElementVolumeVariables<freeFlowMassIndex> prevElemVolVars;
102 struct MassAndEnergyCouplingContext
104 MassAndEnergyCouplingContext(FVElementGeometry<freeFlowMomentumIndex>&& f,
const std::size_t i)
105 : fvGeometry(std::move(f))
109 FVElementGeometry<freeFlowMomentumIndex> fvGeometry;
115 static constexpr auto pressureIdx = VolumeVariables<freeFlowMassIndex>::Indices::pressureIdx;
123 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
124 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
125 GridVariablesTuple&& gridVariables,
126 const SolutionVector&
curSol)
128 this->momentumCouplingContext_().clear();
129 this->massAndEnergyCouplingContext_().clear();
131 this->
setSubProblems(std::make_tuple(momentumProblem, massProblem));
132 gridVariables_ = gridVariables;
135 computeCouplingStencils_();
139 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
140 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
141 GridVariablesTuple&& gridVariables,
142 const SolutionVector&
curSol,
143 const SolutionVector& prevSol)
145 init(momentumProblem, massProblem, std::forward<GridVariablesTuple>(gridVariables),
curSol);
147 Dune::Hybrid::forEach(std::make_index_sequence<Traits::numSubDomains>{}, [&](
auto i)
148 { std::get<i>(prevSolutions_) = &prevSol[i]; });
152 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
153 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
154 GridVariablesTuple&& gridVariables,
157 this->momentumCouplingContext_().clear();
158 this->massAndEnergyCouplingContext_().clear();
160 this->
setSubProblems(std::make_tuple(momentumProblem, massProblem));
161 gridVariables_ = gridVariables;
164 computeCouplingStencils_();
168 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
169 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
170 GridVariablesTuple&& gridVariables,
172 const PrevSolutionVectorStorage& prevSol)
174 init(momentumProblem, massProblem, std::forward<GridVariablesTuple>(gridVariables),
curSol);
175 prevSolutions_ = prevSol;
199 template<std::
size_t j,
class LocalAssemblerI>
201 const LocalAssemblerI& localAssemblerI,
202 const SubControlVolume<freeFlowMomentumIndex>& scvI,
203 Dune::index_constant<j> domainJ,
204 std::size_t dofIdxGlobalJ)
const
206 const auto&
problem = localAssemblerI.problem();
207 const auto& element = localAssemblerI.element();
208 const auto& fvGeometry = localAssemblerI.fvGeometry();
209 const auto& curElemVolVars = localAssemblerI.curElemVolVars();
210 const auto& prevElemVolVars = localAssemblerI.prevElemVolVars();
211 typename LocalAssemblerI::ElementResidualVector residual(localAssemblerI.element().subEntities(1));
212 const auto& localResidual = localAssemblerI.localResidual();
214 localResidual.evalSource(residual,
problem, element, fvGeometry, curElemVolVars, scvI);
216 for (
const auto& scvf : scvfs(fvGeometry, scvI))
217 localResidual.evalFlux(residual,
problem, element, fvGeometry, curElemVolVars, localAssemblerI.elemBcTypes(), localAssemblerI.elemFluxVarsCache(), scvf);
219 if (!localAssemblerI.assembler().isStationaryProblem())
221 assert(isTransient_());
222 localResidual.evalStorage(residual,
problem, element, fvGeometry, prevElemVolVars, curElemVolVars, scvI);
236 Scalar
pressure(
const Element<freeFlowMomentumIndex>& element,
237 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
238 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf)
const
240 assert(scvf.isFrontal() && !scvf.isLateral() && !scvf.boundary());
250 Scalar
cellPressure(
const Element<freeFlowMassIndex>& element,
251 const SubControlVolumeFace<freeFlowMassIndex>& scvf)
const
259 Scalar
density(
const Element<freeFlowMomentumIndex>& element,
260 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
261 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
262 const bool considerPreviousTimeStep =
false)
const
264 assert(!(considerPreviousTimeStep && !isTransient_()));
265 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
266 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
267 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
269 const auto rho = [&](
const auto& elemVolVars)
272 return elemVolVars[insideMassScv].density();
275 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
276 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
278 return 0.5*(elemVolVars[insideMassScv].density() + elemVolVars[outsideMassScv].
density());
282 return considerPreviousTimeStep ? rho(momentumCouplingContext_()[0].prevElemVolVars)
283 : rho(momentumCouplingContext_()[0].curElemVolVars);
287 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
288 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
289 const bool considerPreviousTimeStep =
false)
const
291 assert(!(considerPreviousTimeStep && !isTransient_()));
292 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
293 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
294 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
296 const auto result = [&](
const auto& elemVolVars)
299 return std::make_pair(elemVolVars[insideMassScv].
density(), elemVolVars[insideMassScv].
density());
302 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
303 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
304 return std::make_pair(elemVolVars[insideMassScv].
density(), elemVolVars[outsideMassScv].
density());
308 return considerPreviousTimeStep ? result(momentumCouplingContext_()[0].prevElemVolVars)
309 : result(momentumCouplingContext_()[0].curElemVolVars);
315 Scalar
density(
const Element<freeFlowMomentumIndex>& element,
316 const SubControlVolume<freeFlowMomentumIndex>& scv,
317 const bool considerPreviousTimeStep =
false)
const
319 assert(!(considerPreviousTimeStep && !isTransient_()));
320 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, scv.elementIndex());
321 const auto& massScv = (*scvs(momentumCouplingContext_()[0].fvGeometry).begin());
323 return considerPreviousTimeStep ? momentumCouplingContext_()[0].prevElemVolVars[massScv].density()
324 : momentumCouplingContext_()[0].curElemVolVars[massScv].density();
331 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
332 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf)
const
334 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
336 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
337 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
340 return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
342 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
343 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
345 const auto mu = [&](
const auto& elemVolVars)
348 return 0.5*(elemVolVars[insideMassScv].viscosity() + elemVolVars[outsideMassScv].viscosity());
351 return mu(momentumCouplingContext_()[0].curElemVolVars);
358 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
359 const SubControlVolume<freeFlowMomentumIndex>& scv)
const
361 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
362 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(scv.elementIndex());
363 return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
369 VelocityVector
faceVelocity(
const Element<freeFlowMassIndex>& element,
370 const SubControlVolumeFace<freeFlowMassIndex>& scvf)
const
373 bindCouplingContext_(Dune::index_constant<freeFlowMassIndex>(), element, scvf.insideScvIdx());
376 const auto localMomentumScvIdx = massScvfToMomentumScvIdx_(scvf, massAndEnergyCouplingContext_()[0].fvGeometry);
377 const auto& scvJ = massAndEnergyCouplingContext_()[0].fvGeometry.scv(localMomentumScvIdx);
380 typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition velocity;
381 velocity[scvJ.dofAxis()] = 1.0;
398 template<std::
size_t j>
399 const CouplingStencilType&
couplingStencil(Dune::index_constant<freeFlowMomentumIndex> domainI,
400 const Element<freeFlowMomentumIndex>& elementI,
401 const SubControlVolume<freeFlowMomentumIndex>& scvI,
402 Dune::index_constant<j> domainJ)
const
403 {
return emptyStencil_; }
419 const CouplingStencilType&
couplingStencil(Dune::index_constant<freeFlowMassIndex> domainI,
420 const Element<freeFlowMassIndex>& elementI,
421 Dune::index_constant<freeFlowMomentumIndex> domainJ)
const
424 return massAndEnergyToMomentumStencils_[eIdx];
436 const CouplingStencilType&
couplingStencil(Dune::index_constant<freeFlowMomentumIndex> domainI,
437 const Element<freeFlowMomentumIndex>& elementI,
438 const SubControlVolume<freeFlowMomentumIndex>& scvI,
439 Dune::index_constant<freeFlowMassIndex> domainJ)
const
441 return momentumToMassAndEnergyStencils_[scvI.index()];
452 template<std::
size_t i, std::
size_t j,
class LocalAssemblerI>
454 const LocalAssemblerI& localAssemblerI,
455 Dune::index_constant<j> domainJ,
456 std::size_t dofIdxGlobalJ,
457 const PrimaryVariables<j>& priVarsJ,
460 this->
curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
464 bindCouplingContext_(domainI, localAssemblerI.element());
467 const auto& deflectedElement =
problem.gridGeometry().element(dofIdxGlobalJ);
469 const auto& fvGeometry = momentumCouplingContext_()[0].fvGeometry;
470 const auto scvIdxJ = dofIdxGlobalJ;
471 const auto& scv = fvGeometry.scv(scvIdxJ);
473 if constexpr (ElementVolumeVariables<freeFlowMassIndex>::GridVolumeVariables::cachingEnabled)
474 gridVars_(
freeFlowMassIndex).curGridVolVars().volVars(scv).update(std::move(elemSol),
problem, deflectedElement, scv);
476 momentumCouplingContext_()[0].curElemVolVars[scv].update(std::move(elemSol),
problem, deflectedElement, scv);
497 template<std::
size_t i,
class AssembleElementFunc>
498 void assembleMultithreaded(Dune::index_constant<i> domainI, AssembleElementFunc&& assembleElement)
const
500 if (elementSets_.empty())
501 DUNE_THROW(Dune::InvalidStateException,
"Call computeColorsForAssembly before assembling in parallel!");
508 for (
const auto& elements : elementSets_)
512 const auto element = grid.entity(elements[eIdx]);
513 assembleElement(element);
519 void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
520 const Element<freeFlowMomentumIndex>& elementI)
const
523 bindCouplingContext_(domainI, elementI, eIdx);
526 void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
527 const Element<freeFlowMomentumIndex>& elementI,
528 const std::size_t eIdx)
const
530 if (momentumCouplingContext_().empty())
533 fvGeometry.bind(elementI);
544 momentumCouplingContext_().emplace_back(MomentumCouplingContext{std::move(fvGeometry), std::move(curElemVolVars), std::move(prevElemVolVars), eIdx});
546 else if (eIdx != momentumCouplingContext_()[0].eIdx)
548 momentumCouplingContext_()[0].eIdx = eIdx;
549 momentumCouplingContext_()[0].fvGeometry.bind(elementI);
550 momentumCouplingContext_()[0].curElemVolVars.bind(elementI, momentumCouplingContext_()[0].fvGeometry, this->
curSol(
freeFlowMassIndex));
553 momentumCouplingContext_()[0].prevElemVolVars.bindElement(elementI, momentumCouplingContext_()[0].fvGeometry, prevSol_(
freeFlowMassIndex));
557 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
558 const Element<freeFlowMassIndex>& elementI)
const
561 bindCouplingContext_(domainI, elementI, eIdx);
564 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
565 const Element<freeFlowMassIndex>& elementI,
566 const std::size_t eIdx)
const
568 if (massAndEnergyCouplingContext_().empty())
571 auto fvGeometry =
localView(gridGeometry);
572 fvGeometry.bindElement(elementI);
573 massAndEnergyCouplingContext_().emplace_back(std::move(fvGeometry), eIdx);
575 else if (eIdx != massAndEnergyCouplingContext_()[0].eIdx)
577 massAndEnergyCouplingContext_()[0].eIdx = eIdx;
578 massAndEnergyCouplingContext_()[0].fvGeometry.bindElement(elementI);
586 template<std::
size_t i>
587 const GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
const
589 if (std::get<i>(gridVariables_))
590 return *std::get<i>(gridVariables_);
592 DUNE_THROW(Dune::InvalidStateException,
"The gridVariables pointer was not set. Use setGridVariables() before calling this function");
599 template<std::
size_t i>
600 GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
602 if (std::get<i>(gridVariables_))
603 return *std::get<i>(gridVariables_);
605 DUNE_THROW(Dune::InvalidStateException,
"The gridVariables pointer was not set. Use setGridVariables() before calling this function");
609 void computeCouplingStencils_()
613 auto momentumFvGeometry =
localView(momentumGridGeometry);
614 massAndEnergyToMomentumStencils_.clear();
615 massAndEnergyToMomentumStencils_.resize(momentumGridGeometry.gridView().size(0));
617 momentumToMassAndEnergyStencils_.clear();
618 momentumToMassAndEnergyStencils_.resize(momentumGridGeometry.numScv());
620 for (
const auto& element : elements(momentumGridGeometry.gridView()))
622 const auto eIdx = momentumGridGeometry.elementMapper().index(element);
623 momentumFvGeometry.bind(element);
624 for (
const auto& scv : scvs(momentumFvGeometry))
626 massAndEnergyToMomentumStencils_[eIdx].push_back(scv.dofIndex());
627 momentumToMassAndEnergyStencils_[scv.index()].push_back(eIdx);
630 if constexpr (FluidSystem::isCompressible(0))
633 for (
const auto& scvf : scvfs(momentumFvGeometry, scv))
635 if (scvf.isLateral() && !scvf.boundary())
637 const auto& outsideScv = momentumFvGeometry.scv(scvf.outsideScvIdx());
638 momentumToMassAndEnergyStencils_[scv.index()].push_back(outsideScv.elementIndex());
646 std::size_t massScvfToMomentumScvIdx_(
const SubControlVolumeFace<freeFlowMassIndex>& massScvf,
647 [[maybe_unused]]
const FVElementGeometry<freeFlowMomentumIndex>& momentumFVGeometry)
const
649 if constexpr (ConsistentlyOrientedGrid<typename GridView<freeFlowMomentumIndex>::Grid>{})
650 return massScvf.index();
653 static const bool makeConsistentlyOriented =
getParam<bool>(
"Grid.MakeConsistentlyOriented",
true);
654 if (!makeConsistentlyOriented)
655 return massScvf.index();
657 for (
const auto& momentumScv : scvs(momentumFVGeometry))
659 typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition momentumUnitOuterNormal(0.0);
660 momentumUnitOuterNormal[momentumScv.dofAxis()] = momentumScv.directionSign();
661 if (Dune::FloatCmp::eq<
typename GridView<freeFlowMomentumIndex>::ctype>(massScvf.unitOuterNormal()*momentumUnitOuterNormal, 1.0))
662 return momentumScv.index();
664 DUNE_THROW(Dune::InvalidStateException,
"No Momentum SCV found");
668 CouplingStencilType emptyStencil_;
669 std::vector<CouplingStencilType> momentumToMassAndEnergyStencils_;
670 std::vector<CouplingStencilType> massAndEnergyToMomentumStencils_;
672 std::vector<MomentumCouplingContext>& momentumCouplingContext_()
const
673 {
return momentumCouplingContextImpl_; }
675 std::vector<MassAndEnergyCouplingContext>& massAndEnergyCouplingContext_()
const
676 {
return massAndEnergyCouplingContextImpl_; }
678 mutable std::vector<MassAndEnergyCouplingContext> massAndEnergyCouplingContextImpl_;
679 mutable std::vector<MomentumCouplingContext> momentumCouplingContextImpl_;
682 GridVariablesTuple gridVariables_;
684 bool isTransient_()
const
685 {
return std::get<0>(prevSolutions_) !=
nullptr; }
687 template<std::
size_t i>
688 const SubSolutionVector<i>& prevSol_(Dune::index_constant<i>)
const
689 {
return *std::get<i>(prevSolutions_); }
691 PrevSolutionVectorStorage prevSolutions_;
693 std::deque<std::vector<ElementSeed<freeFlowMomentumIndex>>> elementSets_;