version 3.7
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// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
13#ifndef DUMUX_MULTIDOMAIN_FREEFLOWMOMENTUM_POROUSMEDIUM_COUPLINGMAPPER_HH
14#define DUMUX_MULTIDOMAIN_FREEFLOWMOMENTUM_POROUSMEDIUM_COUPLINGMAPPER_HH
15
16#include <iostream>
17#include <unordered_map>
18#include <tuple>
19#include <vector>
20
21#include <dune/common/timer.hh>
22#include <dune/common/exceptions.hh>
23#include <dune/common/indices.hh>
24
27
28namespace Dumux {
29
35template<class MDTraits, class CouplingManager>
37{
38 using Scalar = typename MDTraits::Scalar;
39
40 template<std::size_t i> using GridGeometry = typename MDTraits::template SubDomain<i>::GridGeometry;
41 template<std::size_t i> using SubControlVolume = typename GridGeometry<i>::SubControlVolume;
42 template<std::size_t i> using SubControlVolumeFace = typename GridGeometry<i>::SubControlVolumeFace;
43 template<std::size_t i> using GridView = typename GridGeometry<i>::GridView;
44 template<std::size_t i> using Element = typename GridView<i>::template Codim<0>::Entity;
45
46 template<std::size_t i>
47 static constexpr auto domainIdx()
48 { return typename MDTraits::template SubDomain<i>::Index{}; }
49
50 template<std::size_t i>
51 static constexpr bool isFcStaggered()
52 { return GridGeometry<i>::discMethod == DiscretizationMethods::fcstaggered; }
53
54 template<std::size_t i>
55 static constexpr bool isCCTpfa()
56 { return GridGeometry<i>::discMethod == DiscretizationMethods::cctpfa; }
57
58 struct ScvfInfoPM
59 {
60 std::size_t eIdxOutside;
61 std::size_t flipScvfIdx;
62 };
63
64 struct ScvfInfoFF
65 {
66 std::size_t eIdxOutside;
67 std::size_t flipScvfIdx;
68 std::size_t dofIdxOutside;
69 };
70
71 using FlipScvfMapTypePM = std::unordered_map<std::size_t, ScvfInfoPM>;
72 using FlipScvfMapTypeFF = std::unordered_map<std::size_t, ScvfInfoFF>;
73 using MapType = std::unordered_map<std::size_t, std::vector<std::size_t>>;
74
75 static constexpr std::size_t numSD = MDTraits::numSubDomains;
76
77public:
81 void update(const CouplingManager& couplingManager)
82 {
83 // TODO: Box and multiple domains
84 static_assert(numSD == 2, "More than two subdomains not implemented!");
85 static_assert(isFcStaggered<0>() && isCCTpfa<1>(), "Only coupling between fcstaggered and cctpfa implemented!");
86
87 Dune::Timer watch;
88 std::cout << "Initializing the coupling map..." << std::endl;
89
90 for (std::size_t domIdx = 0; domIdx < numSD; ++domIdx)
91 stencils_[domIdx].clear();
92
93 std::get<CouplingManager::freeFlowMomentumIndex>(scvfInfo_).clear();
94 std::get<CouplingManager::porousMediumIndex>(scvfInfo_).clear();
95
96 const auto& freeFlowMomentumProblem = couplingManager.problem(CouplingManager::freeFlowMomentumIndex);
97 const auto& porousMediumProblem = couplingManager.problem(CouplingManager::porousMediumIndex);
98 const auto& freeFlowMomentumGG = freeFlowMomentumProblem.gridGeometry();
99 const auto& porousMediumGG = porousMediumProblem.gridGeometry();
100
101 isCoupledFFDof_.resize(freeFlowMomentumGG.numScvf(), false);
102 isCoupledFFElement_.resize(freeFlowMomentumGG.gridView().size(0), false);
103 isCoupledScvf_[CouplingManager::freeFlowMomentumIndex].resize(freeFlowMomentumGG.numScvf(), false);
104 isCoupledScvf_[CouplingManager::porousMediumIndex].resize(porousMediumGG.numScvf(), false);
105
106 auto pmFvGeometry = localView(porousMediumGG);
107 auto ffFvGeometry = localView(freeFlowMomentumGG);
108
109 for (const auto& pmElement : elements(porousMediumGG.gridView()))
110 {
111 pmFvGeometry.bindElement(pmElement);
112
113 for (const auto& pmScvf : scvfs(pmFvGeometry))
114 {
115 // skip all non-boundaries
116 if (!pmScvf.boundary())
117 continue;
118
119 // get elements intersecting with the scvf center
120 // for robustness add epsilon in unit outer normal direction
121 const auto eps = (pmScvf.ipGlobal() - pmFvGeometry.geometry(pmScvf).corner(0)).two_norm()*1e-8;
122 auto globalPos = pmScvf.ipGlobal(); globalPos.axpy(eps, pmScvf.unitOuterNormal());
123 const auto indices = intersectingEntities(globalPos, freeFlowMomentumGG.boundingBoxTree());
124
125 // skip if no intersection was found
126 if (indices.empty())
127 continue;
128
129 // sanity check
130 if (indices.size() > 1)
131 DUNE_THROW(Dune::InvalidStateException, "Are you sure your sub-domain grids are conformingly discretized on the common interface?");
132
133 // add the pair to the multimap
134 const auto pmElemIdx = porousMediumGG.elementMapper().index(pmElement);
135 const auto ffElemIdx = indices[0];
136 const auto& ffElement = freeFlowMomentumGG.element(ffElemIdx);
137 ffFvGeometry.bindElement(ffElement);
138
139 for (const auto& ffScvf : scvfs(ffFvGeometry)) // TODO: maybe better iterate over all scvs
140 {
141 // TODO this only takes the scv directly at the interface, maybe extend
142 if (!ffScvf.boundary() || !ffScvf.isFrontal())
143 continue;
144
145 const auto dist = (pmScvf.ipGlobal() - ffScvf.ipGlobal()).two_norm();
146 if (dist > eps)
147 continue;
148
149 const auto& ffScv = ffFvGeometry.scv(ffScvf.insideScvIdx());
150 stencils_[CouplingManager::porousMediumIndex][pmElemIdx].push_back(ffScv.dofIndex());
151 stencils_[CouplingManager::freeFlowMomentumIndex][ffScv.dofIndex()].push_back(pmElemIdx);
152
153 // mark the scvf and find and mark the flip scvf
154 isCoupledScvf_[CouplingManager::porousMediumIndex][pmScvf.index()] = true;
155 isCoupledScvf_[CouplingManager::freeFlowMomentumIndex][ffScvf.index()] = true;
156
157 // add all lateral free-flow scvfs touching the coupling interface ("standing" or "lying")
158 for (const auto& otherFfScvf : scvfs(ffFvGeometry, ffScv))
159 {
160 if (otherFfScvf.isLateral())
161 {
162 // the orthogonal scvf has to lie on the coupling interface
163 const auto& lateralOrthogonalScvf = ffFvGeometry.lateralOrthogonalScvf(otherFfScvf);
164 isCoupledLateralScvf_[lateralOrthogonalScvf.index()] = true;
165
166 // the "standing" scvf is marked as coupled if it does not lie on a boundary or if that boundary itself is a coupling interface
167 if (!otherFfScvf.boundary())
168 isCoupledLateralScvf_[otherFfScvf.index()] = true;
169 else
170 {
171 // for robustness add epsilon in unit outer normal direction
172 const auto otherScvfEps = (otherFfScvf.ipGlobal() - ffFvGeometry.geometry(otherFfScvf).corner(0)).two_norm()*1e-8;
173 auto otherScvfGlobalPos = otherFfScvf.center(); otherScvfGlobalPos.axpy(otherScvfEps, otherFfScvf.unitOuterNormal());
174
175 if (!intersectingEntities(otherScvfGlobalPos, porousMediumGG.boundingBoxTree()).empty())
176 isCoupledLateralScvf_[otherFfScvf.index()] = true;
177 }
178 }
179 }
180 isCoupledFFDof_[ffScv.dofIndex()] = true;
181 isCoupledFFElement_[ffElemIdx] = true;
182
183 std::get<CouplingManager::porousMediumIndex>(scvfInfo_)[pmScvf.index()] = ScvfInfoPM{ffElemIdx, ffScvf.index()};
184 std::get<CouplingManager::freeFlowMomentumIndex>(scvfInfo_)[ffScvf.index()] = ScvfInfoFF{pmElemIdx, pmScvf.index(), ffScv.dofIndex()};
185 }
186 }
187 }
188
189 std::cout << "took " << watch.elapsed() << " seconds." << std::endl;
190 }
191
206 const std::vector<std::size_t>& couplingStencil(Dune::index_constant<CouplingManager::porousMediumIndex> domainI,
207 const std::size_t eIdxI,
208 Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainJ) const
209 {
210 if (isCoupledElement(domainI, eIdxI))
211 return stencils_[CouplingManager::porousMediumIndex].at(eIdxI);
212 else
213 return emptyStencil_;
214 }
215
231 const std::vector<std::size_t>& couplingStencil(Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainI,
232 const Element<CouplingManager::freeFlowMomentumIndex>& elementI,
233 const SubControlVolume<CouplingManager::freeFlowMomentumIndex>& scvI,
234 Dune::index_constant<CouplingManager::porousMediumIndex> domainJ) const
235 {
236 if (isCoupled(domainI, scvI))
237 return stencils_[CouplingManager::freeFlowMomentumIndex].at(scvI.dofIndex());
238 else
239 return emptyStencil_;
240 }
241
245 template<std::size_t i>
246 bool isCoupledElement(Dune::index_constant<i>, std::size_t eIdx) const
247 {
248 if constexpr (i == CouplingManager::porousMediumIndex)
249 return static_cast<bool>(stencils_[i].count(eIdx));
250 else
251 return isCoupledFFElement_[eIdx];
252 }
253
259 template<std::size_t i>
260 bool isCoupled(Dune::index_constant<i> domainI,
261 const SubControlVolumeFace<i>& scvf) const
262 {
263 return isCoupledScvf_[i].at(scvf.index());
264 }
265
271 bool isCoupledLateralScvf(Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainI,
272 const SubControlVolumeFace<CouplingManager::freeFlowMomentumIndex>& scvf) const
273 { return isCoupledLateralScvf_.count(scvf.index()); }
274
280 bool isCoupled(Dune::index_constant<CouplingManager::freeFlowMomentumIndex> domainI,
281 const SubControlVolume<CouplingManager::freeFlowMomentumIndex>& scv) const
282 { return isCoupledFFDof_[scv.dofIndex()]; }
283
289 template<std::size_t i>
290 std::size_t flipScvfIndex(Dune::index_constant<i> domainI,
291 const SubControlVolumeFace<i>& scvf) const
292 {
293 return std::get<i>(scvfInfo_).at(scvf.index()).flipScvfIdx;
294 }
295
301 template<std::size_t i>
302 std::size_t outsideElementIndex(Dune::index_constant<i> domainI,
303 const SubControlVolumeFace<i>& scvf) const
304 {
305 return std::get<i>(scvfInfo_).at(scvf.index()).eIdxOutside;
306 }
307
313 template<std::size_t i>
314 std::size_t outsideDofIndex(Dune::index_constant<i> domainI,
315 const SubControlVolumeFace<i>& scvf) const
316 {
317 if constexpr (i == CouplingManager::porousMediumIndex)
318 return outsideElementIndex(domainI, scvf);
319 else
320 return std::get<i>(scvfInfo_).at(scvf.index()).dofIdxOutside;
321 }
322
323private:
324 std::array<MapType, numSD> stencils_;
325 std::vector<std::size_t> emptyStencil_;
326 std::array<std::vector<bool>, numSD> isCoupledScvf_;
327 std::unordered_map<std::size_t, bool> isCoupledLateralScvf_;
328 std::vector<bool> isCoupledFFDof_;
329 std::vector<bool> isCoupledFFElement_;
330 std::tuple<FlipScvfMapTypeFF, FlipScvfMapTypePM> scvfInfo_;
331
332};
333
334} // end namespace Dumux
335
336#endif
The interface of the coupling manager for multi domain problems.
Definition: multidomain/couplingmanager.hh:48
const Problem< i > & problem(Dune::index_constant< i > domainIdx) const
Return a reference to the sub problem.
Definition: multidomain/couplingmanager.hh:309
the default mapper for conforming equal dimension boundary coupling between two domains (box or cc)
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:37
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:260
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:246
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:231
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:280
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:271
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:290
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:206
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:314
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:302
void update(const CouplingManager &couplingManager)
Main update routine.
Definition: boundary/freeflowporousmedium/ffmomentumpm/couplingmapper.hh:81
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
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:102
Algorithms that finds which geometric entities intersect.
The available discretization methods in Dumux.
constexpr CCTpfa cctpfa
Definition: method.hh:145
constexpr FCStaggered fcstaggered
Definition: method.hh:151
static constexpr auto freeFlowMomentumIndex
Definition: multidomain/boundary/freeflowporenetwork/couplingmanager.hh:34
static constexpr auto porousMediumIndex
Definition: multidomain/boundary/freeflowporousmedium/couplingmanager.hh:35
Definition: adapt.hh:17