3.5-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh
Go to the documentation of this file.
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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
25#ifndef DUMUX_MULTIDOMAIN_BOUNDARY_FREEFLOWPORENETWORK_FFMASSPORENETWORK_COUPLINGMANAGER_HH
26#define DUMUX_MULTIDOMAIN_BOUNDARY_FREEFLOWPORENETWORK_FFMASSPORENETWORK_COUPLINGMANAGER_HH
27
28#include <utility>
29#include <memory>
30
31#include <dune/common/float_cmp.hh>
32#include <dune/common/exceptions.hh>
37
38namespace Dumux {
39
44template<class MDTraits>
46: public CouplingManager<MDTraits>
47{
48 using Scalar = typename MDTraits::Scalar;
50
51public:
52 static constexpr auto freeFlowMassIndex = typename MDTraits::template SubDomain<0>::Index();
53 static constexpr auto poreNetworkIndex = typename MDTraits::template SubDomain<1>::Index();
54
56private:
57
58 // obtain the type tags of the sub problems
59 using FreeFlowMassTypeTag = typename MDTraits::template SubDomain<freeFlowMassIndex>::TypeTag;
60 using PoreNetworkTypeTag = typename MDTraits::template SubDomain<poreNetworkIndex>::TypeTag;
61
62 using CouplingStencils = std::unordered_map<std::size_t, std::vector<std::size_t> >;
63 using CouplingStencil = CouplingStencils::mapped_type;
64
65 // the sub domain type tags
66 template<std::size_t id>
67 using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag;
68
69 template<std::size_t id> using GridView = typename GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>::GridView;
70 template<std::size_t id> using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>;
71 template<std::size_t id> using ElementVolumeVariables = typename GetPropType<SubDomainTypeTag<id>, Properties::GridVolumeVariables>::LocalView;
72 template<std::size_t id> using GridVolumeVariables = GetPropType<SubDomainTypeTag<id>, Properties::GridVolumeVariables>;
73 template<std::size_t id> using VolumeVariables = typename GetPropType<SubDomainTypeTag<id>, Properties::GridVolumeVariables>::VolumeVariables;
74 template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>;
75 template<std::size_t id> using FVElementGeometry = typename GridGeometry<id>::LocalView;
76 template<std::size_t id> using GridVariables = GetPropType<SubDomainTypeTag<id>, Properties::GridVariables>;
77 template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity;
78 template<std::size_t id> using PrimaryVariables = GetPropType<SubDomainTypeTag<id>, Properties::PrimaryVariables>;
79 template<std::size_t id> using SubControlVolumeFace = typename FVElementGeometry<id>::SubControlVolumeFace;
80 template<std::size_t id> using SubControlVolume = typename FVElementGeometry<id>::SubControlVolume;
81
82 using VelocityVector = typename Element<freeFlowMassIndex>::Geometry::GlobalCoordinate;
83
84 struct FreeFlowMassCouplingContext
85 {
86 SubControlVolume<poreNetworkIndex> scv;
87 VolumeVariables<poreNetworkIndex> volVars;
88 mutable VelocityVector velocity; // velocity needs to be set externally, not availabe in this class
89 };
90
91 struct PoreNetworkCouplingContext
92 {
93 SubControlVolume<freeFlowMassIndex> scv;
94 SubControlVolumeFace<freeFlowMassIndex> scvf;
95 VolumeVariables<freeFlowMassIndex> volVars;
96 mutable VelocityVector velocity; // velocity needs to be set externally, not availabe in this class
97 };
98
99 using CouplingMapper = StaggeredFreeFlowPoreNetworkCouplingMapper;
100
101public:
102
106 // \{
107
109 void init(std::shared_ptr<Problem<freeFlowMassIndex>> freeFlowMassProblem,
110 std::shared_ptr<Problem<poreNetworkIndex>> pnmProblem,
111 std::shared_ptr<CouplingMapper> couplingMapper,
113 {
114 couplingMapper_ = couplingMapper;
115 this->setSubProblems(std::make_tuple(freeFlowMassProblem, pnmProblem));
116 this->attachSolution(curSol);
117 }
118
119 // \}
120
124 // \{
125
129 template<std::size_t i, class Assembler>
130 void bindCouplingContext(Dune::index_constant<i> domainI, const Element<i>& element, const Assembler& assembler) const
131 {
132 bindCouplingContext_(domainI, element);
133 }
134
138 template<std::size_t i, std::size_t j, class LocalAssemblerI>
139 void updateCouplingContext(Dune::index_constant<i> domainI,
140 const LocalAssemblerI& localAssemblerI,
141 Dune::index_constant<j> domainJ,
142 std::size_t dofIdxGlobalJ,
143 const PrimaryVariables<j>& priVarsJ,
144 int pvIdxJ)
145 {
146 this->curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
147
148 // we need to update all solution-dependent components of the coupling context
149 // the dof of domain J has been deflected
150 // if domainJ == freeFlowMassIndex: update volvars in the PoreNetworkCouplingContext
151 // if domainJ == poreNetworkIndex: update volvars in the FreeFlowMassCouplingContext
152 // as the update is symmetric we only need to write this once
153 auto& context = std::get<1-j>(couplingContext_);
154 for (auto& c : context)
155 {
156 if (c.scv.dofIndex() == dofIdxGlobalJ)
157 {
158 const auto& problem = this->problem(domainJ);
159 const auto& element = problem.gridGeometry().element(c.scv.elementIndex());
160 const auto elemSol = elementSolution(element, this->curSol(domainJ), problem.gridGeometry());
161 c.volVars.update(elemSol, problem, element, c.scv);
162 }
163 }
164 }
165
166 // \}
167
171 const auto& couplingContext(Dune::index_constant<freeFlowMassIndex> domainI,
172 const FVElementGeometry<freeFlowMassIndex>& fvGeometry,
173 const SubControlVolumeFace<freeFlowMassIndex> scvf) const
174 {
175 auto& contexts = std::get<freeFlowMassIndex>(couplingContext_);
176 const auto eIdx = scvf.insideScvIdx();
177
178 if (contexts.empty() || couplingContextBoundForElement_[freeFlowMassIndex] != eIdx)
179 bindCouplingContext_(freeFlowMassIndex, fvGeometry);
180
181
182 return contexts[0];
183 }
184
188 const auto& couplingContext(Dune::index_constant<poreNetworkIndex> domainI,
189 const FVElementGeometry<poreNetworkIndex>& fvGeometry,
190 const SubControlVolume<poreNetworkIndex> scv) const
191 {
192 auto& contexts = std::get<poreNetworkIndex>(couplingContext_);
193 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
194
195 if (contexts.empty() || couplingContextBoundForElement_[poreNetworkIndex] != eIdx)
196 bindCouplingContext_(poreNetworkIndex, fvGeometry);
197
198 return contexts;
199 }
200
204 // \{
205
209 template<std::size_t i, std::size_t j>
210 const CouplingStencil& couplingStencil(Dune::index_constant<i> domainI,
211 const Element<i>& element,
212 Dune::index_constant<j> domainJ) const
213 {
214 const auto eIdx = this->problem(domainI).gridGeometry().elementMapper().index(element);
215 if constexpr (domainI == freeFlowMassIndex)
216 return couplingMapper_->freeFlowMassToPoreNetworkCouplingStencil(eIdx);
217 else
218 return couplingMapper_->poreNetworkToFreeFlowMassCouplingStencil(eIdx);
219 }
220
221 // \}
222
226 bool isCoupled(Dune::index_constant<freeFlowMassIndex> domainI,
227 const SubControlVolumeFace<freeFlowMassIndex>& scvf) const
228 { return couplingMapper_->isCoupledFreeFlowMassScvf(scvf.index()); }
229
235 bool isCoupled(Dune::index_constant<poreNetworkIndex> domainI,
236 const SubControlVolume<poreNetworkIndex>& scv) const
237 { return couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()); }
238
239private:
243 template<std::size_t i>
244 bool isCoupledElement_(Dune::index_constant<i> domainI, std::size_t eIdx) const
245 {
246 if constexpr (domainI == freeFlowMassIndex)
247 return couplingMapper_->isCoupledFreeFlowElement(eIdx);
248 else
249 return couplingMapper_->isCoupledPoreNetworkElement(eIdx);
250 }
251
253 template<std::size_t i>
254 VolumeVariables<i> volVars_(Dune::index_constant<i> domainI,
255 const Element<i>& element,
256 const SubControlVolume<i>& scv) const
257 {
258 VolumeVariables<i> volVars;
259 const auto elemSol = elementSolution(
260 element, this->curSol(domainI), this->problem(domainI).gridGeometry()
261 );
262 volVars.update(elemSol, this->problem(domainI), element, scv);
263 return volVars;
264 }
265
269 template<std::size_t i>
270 void bindCouplingContext_(Dune::index_constant<i> domainI, const Element<i>& element) const
271 {
272 const auto fvGeometry = localView(this->problem(domainI).gridGeometry()).bindElement(element);
273 bindCouplingContext_(domainI, fvGeometry);
274 }
275
279 void bindCouplingContext_(Dune::index_constant<poreNetworkIndex> domainI, const FVElementGeometry<poreNetworkIndex>& fvGeometry) const
280 {
281 auto& context = std::get<domainI>(couplingContext_);
282 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
283
284 // do nothing if the element is already bound or not coupled to the other domain
285 if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx))
286 return;
287
288 context.clear();
289 couplingContextBoundForElement_[domainI] = eIdx;
290
291 const auto& stencil = couplingStencil(poreNetworkIndex, fvGeometry.element(), freeFlowMassIndex);
292 const auto& freeFlowElements = couplingMapper_->pnmElementToFreeFlowElementsMap().at(eIdx);
293 auto ffFVGeometry = localView(this->problem(freeFlowMassIndex).gridGeometry());
294
295 for (const auto ffElementIdx : freeFlowElements)
296 {
297 const auto& ffElement = this->problem(freeFlowMassIndex).gridGeometry().element(ffElementIdx);
298 ffFVGeometry.bindElement(ffElement);
299
300 for (const auto& scvf : scvfs(ffFVGeometry))
301 {
302 if (couplingMapper_->isCoupledFreeFlowMassScvf(scvf.index()))
303 {
304 const auto& scv = ffFVGeometry.scv(scvf.insideScvIdx());
305 const auto dofIdx = scv.dofIndex();
306 if (std::any_of(stencil.begin(), stencil.end(), [&](const auto x){ return dofIdx == x; } ))
307 {
308 context.push_back({scv,
309 scvf,
310 volVars_(freeFlowMassIndex, ffElement, scv),
311 VelocityVector{}}
312 );
313 }
314 }
315 }
316 }
317 }
318
322 void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI, const FVElementGeometry<freeFlowMassIndex>& fvGeometry) const
323 {
324 auto& context = std::get<domainI>(couplingContext_);
325 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
326
327 // do nothing if the element is already bound or not coupled to the other domain
328 if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx))
329 return;
330
331 context.clear();
332 couplingContextBoundForElement_[domainI] = eIdx;
333
334
335 auto poreNetworkFVGeometry = localView(this->problem(poreNetworkIndex).gridGeometry());
336 const auto poreNetworkElemIdx = couplingMapper_->freeFlowElementToPNMElementMap().at(eIdx);
337 const auto& poreNetworkElement = this->problem(poreNetworkIndex).gridGeometry().element(poreNetworkElemIdx);
338 poreNetworkFVGeometry.bindElement(poreNetworkElement);
339
340 auto poreNetworkScv = [&]
341 {
342 SubControlVolume<poreNetworkIndex> result;
343 std::size_t counter = 0;
344 for (auto&& scv : scvs(poreNetworkFVGeometry))
345 {
346 if (couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()))
347 {
348 result = scv;
349 ++counter;
350 }
351 }
352
353 if (counter > 1)
354 DUNE_THROW(Dune::InvalidStateException, "Only one pore per throat may be coupled");
355 else
356 return result;
357 }();
358
359 auto volVars = volVars_(poreNetworkIndex, poreNetworkElement, poreNetworkScv);
360
361 context.push_back({std::move(poreNetworkScv),
362 std::move(volVars),
363 VelocityVector{}}
364 );
365 }
366
367 mutable std::tuple<std::vector<FreeFlowMassCouplingContext>, std::vector<PoreNetworkCouplingContext>> couplingContext_;
368 mutable std::array<std::size_t, 2> couplingContextBoundForElement_;
369
370 std::shared_ptr<CouplingMapper> couplingMapper_;
371};
372
373} // end namespace Dumux
374
375#endif
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:38
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::box, BoxElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for box schemes.
Definition: box/elementsolution.hh:118
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
A vector of primary variables.
Definition: common/properties.hh:49
Property to specify the type of a problem which has to be solved.
Definition: common/properties.hh:57
Definition: common/properties.hh:102
The type for a global container for the volume variables.
Definition: common/properties.hh:109
The grid variables object managing variable data on the grid (volvars/fluxvars cache)
Definition: common/properties.hh:123
Coupling manager for free-flow mass and pore-network models.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:47
bool isCoupled(Dune::index_constant< poreNetworkIndex > domainI, const SubControlVolume< poreNetworkIndex > &scv) const
If the boundary entity is on a coupling boundary.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:235
static constexpr auto poreNetworkIndex
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:53
typename ParentType::SolutionVectorStorage SolutionVectorStorage
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:55
void bindCouplingContext(Dune::index_constant< i > domainI, const Element< i > &element, const Assembler &assembler) const
Methods to be accessed by the assembly.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:130
void init(std::shared_ptr< Problem< freeFlowMassIndex > > freeFlowMassProblem, std::shared_ptr< Problem< poreNetworkIndex > > pnmProblem, std::shared_ptr< CouplingMapper > couplingMapper, SolutionVectorStorage &curSol)
Methods to be accessed by main.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:109
const auto & couplingContext(Dune::index_constant< poreNetworkIndex > domainI, const FVElementGeometry< poreNetworkIndex > &fvGeometry, const SubControlVolume< poreNetworkIndex > scv) const
Access the coupling context needed for the PNM domain.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:188
const auto & couplingContext(Dune::index_constant< freeFlowMassIndex > domainI, const FVElementGeometry< freeFlowMassIndex > &fvGeometry, const SubControlVolumeFace< freeFlowMassIndex > scvf) const
Access the coupling context needed for the Stokes domain.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:171
static constexpr auto freeFlowMassIndex
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:52
const CouplingStencil & couplingStencil(Dune::index_constant< i > domainI, const Element< i > &element, Dune::index_constant< j > domainJ) const
The coupling stencils.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:210
bool isCoupled(Dune::index_constant< freeFlowMassIndex > domainI, const SubControlVolumeFace< freeFlowMassIndex > &scvf) const
Returns whether a given scvf is coupled to the other domain.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:226
void updateCouplingContext(Dune::index_constant< i > domainI, const LocalAssemblerI &localAssemblerI, Dune::index_constant< j > domainJ, std::size_t dofIdxGlobalJ, const PrimaryVariables< j > &priVarsJ, int pvIdxJ)
Update the coupling context.
Definition: multidomain/boundary/freeflowporenetwork/ffmassporenetwork/couplingmanager.hh:139
The interface of the coupling manager for multi domain problems.
Definition: multidomain/couplingmanager.hh:60
void attachSolution(SolutionVectorStorage &curSol)
Attach a solution vector stored outside of this class.
Definition: multidomain/couplingmanager.hh:334
decltype(auto) curSol()
the solution vector of the coupled problem
Definition: multidomain/couplingmanager.hh:370
void setSubProblems(const std::tuple< std::shared_ptr< SubProblems >... > &problems)
set the pointers to the sub problems
Definition: multidomain/couplingmanager.hh:299
const Problem< i > & problem(Dune::index_constant< i > domainIdx) const
Return a reference to the sub problem.
Definition: multidomain/couplingmanager.hh:321
typename Traits::template TupleOfSharedPtr< SubSolutionVector > SolutionVectorStorage
the type in which the solution vector is stored in the manager
Definition: multidomain/couplingmanager.hh:83
Declares all properties used in Dumux.
The local element solution class for staggered methods.
The interface of the coupling manager for multi domain problems.