version 3.11-dev
Loading...
Searching...
No Matches
couplingmapper_boundaryfaces.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-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12
13#ifndef DUMUX_MULTIDOMAIN_COUPLINGMAPPER_BOUNDARYFACES_HH
14#define DUMUX_MULTIDOMAIN_COUPLINGMAPPER_BOUNDARYFACES_HH
15
16#include <algorithm>
17#include <array>
18#include <iostream>
19#include <map>
20#include <tuple>
21#include <utility>
22#include <vector>
23
24#include <dune/common/timer.hh>
25#include <dune/common/exceptions.hh>
26#include <dune/common/indices.hh>
27
30
31namespace Dumux {
32
38template<class MDTraits, class CouplingManager>
40{
41 template<std::size_t i> using GridDiscretization = typename MDTraits::template SubDomain<i>::GridGeometry;
42 template<std::size_t i> using GridView = typename GridDiscretization<i>::GridView;
43
44 template<std::size_t i>
45 static constexpr auto domainIdx()
46 { return typename MDTraits::template SubDomain<i>::Index{}; }
47
48 struct FaceInfo
49 {
50 std::size_t eIdxOutside;
51 std::size_t iIdxOutside;
52 };
53
54 using FlipIntersectionMapType = std::map<std::pair<std::size_t,std::size_t>, FaceInfo>;
55 using MapType = std::map<std::size_t, std::vector<std::size_t>>;
56
57 static constexpr std::size_t numSD = MDTraits::numSubDomains;
58
59public:
60 using CouplingStencil = std::vector<std::size_t>;
61
65 void update(const CouplingManager& couplingManager)
66 {
67 static_assert(numSD == 2, "More than two subdomains not implemented!");
68
69 Dune::Timer watch;
70 std::cout << "Initializing the coupling map..." << std::endl;
71
72 for (std::size_t domIdx = 0; domIdx < numSD; ++domIdx)
73 stencils_[domIdx].clear();
74
75 std::get<0>(intersectionInfo_).clear();
76 std::get<1>(intersectionInfo_).clear();
77
78 const auto& problem0 = couplingManager.problem(domainIdx<0>());
79 const auto& problem1 = couplingManager.problem(domainIdx<1>());
80 const auto& gridDisc0 = Dumux::gridDiscretization(problem0);
81 const auto& gridDisc1 = Dumux::gridDiscretization(problem1);
82
83 isCoupledDof_[0].assign(gridDisc0.numDofs(), false);
84 isCoupledDof_[1].assign(gridDisc1.numDofs(), false);
85
86 auto elemDisc0 = localView(gridDisc0);
87 auto elemDisc1 = localView(gridDisc1);
88
89 for (const auto& element1 : elements(gridDisc1.gridView()))
90 {
91 elemDisc1.bindElement(element1);
92
93 // the outside elements already added to the stencils for this element,
94 // which may touch the coupling interface with more than one intersection
95 std::vector<std::size_t> coupledOutsideElements;
96
97 for (const auto& boundaryFace1 : boundaryFaces(elemDisc1))
98 {
99 // get elements intersecting with the face center
100 // for robustness add epsilon in normal direction
101 const auto eps = boundaryFace1.area()*1e-8;
102 auto globalPos = boundaryFace1.center(); globalPos.axpy(eps, boundaryFace1.unitOuterNormal());
103 const auto indices = intersectingEntities(globalPos, gridDisc0.boundingBoxTree());
104
105 // skip if no intersection was found
106 if (indices.empty())
107 continue;
108
109 // sanity check
110 if (indices.size() > 1)
111 DUNE_THROW(Dune::InvalidStateException, "Are you sure your sub-domain grids are conformingly discretized on the common interface?");
112
113 // add the pair to the multimap
114 const auto eIdx1 = gridDisc1.elementMapper().index(element1);
115 const auto eIdx0 = indices[0];
116 const auto& element0 = gridDisc0.element(eIdx0);
117 elemDisc0.bindElement(element0);
118
119 // add the element dofs once per pair of coupled elements
120 if (std::find(coupledOutsideElements.begin(), coupledOutsideElements.end(), eIdx0) == coupledOutsideElements.end())
121 {
122 coupledOutsideElements.push_back(eIdx0);
123
124 for(auto&& localDof : localDofs(elemDisc1))
125 stencils_[0][eIdx0].push_back(localDof.dofIndex());
126
127 for(auto&& localDof : localDofs(elemDisc0))
128 stencils_[1][eIdx1].push_back(localDof.dofIndex());
129 }
130
131 for (const auto& boundaryFace0 : boundaryFaces(elemDisc0))
132 {
133 const auto dist = (boundaryFace1.center() - boundaryFace0.center()).two_norm();
134 if (dist > eps)
135 continue;
136
137 for(const auto& localDof : localDofs(elemDisc0, boundaryFace0))
138 isCoupledDof_[0][localDof.dofIndex()] = true;
139
140 for(const auto& localDof : localDofs(elemDisc1, boundaryFace1))
141 isCoupledDof_[1][localDof.dofIndex()] = true;
142
143 std::get<0>(intersectionInfo_)[std::make_pair(eIdx0, static_cast<std::size_t>(boundaryFace0.intersectionIndex()))]
144 = FaceInfo{eIdx1, static_cast<std::size_t>(boundaryFace1.intersectionIndex())};
145 std::get<1>(intersectionInfo_)[std::make_pair(eIdx1, static_cast<std::size_t>(boundaryFace1.intersectionIndex()))]
146 = FaceInfo{eIdx0, static_cast<std::size_t>(boundaryFace0.intersectionIndex())};
147 }
148 }
149 }
150
151 // dofs are shared between elements, so the same dof may have been added several times.
152 // Duplicate entries would make the coupling derivatives be accumulated more than once.
153 for (auto& stencil : stencils_)
154 for (auto& [eIdx, dofs] : stencil)
155 {
156 std::sort(dofs.begin(), dofs.end());
157 dofs.erase(std::unique(dofs.begin(), dofs.end()), dofs.end());
158 }
159
160 std::cout << "took " << watch.elapsed() << " seconds." << std::endl;
161 }
162
173 template<std::size_t i, std::size_t j>
174 const std::vector<std::size_t>& couplingStencil(Dune::index_constant<i> domainI,
175 const std::size_t eIdxI,
176 Dune::index_constant<j> domainJ) const
177 {
178 if (isCoupledElement(domainI, eIdxI))
179 return stencils_[i].at(eIdxI);
180 else
181 return emptyStencil_;
182 }
183
187 template<std::size_t i>
188 bool isCoupledElement(Dune::index_constant<i>, std::size_t eIdx) const
189 {
190 return static_cast<bool>(stencils_[i].count(eIdx));
191 }
192
196 template<std::size_t i>
197 bool isCoupledDof(Dune::index_constant<i>, std::size_t dofIdx) const
198 {
199 return isCoupledDof_[i][dofIdx];
200 }
201
208 template<std::size_t i>
209 bool isCoupled(Dune::index_constant<i> domainI,
210 std::size_t eIdxI,
211 std::size_t iIdxI) const
212 {
213 return static_cast<bool>(std::get<i>(intersectionInfo_).count(std::make_pair(eIdxI, iIdxI)));
214 }
215
222 template<std::size_t i>
223 std::size_t outsideElementIndex(Dune::index_constant<i> domainI,
224 std::size_t eIdxI,
225 std::size_t iIdxI) const
226 {
227 return std::get<i>(intersectionInfo_).at(std::make_pair(eIdxI, iIdxI)).eIdxOutside;
228 }
229
236 template<std::size_t i>
237 std::size_t flipIntersectionIndex(Dune::index_constant<i> domainI,
238 std::size_t eIdxI,
239 std::size_t iIdxI) const
240 {
241 return std::get<i>(intersectionInfo_).at(std::make_pair(eIdxI, iIdxI)).iIdxOutside;
242 }
243
244private:
245 std::array<MapType, numSD> stencils_;
246 std::vector<std::size_t> emptyStencil_;
247 std::array<std::vector<bool>, numSD> isCoupledDof_;
248 std::tuple<FlipIntersectionMapType, FlipIntersectionMapType> intersectionInfo_;
249};
250
251} // end namespace Dumux
252
253#endif
The interface of the coupling manager for multi domain problems.
Definition multidomain/couplingmanager.hh:37
const Problem< i > & problem(Dune::index_constant< i > domainIdx) const
Return a reference to the sub problem.
Definition multidomain/couplingmanager.hh:318
Mapper for the boundary coupling of two domains of equal dimension using the boundary faces for coupl...
Definition couplingmapper_boundaryfaces.hh:40
const std::vector< std::size_t > & couplingStencil(Dune::index_constant< i > domainI, const std::size_t eIdxI, Dune::index_constant< j > domainJ) const
returns an iterable container of all indices of degrees of freedom of domain j that couple with the e...
Definition couplingmapper_boundaryfaces.hh:174
bool isCoupled(Dune::index_constant< i > domainI, std::size_t eIdxI, std::size_t iIdxI) const
If the boundary entity is on a coupling boundary.
Definition couplingmapper_boundaryfaces.hh:209
bool isCoupledDof(Dune::index_constant< i >, std::size_t dofIdx) const
Return if a dof with index dofIdx of domain i is coupled to domain j.
Definition couplingmapper_boundaryfaces.hh:197
std::size_t flipIntersectionIndex(Dune::index_constant< i > domainI, std::size_t eIdxI, std::size_t iIdxI) const
Return the intersection index on the outside element (the other domain).
Definition couplingmapper_boundaryfaces.hh:237
std::size_t outsideElementIndex(Dune::index_constant< i > domainI, std::size_t eIdxI, std::size_t iIdxI) const
Return the outside element index (the element index of the other domain).
Definition couplingmapper_boundaryfaces.hh:223
void update(const CouplingManager &couplingManager)
Main update routine.
Definition couplingmapper_boundaryfaces.hh:65
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 couplingmapper_boundaryfaces.hh:188
std::vector< std::size_t > CouplingStencil
Definition couplingmapper_boundaryfaces.hh:60
Type traits for classes providing a grid discretization.
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::pair< int, std::size_t > > intersectingEntities(const Dune::FieldVector< ctype, dimworld > &point, const DistributedBoundingBoxTree< EntitySet > &tree, bool isCartesianGrid=false, bool onlyOwned=true)
Compute all intersections between entities and a point on a distributed tree.
Definition distributedintersectingentities.hh:81
decltype(auto) gridDiscretization(const T &t, Args &&... args)
The grid discretization.
Definition griddiscretization.hh:65
Algorithms that finds which geometric entities intersect.
Definition adapt.hh:17
auto localDofs(const FVElementGeometry &fvGeometry)
range over local dofs
Definition localdof.hh:50