GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/multidomain/freeflow/couplingmanager_staggered.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 195 200 97.5%
Functions: 381 431 88.4%
Branches: 160 291 55.0%

Line Branch Exec Source
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 //
4 // SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7 /*!
8 * \file
9 * \ingroup MultiDomain
10 * \brief Freeflow coupling managers (Navier-Stokes mass-momentum coupling)
11 */
12 #ifndef DUMUX_MULTIDOMAIN_FREEFLOW_COUPLING_MANAGER_STAGGERED_HH
13 #define DUMUX_MULTIDOMAIN_FREEFLOW_COUPLING_MANAGER_STAGGERED_HH
14
15 #include <memory>
16 #include <tuple>
17 #include <vector>
18 #include <deque>
19
20 #include <dune/common/exceptions.hh>
21 #include <dune/common/indices.hh>
22 #include <dune/common/float_cmp.hh>
23
24 #include <dumux/common/properties.hh>
25 #include <dumux/common/typetraits/typetraits.hh>
26
27 #include <dumux/discretization/method.hh>
28 #include <dumux/discretization/evalsolution.hh>
29 #include <dumux/discretization/elementsolution.hh>
30
31 #include <dumux/multidomain/couplingmanager.hh>
32 #include <dumux/multidomain/fvassembler.hh>
33 #include <dumux/discretization/facecentered/staggered/consistentlyorientedgrid.hh>
34
35 #include <dumux/parallel/parallel_for.hh>
36 #include <dumux/assembly/coloring.hh>
37
38 namespace Dumux {
39
40 /*!
41 * \ingroup MultiDomain
42 * \brief The interface of the coupling manager for free flow systems
43 * \note coupling manager the face-centered staggered discretization scheme
44 */
45 template<class Traits>
46 class FCStaggeredFreeFlowCouplingManager
47 : public CouplingManager<Traits>
48 {
49 using ParentType = CouplingManager<Traits>;
50 public:
51 static constexpr auto freeFlowMomentumIndex = typename Traits::template SubDomain<0>::Index();
52 static constexpr auto freeFlowMassIndex = typename Traits::template SubDomain<1>::Index();
53
54 // this can be used if the coupling manager is used inside a meta-coupling manager (e.g. multi-binary)
55 // to manager the solution vector storage outside this class
56 using SolutionVectorStorage = typename ParentType::SolutionVectorStorage;
57 private:
58 template<std::size_t id> using SubDomainTypeTag = typename Traits::template SubDomain<id>::TypeTag;
59 template<std::size_t id> using PrimaryVariables = GetPropType<SubDomainTypeTag<id>, Properties::PrimaryVariables>;
60 template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>;
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;
70 template<std::size_t id> using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>;
71 template<std::size_t id> using VolumeVariables = GetPropType<SubDomainTypeTag<id>, Properties::VolumeVariables>;
72
73 using Scalar = typename Traits::Scalar;
74 using SolutionVector = typename Traits::SolutionVector;
75
76 template<std::size_t id>
77 using SubSolutionVector
78 = std::decay_t<decltype(std::declval<SolutionVector>()[Dune::index_constant<id>()])>;
79
80 template<std::size_t id>
81 using ConstSubSolutionVectorPtr = const SubSolutionVector<id>*;
82
83 using PrevSolutionVectorStorage = typename Traits::template Tuple<ConstSubSolutionVectorPtr>;
84
85 using CouplingStencilType = std::vector<std::size_t>;
86
87 using GridVariablesTuple = typename Traits::template TupleOfSharedPtr<GridVariables>;
88
89 using FluidSystem = typename VolumeVariables<freeFlowMassIndex>::FluidSystem;
90
91 using VelocityVector = typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition;
92 static_assert(std::is_same_v<VelocityVector, typename SubControlVolumeFace<freeFlowMomentumIndex>::GlobalPosition>);
93
94 struct MomentumCouplingContext
95 {
96 FVElementGeometry<freeFlowMassIndex> fvGeometry;
97 ElementVolumeVariables<freeFlowMassIndex> curElemVolVars;
98 ElementVolumeVariables<freeFlowMassIndex> prevElemVolVars;
99 std::size_t eIdx;
100 };
101
102 struct MassAndEnergyCouplingContext
103 {
104 66 MassAndEnergyCouplingContext(FVElementGeometry<freeFlowMomentumIndex>&& f, const std::size_t i)
105 66 : fvGeometry(std::move(f))
106 66 , eIdx(i)
107 {}
108
109 FVElementGeometry<freeFlowMomentumIndex> fvGeometry;
110 std::size_t eIdx;
111 };
112
113 public:
114
115 static constexpr auto pressureIdx = VolumeVariables<freeFlowMassIndex>::Indices::pressureIdx;
116
117 /*!
118 * \brief Methods to be accessed by main
119 */
120 // \{
121
122 //! use as regular coupling manager
123 45 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
124 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
125 GridVariablesTuple&& gridVariables,
126 const SolutionVector& curSol)
127 {
128 90 this->momentumCouplingContext_().clear();
129 90 this->massAndEnergyCouplingContext_().clear();
130
131 90 this->setSubProblems(std::make_tuple(momentumProblem, massProblem));
132 45 gridVariables_ = gridVariables;
133 45 this->updateSolution(curSol);
134
135 45 computeCouplingStencils_();
136 45 }
137
138 //! use as regular coupling manager in a transient setting
139 23 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)
144 {
145
2/6
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
46 init(momentumProblem, massProblem, std::forward<GridVariablesTuple>(gridVariables), curSol);
146
147 23 Dune::Hybrid::forEach(std::make_index_sequence<Traits::numSubDomains>{}, [&](auto i)
148 23 { std::get<i>(prevSolutions_) = &prevSol[i]; });
149 23 }
150
151 //! use as binary coupling manager in multi model context
152 21 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
153 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
154 GridVariablesTuple&& gridVariables,
155 const typename ParentType::SolutionVectorStorage& curSol)
156 {
157 42 this->momentumCouplingContext_().clear();
158 42 this->massAndEnergyCouplingContext_().clear();
159
160 42 this->setSubProblems(std::make_tuple(momentumProblem, massProblem));
161 21 gridVariables_ = gridVariables;
162 21 this->attachSolution(curSol);
163
164 21 computeCouplingStencils_();
165 21 }
166
167 //! use as binary coupling manager in multi model context and for transient problems
168 5 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
169 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
170 GridVariablesTuple&& gridVariables,
171 const typename ParentType::SolutionVectorStorage& curSol,
172 const PrevSolutionVectorStorage& prevSol)
173 {
174
2/6
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 init(momentumProblem, massProblem, std::forward<GridVariablesTuple>(gridVariables), curSol);
175 5 prevSolutions_ = prevSol;
176 5 }
177
178 // \}
179
180 using CouplingManager<Traits>::evalCouplingResidual;
181
182 /*!
183 * \brief evaluates the element residual of a coupled element of domain i which depends on the variables
184 * at the degree of freedom with index dofIdxGlobalJ of domain j
185 *
186 * \param domainI the domain index of domain i
187 * \param localAssemblerI the local assembler assembling the element residual of an element of domain i
188 * \param scvI the sub-control-volume of domain i
189 * \param domainJ the domain index of domain j
190 * \param dofIdxGlobalJ the index of the degree of freedom of domain j which has an influence on the element residual of domain i
191 *
192 * \note the element whose residual is to be evaluated can be retrieved from the local assembler
193 * as localAssemblerI.element() as well as all up-to-date variables and caches.
194 * \note the default implementation evaluates the complete element residual
195 * if only parts (i.e. only certain scvs, or only certain terms of the residual) of the residual are coupled
196 * to dof with index dofIdxGlobalJ the function can be overloaded in the coupling manager
197 * \return the element residual
198 */
199 template<std::size_t j, class LocalAssemblerI>
200 26774876 decltype(auto) evalCouplingResidual(Dune::index_constant<freeFlowMomentumIndex> domainI,
201 const LocalAssemblerI& localAssemblerI,
202 const SubControlVolume<freeFlowMomentumIndex>& scvI,
203 Dune::index_constant<j> domainJ,
204 std::size_t dofIdxGlobalJ) const
205 {
206 26774876 const auto& problem = localAssemblerI.problem();
207 26774876 const auto& element = localAssemblerI.element();
208 26774876 const auto& fvGeometry = localAssemblerI.fvGeometry();
209 26774876 const auto& curElemVolVars = localAssemblerI.curElemVolVars();
210 26774876 const auto& prevElemVolVars = localAssemblerI.prevElemVolVars();
211 26831452 typename LocalAssemblerI::ElementResidualVector residual(localAssemblerI.element().subEntities(1));
212 26774876 const auto& localResidual = localAssemblerI.localResidual();
213
214 26774876 localResidual.evalSource(residual, problem, element, fvGeometry, curElemVolVars, scvI);
215
216
2/2
✓ Branch 2 taken 81195952 times.
✓ Branch 3 taken 26774876 times.
189166780 for (const auto& scvf : scvfs(fvGeometry, scvI))
217 81195952 localResidual.evalFlux(residual, problem, element, fvGeometry, curElemVolVars, localAssemblerI.elemBcTypes(), localAssemblerI.elemFluxVarsCache(), scvf);
218
219
2/2
✓ Branch 0 taken 19166600 times.
✓ Branch 1 taken 7608276 times.
26774876 if (!localAssemblerI.assembler().isStationaryProblem())
220 {
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19166600 times.
19166600 assert(isTransient_());
222 19166600 localResidual.evalStorage(residual, problem, element, fvGeometry, prevElemVolVars, curElemVolVars, scvI);
223 }
224
225 26774876 return residual;
226 }
227
228 /*!
229 * \name member functions concerning the coupling stencils
230 */
231 // \{
232
233 /*!
234 * \brief Returns the pressure at a given _frontal_ sub control volume face.
235 */
236
1/2
✓ Branch 0 taken 103819484 times.
✗ Branch 1 not taken.
103819484 Scalar pressure(const Element<freeFlowMomentumIndex>& element,
237 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
238 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf) const
239 {
240
2/4
✓ Branch 0 taken 103819484 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103819484 times.
103819484 assert(scvf.isFrontal() && !scvf.isLateral() && !scvf.boundary());
241 103819484 return this->curSol(freeFlowMassIndex)[fvGeometry.elementIndex()][pressureIdx];
242 }
243
244 /*!
245 * \brief Returns the pressure at the center of a sub control volume corresponding to a given sub control volume face.
246 * This is used for setting a Dirichlet pressure for the mass model when a fixed pressure for the momentum balance is set at another
247 * boundary. Since the the pressure at the given scvf is solution-dependent and thus unknown a priori, we just use the value
248 * of the interior cell here.
249 */
250 18395 Scalar cellPressure(const Element<freeFlowMassIndex>& element,
251 const SubControlVolumeFace<freeFlowMassIndex>& scvf) const
252 {
253
2/3
✓ Branch 1 taken 14925 times.
✗ Branch 2 not taken.
✓ Branch 0 taken 3470 times.
18395 return this->curSol(freeFlowMassIndex)[scvf.insideScvIdx()][pressureIdx];
254 }
255
256 /*!
257 * \brief Returns the density at a given sub control volume face.
258 */
259 67194798 Scalar density(const Element<freeFlowMomentumIndex>& element,
260 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
261 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
262 const bool considerPreviousTimeStep = false) const
263 {
264
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 67194798 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
67194798 assert(!(considerPreviousTimeStep && !isTransient_()));
265 67194798 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65282646 times.
67194798 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
267 69106950 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
268
269 134389596 const auto rho = [&](const auto& elemVolVars)
270 {
271
2/2
✓ Branch 0 taken 85740 times.
✓ Branch 1 taken 67109058 times.
67194798 if (scvf.boundary())
272 85740 return elemVolVars[insideMassScv].density();
273 else
274 {
275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65205530 times.
67109058 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
276 69012586 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
277 // TODO distance weighting
278 67109058 return 0.5*(elemVolVars[insideMassScv].density() + elemVolVars[outsideMassScv].density());
279 }
280 };
281
282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67194798 times.
67194798 return considerPreviousTimeStep ? rho(momentumCouplingContext_()[0].prevElemVolVars)
283 134389596 : rho(momentumCouplingContext_()[0].curElemVolVars);
284 }
285
286 132768324 auto insideAndOutsideDensity(const Element<freeFlowMomentumIndex>& element,
287 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
288 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
289 const bool considerPreviousTimeStep = false) const
290 {
291
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 132768324 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
132768324 assert(!(considerPreviousTimeStep && !isTransient_()));
292 132768324 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129051204 times.
132768324 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
294 136485444 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
295
296 265536648 const auto result = [&](const auto& elemVolVars)
297 {
298
2/2
✓ Branch 0 taken 50888 times.
✓ Branch 1 taken 132717436 times.
132768324 if (scvf.boundary())
299 50888 return std::make_pair(elemVolVars[insideMassScv].density(), elemVolVars[insideMassScv].density());
300 else
301 {
302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129000844 times.
132717436 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
303 132717436 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
304 132717436 return std::make_pair(elemVolVars[insideMassScv].density(), elemVolVars[outsideMassScv].density());
305 }
306 };
307
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132768324 times.
132768324 return considerPreviousTimeStep ? result(momentumCouplingContext_()[0].prevElemVolVars)
309 265536648 : result(momentumCouplingContext_()[0].curElemVolVars);
310 }
311
312 /*!
313 * \brief Returns the density at a given sub control volume.
314 */
315 226036228 Scalar density(const Element<freeFlowMomentumIndex>& element,
316 const SubControlVolume<freeFlowMomentumIndex>& scv,
317 const bool considerPreviousTimeStep = false) const
318 {
319
3/4
✓ Branch 0 taken 59953376 times.
✓ Branch 1 taken 166082852 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 59953376 times.
226036228 assert(!(considerPreviousTimeStep && !isTransient_()));
320 226036228 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, scv.elementIndex());
321 226036228 const auto& massScv = (*scvs(momentumCouplingContext_()[0].fvGeometry).begin());
322
323
2/2
✓ Branch 0 taken 59953376 times.
✓ Branch 1 taken 166082852 times.
285989604 return considerPreviousTimeStep ? momentumCouplingContext_()[0].prevElemVolVars[massScv].density()
324 166082852 : momentumCouplingContext_()[0].curElemVolVars[massScv].density();
325 }
326
327 /*!
328 * \brief Returns the pressure at a given sub control volume face.
329 */
330 309689520 Scalar effectiveViscosity(const Element<freeFlowMomentumIndex>& element,
331 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
332 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf) const
333 {
334 309689520 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
335
336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303531816 times.
309689520 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
337
2/2
✓ Branch 0 taken 99584 times.
✓ Branch 1 taken 6058120 times.
309689520 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
338
339
2/2
✓ Branch 0 taken 3782882 times.
✓ Branch 1 taken 305906638 times.
309689520 if (scvf.boundary())
340 3782882 return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
341
342 305906638 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
343 311964758 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
344
345 611813276 const auto mu = [&](const auto& elemVolVars)
346 {
347 // TODO distance weighting
348 305906638 return 0.5*(elemVolVars[insideMassScv].viscosity() + elemVolVars[outsideMassScv].viscosity());
349 };
350
351 305906638 return mu(momentumCouplingContext_()[0].curElemVolVars);
352 }
353
354 /*!
355 * \brief Returns the pressure at a given sub control volume.
356 */
357 90344 Scalar effectiveViscosity(const Element<freeFlowMomentumIndex>& element,
358 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
359 const SubControlVolume<freeFlowMomentumIndex>& scv) const
360 {
361 90344 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
362 90344 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(scv.elementIndex());
363 90344 return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
364 }
365
366 /*!
367 * \brief Returns the velocity at a given sub control volume face.
368 */
369 141491854 VelocityVector faceVelocity(const Element<freeFlowMassIndex>& element,
370 const SubControlVolumeFace<freeFlowMassIndex>& scvf) const
371 {
372 // TODO: rethink this! Maybe we only need scvJ.dofIndex()
373 141491854 bindCouplingContext_(Dune::index_constant<freeFlowMassIndex>(), element, scvf.insideScvIdx()/*eIdx*/);
374
375 // the TPFA scvf index corresponds to the staggered scv index (might need mapping)
376 143595722 const auto localMomentumScvIdx = massScvfToMomentumScvIdx_(scvf, massAndEnergyCouplingContext_()[0].fvGeometry);
377 282983708 const auto& scvJ = massAndEnergyCouplingContext_()[0].fvGeometry.scv(localMomentumScvIdx);
378
379 // create a unit normal vector oriented in positive coordinate direction
380 141491854 typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition velocity;
381 141491854 velocity[scvJ.dofAxis()] = 1.0;
382
383 // create the actual velocity vector
384 141491854 velocity *= this->curSol(freeFlowMomentumIndex)[scvJ.dofIndex()];
385
386 141491854 return velocity;
387 }
388
389 /*!
390 * \brief The coupling stencil of domain I, i.e. which domain J DOFs
391 * the given domain I scv's residual depends on.
392 *
393 * \param domainI the domain index of domain i
394 * \param elementI the coupled element of domain í
395 * \param scvI the sub-control volume of domain i
396 * \param domainJ the domain index of domain j
397 */
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_; }
404
405 /*!
406 * \brief returns an iterable container of all indices of degrees of freedom of domain j
407 * that couple with / influence the element residual of the given element of domain i
408 *
409 * \param domainI the domain index of domain i
410 * \param elementI the coupled element of domain í
411 * \param domainJ the domain index of domain j
412 *
413 * \note The element residual definition depends on the discretization scheme of domain i
414 * box: a container of the residuals of all sub control volumes
415 * cc : the residual of the (sub) control volume
416 * fem: the residual of the element
417 * \note This function has to be implemented by all coupling managers for all combinations of i and j
418 */
419 2433937 const CouplingStencilType& couplingStencil(Dune::index_constant<freeFlowMassIndex> domainI,
420 const Element<freeFlowMassIndex>& elementI,
421 Dune::index_constant<freeFlowMomentumIndex> domainJ) const
422 {
423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2433937 times.
2433937 const auto eIdx = this->problem(freeFlowMassIndex).gridGeometry().elementMapper().index(elementI);
424 2433937 return massAndEnergyToMomentumStencils_[eIdx];
425 }
426
427 /*!
428 * \brief returns an iterable container of all indices of degrees of freedom of domain j
429 * that couple with / influence the residual of the given sub-control volume of domain i
430 *
431 * \param domainI the domain index of domain i
432 * \param elementI the coupled element of domain í
433 * \param scvI the sub-control volume of domain i
434 * \param domainJ the domain index of domain j
435 */
436 9753428 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
440 {
441 9753428 return momentumToMassAndEnergyStencils_[scvI.index()];
442 }
443
444 // \}
445
446 /*!
447 * \name member functions concerning variable caching for element residual evaluations
448 */
449 // \{
450
451 //! \copydoc CouplingManager::updateCouplingContext
452 template<std::size_t i, std::size_t j, class LocalAssemblerI>
453 185250256 void updateCouplingContext(Dune::index_constant<i> domainI,
454 const LocalAssemblerI& localAssemblerI,
455 Dune::index_constant<j> domainJ,
456 std::size_t dofIdxGlobalJ,
457 const PrimaryVariables<j>& priVarsJ,
458 int pvIdxJ)
459 {
460
3/4
✓ Branch 2 taken 705218 times.
✓ Branch 3 taken 456288 times.
✓ Branch 4 taken 7072 times.
✗ Branch 5 not taken.
185250256 this->curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
461
462 if constexpr (domainI == freeFlowMomentumIndex && domainJ == freeFlowMassIndex)
463 {
464 32100956 bindCouplingContext_(domainI, localAssemblerI.element());
465
466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32100956 times.
32100956 const auto& problem = this->problem(domainJ);
467 32100956 const auto& deflectedElement = problem.gridGeometry().element(dofIdxGlobalJ);
468
1/2
✓ Branch 1 taken 56576 times.
✗ Branch 2 not taken.
32100956 const auto elemSol = elementSolution(deflectedElement, this->curSol(domainJ), problem.gridGeometry());
469 32100956 const auto& fvGeometry = momentumCouplingContext_()[0].fvGeometry;
470 32100956 const auto scvIdxJ = dofIdxGlobalJ;
471
2/3
✓ Branch 0 taken 468288 times.
✓ Branch 1 taken 881888 times.
✗ Branch 2 not taken.
32100956 const auto& scv = fvGeometry.scv(scvIdxJ);
472
473 if constexpr (ElementVolumeVariables<freeFlowMassIndex>::GridVolumeVariables::cachingEnabled)
474
2/4
✓ Branch 1 taken 28288 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28288 times.
✗ Branch 5 not taken.
30807356 gridVars_(freeFlowMassIndex).curGridVolVars().volVars(scv).update(std::move(elemSol), problem, deflectedElement, scv);
475 else
476
1/2
✓ Branch 1 taken 28288 times.
✗ Branch 2 not taken.
1350176 momentumCouplingContext_()[0].curElemVolVars[scv].update(std::move(elemSol), problem, deflectedElement, scv);
477 56576 }
478 32100956 }
479
480 // \}
481
482 /*!
483 * \brief Compute colors for multithreaded assembly
484 */
485 void computeColorsForAssembly()
486 {
487 // use coloring of the fc staggered discretization for both domains
488 elementSets_ = computeColoring(this->problem(freeFlowMomentumIndex).gridGeometry()).sets;
489 }
490
491 /*!
492 * \brief Execute assembly kernel in parallel
493 *
494 * \param domainI the domain index of domain i
495 * \param assembleElement kernel function to execute for one element
496 */
497 template<std::size_t i, class AssembleElementFunc>
498 void assembleMultithreaded(Dune::index_constant<i> domainI, AssembleElementFunc&& assembleElement) const
499 {
500 if (elementSets_.empty())
501 DUNE_THROW(Dune::InvalidStateException, "Call computeColorsForAssembly before assembling in parallel!");
502
503 // make this element loop run in parallel
504 // for this we have to color the elements so that we don't get
505 // race conditions when writing into the global matrix
506 // each color can be assembled using multiple threads
507 const auto& grid = this->problem(freeFlowMomentumIndex).gridGeometry().gridView().grid();
508 for (const auto& elements : elementSets_)
509 {
510 Dumux::parallelFor(elements.size(), [&](const std::size_t eIdx)
511 {
512 const auto element = grid.entity(elements[eIdx]);
513 assembleElement(element);
514 });
515 }
516 }
517
518 private:
519 32100956 void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
520 const Element<freeFlowMomentumIndex>& elementI) const
521 {
522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32100956 times.
32100956 const auto eIdx = this->problem(freeFlowMomentumIndex).gridGeometry().elementMapper().index(elementI);
523 32100956 bindCouplingContext_(domainI, elementI, eIdx);
524 32100956 }
525
526 767880170 void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
527 const Element<freeFlowMomentumIndex>& elementI,
528 const std::size_t eIdx) const
529 {
530 767880170 if (momentumCouplingContext_().empty())
531 {
532
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
66 auto fvGeometry = localView(this->problem(freeFlowMassIndex).gridGeometry());
533 66 fvGeometry.bind(elementI);
534
535
3/5
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 59 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✗ Branch 3 not taken.
66 auto curElemVolVars = localView(gridVars_(freeFlowMassIndex).curGridVolVars());
536
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 curElemVolVars.bind(elementI, fvGeometry, this->curSol(freeFlowMassIndex));
537
538
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 38 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
104 auto prevElemVolVars = isTransient_() ? localView(gridVars_(freeFlowMassIndex).prevGridVolVars())
539
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 : localView(gridVars_(freeFlowMassIndex).curGridVolVars());
540
541
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
66 if (isTransient_())
542
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 prevElemVolVars.bindElement(elementI, fvGeometry, prevSol_(freeFlowMassIndex));
543
544
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 momentumCouplingContext_().emplace_back(MomentumCouplingContext{std::move(fvGeometry), std::move(curElemVolVars), std::move(prevElemVolVars), eIdx});
545 131 }
546 767880104 else if (eIdx != momentumCouplingContext_()[0].eIdx)
547 {
548 2755003 momentumCouplingContext_()[0].eIdx = eIdx;
549 5510006 momentumCouplingContext_()[0].fvGeometry.bind(elementI);
550 2786035 momentumCouplingContext_()[0].curElemVolVars.bind(elementI, momentumCouplingContext_()[0].fvGeometry, this->curSol(freeFlowMassIndex));
551
552
2/2
✓ Branch 0 taken 27499 times.
✓ Branch 1 taken 3533 times.
2755003 if (isTransient_())
553 27499 momentumCouplingContext_()[0].prevElemVolVars.bindElement(elementI, momentumCouplingContext_()[0].fvGeometry, prevSol_(freeFlowMassIndex));
554 }
555 767880236 }
556
557 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
558 const Element<freeFlowMassIndex>& elementI) const
559 {
560 const auto eIdx = this->problem(freeFlowMassIndex).gridGeometry().elementMapper().index(elementI);
561 bindCouplingContext_(domainI, elementI, eIdx);
562 }
563
564 141491854 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
565 const Element<freeFlowMassIndex>& elementI,
566 const std::size_t eIdx) const
567 {
568 141491854 if (massAndEnergyCouplingContext_().empty())
569 {
570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 const auto& gridGeometry = this->problem(freeFlowMomentumIndex).gridGeometry();
571 66 auto fvGeometry = localView(gridGeometry);
572 66 fvGeometry.bindElement(elementI);
573 66 massAndEnergyCouplingContext_().emplace_back(std::move(fvGeometry), eIdx);
574 }
575 141491788 else if (eIdx != massAndEnergyCouplingContext_()[0].eIdx)
576 {
577 26814208 massAndEnergyCouplingContext_()[0].eIdx = eIdx;
578 26814208 massAndEnergyCouplingContext_()[0].fvGeometry.bindElement(elementI);
579 }
580 141491854 }
581
582 /*!
583 * \brief Return a reference to the grid variables of a sub problem
584 * \param domainIdx The domain index
585 */
586 template<std::size_t i>
587 132 const GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx) const
588 {
589
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 if (std::get<i>(gridVariables_))
590 132 return *std::get<i>(gridVariables_);
591 else
592 DUNE_THROW(Dune::InvalidStateException, "The gridVariables pointer was not set. Use setGridVariables() before calling this function");
593 }
594
595 /*!
596 * \brief Return a reference to the grid variables of a sub problem
597 * \param domainIdx The domain index
598 */
599 template<std::size_t i>
600 30779068 GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
601 {
602
1/2
✓ Branch 0 taken 30779068 times.
✗ Branch 1 not taken.
30779068 if (std::get<i>(gridVariables_))
603 30779068 return *std::get<i>(gridVariables_);
604 else
605 DUNE_THROW(Dune::InvalidStateException, "The gridVariables pointer was not set. Use setGridVariables() before calling this function");
606 }
607
608
609 66 void computeCouplingStencils_()
610 {
611 // TODO higher order
612
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62 times.
66 const auto& momentumGridGeometry = this->problem(freeFlowMomentumIndex).gridGeometry();
613 66 auto momentumFvGeometry = localView(momentumGridGeometry);
614
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 massAndEnergyToMomentumStencils_.clear();
615 66 massAndEnergyToMomentumStencils_.resize(momentumGridGeometry.gridView().size(0));
616
617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 momentumToMassAndEnergyStencils_.clear();
618 66 momentumToMassAndEnergyStencils_.resize(momentumGridGeometry.numScv());
619
620
9/10
✓ Branch 2 taken 340459 times.
✓ Branch 3 taken 101 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 12338 times.
✓ Branch 8 taken 3539 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3536 times.
✓ Branch 11 taken 6 times.
✓ Branch 7 taken 12335 times.
✓ Branch 4 taken 100 times.
1065661 for (const auto& element : elements(momentumGridGeometry.gridView()))
621 {
622
2/4
✓ Branch 1 taken 3536 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3536 times.
✗ Branch 5 not taken.
356368 const auto eIdx = momentumGridGeometry.elementMapper().index(element);
623 368440 momentumFvGeometry.bind(element);
624
3/3
✓ Branch 0 taken 1372346 times.
✓ Branch 1 taken 398977 times.
✓ Branch 2 taken 14203 times.
2117693 for (const auto& scv : scvs(momentumFvGeometry))
625 {
626
1/2
✓ Branch 1 taken 63884 times.
✗ Branch 2 not taken.
1429158 massAndEnergyToMomentumStencils_[eIdx].push_back(scv.dofIndex());
627
1/2
✓ Branch 1 taken 63884 times.
✗ Branch 2 not taken.
1429158 momentumToMassAndEnergyStencils_[scv.index()].push_back(eIdx);
628
629 // extend the stencil for fluids with variable viscosity and density,
630 if constexpr (FluidSystem::isCompressible(0/*phaseIdx*/))
631 // if constexpr (FluidSystem::isCompressible(0/*phaseIdx*/) || !FluidSystem::viscosityIsConstant(0/*phaseIdx*/)) // TODO fix on master
632 {
633
4/4
✓ Branch 1 taken 65840 times.
✓ Branch 2 taken 34148 times.
✓ Branch 4 taken 99988 times.
✓ Branch 5 taken 32920 times.
298736 for (const auto& scvf : scvfs(momentumFvGeometry, scv))
634 {
635
4/4
✓ Branch 0 taken 65840 times.
✓ Branch 1 taken 34148 times.
✓ Branch 2 taken 63384 times.
✓ Branch 3 taken 2456 times.
99988 if (scvf.isLateral() && !scvf.boundary())
636 {
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53684 times.
63384 const auto& outsideScv = momentumFvGeometry.scv(scvf.outsideScvIdx());
638 63384 momentumToMassAndEnergyStencils_[scv.index()].push_back(outsideScv.elementIndex());
639 }
640 }
641 }
642 }
643 }
644 66 }
645
646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136301986 times.
141491854 std::size_t massScvfToMomentumScvIdx_(const SubControlVolumeFace<freeFlowMassIndex>& massScvf,
647 [[maybe_unused]] const FVElementGeometry<freeFlowMomentumIndex>& momentumFVGeometry) const
648 {
649 if constexpr (ConsistentlyOrientedGrid<typename GridView<freeFlowMomentumIndex>::Grid>{})
650
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136301986 times.
139387986 return massScvf.index();
651 else
652 {
653
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2103858 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
2103868 static const bool makeConsistentlyOriented = getParam<bool>("Grid.MakeConsistentlyOriented", true);
654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2103868 times.
2103868 if (!makeConsistentlyOriented)
655 return massScvf.index();
656
657
2/3
✓ Branch 1 taken 4795766 times.
✗ Branch 2 not taken.
✓ Branch 0 taken 457120 times.
5252886 for (const auto& momentumScv : scvs(momentumFVGeometry))
658 {
659 5252886 typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition momentumUnitOuterNormal(0.0);
660 5252886 momentumUnitOuterNormal[momentumScv.dofAxis()] = momentumScv.directionSign();
661
4/4
✓ Branch 0 taken 2097084 times.
✓ Branch 1 taken 3155802 times.
✓ Branch 2 taken 2103868 times.
✓ Branch 3 taken 3149018 times.
12602856 if (Dune::FloatCmp::eq<typename GridView<freeFlowMomentumIndex>::ctype>(massScvf.unitOuterNormal()*momentumUnitOuterNormal, 1.0))
662 2103868 return momentumScv.index();
663 }
664 DUNE_THROW(Dune::InvalidStateException, "No Momentum SCV found");
665 }
666 }
667
668 CouplingStencilType emptyStencil_;
669 std::vector<CouplingStencilType> momentumToMassAndEnergyStencils_;
670 std::vector<CouplingStencilType> massAndEnergyToMomentumStencils_;
671
672 66 std::vector<MomentumCouplingContext>& momentumCouplingContext_() const
673
30/33
✓ Branch 0 taken 9113008 times.
✓ Branch 1 taken 231702464 times.
✓ Branch 4 taken 4005552 times.
✓ Branch 5 taken 58594777 times.
✓ Branch 9 taken 63017 times.
✓ Branch 10 taken 279860778 times.
✓ Branch 14 taken 172860124 times.
✓ Branch 15 taken 562741650 times.
✓ Branch 16 taken 18536906 times.
✓ Branch 17 taken 3533 times.
✓ Branch 18 taken 8228699 times.
✓ Branch 19 taken 481753021 times.
✓ Branch 23 taken 70534641 times.
✓ Branch 24 taken 133467422 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 3716649 times.
✓ Branch 2 taken 924160 times.
✓ Branch 6 taken 79807429 times.
✓ Branch 11 taken 129609952 times.
✓ Branch 12 taken 23 times.
✓ Branch 13 taken 18942868 times.
✓ Branch 20 taken 9866588 times.
✓ Branch 25 taken 468256 times.
✓ Branch 29 taken 1947004 times.
✓ Branch 22 taken 653696 times.
✓ Branch 3 taken 2052568 times.
✓ Branch 7 taken 3 times.
✓ Branch 21 taken 857133 times.
✓ Branch 30 taken 4137472 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 26 taken 28288 times.
1754781449 { return momentumCouplingContextImpl_; }
674
675 66 std::vector<MassAndEnergyCouplingContext>& massAndEnergyCouplingContext_() const
676
8/9
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 141491788 times.
✓ Branch 3 taken 26814208 times.
✓ Branch 4 taken 114677580 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 136301986 times.
✓ Branch 8 taken 1921021 times.
✓ Branch 9 taken 58 times.
✓ Branch 10 taken 7 times.
282983840 { return massAndEnergyCouplingContextImpl_; }
677
678 mutable std::vector<MassAndEnergyCouplingContext> massAndEnergyCouplingContextImpl_;
679 mutable std::vector<MomentumCouplingContext> momentumCouplingContextImpl_;
680
681 //! A tuple of std::shared_ptrs to the grid variables of the sub problems
682 GridVariablesTuple gridVariables_;
683
684 79151078 bool isTransient_() const
685
12/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 54 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 27513 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 5791456 times.
✓ Branch 9 taken 3533 times.
✓ Branch 10 taken 52214920 times.
✓ Branch 11 taken 1947000 times.
✓ Branch 12 taken 18196400 times.
✓ Branch 13 taken 970200 times.
81875111 { return std::get<0>(prevSolutions_) != nullptr; }
686
687 template<std::size_t i>
688 27500 const SubSolutionVector<i>& prevSol_(Dune::index_constant<i>) const
689
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
27500 { return *std::get<i>(prevSolutions_); }
690
691 PrevSolutionVectorStorage prevSolutions_;
692
693 std::deque<std::vector<ElementSeed<freeFlowMomentumIndex>>> elementSets_;
694 };
695
696 // multi-threading is not supported because we have only one coupling context instance and a mutable cache
697 template<class T>
698 struct CouplingManagerSupportsMultithreadedAssembly<FCStaggeredFreeFlowCouplingManager<T>>
699 : public std::false_type {};
700
701 } // end namespace Dumux
702
703 #endif
704