GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/multidomain/freeflow/couplingmanager_staggered.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 165 189 87.3%
Functions: 258 477 54.1%
Branches: 192 339 56.6%

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-FileCopyrightInfo: 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 using CouplingStencilType = std::vector<std::size_t>;
77
78 using GridVariablesTuple = typename Traits::template TupleOfSharedPtr<GridVariables>;
79
80 using FluidSystem = typename VolumeVariables<freeFlowMassIndex>::FluidSystem;
81
82 using VelocityVector = typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition;
83 static_assert(std::is_same_v<VelocityVector, typename SubControlVolumeFace<freeFlowMomentumIndex>::GlobalPosition>);
84
85 96 struct MomentumCouplingContext
86 {
87 FVElementGeometry<freeFlowMassIndex> fvGeometry;
88 ElementVolumeVariables<freeFlowMassIndex> curElemVolVars;
89 ElementVolumeVariables<freeFlowMassIndex> prevElemVolVars;
90 std::size_t eIdx;
91 };
92
93 struct MassAndEnergyCouplingContext
94 {
95 55 MassAndEnergyCouplingContext(FVElementGeometry<freeFlowMomentumIndex>&& f, const std::size_t i)
96 55 : fvGeometry(std::move(f))
97 55 , eIdx(i)
98 {}
99
100 FVElementGeometry<freeFlowMomentumIndex> fvGeometry;
101 std::size_t eIdx;
102 };
103
104 public:
105
106 static constexpr auto pressureIdx = VolumeVariables<freeFlowMassIndex>::Indices::pressureIdx;
107
108 /*!
109 * \brief Methods to be accessed by main
110 */
111 // \{
112
113 //! use as regular coupling manager
114 39 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
115 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
116 GridVariablesTuple&& gridVariables,
117 const SolutionVector& curSol)
118 {
119 78 this->setSubProblems(std::make_tuple(momentumProblem, massProblem));
120 39 gridVariables_ = gridVariables;
121 39 this->updateSolution(curSol);
122
123 39 computeCouplingStencils_();
124 39 }
125
126 //! use as regular coupling manager in a transient setting
127 21 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
128 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
129 GridVariablesTuple&& gridVariables,
130 const SolutionVector& curSol,
131 const SolutionVector& prevSol)
132 {
133
3/10
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
42 init(momentumProblem, massProblem, std::forward<GridVariablesTuple>(gridVariables), curSol);
134 21 prevSol_ = &prevSol;
135 21 isTransient_ = true;
136 21 }
137
138 //! use as binary coupling manager in multi model context
139 16 void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
140 std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
141 GridVariablesTuple&& gridVariables,
142 typename ParentType::SolutionVectorStorage& curSol)
143 {
144 32 this->setSubProblems(std::make_tuple(momentumProblem, massProblem));
145 16 gridVariables_ = gridVariables;
146 16 this->attachSolution(curSol);
147
148 16 computeCouplingStencils_();
149 16 }
150
151 // \}
152
153 using CouplingManager<Traits>::evalCouplingResidual;
154
155 /*!
156 * \brief evaluates the element residual of a coupled element of domain i which depends on the variables
157 * at the degree of freedom with index dofIdxGlobalJ of domain j
158 *
159 * \param domainI the domain index of domain i
160 * \param localAssemblerI the local assembler assembling the element residual of an element of domain i
161 * \param scvI the sub-control-volume of domain i
162 * \param domainJ the domain index of domain j
163 * \param dofIdxGlobalJ the index of the degree of freedom of domain j which has an influence on the element residual of domain i
164 *
165 * \note the element whose residual is to be evaluated can be retrieved from the local assembler
166 * as localAssemblerI.element() as well as all up-to-date variables and caches.
167 * \note the default implementation evaluates the complete element residual
168 * if only parts (i.e. only certain scvs, or only certain terms of the residual) of the residual are coupled
169 * to dof with index dofIdxGlobalJ the function can be overloaded in the coupling manager
170 * \return the element residual
171 */
172 template<std::size_t j, class LocalAssemblerI>
173 23478912 decltype(auto) evalCouplingResidual(Dune::index_constant<freeFlowMomentumIndex> domainI,
174 const LocalAssemblerI& localAssemblerI,
175 const SubControlVolume<freeFlowMomentumIndex>& scvI,
176 Dune::index_constant<j> domainJ,
177 std::size_t dofIdxGlobalJ) const
178 {
179 23478912 const auto& problem = localAssemblerI.problem();
180 23478912 const auto& element = localAssemblerI.element();
181 23478912 const auto& fvGeometry = localAssemblerI.fvGeometry();
182 23478912 const auto& curElemVolVars = localAssemblerI.curElemVolVars();
183 23478912 const auto& prevElemVolVars = localAssemblerI.prevElemVolVars();
184 46899648 typename LocalAssemblerI::ElementResidualVector residual(localAssemblerI.element().subEntities(1));
185 23478912 const auto& localResidual = localAssemblerI.localResidual();
186
187 23478912 localResidual.evalSource(residual, problem, element, fvGeometry, curElemVolVars, scvI);
188
189
4/4
✓ Branch 1 taken 71081504 times.
✓ Branch 2 taken 23478912 times.
✓ Branch 3 taken 71081504 times.
✓ Branch 4 taken 23478912 times.
94560416 for (const auto& scvf : scvfs(fvGeometry, scvI))
190 213244512 localResidual.evalFlux(residual, problem, element, fvGeometry, curElemVolVars, localAssemblerI.elemBcTypes(), localAssemblerI.elemFluxVarsCache(), scvf);
191
192
4/4
✓ Branch 0 taken 16207792 times.
✓ Branch 1 taken 7271120 times.
✓ Branch 2 taken 16207792 times.
✓ Branch 3 taken 7271120 times.
46957824 if (!localAssemblerI.assembler().isStationaryProblem())
193 {
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16207792 times.
16207792 assert(isTransient_);
195 16207792 localResidual.evalStorage(residual, problem, element, fvGeometry, prevElemVolVars, curElemVolVars, scvI);
196 }
197
198 23478912 return residual;
199 }
200
201 /*!
202 * \name member functions concerning the coupling stencils
203 */
204 // \{
205
206 /*!
207 * \brief Returns the pressure at a given _frontal_ sub control volume face.
208 */
209 Scalar pressure(const Element<freeFlowMomentumIndex>& element,
210 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
211 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf) const
212 {
213 assert(scvf.isFrontal() && !scvf.isLateral() && !scvf.boundary());
214 return this->curSol(freeFlowMassIndex)[fvGeometry.elementIndex()][pressureIdx];
215 }
216
217 /*!
218 * \brief Returns the pressure at the center of a sub control volume corresponding to a given sub control volume face.
219 * This is used for setting a Dirichlet pressure for the mass model when a fixed pressure for the momentum balance is set at another
220 * boundary. Since the the pressure at the given scvf is solution-dependent and thus unknown a priori, we just use the value
221 * of the interior cell here.
222 */
223 Scalar cellPressure(const Element<freeFlowMassIndex>& element,
224 const SubControlVolumeFace<freeFlowMassIndex>& scvf) const
225 {
226
20/20
✓ Branch 0 taken 1420 times.
✓ Branch 1 taken 9300 times.
✓ Branch 2 taken 1420 times.
✓ Branch 3 taken 9300 times.
✓ Branch 4 taken 1420 times.
✓ Branch 5 taken 9300 times.
✓ Branch 6 taken 1420 times.
✓ Branch 7 taken 9300 times.
✓ Branch 8 taken 1420 times.
✓ Branch 9 taken 9300 times.
✓ Branch 10 taken 2050 times.
✓ Branch 11 taken 1750 times.
✓ Branch 12 taken 2050 times.
✓ Branch 13 taken 1750 times.
✓ Branch 14 taken 2050 times.
✓ Branch 15 taken 1750 times.
✓ Branch 16 taken 2050 times.
✓ Branch 17 taken 1750 times.
✓ Branch 18 taken 2050 times.
✓ Branch 19 taken 1750 times.
83300 return this->curSol(freeFlowMassIndex)[scvf.insideScvIdx()][pressureIdx];
227 }
228
229 /*!
230 * \brief Returns the density at a given sub control volume face.
231 */
232 65362606 Scalar density(const Element<freeFlowMomentumIndex>& element,
233 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
234 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
235 const bool considerPreviousTimeStep = false) const
236 {
237
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 65362606 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
65362606 assert(!(considerPreviousTimeStep && !isTransient_));
238 128813060 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
239
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 63450454 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63450454 times.
130725212 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
240
2/2
✓ Branch 1 taken 1912152 times.
✓ Branch 2 taken 63450454 times.
65362606 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
241
242 196002078 const auto rho = [&](const auto& elemVolVars)
243 {
244
2/2
✓ Branch 0 taken 85740 times.
✓ Branch 1 taken 65276866 times.
65362606 if (scvf.boundary())
245 85740 return elemVolVars[insideMassScv].density();
246 else
247 {
248
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 63373338 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63373338 times.
130553732 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
249
1/2
✓ Branch 1 taken 1903528 times.
✗ Branch 2 not taken.
65276866 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
250 // TODO distance weighting
251 65276866 return 0.5*(elemVolVars[insideMassScv].density() + elemVolVars[outsideMassScv].density());
252 }
253 };
254
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65362606 times.
65362606 return considerPreviousTimeStep ? rho(momentumCouplingContext_()[0].prevElemVolVars)
256 65362606 : rho(momentumCouplingContext_()[0].curElemVolVars);
257 }
258
259 129364612 auto insideAndOutsideDensity(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 129364612 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
129364612 assert(!(considerPreviousTimeStep && !isTransient_));
265 255012104 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
266
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 125647492 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 125647492 times.
258729224 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
267
3/4
✓ Branch 1 taken 3717120 times.
✓ Branch 2 taken 125647492 times.
✓ Branch 3 taken 3717120 times.
✗ Branch 4 not taken.
129364612 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
268
269 388042948 const auto result = [&](const auto& elemVolVars)
270 {
271
2/2
✓ Branch 0 taken 50888 times.
✓ Branch 1 taken 129313724 times.
129364612 if (scvf.boundary())
272 50888 return std::make_pair(elemVolVars[insideMassScv].density(), elemVolVars[insideMassScv].density());
273 else
274 {
275
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 125597132 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 125597132 times.
258627448 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
276
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3716592 times.
129313724 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
277 129313724 return std::make_pair(elemVolVars[insideMassScv].density(), elemVolVars[outsideMassScv].density());
278 }
279 };
280
281 return considerPreviousTimeStep ? result(momentumCouplingContext_()[0].prevElemVolVars)
282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129364612 times.
129364612 : result(momentumCouplingContext_()[0].curElemVolVars);
283 }
284
285 /*!
286 * \brief Returns the density at a given sub control volume.
287 */
288 200944950 Scalar density(const Element<freeFlowMomentumIndex>& element,
289 const SubControlVolume<freeFlowMomentumIndex>& scv,
290 const bool considerPreviousTimeStep = false) const
291 {
292
3/4
✓ Branch 0 taken 52411520 times.
✓ Branch 1 taken 148533430 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 52411520 times.
200944950 assert(!(considerPreviousTimeStep && !isTransient_));
293 200944950 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, scv.elementIndex());
294
4/4
✓ Branch 1 taken 52411520 times.
✓ Branch 2 taken 148533430 times.
✓ Branch 3 taken 50464520 times.
✓ Branch 4 taken 144395958 times.
200944950 const auto& massScv = (*scvs(momentumCouplingContext_()[0].fvGeometry).begin());
295
296
2/2
✓ Branch 0 taken 52411520 times.
✓ Branch 1 taken 148533430 times.
493874338 return considerPreviousTimeStep ? momentumCouplingContext_()[0].prevElemVolVars[massScv].density()
297 148533430 : momentumCouplingContext_()[0].curElemVolVars[massScv].density();
298 }
299
300 /*!
301 * \brief Returns the pressure at a given sub control volume face.
302 */
303 280919120 Scalar effectiveViscosity(const Element<freeFlowMomentumIndex>& element,
304 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
305 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf) const
306 {
307 555680536 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
308
309
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 274761416 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 274761416 times.
561838240 const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
310
2/2
✓ Branch 1 taken 8925270 times.
✓ Branch 2 taken 271993850 times.
280919120 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
311
312
2/2
✓ Branch 0 taken 2867150 times.
✓ Branch 1 taken 278051970 times.
280919120 if (scvf.boundary())
313 2867150 return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
314
315
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 271993850 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 271993850 times.
556103940 const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
316
2/2
✓ Branch 1 taken 2052568 times.
✓ Branch 2 taken 4005552 times.
278051970 const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
317
318 834155910 const auto mu = [&](const auto& elemVolVars)
319 {
320 // TODO distance weighting
321 278051970 return 0.5*(elemVolVars[insideMassScv].viscosity() + elemVolVars[outsideMassScv].viscosity());
322 };
323
324 278051970 return mu(momentumCouplingContext_()[0].curElemVolVars);
325 }
326
327 /*!
328 * \brief Returns the pressure at a given sub control volume.
329 */
330 90344 Scalar effectiveViscosity(const Element<freeFlowMomentumIndex>& element,
331 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
332 const SubControlVolume<freeFlowMomentumIndex>& scv) const
333 {
334 180688 bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
335 90344 const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(scv.elementIndex());
336 90344 return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
337 }
338
339 /*!
340 * \brief Returns the velocity at a given sub control volume face.
341 */
342 127071136 VelocityVector faceVelocity(const Element<freeFlowMassIndex>& element,
343 const SubControlVolumeFace<freeFlowMassIndex>& scvf) const
344 {
345 // TODO: rethink this! Maybe we only need scvJ.dofIndex()
346 254142272 bindCouplingContext_(Dune::index_constant<freeFlowMassIndex>(), element, scvf.insideScvIdx()/*eIdx*/);
347
348 // the TPFA scvf index corresponds to the staggered scv index (might need mapping)
349 127071136 const auto localMomentumScvIdx = massScvfToMomentumScvIdx_(scvf, massAndEnergyCouplingContext_()[0].fvGeometry);
350
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 123609520 times.
✓ Branch 2 taken 192768 times.
127071136 const auto& scvJ = massAndEnergyCouplingContext_()[0].fvGeometry.scv(localMomentumScvIdx);
351
352 // create a unit normal vector oriented in positive coordinate direction
353 127071136 typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition velocity;
354 127071136 velocity[scvJ.dofAxis()] = 1.0;
355
356 // create the actual velocity vector
357 381216016 velocity *= this->curSol(freeFlowMomentumIndex)[scvJ.dofIndex()];
358
359 127071136 return velocity;
360 }
361
362 /*!
363 * \brief The coupling stencil of domain I, i.e. which domain J DOFs
364 * the given domain I scv's residual depends on.
365 *
366 * \param domainI the domain index of domain i
367 * \param elementI the coupled element of domain í
368 * \param scvI the sub-control volume of domain i
369 * \param domainJ the domain index of domain j
370 */
371 template<std::size_t j>
372 const CouplingStencilType& couplingStencil(Dune::index_constant<freeFlowMomentumIndex> domainI,
373 const Element<freeFlowMomentumIndex>& elementI,
374 const SubControlVolume<freeFlowMomentumIndex>& scvI,
375 Dune::index_constant<j> domainJ) const
376 { return emptyStencil_; }
377
378 /*!
379 * \brief returns an iterable container of all indices of degrees of freedom of domain j
380 * that couple with / influence the element residual of the given element of domain i
381 *
382 * \param domainI the domain index of domain i
383 * \param elementI the coupled element of domain í
384 * \param domainJ the domain index of domain j
385 *
386 * \note The element residual definition depends on the discretization scheme of domain i
387 * box: a container of the residuals of all sub control volumes
388 * cc : the residual of the (sub) control volume
389 * fem: the residual of the element
390 * \note This function has to be implemented by all coupling managers for all combinations of i and j
391 */
392 const CouplingStencilType& couplingStencil(Dune::index_constant<freeFlowMassIndex> domainI,
393 const Element<freeFlowMassIndex>& elementI,
394 Dune::index_constant<freeFlowMomentumIndex> domainJ) const
395 {
396 const auto eIdx = this->problem(freeFlowMassIndex).gridGeometry().elementMapper().index(elementI);
397 return massAndEnergyToMomentumStencils_[eIdx];
398 }
399
400 /*!
401 * \brief returns an iterable container of all indices of degrees of freedom of domain j
402 * that couple with / influence the residual of the given sub-control volume of domain i
403 *
404 * \param domainI the domain index of domain i
405 * \param elementI the coupled element of domain í
406 * \param scvI the sub-control volume of domain i
407 * \param domainJ the domain index of domain j
408 */
409 const CouplingStencilType& couplingStencil(Dune::index_constant<freeFlowMomentumIndex> domainI,
410 const Element<freeFlowMomentumIndex>& elementI,
411 const SubControlVolume<freeFlowMomentumIndex>& scvI,
412 Dune::index_constant<freeFlowMassIndex> domainJ) const
413 {
414 17959632 return momentumToMassAndEnergyStencils_[scvI.index()];
415 }
416
417 // \}
418
419 /*!
420 * \name member functions concerning variable caching for element residual evaluations
421 */
422 // \{
423
424 //! \copydoc CouplingManager::updateCouplingContext
425 template<std::size_t i, std::size_t j, class LocalAssemblerI>
426 55596704 void updateCouplingContext(Dune::index_constant<i> domainI,
427 const LocalAssemblerI& localAssemblerI,
428 Dune::index_constant<j> domainJ,
429 std::size_t dofIdxGlobalJ,
430 const PrimaryVariables<j>& priVarsJ,
431 int pvIdxJ)
432 {
433
14/16
✗ Branch 0 not taken.
✓ Branch 1 taken 1199200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1904300 times.
✓ Branch 4 taken 246504 times.
✓ Branch 5 taken 1904300 times.
✓ Branch 6 taken 246620 times.
✓ Branch 7 taken 897656 times.
✓ Branch 8 taken 246620 times.
✓ Branch 9 taken 185535 times.
✓ Branch 10 taken 53037 times.
✓ Branch 11 taken 185535 times.
✓ Branch 12 taken 45965 times.
✓ Branch 13 taken 192556 times.
✓ Branch 14 taken 116 times.
✓ Branch 15 taken 185484 times.
596355424 this->curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
434
435 if constexpr (domainI == freeFlowMomentumIndex && domainJ == freeFlowMassIndex)
436 {
437 55596704 bindCouplingContext_(domainI, localAssemblerI.element());
438
439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27798352 times.
55596704 const auto& problem = this->problem(domainJ);
440 111193408 const auto& deflectedElement = problem.gridGeometry().element(dofIdxGlobalJ);
441
3/6
✓ Branch 1 taken 56576 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 56576 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 56576 times.
✗ Branch 8 not taken.
166790112 const auto elemSol = elementSolution(deflectedElement, this->curSol(domainJ), problem.gridGeometry());
442 55596704 const auto& fvGeometry = momentumCouplingContext_()[0].fvGeometry;
443 55596704 const auto scvIdxJ = dofIdxGlobalJ;
444
2/3
✓ Branch 0 taken 468288 times.
✓ Branch 1 taken 881888 times.
✗ Branch 2 not taken.
55596704 const auto& scv = fvGeometry.scv(scvIdxJ);
445
446 if constexpr (ElementVolumeVariables<freeFlowMassIndex>::GridVolumeVariables::cachingEnabled)
447
3/6
✓ Branch 1 taken 28288 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28288 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 28288 times.
✗ Branch 8 not taken.
52952928 gridVars_(freeFlowMassIndex).curGridVolVars().volVars(scv).update(std::move(elemSol), problem, deflectedElement, scv);
448 else
449
1/2
✓ Branch 3 taken 28288 times.
✗ Branch 4 not taken.
2643776 momentumCouplingContext_()[0].curElemVolVars[scv].update(std::move(elemSol), problem, deflectedElement, scv);
450 }
451 55596704 }
452
453 // \}
454
455 /*!
456 * \brief Compute colors for multithreaded assembly
457 */
458 void computeColorsForAssembly()
459 {
460 // use coloring of the fc staggered discretization for both domains
461 elementSets_ = computeColoring(this->problem(freeFlowMomentumIndex).gridGeometry()).sets;
462 }
463
464 /*!
465 * \brief Execute assembly kernel in parallel
466 *
467 * \param domainI the domain index of domain i
468 * \param assembleElement kernel function to execute for one element
469 */
470 template<std::size_t i, class AssembleElementFunc>
471 void assembleMultithreaded(Dune::index_constant<i> domainI, AssembleElementFunc&& assembleElement) const
472 {
473 if (elementSets_.empty())
474 DUNE_THROW(Dune::InvalidStateException, "Call computeColorsForAssembly before assembling in parallel!");
475
476 // make this element loop run in parallel
477 // for this we have to color the elements so that we don't get
478 // race conditions when writing into the global matrix
479 // each color can be assembled using multiple threads
480 const auto& grid = this->problem(freeFlowMomentumIndex).gridGeometry().gridView().grid();
481 for (const auto& elements : elementSets_)
482 {
483 Dumux::parallelFor(elements.size(), [&](const std::size_t eIdx)
484 {
485 const auto element = grid.entity(elements[eIdx]);
486 assembleElement(element);
487 });
488 }
489 }
490
491 private:
492 void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
493 const Element<freeFlowMomentumIndex>& elementI) const
494 {
495 const auto eIdx = this->problem(freeFlowMomentumIndex).gridGeometry().elementMapper().index(elementI);
496 bindCouplingContext_(domainI, elementI, eIdx);
497 }
498
499 704479984 void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
500 const Element<freeFlowMomentumIndex>& elementI,
501 const std::size_t eIdx) const
502 {
503
4/4
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 704479929 times.
✓ Branch 3 taken 55 times.
✓ Branch 4 taken 704479929 times.
704479984 if (momentumCouplingContext_().empty())
504 {
505
3/8
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
62 auto fvGeometry = localView(this->problem(freeFlowMassIndex).gridGeometry());
506
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
55 fvGeometry.bind(elementI);
507
508
6/10
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
110 auto curElemVolVars = localView(gridVars_(freeFlowMassIndex).curGridVolVars());
509
2/4
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
110 curElemVolVars.bind(elementI, fvGeometry, this->curSol(freeFlowMassIndex));
510
511
3/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 34 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
55 auto prevElemVolVars = isTransient_ ? localView(gridVars_(freeFlowMassIndex).prevGridVolVars())
512
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 : localView(gridVars_(freeFlowMassIndex).curGridVolVars());
513
514
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (isTransient_)
515
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 prevElemVolVars.bindElement(elementI, fvGeometry, (*prevSol_)[freeFlowMassIndex]);
516
517
7/11
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 44 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 11 times.
✓ Branch 10 taken 44 times.
✗ Branch 11 not taken.
235 momentumCouplingContext_().emplace_back(MomentumCouplingContext{std::move(fvGeometry), std::move(curElemVolVars), std::move(prevElemVolVars), eIdx});
518 }
519
2/2
✓ Branch 1 taken 2599055 times.
✓ Branch 2 taken 701880874 times.
704479929 else if (eIdx != momentumCouplingContext_()[0].eIdx)
520 {
521 2599055 momentumCouplingContext_()[0].eIdx = eIdx;
522 2599055 momentumCouplingContext_()[0].fvGeometry.bind(elementI);
523 2599055 momentumCouplingContext_()[0].curElemVolVars.bind(elementI, momentumCouplingContext_()[0].fvGeometry, this->curSol(freeFlowMassIndex));
524
525
2/2
✓ Branch 0 taken 1244783 times.
✓ Branch 1 taken 1354272 times.
2599055 if (isTransient_)
526 1244783 momentumCouplingContext_()[0].prevElemVolVars.bindElement(elementI, momentumCouplingContext_()[0].fvGeometry, (*prevSol_)[freeFlowMassIndex]);
527 }
528 704479984 }
529
530 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
531 const Element<freeFlowMassIndex>& elementI) const
532 {
533 const auto eIdx = this->problem(freeFlowMassIndex).gridGeometry().elementMapper().index(elementI);
534 bindCouplingContext_(domainI, elementI, eIdx);
535 }
536
537 127071136 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
538 const Element<freeFlowMassIndex>& elementI,
539 const std::size_t eIdx) const
540 {
541
4/4
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 127071081 times.
✓ Branch 3 taken 55 times.
✓ Branch 4 taken 127071081 times.
127071136 if (massAndEnergyCouplingContext_().empty())
542 {
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 const auto& gridGeometry = this->problem(freeFlowMomentumIndex).gridGeometry();
544 55 auto fvGeometry = localView(gridGeometry);
545 55 fvGeometry.bindElement(elementI);
546 55 massAndEnergyCouplingContext_().emplace_back(std::move(fvGeometry), eIdx);
547 }
548
2/2
✓ Branch 1 taken 24476096 times.
✓ Branch 2 taken 102594985 times.
127071081 else if (eIdx != massAndEnergyCouplingContext_()[0].eIdx)
549 {
550 24476096 massAndEnergyCouplingContext_()[0].eIdx = eIdx;
551 24476096 massAndEnergyCouplingContext_()[0].fvGeometry.bindElement(elementI);
552 }
553 127071136 }
554
555 /*!
556 * \brief Return a reference to the grid variables of a sub problem
557 * \param domainIdx The domain index
558 */
559 template<std::size_t i>
560 110 const GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx) const
561 {
562
2/4
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
220 if (std::get<i>(gridVariables_))
563 330 return *std::get<i>(gridVariables_);
564 else
565 DUNE_THROW(Dune::InvalidStateException, "The gridVariables pointer was not set. Use setGridVariables() before calling this function");
566 }
567
568 /*!
569 * \brief Return a reference to the grid variables of a sub problem
570 * \param domainIdx The domain index
571 */
572 template<std::size_t i>
573 26476464 GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
574 {
575
2/4
✓ Branch 0 taken 26476464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26476464 times.
✗ Branch 3 not taken.
52952928 if (std::get<i>(gridVariables_))
576 79429392 return *std::get<i>(gridVariables_);
577 else
578 DUNE_THROW(Dune::InvalidStateException, "The gridVariables pointer was not set. Use setGridVariables() before calling this function");
579 }
580
581
582 55 void computeCouplingStencils_()
583 {
584 // TODO higher order
585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 const auto& momentumGridGeometry = this->problem(freeFlowMomentumIndex).gridGeometry();
586 55 auto momentumFvGeometry = localView(momentumGridGeometry);
587 55 massAndEnergyToMomentumStencils_.clear();
588 111 massAndEnergyToMomentumStencils_.resize(momentumGridGeometry.gridView().size(0));
589
590 55 momentumToMassAndEnergyStencils_.clear();
591 106 momentumToMassAndEnergyStencils_.resize(momentumGridGeometry.numScv());
592
593
11/14
✓ Branch 2 taken 327323 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 100 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3536 times.
✓ Branch 9 taken 6 times.
✓ Branch 10 taken 3536 times.
✓ Branch 11 taken 6 times.
✓ Branch 13 taken 3536 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 3536 times.
✗ Branch 17 not taken.
665281 for (const auto& element : elements(momentumGridGeometry.gridView()))
594 {
595
2/4
✓ Branch 1 taken 3536 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3536 times.
✗ Branch 5 not taken.
661620 const auto eIdx = momentumGridGeometry.elementMapper().index(element);
596
1/2
✓ Branch 1 taken 3536 times.
✗ Branch 2 not taken.
330810 momentumFvGeometry.bind(element);
597
5/5
✓ Branch 0 taken 12072 times.
✓ Branch 1 taken 1315986 times.
✓ Branch 2 taken 327792 times.
✓ Branch 3 taken 1312968 times.
✓ Branch 4 taken 327792 times.
2946418 for (const auto& scv : scvs(momentumFvGeometry))
598 {
599
2/4
✓ Branch 1 taken 14144 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14144 times.
✗ Branch 5 not taken.
2650080 massAndEnergyToMomentumStencils_[eIdx].push_back(scv.dofIndex());
600
2/4
✓ Branch 1 taken 14144 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14144 times.
✗ Branch 5 not taken.
2650080 momentumToMassAndEnergyStencils_[scv.index()].push_back(eIdx);
601
602 // extend the stencil for fluids with variable viscosity and density,
603 if constexpr (FluidSystem::isCompressible(0/*phaseIdx*/))
604 // if constexpr (FluidSystem::isCompressible(0/*phaseIdx*/) || !FluidSystem::viscosityIsConstant(0/*phaseIdx*/)) // TODO fix on master
605 {
606
4/4
✓ Branch 1 taken 83170 times.
✓ Branch 2 taken 27400 times.
✓ Branch 3 taken 83170 times.
✓ Branch 4 taken 27400 times.
110570 for (const auto& scvf : scvfs(momentumFvGeometry, scv))
607 {
608
4/4
✓ Branch 0 taken 54800 times.
✓ Branch 1 taken 28370 times.
✓ Branch 2 taken 52860 times.
✓ Branch 3 taken 1940 times.
83170 if (scvf.isLateral() && !scvf.boundary())
609 {
610
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 43160 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 43160 times.
105720 const auto& outsideScv = momentumFvGeometry.scv(scvf.outsideScvIdx());
611 105720 momentumToMassAndEnergyStencils_[scv.index()].push_back(outsideScv.elementIndex());
612 }
613 }
614 }
615 }
616 }
617 55 }
618
619 375616 std::size_t massScvfToMomentumScvIdx_(const SubControlVolumeFace<freeFlowMassIndex>& massScvf,
620 [[maybe_unused]] const FVElementGeometry<freeFlowMomentumIndex>& momentumFVGeometry) const
621 {
622 if constexpr (ConsistentlyOrientedGrid<typename GridView<freeFlowMomentumIndex>::Grid>{})
623 126695520 return massScvf.index();
624 else
625 {
626
4/6
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 375609 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
375616 static const bool makeConsistentlyOriented = getParam<bool>("Grid.MakeConsistentlyOriented", true);
627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 375616 times.
375616 if (!makeConsistentlyOriented)
628 return massScvf.index();
629
630
3/5
✓ Branch 0 taken 457120 times.
✓ Branch 1 taken 482000 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 482000 times.
✗ Branch 4 not taken.
1121968 for (const auto& momentumScv : scvs(momentumFVGeometry))
631 {
632 939120 typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition momentumUnitOuterNormal(0.0);
633 939120 momentumUnitOuterNormal[momentumScv.dofAxis()] = momentumScv.directionSign();
634
4/4
✓ Branch 0 taken 375696 times.
✓ Branch 1 taken 563424 times.
✓ Branch 2 taken 375616 times.
✓ Branch 3 taken 563504 times.
3193056 if (Dune::FloatCmp::eq<typename GridView<freeFlowMomentumIndex>::ctype>(massScvf.unitOuterNormal()*momentumUnitOuterNormal, 1.0))
635 375616 return momentumScv.index();
636 }
637 DUNE_THROW(Dune::InvalidStateException, "No Momentum SCV found");
638 }
639 }
640
641 CouplingStencilType emptyStencil_;
642 std::vector<CouplingStencilType> momentumToMassAndEnergyStencils_;
643 std::vector<CouplingStencilType> massAndEnergyToMomentumStencils_;
644
645 // the coupling context exists for each thread
646 // TODO this is a bad pattern, just like mutable caches
647 // we should really construct and pass the context and not store it globally
648 std::vector<MomentumCouplingContext>& momentumCouplingContext_() const
649 {
650 thread_local static std::vector<MomentumCouplingContext> c;
651 return c;
652 }
653
654 // the coupling context exists for each thread
655 std::vector<MassAndEnergyCouplingContext>& massAndEnergyCouplingContext_() const
656 {
657 thread_local static std::vector<MassAndEnergyCouplingContext> c;
658 return c;
659 }
660
661 //! A tuple of std::shared_ptrs to the grid variables of the sub problems
662 GridVariablesTuple gridVariables_;
663
664 const SolutionVector* prevSol_;
665 bool isTransient_;
666
667 std::deque<std::vector<ElementSeed<freeFlowMomentumIndex>>> elementSets_;
668 };
669
670 //! TODO The infrastructure for multithreaded assembly is implemented (see code in the class above) but the current implementation seems to have a bug and may cause race conditions. The result is different when running in parallel. After this has been fixed activate multithreaded assembly by inheriting from std::true_type here.
671 template<class T>
672 struct CouplingManagerSupportsMultithreadedAssembly<FCStaggeredFreeFlowCouplingManager<T>>
673 : public std::false_type {};
674
675 } // end namespace Dumux
676
677 #endif
678