GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 73 96 76.0%
Functions: 11 23 47.8%
Branches: 95 206 46.1%

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 FreeFlowPoreNetworkCoupling
10 * \copydoc Dumux::FreeFlowMassPoreNetworkCouplingManager
11 */
12
13 #ifndef DUMUX_MULTIDOMAIN_BOUNDARY_FREEFLOWPORENETWORK_FFMASSPORENETWORK_COUPLINGMANAGER_HH
14 #define DUMUX_MULTIDOMAIN_BOUNDARY_FREEFLOWPORENETWORK_FFMASSPORENETWORK_COUPLINGMANAGER_HH
15
16 #include <utility>
17 #include <memory>
18
19 #include <dune/common/float_cmp.hh>
20 #include <dune/common/exceptions.hh>
21 #include <dumux/common/properties.hh>
22 #include <dumux/discretization/staggered/elementsolution.hh>
23 #include <dumux/multidomain/couplingmanager.hh>
24 #include <dumux/multidomain/boundary/freeflowporenetwork/couplingmapper.hh>
25
26 namespace Dumux {
27
28 /*!
29 * \ingroup FreeFlowPoreNetworkCoupling
30 * \brief Coupling manager for free-flow mass and pore-network models.
31 */
32 template<class MDTraits>
33 class FreeFlowMassPoreNetworkCouplingManager
34 : public CouplingManager<MDTraits>
35 {
36 using Scalar = typename MDTraits::Scalar;
37 using ParentType = CouplingManager<MDTraits>;
38
39 public:
40 static constexpr auto freeFlowMassIndex = typename MDTraits::template SubDomain<0>::Index();
41 static constexpr auto poreNetworkIndex = typename MDTraits::template SubDomain<1>::Index();
42
43 using SolutionVectorStorage = typename ParentType::SolutionVectorStorage;
44 private:
45
46 // obtain the type tags of the sub problems
47 using FreeFlowMassTypeTag = typename MDTraits::template SubDomain<freeFlowMassIndex>::TypeTag;
48 using PoreNetworkTypeTag = typename MDTraits::template SubDomain<poreNetworkIndex>::TypeTag;
49
50 using CouplingStencils = std::unordered_map<std::size_t, std::vector<std::size_t> >;
51 using CouplingStencil = CouplingStencils::mapped_type;
52
53 // the sub domain type tags
54 template<std::size_t id>
55 using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag;
56
57 template<std::size_t id> using GridView = typename GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>::GridView;
58 template<std::size_t id> using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>;
59 template<std::size_t id> using ElementVolumeVariables = typename GetPropType<SubDomainTypeTag<id>, Properties::GridVolumeVariables>::LocalView;
60 template<std::size_t id> using GridVolumeVariables = GetPropType<SubDomainTypeTag<id>, Properties::GridVolumeVariables>;
61 template<std::size_t id> using VolumeVariables = typename GetPropType<SubDomainTypeTag<id>, Properties::GridVolumeVariables>::VolumeVariables;
62 template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>;
63 template<std::size_t id> using FVElementGeometry = typename GridGeometry<id>::LocalView;
64 template<std::size_t id> using GridVariables = GetPropType<SubDomainTypeTag<id>, Properties::GridVariables>;
65 template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity;
66 template<std::size_t id> using PrimaryVariables = GetPropType<SubDomainTypeTag<id>, Properties::PrimaryVariables>;
67 template<std::size_t id> using SubControlVolumeFace = typename FVElementGeometry<id>::SubControlVolumeFace;
68 template<std::size_t id> using SubControlVolume = typename FVElementGeometry<id>::SubControlVolume;
69
70 using VelocityVector = typename Element<freeFlowMassIndex>::Geometry::GlobalCoordinate;
71
72 struct FreeFlowMassCouplingContext
73 {
74 SubControlVolume<poreNetworkIndex> scv;
75 VolumeVariables<poreNetworkIndex> volVars;
76 mutable VelocityVector velocity; // velocity needs to be set externally, not available in this class
77 };
78
79 struct PoreNetworkCouplingContext
80 {
81 SubControlVolume<freeFlowMassIndex> scv;
82 SubControlVolumeFace<freeFlowMassIndex> scvf;
83 VolumeVariables<freeFlowMassIndex> volVars;
84 mutable VelocityVector velocity; // velocity needs to be set externally, not available in this class
85 };
86
87 using CouplingMapper = StaggeredFreeFlowPoreNetworkCouplingMapper;
88
89 public:
90
91 /*!
92 * \brief Methods to be accessed by main
93 */
94 // \{
95
96 //! Initialize the coupling manager
97 2 void init(std::shared_ptr<Problem<freeFlowMassIndex>> freeFlowMassProblem,
98 std::shared_ptr<Problem<poreNetworkIndex>> pnmProblem,
99 std::shared_ptr<CouplingMapper> couplingMapper,
100 SolutionVectorStorage& curSol)
101 {
102 2 couplingMapper_ = couplingMapper;
103 4 this->setSubProblems(std::make_tuple(freeFlowMassProblem, pnmProblem));
104 2 this->attachSolution(curSol);
105 2 }
106
107 // \}
108
109 /*!
110 * \brief Methods to be accessed by the assembly
111 */
112 // \{
113
114 /*!
115 * \brief prepares all data and variables that are necessary to evaluate the residual (called from the local assembler)
116 */
117 template<std::size_t i, class Assembler>
118 void bindCouplingContext(Dune::index_constant<i> domainI, const Element<i>& element, const Assembler& assembler) const
119 {
120
0/18
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
966 bindCouplingContext_(domainI, element);
121 }
122
123 /*!
124 * \brief Update the coupling context
125 */
126 template<std::size_t i, std::size_t j, class LocalAssemblerI>
127 4312 void updateCouplingContext(Dune::index_constant<i> domainI,
128 const LocalAssemblerI& localAssemblerI,
129 Dune::index_constant<j> domainJ,
130 std::size_t dofIdxGlobalJ,
131 const PrimaryVariables<j>& priVarsJ,
132 int pvIdxJ)
133 {
134 8624 this->curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
135
136 // we need to update all solution-dependent components of the coupling context
137 // the dof of domain J has been deflected
138 // if domainJ == freeFlowMassIndex: update volvars in the PoreNetworkCouplingContext
139 // if domainJ == poreNetworkIndex: update volvars in the FreeFlowMassCouplingContext
140 // as the update is symmetric we only need to write this once
141 4312 auto& context = std::get<1-j>(couplingContext_);
142
4/4
✓ Branch 0 taken 4964 times.
✓ Branch 1 taken 2156 times.
✓ Branch 2 taken 4964 times.
✓ Branch 3 taken 2156 times.
22864 for (auto& c : context)
143 {
144
4/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 4796 times.
✓ Branch 2 taken 92 times.
✓ Branch 3 taken 4714 times.
19540 if (c.scv.dofIndex() == dofIdxGlobalJ)
145 {
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
336 const auto& problem = this->problem(domainJ);
147
2/4
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76 times.
✗ Branch 5 not taken.
672 const auto& element = problem.gridGeometry().element(c.scv.elementIndex());
148
3/6
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 76 times.
✗ Branch 8 not taken.
1008 const auto elemSol = elementSolution(element, this->curSol(domainJ), problem.gridGeometry());
149
1/2
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
336 c.volVars.update(elemSol, problem, element, c.scv);
150 }
151 }
152 4312 }
153
154 // \}
155
156 /*!
157 * \brief Access the coupling context needed for the Stokes domain
158 */
159 const auto& couplingContext(Dune::index_constant<freeFlowMassIndex> domainI,
160 const FVElementGeometry<freeFlowMassIndex>& fvGeometry,
161 const SubControlVolumeFace<freeFlowMassIndex> scvf) const
162 {
163 auto& contexts = std::get<freeFlowMassIndex>(couplingContext_);
164 const auto eIdx = scvf.insideScvIdx();
165
166 if (contexts.empty() || couplingContextBoundForElement_[freeFlowMassIndex] != eIdx)
167 bindCouplingContext_(freeFlowMassIndex, fvGeometry);
168
169
170 return contexts[0];
171 }
172
173 /*!
174 * \brief Access the coupling context needed for the PNM domain
175 */
176 const auto& couplingContext(Dune::index_constant<poreNetworkIndex> domainI,
177 const FVElementGeometry<poreNetworkIndex>& fvGeometry,
178 const SubControlVolume<poreNetworkIndex> scv) const
179 {
180 auto& contexts = std::get<poreNetworkIndex>(couplingContext_);
181 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
182
183 if (contexts.empty() || couplingContextBoundForElement_[poreNetworkIndex] != eIdx)
184 bindCouplingContext_(poreNetworkIndex, fvGeometry);
185
186 return contexts;
187 }
188
189 /*!
190 * \brief The coupling stencils
191 */
192 // \{
193
194 /*!
195 * \brief The Stokes cell center coupling stencil w.r.t. Darcy DOFs
196 */
197 template<std::size_t i, std::size_t j>
198 const CouplingStencil& couplingStencil(Dune::index_constant<i> domainI,
199 const Element<i>& element,
200 Dune::index_constant<j> domainJ) const
201 {
202 const auto eIdx = this->problem(domainI).gridGeometry().elementMapper().index(element);
203 if constexpr (domainI == freeFlowMassIndex)
204 return couplingMapper_->freeFlowMassToPoreNetworkCouplingStencil(eIdx);
205 else
206 return couplingMapper_->poreNetworkToFreeFlowMassCouplingStencil(eIdx);
207 }
208
209 // \}
210
211 /*!
212 * \brief Returns whether a given scvf is coupled to the other domain
213 */
214 bool isCoupled(Dune::index_constant<freeFlowMassIndex> domainI,
215 const SubControlVolumeFace<freeFlowMassIndex>& scvf) const
216
6/6
✓ Branch 10 taken 405 times.
✓ Branch 11 taken 3151 times.
✓ Branch 14 taken 225 times.
✓ Branch 15 taken 1770 times.
✓ Branch 18 taken 288 times.
✓ Branch 19 taken 2409 times.
16496 { return couplingMapper_->isCoupledFreeFlowMassScvf(scvf.index()); }
217
218 /*!
219 * \brief If the boundary entity is on a coupling boundary
220 * \param domainI the domain index for which to compute the flux
221 * \param scv the sub control volume
222 */
223 bool isCoupled(Dune::index_constant<poreNetworkIndex> domainI,
224 const SubControlVolume<poreNetworkIndex>& scv) const
225
12/12
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 262 times.
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 262 times.
✓ Branch 4 taken 168 times.
✓ Branch 5 taken 262 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 44 times.
✓ Branch 8 taken 14 times.
✓ Branch 9 taken 44 times.
✓ Branch 10 taken 14 times.
✓ Branch 11 taken 44 times.
1464 { return couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()); }
226
227 private:
228 /*!
229 * \brief Returns whether a given scvf is coupled to the other domain
230 */
231 template<std::size_t i>
232 bool isCoupledElement_(Dune::index_constant<i> domainI, std::size_t eIdx) const
233 {
234 if constexpr (domainI == freeFlowMassIndex)
235 975 return couplingMapper_->isCoupledFreeFlowElement(eIdx);
236 else
237 24 return couplingMapper_->isCoupledPoreNetworkElement(eIdx);
238 }
239
240 //! Return the volume variables of domain i for a given element and scv
241 template<std::size_t i>
242 148 VolumeVariables<i> volVars_(Dune::index_constant<i> domainI,
243 const Element<i>& element,
244 const SubControlVolume<i>& scv) const
245 {
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
148 VolumeVariables<i> volVars;
247 296 const auto elemSol = elementSolution(
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
148 element, this->curSol(domainI), this->problem(domainI).gridGeometry()
249 );
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
212 volVars.update(elemSol, this->problem(domainI), element, scv);
251 148 return volVars;
252 }
253
254 /*!
255 * \brief prepares all data and variables that are necessary to evaluate the residual of an Darcy element (i.e. Stokes information)
256 */
257 template<std::size_t i>
258 46 void bindCouplingContext_(Dune::index_constant<i> domainI, const Element<i>& element) const
259 {
260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
92 const auto fvGeometry = localView(this->problem(domainI).gridGeometry()).bindElement(element);
261
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
46 bindCouplingContext_(domainI, fvGeometry);
262 46 }
263
264 /*!
265 * \brief prepares all data and variables that are necessary to evaluate the residual of an Darcy element (i.e. Stokes information)
266 */
267 26 void bindCouplingContext_(Dune::index_constant<poreNetworkIndex> domainI, const FVElementGeometry<poreNetworkIndex>& fvGeometry) const
268 {
269 26 auto& context = std::get<domainI>(couplingContext_);
270 78 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
271
272 // do nothing if the element is already bound or not coupled to the other domain
273
10/10
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 2 times.
✓ Branch 9 taken 14 times.
✓ Branch 10 taken 10 times.
52 if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx))
274 16 return;
275
276
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 context.clear();
277 10 couplingContextBoundForElement_[domainI] = eIdx;
278
279 20 const auto& stencil = couplingStencil(poreNetworkIndex, fvGeometry.element(), freeFlowMassIndex);
280 30 const auto& freeFlowElements = couplingMapper_->pnmElementToFreeFlowElementsMap().at(eIdx);
281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 auto ffFVGeometry = localView(this->problem(freeFlowMassIndex).gridGeometry());
282
283
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 10 times.
62 for (const auto ffElementIdx : freeFlowElements)
284 {
285
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
32 const auto& ffElement = this->problem(freeFlowMassIndex).gridGeometry().element(ffElementIdx);
286 32 ffFVGeometry.bindElement(ffElement);
287
288
4/4
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 128 times.
✓ Branch 3 taken 32 times.
192 for (const auto& scvf : scvfs(ffFVGeometry))
289 {
290
2/2
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 96 times.
256 if (couplingMapper_->isCoupledFreeFlowMassScvf(scvf.index()))
291 {
292 64 const auto& scv = ffFVGeometry.scv(scvf.insideScvIdx());
293 32 const auto dofIdx = scv.dofIndex();
294
8/10
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 11 taken 32 times.
✗ Branch 12 not taken.
156 if (std::any_of(stencil.begin(), stencil.end(), [&](const auto x){ return dofIdx == x; } ))
295 {
296
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
32 context.push_back({scv,
297 scvf,
298 volVars_(freeFlowMassIndex, ffElement, scv),
299 VelocityVector{}}
300 );
301 }
302 }
303 }
304 }
305 }
306
307 /*!
308 * \brief prepares all data and variables that are necessary to evaluate the residual of an Darcy element (i.e. Stokes information)
309 */
310 975 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI, const FVElementGeometry<freeFlowMassIndex>& fvGeometry) const
311 {
312 975 auto& context = std::get<domainI>(couplingContext_);
313 2925 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
314
315 // do nothing if the element is already bound or not coupled to the other domain
316
8/10
✓ Branch 0 taken 963 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 963 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 963 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 963 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 933 times.
✓ Branch 10 taken 42 times.
1950 if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx))
317 933 return;
318
319
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 2 times.
42 context.clear();
320
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 couplingContextBoundForElement_[domainI] = eIdx;
321
322
323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 auto poreNetworkFVGeometry = localView(this->problem(poreNetworkIndex).gridGeometry());
324 126 const auto poreNetworkElemIdx = couplingMapper_->freeFlowElementToPNMElementMap().at(eIdx);
325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 const auto& poreNetworkElement = this->problem(poreNetworkIndex).gridGeometry().element(poreNetworkElemIdx);
326 42 poreNetworkFVGeometry.bindElement(poreNetworkElement);
327
328 42 auto poreNetworkScv = [&]
329 {
330 42 SubControlVolume<poreNetworkIndex> result;
331 42 std::size_t counter = 0;
332
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 42 times.
168 for (auto&& scv : scvs(poreNetworkFVGeometry))
333 {
334
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 42 times.
168 if (couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()))
335 {
336 42 result = scv;
337 42 ++counter;
338 }
339 }
340
341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (counter > 1)
342 DUNE_THROW(Dune::InvalidStateException, "Only one pore per throat may be coupled");
343 else
344 42 return result;
345
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 42 times.
126 }();
346
347 42 auto volVars = volVars_(poreNetworkIndex, poreNetworkElement, poreNetworkScv);
348
349 42 context.push_back({std::move(poreNetworkScv),
350 42 std::move(volVars),
351 VelocityVector{}}
352 );
353 }
354
355 mutable std::tuple<std::vector<FreeFlowMassCouplingContext>, std::vector<PoreNetworkCouplingContext>> couplingContext_;
356 mutable std::array<std::size_t, 2> couplingContextBoundForElement_;
357
358 std::shared_ptr<CouplingMapper> couplingMapper_;
359 };
360
361 } // end namespace Dumux
362
363 #endif
364