3.6-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.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_FREEFLOWMOMENTUM_POROUSMEDIUM_COUPLINGMAPPER_HH
26#define DUMUX_MULTIDOMAIN_FREEFLOWMOMENTUM_POROUSMEDIUM_COUPLINGMAPPER_HH
27
28#include <iostream>
29#include <unordered_map>
30#include <tuple>
31#include <vector>
32
33#include <dune/common/timer.hh>
34#include <dune/common/exceptions.hh>
35#include <dune/common/indices.hh>
36
39
40namespace Dumux {
41
47template<class MDTraits, class CouplingManager>
49{
50 using Scalar = typename MDTraits::Scalar;
51
52 template<std::size_t i> using GridGeometry = typename MDTraits::template SubDomain<i>::GridGeometry;
53 template<std::size_t i> using SubControlVolume = typename GridGeometry<i>::SubControlVolume;
54 template<std::size_t i> using SubControlVolumeFace = typename GridGeometry<i>::SubControlVolumeFace;
55 template<std::size_t i> using GridView = typename GridGeometry<i>::GridView;
56 template<std::size_t i> using Element = typename GridView<i>::template Codim<0>::Entity;
57
58 template<std::size_t i>
59 static constexpr auto domainIdx()
60 { return typename MDTraits::template SubDomain<i>::Index{}; }
61
62 template<std::size_t i>
63 static constexpr bool isFcStaggered()
64 { return GridGeometry<i>::discMethod == DiscretizationMethods::fcstaggered; }
65
66 template<std::size_t i>
67 static constexpr bool isCCTpfa()
68 { return GridGeometry<i>::discMethod == DiscretizationMethods::cctpfa; }
69
70 struct ScvfInfoPM
71 {
72 std::size_t eIdxOutside;
73 std::size_t flipScvfIdx;
74 };
75
76 struct ScvfInfoFF
77 {
78 std::size_t eIdxOutside;
79 std::size_t flipScvfIdx;
80 std::size_t dofIdxOutside;
81 };
82
83 using FlipScvfMapTypePM = std::unordered_map<std::size_t, ScvfInfoPM>;
84 using FlipScvfMapTypeFF = std::unordered_map<std::size_t, ScvfInfoFF>;
85 using MapType = std::unordered_map<std::size_t, std::vector<std::size_t>>;
86
87 static constexpr std::size_t numSD = MDTraits::numSubDomains;
88
89public:
93 void update(const CouplingManager& couplingManager)
94 {
95 // TODO: Box and multiple domains
96 static_assert(numSD == 2, "More than two subdomains not implemented!");
97 static_assert(isFcStaggered<0>() && isCCTpfa<1>(), "Only coupling between fcstaggered and cctpfa implemented!");
98
99 Dune::Timer watch;
100 std::cout << "Initializing the coupling map..." << std::endl;
101
102 for (std::size_t domIdx = 0; domIdx < numSD; ++domIdx)
103 stencils_[domIdx].clear();
104
105 std::get<CouplingManager::freeFlowMomentumIndex>(scvfInfo_).clear();
106 std::get<CouplingManager::porousMediumIndex>(scvfInfo_).clear();
107
108 const auto& freeFlowMomentumProblem = couplingManager.problem(CouplingManager::freeFlowMomentumIndex);
109 const auto& porousMediumProblem = couplingManager.problem(CouplingManager::porousMediumIndex);
110 const auto& freeFlowMomentumGG = freeFlowMomentumProblem.gridGeometry();
111 const auto& porousMediumGG = porousMediumProblem.gridGeometry();
112
113 isCoupledFFDof_.resize(freeFlowMomentumGG.numScvf(), false);
114 isCoupledFFElement_.resize(freeFlowMomentumGG.gridView().size(0), false);
115 isCoupledScvf_[CouplingManager::freeFlowMomentumIndex].resize(freeFlowMomentumGG.numScvf(), false);
116 isCoupledScvf_[CouplingManager::porousMediumIndex].resize(porousMediumGG.numScvf(), false);
117
118 auto pmFvGeometry = localView(porousMediumGG);
119 auto ffFvGeometry = localView(freeFlowMomentumGG);
120
121 for (const auto& pmElement : elements(porousMediumGG.gridView()))
122 {
123 pmFvGeometry.bindElement(pmElement);
124
125 for (const auto& pmScvf : scvfs(pmFvGeometry))
126 {
127 // skip all non-boundaries
128 if (!pmScvf.boundary())
129 continue;
130
131 // get elements intersecting with the scvf center
132 // for robustness add epsilon in unit outer normal direction
133 const auto eps = (pmScvf.ipGlobal() - pmFvGeometry.geometry(pmScvf).corner(0)).two_norm()*1e-8;
134 auto globalPos = pmScvf.ipGlobal(); globalPos.axpy(eps, pmScvf.unitOuterNormal());
135 const auto indices = intersectingEntities(globalPos, freeFlowMomentumGG.boundingBoxTree());
136
137 // skip if no intersection was found
138 if (indices.empty())
139 continue;
140
141 // sanity check
142 if (indices.size() > 1)
143 DUNE_THROW(Dune::InvalidStateException, "Are you sure your sub-domain grids are conformingly discretized on the common interface?");
144
145 // add the pair to the multimap
146 const auto pmElemIdx = porousMediumGG.elementMapper().index(pmElement);
147 const auto ffElemIdx = indices[0];
148 const auto& ffElement = freeFlowMomentumGG.element(ffElemIdx);
149 ffFvGeometry.bindElement(ffElement);
150
151 for (const auto& ffScvf : scvfs(ffFvGeometry)) // TODO: maybe better iterate over all scvs
152 {
153 // TODO this only takes the scv directly at the interface, maybe extend
154 if (!ffScvf.boundary() || !ffScvf.isFrontal())
155 continue;
156
157 const auto dist = (pmScvf.ipGlobal() - ffScvf.ipGlobal()).two_norm();
158 if (dist > eps)
159 continue;
160
161 const auto& ffScv = ffFvGeometry.scv(ffScvf.insideScvIdx());
162 stencils_[CouplingManager::porousMediumIndex][pmElemIdx].push_back(ffScv.dofIndex());
163 stencils_[CouplingManager::freeFlowMomentumIndex][ffScv.dofIndex()].push_back(pmElemIdx);
164
165 // mark the scvf and find and mark the flip scvf
166 isCoupledScvf_[CouplingManager::porousMediumIndex][pmScvf.index()] = true;
167 isCoupledScvf_[CouplingManager::freeFlowMomentumIndex][ffScvf.index()] = true;
168
169 // add all lateral free-flow scvfs touching the coupling interface ("standing" or "lying")
170 for (const auto& otherFfScvf : scvfs(ffFvGeometry, ffScv))
171 {
172 if (otherFfScvf.isLateral())
173 {
174 // the orthogonal scvf has to lie on the coupling interface
175 const auto& lateralOrthogonalScvf = ffFvGeometry.lateralOrthogonalScvf(otherFfScvf);
176 isCoupledLateralScvf_[lateralOrthogonalScvf.index()] = true;
177
178 // the "standing" scvf is marked as coupled if it does not lie on a boundary or if that boundary itself is a coupling interface
179 if (!otherFfScvf.boundary())
180 isCoupledLateralScvf_[otherFfScvf.index()] = true;
181 else
182 {
183 // for robustness add epsilon in unit outer normal direction
184 const auto otherScvfEps = (otherFfScvf.ipGlobal() - ffFvGeometry.geometry(otherFfScvf).corner(0)).two_norm()*1e-8;
185 auto otherScvfGlobalPos = otherFfScvf.center(); otherScvfGlobalPos.axpy(otherScvfEps, otherFfScvf.unitOuterNormal());
186
187 if (!intersectingEntities(otherScvfGlobalPos, porousMediumGG.boundingBoxTree()).empty())
188 isCoupledLateralScvf_[otherFfScvf.index()] = true;
189 }
190 }
191 }
192 isCoupledFFDof_[ffScv.dofIndex()] = true;
193 isCoupledFFElement_[ffElemIdx] = true;
194
195 std::get<CouplingManager::porousMediumIndex>(scvfInfo_)[pmScvf.index()] = ScvfInfoPM{ffElemIdx, ffScvf.index()};
196 std::get<CouplingManager::freeFlowMomentumIndex>(scvfInfo_)[ffScvf.index()] = ScvfInfoFF{pmElemIdx, pmScvf.index(), ffScv.dofIndex()};
197 }
198 }
199 }
200
201 std::cout << "took " << watch.elapsed() << " seconds." << std::endl;
202 }
203
218 const std::vector<std::size_t>& couplingStencil(Dune::index_constant<CouplingManager::porousMediumIndex> domainI,
219 const std::size_t eIdxI,
220 Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainJ) const
221 {
222 if (isCoupledElement(domainI, eIdxI))
223 return stencils_[CouplingManager::porousMediumIndex].at(eIdxI);
224 else
225 return emptyStencil_;
226 }
227
243 const std::vector<std::size_t>& couplingStencil(Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainI,
244 const Element<CouplingManager::freeFlowMomentumIndex>& elementI,
245 const SubControlVolume<CouplingManager::freeFlowMomentumIndex>& scvI,
246 Dune::index_constant<CouplingManager::porousMediumIndex> domainJ) const
247 {
248 if (isCoupled(domainI, scvI))
249 return stencils_[CouplingManager::freeFlowMomentumIndex].at(scvI.dofIndex());
250 else
251 return emptyStencil_;
252 }
253
257 template<std::size_t i>
258 bool isCoupledElement(Dune::index_constant<i>, std::size_t eIdx) const
259 {
260 if constexpr (i == CouplingManager::porousMediumIndex)
261 return static_cast<bool>(stencils_[i].count(eIdx));
262 else
263 return isCoupledFFElement_[eIdx];
264 }
265
271 template<std::size_t i>
272 bool isCoupled(Dune::index_constant<i> domainI,
273 const SubControlVolumeFace<i>& scvf) const
274 {
275 return isCoupledScvf_[i].at(scvf.index());
276 }
277
283 bool isCoupledLateralScvf(Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainI,
284 const SubControlVolumeFace<CouplingManager::freeFlowMomentumIndex>& scvf) const
285 { return isCoupledLateralScvf_.count(scvf.index()); }
286
292 bool isCoupled(Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainI,
293 const SubControlVolume<CouplingManager::freeFlowMomentumIndex>& scv) const
294 { return isCoupledFFDof_[scv.dofIndex()]; }
295
301 template<std::size_t i>
302 std::size_t flipScvfIndex(Dune::index_constant<i> domainI,
303 const SubControlVolumeFace<i>& scvf) const
304 {
305 return std::get<i>(scvfInfo_).at(scvf.index()).flipScvfIdx;
306 }
307
313 template<std::size_t i>
314 std::size_t outsideElementIndex(Dune::index_constant<i> domainI,
315 const SubControlVolumeFace<i>& scvf) const
316 {
317 return std::get<i>(scvfInfo_).at(scvf.index()).eIdxOutside;
318 }
319
325 template<std::size_t i>
326 std::size_t outsideDofIndex(Dune::index_constant<i> domainI,
327 const SubControlVolumeFace<i>& scvf) const
328 {
329 if constexpr (i == CouplingManager::porousMediumIndex)
330 return outsideElementIndex(domainI, scvf);
331 else
332 return std::get<i>(scvfInfo_).at(scvf.index()).dofIdxOutside;
333 }
334
335private:
336 std::array<MapType, numSD> stencils_;
337 std::vector<std::size_t> emptyStencil_;
338 std::array<std::vector<bool>, numSD> isCoupledScvf_;
339 std::unordered_map<std::size_t, bool> isCoupledLateralScvf_;
340 std::vector<bool> isCoupledFFDof_;
341 std::vector<bool> isCoupledFFElement_;
342 std::tuple<FlipScvfMapTypeFF, FlipScvfMapTypePM> scvfInfo_;
343
344};
345
346} // end namespace Dumux
347
348#endif
The available discretization methods in Dumux.
Algorithms that finds which geometric entities intersect.
std::vector< std::size_t > intersectingEntities(const Dune::FieldVector< ctype, dimworld > &point, const BoundingBoxTree< EntitySet > &tree, bool isCartesianGrid=false)
Compute all intersections between entities and a point.
Definition: intersectingentities.hh:114
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:38
Adaption of the non-isothermal two-phase two-component flow model to problems with CO2.
Definition: adapt.hh:29
constexpr CCTpfa cctpfa
Definition: method.hh:134
constexpr FCStaggered fcstaggered
Definition: method.hh:140
static constexpr auto freeFlowMomentumIndex
Definition: multidomain/boundary/freeflowporenetwork/couplingmanager.hh:46
static constexpr auto porousMediumIndex
Definition: multidomain/boundary/freeflowporousmedium/couplingmanager.hh:47
the default mapper for conforming equal dimension boundary coupling between two domains (box or cc)
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:49
bool isCoupled(Dune::index_constant< i > domainI, const SubControlVolumeFace< i > &scvf) const
If the boundary entity is on a coupling boundary.
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:272
bool isCoupledElement(Dune::index_constant< i >, std::size_t eIdx) const
Return if an element residual with index eIdx of domain i is coupled to domain j.
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:258
const std::vector< std::size_t > & couplingStencil(Dune::index_constant< CouplingManager::freeFlowMomentumIndex > domainI, const Element< CouplingManager::freeFlowMomentumIndex > &elementI, const SubControlVolume< CouplingManager::freeFlowMomentumIndex > &scvI, Dune::index_constant< CouplingManager::porousMediumIndex > domainJ) const
returns an iterable container of all indices of degrees of freedom of domain j that couple with / inf...
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:243
bool isCoupled(Dune::index_constant< CouplingManager::freeFlowMomentumIndex > domainI, const SubControlVolume< CouplingManager::freeFlowMomentumIndex > &scv) const
If the boundary entity is on a coupling boundary.
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:292
bool isCoupledLateralScvf(Dune::index_constant< CouplingManager::freeFlowMomentumIndex > domainI, const SubControlVolumeFace< CouplingManager::freeFlowMomentumIndex > &scvf) const
If the boundary entity is on a coupling boundary.
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:283
std::size_t flipScvfIndex(Dune::index_constant< i > domainI, const SubControlVolumeFace< i > &scvf) const
Return the scvf index of the flipped scvf in the other domain.
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:302
const std::vector< std::size_t > & couplingStencil(Dune::index_constant< CouplingManager::porousMediumIndex > domainI, const std::size_t eIdxI, Dune::index_constant< CouplingManager::freeFlowMomentumIndex > domainJ) const
returns an iterable container of all indices of degrees of freedom of domain j that couple with / inf...
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:218
std::size_t outsideDofIndex(Dune::index_constant< i > domainI, const SubControlVolumeFace< i > &scvf) const
Return the outside element index (the element index of the other domain)
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:326
std::size_t outsideElementIndex(Dune::index_constant< i > domainI, const SubControlVolumeFace< i > &scvf) const
Return the outside element index (the element index of the other domain)
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:314
void update(const CouplingManager &couplingManager)
Main update routine.
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:93
The interface of the coupling manager for multi domain problems.
Definition: multidomain/couplingmanager.hh:60
const Problem< i > & problem(Dune::index_constant< i > domainIdx) const
Return a reference to the sub problem.
Definition: multidomain/couplingmanager.hh:321