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 |