version 3.10-dev
dualnetwork/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//
14#ifndef DUMUX_DUAL_NETWORK_COUPLINGMAPPER_HH
15#define DUMUX_DUAL_NETWORK_COUPLINGMAPPER_HH
16
17#include <type_traits>
18#include <unordered_map>
19#include <algorithm>
20#include <vector>
21#include <iostream>
22#include <cassert>
23
24#include <dune/common/iteratorrange.hh>
25#include <dune/common/iteratorfacades.hh>
26
27#include <dune/common/exceptions.hh>
29
30namespace Dumux::PoreNetwork {
31
38template<class Scalar>
40{
41 struct HostGridConnectionInfo
42 {
43 std::size_t hostGridElementIndex;
44 std::size_t voidVertexHostIdx;
45 std::size_t solidVertexHostIdx;
46 Scalar connectionArea;
47 Scalar connectionLength;
48 std::vector<std::size_t> voidElementHostIdx;
49 std::vector<std::size_t> solidElementHostIdx;
50 std::vector<std::size_t> coupledVoidVertexHostIdx;
51 std::vector<std::size_t> coupledSolidVertexHostIdx;
52 std::size_t connectionGlobalId;
53 };
54
55 struct SubGridConnectionInfo
56 {
57 std::size_t id; // the global id of the connections
58 std::size_t solidVertexIdx; // the directly coupled solid vertex
59 std::size_t voidVertexIdx; // the directly coupled void vertex
60 std::size_t someSolidElementIdx; // index of one the solid elements adjacent to the solid vertex
61 std::size_t someVoidElementIdx; // index of one the void elements adjacent to the solid vertex
62 std::vector<std::size_t> convectionVoidElementIdx; // all void elements adjacent to the own void vertex coupled to the same solid vertex
63 Scalar connectionArea;
64 Scalar connectionLength;
65 };
66
67 template<class Vector>
68 class ConnectionIterator : public Dune::ForwardIteratorFacade<ConnectionIterator<Vector>, const SubGridConnectionInfo>
69 {
70 using ThisType = ConnectionIterator<Vector>;
71 using Iterator = typename Vector::const_iterator;
72 public:
73 ConnectionIterator(const Iterator& it, const std::vector<SubGridConnectionInfo>& info)
74 : it_(it), InfoPtr_(&info) {}
75
76 ConnectionIterator() : it_(Iterator()), InfoPtr_(nullptr) {}
77
79 const SubGridConnectionInfo& dereference() const
80 { return InfoPtr_->at(*it_); }
81 // { return (*InfoPtr_)[*it_]; }
82
83 bool equals(const ThisType& other) const
84 { return it_ == other.it_; }
85
86 void increment()
87 { ++it_; }
88
89 private:
90 Iterator it_;
91 const std::vector<SubGridConnectionInfo>* InfoPtr_;
92 };
93
94public:
95 using Stencil = std::vector<std::size_t>;
96
97 template<class HostGridView, class HostGridData, class VoidGridGeometry, class SolidGridGeometry>
98 DualNetworkCouplingMapper(const HostGridView& hostGridView,
99 const HostGridData& hostGridData,
100 const VoidGridGeometry& voidGridGeometry,
101 const SolidGridGeometry& solidGridGeometry)
102 {
103 fillVertexMap_(hostGridView, voidGridGeometry, voidHostToSubVertexIdxMap_);
104 fillVertexMap_(hostGridView, solidGridGeometry, solidHostToSubVertexIdxMap_);
105 fillElementMap_(hostGridView, voidGridGeometry, voidHostToSubElementIdxMap_);
106 fillElementMap_(hostGridView, solidGridGeometry, solidHostToSubElementIdxMap_);
107
108 isCoupledVoidDof_.resize(voidGridGeometry.gridView().size(1), false);
109 isCoupledSolidDof_.resize(solidGridGeometry.gridView().size(1), false);
110
111 const auto connectionInfo = getConnectionInfo_(hostGridView, hostGridData);
112 connectionInfo_.resize(connectionInfo.size());
113 for (const auto& info : connectionInfo)
114 {
115 auto voidHostToSubVertexIdx = [&](const auto hostIdx)
116 { return voidHostToSubVertexIdxMap_.at(hostIdx); };
117
118 auto solidHostToSubVertexIdx = [&](const auto hostIdx)
119 { return solidHostToSubVertexIdxMap_.at(hostIdx); };
120
121 const auto directlyCoupledVoidDofIdx = voidHostToSubVertexIdx(info.voidVertexHostIdx);
122 const auto directlyCoupledSolidDofIdx = solidHostToSubVertexIdx(info.solidVertexHostIdx);
123
124 auto coupledVoidElementIdxSub = info.voidElementHostIdx;
125 auto coupledSolidElementIdxSub = info.solidElementHostIdx;
126
127 // convert hostgrid indices to subgrid indices
128 std::transform(coupledVoidElementIdxSub.begin(), coupledVoidElementIdxSub.end(),
129 coupledVoidElementIdxSub.begin(), [&](const auto eIdx){ return voidHostToSubElementIdxMap_.at(eIdx); });
130 std::transform(coupledSolidElementIdxSub.begin(), coupledSolidElementIdxSub.end(),
131 coupledSolidElementIdxSub.begin(), [&](const auto eIdx){ return solidHostToSubElementIdxMap_.at(eIdx); });
132
133 // initialize an empty vector - will be filled later in a second loop
134 auto convectionVoidElementIdx = std::vector<std::size_t>();
135
136 voidToSolidConnectionIds_[directlyCoupledVoidDofIdx].emplace_back(info.connectionGlobalId);
137 solidToVoidConnectionIds_[directlyCoupledSolidDofIdx].emplace_back(info.connectionGlobalId);
138
139 connectionInfo_[info.connectionGlobalId] = SubGridConnectionInfo{info.connectionGlobalId,
140 directlyCoupledSolidDofIdx,
141 directlyCoupledVoidDofIdx,
142 coupledSolidElementIdxSub[0],
143 coupledVoidElementIdxSub[0],
144 convectionVoidElementIdx,
145 info.connectionArea,
146 info.connectionLength};
147
148 hostGridElementIndexToGlobalId_[info.hostGridElementIndex] = info.connectionGlobalId;
149
150 isCoupledVoidDof_[directlyCoupledVoidDofIdx] = true;
151 isCoupledSolidDof_[directlyCoupledSolidDofIdx] = true;
152
153 for (const auto eIdxVoidHost : info.voidElementHostIdx)
154 {
155 const auto eIdxSubVoid = voidHostToSubElementIdxMap_.at(eIdxVoidHost);
156 voidToSolidStencils_[eIdxSubVoid].push_back(directlyCoupledSolidDofIdx);
157 }
158
159 for (const auto eIdxSolidHost : info.solidElementHostIdx)
160 {
161 const auto eIdxSubSolid = solidHostToSubElementIdxMap_.at(eIdxSolidHost);
162 solidToVoidStencils_[eIdxSubSolid].push_back(directlyCoupledVoidDofIdx);
163 }
164 }
165
166 for (auto& stencil : voidToSolidStencils_)
167 removeDuplicates_(stencil.second);
168 for (auto& stencil : solidToVoidStencils_)
169 removeDuplicates_(stencil.second);
170
171 // second loop: find void element coupling for convective transport
172 auto voidFVGeometry = localView(voidGridGeometry);
173 for (const auto& voidElement : elements(voidGridGeometry.gridView()))
174 {
175 voidFVGeometry.bindElement(voidElement);
176 std::array<std::size_t, 2> dofIndex;
177 std::array<std::vector<std::size_t>, 2> coupledSolidVertexIdx;
178 for (const auto& scv : scvs(voidFVGeometry))
179 dofIndex[scv.indexInElement()] = scv.dofIndex();
180
181 // check if both void pores couple to the same solid pore
182 if (isCoupledVoidDof_[dofIndex[0]] && isCoupledVoidDof_[dofIndex[1]])
183 {
184 for (auto& conn0 : voidToSolidConnectionIds_[dofIndex[0]])
185 {
186 for (auto& conn1 : voidToSolidConnectionIds_[dofIndex[1]])
187 {
188 const auto globalId0 = conn0;
189 const auto globalId1 = conn1;
190 assert(globalId0 != globalId1);
191
192 if (connectionInfo_[globalId0].solidVertexIdx == connectionInfo_[globalId1].solidVertexIdx)
193 {
194 const auto voidElemIdx = voidGridGeometry.elementMapper().index(voidElement);
195 connectionInfo_[globalId0].convectionVoidElementIdx.push_back(voidElemIdx);
196 connectionInfo_[globalId1].convectionVoidElementIdx.push_back(voidElemIdx);
197 }
198 }
199 }
200 }
201 }
202
203 for (auto& entry : voidToSolidConnectionIds_)
204 {
205 removeDuplicates_(entry.second);
206
207 std::cout << "void dof " << entry.first << " couples to " << entry.second.size() << " solid dofs: " << std::endl;
208 for (auto& conn : entry.second)
209 {
210 const auto& info = connectionInfo_[conn];
211 assert(entry.first == info.voidVertexIdx);
212 std::cout << "solid vertex " << info.solidVertexIdx << " with elems ";
213 for (const auto e : info.convectionVoidElementIdx)
214 std::cout << e << " ";
215 std:: cout << "||" << std::endl;
216 }
217
218 std::cout << std::endl;
219 }
220
221 for (auto& entry : solidToVoidConnectionIds_)
222 {
223 removeDuplicates_(entry.second);
224
225 std::cout << "solid dof " << entry.first << " couples to " << entry.second.size() << " void dofs: " << std::endl;
226 for (auto& conn : entry.second)
227 {
228 const auto& info = connectionInfo_[conn];
229 assert(entry.first == info.solidVertexIdx);
230 std::cout << "void vertex " << info.voidVertexIdx << " with elems ";
231 for (const auto e : info.convectionVoidElementIdx)
232 std::cout << e << " ";
233 std:: cout << "||" << std::endl;
234 }
235
236 std::cout << std::endl;
237 }
238
239 // TODO maybe delete hostToSub maps? or make public?
240 }
241
242 const auto& voidToSolidStencils() const
243 { return voidToSolidStencils_; }
244
245 const auto& solidToVoidStencils() const
246 { return solidToVoidStencils_; }
247
248 const std::vector<bool>& isCoupledVoidDof() const
249 { return isCoupledVoidDof_; }
250
251 const std::vector<bool>& isCoupledSolidDof() const
252 { return isCoupledSolidDof_; }
253
255 auto voidToSolidConnections(const std::size_t dofIdx) const
256 {
257 const auto& ids = voidToSolidConnectionIds().at(dofIdx);
258 using Iterator = ConnectionIterator<std::vector<std::size_t>>;
259 return Dune::IteratorRange<Iterator>(Iterator(ids.cbegin(), connectionInfo()),
260 Iterator(ids.cend(), connectionInfo()));
261 }
262
263 auto solidToVoidConnections(const std::size_t dofIdx) const
264 {
265 const auto& ids = solidToVoidConnectionIds().at(dofIdx);
266 using Iterator = ConnectionIterator<std::vector<std::size_t>>;
267 return Dune::IteratorRange<Iterator>(Iterator(ids.cbegin(), connectionInfo()),
268 Iterator(ids.cend(), connectionInfo()));
269 }
270
271 const auto& voidToSolidConnectionIds() const
272 { return voidToSolidConnectionIds_; }
273
274 const auto& solidToVoidConnectionIds() const
275 { return solidToVoidConnectionIds_; }
276
277 const auto& connectionInfo() const
278 { return connectionInfo_; }
279
280 const auto& voidHostToSubVertexIdxMap() const
281 { return voidHostToSubVertexIdxMap_; }
282
283 const auto& solidHostToSubVertexIdxMap() const
284 { return solidHostToSubVertexIdxMap_; }
285
286 const auto& voidHostToSubElementIdxMap() const
287 { return voidHostToSubElementIdxMap_; }
288
289 const auto& solidHostToSubElementIdxMap() const
290 { return solidHostToSubElementIdxMap_; }
291
293 { return hostGridElementIndexToGlobalId_; }
294
295private:
296
297 template<class HostGridView, class HostGridData>
298 std::vector<HostGridConnectionInfo> getConnectionInfo_(const HostGridView& hostGridView,
299 const HostGridData& hostGridData)
300 {
301 std::vector<HostGridConnectionInfo> connectionInfo;
302 std::size_t connectionGlobalId = 0;
303
304 for (const auto& element : elements(hostGridView))
305 {
306 if (hostGridData.getParameter(element, "ThroatDomainType") == 2) // interconnection throat
307 {
308 const auto& vertex0 = element.template subEntity<1>(0);
309 const auto& vertex1 = element.template subEntity<1>(1);
310
311 HostGridConnectionInfo info;
312 info.hostGridElementIndex = hostGridView.indexSet().index(element);
313 info.connectionGlobalId = connectionGlobalId++;
314 info.voidVertexHostIdx = hostGridView.indexSet().index(vertex0);
315 info.solidVertexHostIdx = hostGridView.indexSet().index(vertex1);
316
317 if (hostGridData.getParameter(vertex0, "PoreDomainType") == 1)
318 {
319 assert(hostGridData.getParameter(vertex1, "PoreDomainType") == 0);
320 using std::swap;
321 swap(info.voidVertexHostIdx, info.solidVertexHostIdx);
322 }
323
324 info.connectionArea = hostGridData.getParameter(element, "ThroatCrossSectionalArea");
325 info.connectionLength = element.geometry().volume();
326
327 for (const auto& intersection : intersections(hostGridView, element))
328 {
329 if (!intersection.neighbor())
330 continue;
331
332 const auto& outsideElement = intersection.outside();
333
334 // skip other interconnection throats
335 if (hostGridData.getParameter(outsideElement, "ThroatDomainType") == 2)
336 continue;
337
338 const auto outsideElementIdx = hostGridView.indexSet().index(outsideElement);
339
340 if (hostGridData.getParameter(outsideElement, "ThroatDomainType") == 0)
341 info.voidElementHostIdx.push_back(outsideElementIdx);
342 else
343 info.solidElementHostIdx.push_back(outsideElementIdx);
344
345 std::array outsideDomainType = {-1, -1};
346 for (int localVIdx = 0; localVIdx < 2; ++localVIdx)
347 {
348 const auto& outsideVertex = outsideElement.template subEntity<1>(localVIdx);
349 const auto outsideVertexIdx = hostGridView.indexSet().index(outsideVertex);
350 outsideDomainType[localVIdx] = hostGridData.getParameter(outsideVertex, "PoreDomainType");
351
352 if (localVIdx == 1 && (outsideDomainType[1] != outsideDomainType[0]))
353 DUNE_THROW(Dune::IOError, "Pore with hostIdx " << hostGridView.indexSet().index(outsideElement.template subEntity<1>(0))
354 << " has domain type " << outsideDomainType[0]
355 << ", but pore with hostIdx " << outsideVertexIdx
356 << " has domain type " << outsideDomainType[1] << ". Check your grid file");
357
358 if (outsideDomainType[localVIdx] == 0)
359 info.coupledVoidVertexHostIdx.push_back(outsideVertexIdx);
360 else
361 info.coupledSolidVertexHostIdx.push_back(outsideVertexIdx);
362 }
363 }
364
365 connectionInfo.emplace_back(std::move(info));
366 }
367 }
368
369 return connectionInfo;
370 }
371
372 template<class HostGridView, class SubGridGeometry, class Map>
373 void fillVertexMap_(const HostGridView& hostGridView, const SubGridGeometry& subGridGeometry, Map& map)
374 {
375 for (const auto& vertex : vertices(subGridGeometry.gridView()))
376 {
377 const auto vIdxSub = subGridGeometry.vertexMapper().index(vertex);
378 const auto vIdxHost = hostGridView.indexSet().index(vertex.impl().hostEntity());
379 map[vIdxHost] = vIdxSub;
380 }
381 }
382
383 template<class HostGridView, class SubGridGeometry, class Map>
384 void fillElementMap_(const HostGridView& hostGridView, const SubGridGeometry& subGridGeometry, Map& map)
385 {
386 for (const auto& element : elements(subGridGeometry.gridView()))
387 {
388 const auto eIdxSub = subGridGeometry.elementMapper().index(element);
389 const auto eIdxHost = hostGridView.indexSet().index(element.impl().hostEntity());
390 map[eIdxHost] = eIdxSub;
391 }
392 }
393
395 void removeDuplicates_(std::vector<std::size_t>& stencil)
396 {
397 std::sort(stencil.begin(), stencil.end());
398 stencil.erase(std::unique(stencil.begin(), stencil.end()), stencil.end());
399 }
400
401 std::unordered_map<std::size_t, std::size_t> voidHostToSubVertexIdxMap_;
402 std::unordered_map<std::size_t, std::size_t> solidHostToSubVertexIdxMap_;
403 std::unordered_map<std::size_t, std::size_t> voidHostToSubElementIdxMap_;
404 std::unordered_map<std::size_t, std::size_t> solidHostToSubElementIdxMap_;
405
406 std::vector<bool> isCoupledVoidDof_;
407 std::vector<bool> isCoupledSolidDof_;
408
409 std::unordered_map<std::size_t, Stencil> voidToSolidStencils_;
410 std::unordered_map<std::size_t, Stencil> solidToVoidStencils_;
411
412 std::unordered_map<std::size_t, std::vector<std::size_t>> voidToSolidConnectionIds_;
413 std::unordered_map<std::size_t, std::vector<std::size_t>> solidToVoidConnectionIds_;
414
415 std::vector<SubGridConnectionInfo> connectionInfo_;
416 std::unordered_map<std::size_t, std::size_t> hostGridElementIndexToGlobalId_;
417};
418
419} // end namespace Dumux::PoreNetwork
420
421#endif
Coupling mapper for Stokes and Darcy domains with equal dimension.
Definition: dualnetwork/couplingmapper.hh:40
const auto & solidToVoidConnectionIds() const
Definition: dualnetwork/couplingmapper.hh:274
auto voidToSolidConnections(const std::size_t dofIdx) const
Returns an iterator allowing for (const auto& conn : voidToSolidConnections(dofIdx)) {....
Definition: dualnetwork/couplingmapper.hh:255
const auto & voidToSolidStencils() const
Definition: dualnetwork/couplingmapper.hh:242
std::vector< std::size_t > Stencil
Definition: dualnetwork/couplingmapper.hh:95
const std::vector< bool > & isCoupledVoidDof() const
Definition: dualnetwork/couplingmapper.hh:248
const std::vector< bool > & isCoupledSolidDof() const
Definition: dualnetwork/couplingmapper.hh:251
const auto & voidToSolidConnectionIds() const
Definition: dualnetwork/couplingmapper.hh:271
const auto & connectionInfo() const
Definition: dualnetwork/couplingmapper.hh:277
DualNetworkCouplingMapper(const HostGridView &hostGridView, const HostGridData &hostGridData, const VoidGridGeometry &voidGridGeometry, const SolidGridGeometry &solidGridGeometry)
Definition: dualnetwork/couplingmapper.hh:98
auto solidToVoidConnections(const std::size_t dofIdx) const
Definition: dualnetwork/couplingmapper.hh:263
const auto & hostGridElementIndexToGlobalId() const
Definition: dualnetwork/couplingmapper.hh:292
const auto & solidHostToSubVertexIdxMap() const
Definition: dualnetwork/couplingmapper.hh:283
const auto & solidHostToSubElementIdxMap() const
Definition: dualnetwork/couplingmapper.hh:289
const auto & voidHostToSubElementIdxMap() const
Definition: dualnetwork/couplingmapper.hh:286
const auto & solidToVoidStencils() const
Definition: dualnetwork/couplingmapper.hh:245
const auto & voidHostToSubVertexIdxMap() const
Definition: dualnetwork/couplingmapper.hh:280
A map from indices to entities using grid entity seeds.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
Definition: discretization/porenetwork/fvelementgeometry.hh:24