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