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 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 | 6 | 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 | 6 | void init(std::shared_ptr<Problem<freeFlowMassIndex>> freeFlowMassProblem, | |
98 | std::shared_ptr<Problem<poreNetworkIndex>> pnmProblem, | ||
99 | std::shared_ptr<CouplingMapper> couplingMapper, | ||
100 | const SolutionVectorStorage& curSol) | ||
101 | { | ||
102 | 6 | couplingMapper_ = couplingMapper; | |
103 | 12 | this->setSubProblems(std::make_tuple(freeFlowMassProblem, pnmProblem)); | |
104 | 6 | this->attachSolution(curSol); | |
105 | 6 | } | |
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 | 73743 | void bindCouplingContext(Dune::index_constant<i> domainI, const Element<i>& element, const Assembler& assembler) const | |
119 | { | ||
120 | 73743 | 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 | 682192 | 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 | 682192 | 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 | 682192 | auto& context = std::get<1-j>(couplingContext_); | |
142 |
2/2✓ Branch 0 taken 1074328 times.
✓ Branch 1 taken 341096 times.
|
2830848 | for (auto& c : context) |
143 | { | ||
144 |
2/2✓ Branch 0 taken 7850 times.
✓ Branch 1 taken 1066478 times.
|
2148656 | if (c.scv.dofIndex() == dofIdxGlobalJ) |
145 | { | ||
146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7850 times.
|
15700 | const auto& problem = this->problem(domainJ); |
147 |
1/2✓ Branch 1 taken 4710 times.
✗ Branch 2 not taken.
|
15700 | const auto& element = problem.gridGeometry().element(c.scv.elementIndex()); |
148 | 15700 | const auto elemSol = elementSolution(element, this->curSol(domainJ), problem.gridGeometry()); | |
149 |
1/2✓ Branch 1 taken 4710 times.
✗ Branch 2 not taken.
|
15972 | c.volVars.update(elemSol, problem, element, c.scv); |
150 | } | ||
151 | } | ||
152 | 682192 | } | |
153 | |||
154 | // \} | ||
155 | |||
156 | /*! | ||
157 | * \brief Access the coupling context needed for the Stokes domain | ||
158 | */ | ||
159 | 11777 | const auto& couplingContext(Dune::index_constant<freeFlowMassIndex> domainI, | |
160 | const FVElementGeometry<freeFlowMassIndex>& fvGeometry, | ||
161 | const SubControlVolumeFace<freeFlowMassIndex> scvf) const | ||
162 | { | ||
163 |
2/4✓ Branch 0 taken 7981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3796 times.
✗ Branch 3 not taken.
|
11777 | auto& contexts = std::get<freeFlowMassIndex>(couplingContext_); |
164 |
2/4✓ Branch 0 taken 7981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3796 times.
✗ Branch 3 not taken.
|
11777 | const auto eIdx = scvf.insideScvIdx(); |
165 | |||
166 |
5/8✓ Branch 0 taken 7981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 7972 times.
✓ Branch 4 taken 3796 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3796 times.
|
11777 | if (contexts.empty() || couplingContextBoundForElement_[freeFlowMassIndex] != eIdx) |
167 | 9 | bindCouplingContext_(freeFlowMassIndex, fvGeometry); | |
168 | |||
169 | |||
170 | 11777 | return contexts[0]; | |
171 | } | ||
172 | |||
173 | /*! | ||
174 | * \brief Access the coupling context needed for the PNM domain | ||
175 | */ | ||
176 | 5626 | const auto& couplingContext(Dune::index_constant<poreNetworkIndex> domainI, | |
177 | const FVElementGeometry<poreNetworkIndex>& fvGeometry, | ||
178 | const SubControlVolume<poreNetworkIndex> scv) const | ||
179 | { | ||
180 | 5626 | auto& contexts = std::get<poreNetworkIndex>(couplingContext_); | |
181 |
1/2✓ Branch 1 taken 5626 times.
✗ Branch 2 not taken.
|
5626 | const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element()); |
182 | |||
183 |
3/4✓ Branch 0 taken 5626 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5623 times.
|
5626 | if (contexts.empty() || couplingContextBoundForElement_[poreNetworkIndex] != eIdx) |
184 | 3 | bindCouplingContext_(poreNetworkIndex, fvGeometry); | |
185 | |||
186 | 5626 | 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 | 152126 | const CouplingStencil& couplingStencil(Dune::index_constant<i> domainI, | |
199 | const Element<i>& element, | ||
200 | Dune::index_constant<j> domainJ) const | ||
201 | { | ||
202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76063 times.
|
152126 | const auto eIdx = this->problem(domainI).gridGeometry().elementMapper().index(element); |
203 | if constexpr (domainI == freeFlowMassIndex) | ||
204 | 151684 | return couplingMapper_->freeFlowMassToPoreNetworkCouplingStencil(eIdx); | |
205 | else | ||
206 | 442 | return couplingMapper_->poreNetworkToFreeFlowMassCouplingStencil(eIdx); | |
207 | } | ||
208 | |||
209 | // \} | ||
210 | |||
211 | /*! | ||
212 | * \brief Returns whether a given scvf is coupled to the other domain | ||
213 | */ | ||
214 | 343262 | bool isCoupled(Dune::index_constant<freeFlowMassIndex> domainI, | |
215 | const SubControlVolumeFace<freeFlowMassIndex>& scvf) const | ||
216 |
4/4✓ Branch 2 taken 89795 times.
✓ Branch 3 taken 39016 times.
✓ Branch 5 taken 118930 times.
✓ Branch 6 taken 77650 times.
|
686524 | { 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 | 8092 | bool isCoupled(Dune::index_constant<poreNetworkIndex> domainI, | |
224 | const SubControlVolume<poreNetworkIndex>& scv) const | ||
225 |
4/4✓ Branch 0 taken 3791 times.
✓ Branch 1 taken 3927 times.
✓ Branch 2 taken 201 times.
✓ Branch 3 taken 173 times.
|
8092 | { 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 | 73601 | bool isCoupledElement_(Dune::index_constant<i> domainI, std::size_t eIdx) const | |
233 | { | ||
234 | if constexpr (domainI == freeFlowMassIndex) | ||
235 | 147126 | return couplingMapper_->isCoupledFreeFlowElement(eIdx); | |
236 | else | ||
237 | 76 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 620 times.
|
1240 | VolumeVariables<i> volVars_(Dune::index_constant<i> domainI, |
243 | const Element<i>& element, | ||
244 | const SubControlVolume<i>& scv) const | ||
245 | { | ||
246 | 1240 | VolumeVariables<i> volVars; | |
247 | 1240 | const auto elemSol = elementSolution( | |
248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 620 times.
|
1240 | element, this->curSol(domainI), this->problem(domainI).gridGeometry() |
249 | ); | ||
250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 565 times.
|
1240 | volVars.update(elemSol, this->problem(domainI), element, scv); |
251 | 1240 | 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 | 147486 | void bindCouplingContext_(Dune::index_constant<i> domainI, const Element<i>& element) const | |
259 | { | ||
260 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 73743 times.
|
147864 | const auto fvGeometry = localView(this->problem(domainI).gridGeometry()).bindElement(element); |
261 | 147486 | bindCouplingContext_(domainI, fvGeometry); | |
262 | 147486 | } | |
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 | 192 | void bindCouplingContext_(Dune::index_constant<poreNetworkIndex> domainI, const FVElementGeometry<poreNetworkIndex>& fvGeometry) const | |
268 | { | ||
269 | 192 | auto& context = std::get<domainI>(couplingContext_); | |
270 |
2/2✓ Branch 1 taken 179 times.
✓ Branch 2 taken 13 times.
|
192 | 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 |
6/6✓ Branch 0 taken 179 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 154 times.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 17 times.
|
230 | if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx)) |
274 | 175 | return; | |
275 | |||
276 | 17 | context.clear(); | |
277 | 17 | couplingContextBoundForElement_[domainI] = eIdx; | |
278 | |||
279 | 17 | const auto& stencil = couplingStencil(poreNetworkIndex, fvGeometry.element(), freeFlowMassIndex); | |
280 | 17 | const auto& freeFlowElements = couplingMapper_->pnmElementToFreeFlowElementsMap().at(eIdx); | |
281 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | auto ffFVGeometry = localView(this->problem(freeFlowMassIndex).gridGeometry()); |
282 | |||
283 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 17 times.
|
72 | for (const auto ffElementIdx : freeFlowElements) |
284 | { | ||
285 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | const auto& ffElement = this->problem(freeFlowMassIndex).gridGeometry().element(ffElementIdx); |
286 | 55 | ffFVGeometry.bindElement(ffElement); | |
287 | |||
288 |
2/2✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
|
275 | for (const auto& scvf : scvfs(ffFVGeometry)) |
289 | { | ||
290 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
440 | if (couplingMapper_->isCoupledFreeFlowMassScvf(scvf.index())) |
291 | { | ||
292 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | const auto& scv = ffFVGeometry.scv(scvf.insideScvIdx()); |
293 | 55 | const auto dofIdx = scv.dofIndex(); | |
294 |
14/16✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 30 times.
✓ Branch 10 taken 15 times.
✓ Branch 11 taken 15 times.
✓ Branch 12 taken 17 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 55 times.
✗ Branch 15 not taken.
|
157 | if (std::any_of(stencil.begin(), stencil.end(), [&](const auto x){ return dofIdx == x; } )) |
295 | { | ||
296 | 55 | context.push_back({scv, | |
297 | scvf, | ||
298 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
55 | 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 | 73563 | void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI, const FVElementGeometry<freeFlowMassIndex>& fvGeometry) const | |
311 | { | ||
312 | 73563 | auto& context = std::get<domainI>(couplingContext_); | |
313 |
2/2✓ Branch 1 taken 73507 times.
✓ Branch 2 taken 56 times.
|
73563 | 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 |
5/6✓ Branch 0 taken 73507 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 73507 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 72998 times.
✓ Branch 6 taken 565 times.
|
147126 | if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx)) |
317 | 72998 | return; | |
318 | |||
319 | 565 | context.clear(); | |
320 | 565 | couplingContextBoundForElement_[domainI] = eIdx; | |
321 | |||
322 | |||
323 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 565 times.
|
565 | auto poreNetworkFVGeometry = localView(this->problem(poreNetworkIndex).gridGeometry()); |
324 | 565 | const auto poreNetworkElemIdx = couplingMapper_->freeFlowElementToPNMElementMap().at(eIdx); | |
325 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 565 times.
|
565 | const auto& poreNetworkElement = this->problem(poreNetworkIndex).gridGeometry().element(poreNetworkElemIdx); |
326 | 565 | poreNetworkFVGeometry.bindElement(poreNetworkElement); | |
327 | |||
328 | 565 | auto poreNetworkScv = [&] | |
329 | { | ||
330 | 565 | SubControlVolume<poreNetworkIndex> result; | |
331 | 565 | std::size_t counter = 0; | |
332 |
2/2✓ Branch 0 taken 1130 times.
✓ Branch 1 taken 565 times.
|
1695 | for (auto&& scv : scvs(poreNetworkFVGeometry)) |
333 | { | ||
334 |
2/2✓ Branch 0 taken 565 times.
✓ Branch 1 taken 565 times.
|
1130 | if (couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex())) |
335 | { | ||
336 | 565 | result = scv; | |
337 | 565 | ++counter; | |
338 | } | ||
339 | } | ||
340 | |||
341 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 565 times.
|
565 | if (counter > 1) |
342 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Only one pore per throat may be coupled"); | |
343 | else | ||
344 | 565 | return result; | |
345 | 565 | }(); | |
346 | |||
347 | 565 | auto volVars = volVars_(poreNetworkIndex, poreNetworkElement, poreNetworkScv); | |
348 | |||
349 | 565 | context.push_back({std::move(poreNetworkScv), | |
350 | 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 |