Line | Branch | Exec | Source |
---|---|---|---|
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 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup PoreNetworkDiscretization | ||
10 | * \brief Base class for the finite volume geometry for porenetwork models | ||
11 | */ | ||
12 | #ifndef DUMUX_DISCRETIZATION_PNM_GRID_GEOMETRY_HH | ||
13 | #define DUMUX_DISCRETIZATION_PNM_GRID_GEOMETRY_HH | ||
14 | |||
15 | #include <string> | ||
16 | #include <utility> | ||
17 | #include <unordered_map> | ||
18 | #include <functional> | ||
19 | |||
20 | #include <dune/common/exceptions.hh> | ||
21 | #include <dune/localfunctions/lagrange/lagrangelfecache.hh> | ||
22 | |||
23 | #include <dumux/discretization/method.hh> | ||
24 | #include <dumux/common/indextraits.hh> | ||
25 | #include <dumux/common/defaultmappertraits.hh> | ||
26 | #include <dumux/common/parameters.hh> | ||
27 | |||
28 | #include <dumux/discretization/basegridgeometry.hh> | ||
29 | #include <dumux/discretization/porenetwork/fvelementgeometry.hh> | ||
30 | #include <dumux/discretization/porenetwork/subcontrolvolume.hh> | ||
31 | #include <dumux/discretization/porenetwork/subcontrolvolumeface.hh> | ||
32 | #include <dumux/porenetwork/common/throatproperties.hh> | ||
33 | #include <dumux/porenetwork/common/poreproperties.hh> | ||
34 | #include <dumux/discretization/extrusion.hh> | ||
35 | |||
36 | namespace Dumux::PoreNetwork { | ||
37 | |||
38 | /*! | ||
39 | * \ingroup PoreNetworkDiscretization | ||
40 | * \brief Base class for geometry data extraction from the grid data format | ||
41 | */ | ||
42 | template<class Scalar, class GridView> | ||
43 | class DefaultPNMData | ||
44 | { | ||
45 | using GridIndex = typename IndexTraits<GridView>::GridIndex; | ||
46 | using SmallLocalIndex = typename IndexTraits<GridView>::SmallLocalIndex; | ||
47 | using Label = std::int_least8_t; | ||
48 | using Vertex = typename GridView::template Codim<GridView::dimension>::Entity; | ||
49 | using Element = typename GridView::template Codim<0>::Entity; | ||
50 | |||
51 | static const int dim = GridView::dimension; | ||
52 | |||
53 | public: | ||
54 | |||
55 | template<class GridData> | ||
56 | 24 | void update(const GridView& gridView, const GridData& gridData) | |
57 | { | ||
58 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
|
24 | coordinationNumber_ = gridData.getCoordinationNumbers(); |
59 | |||
60 | 24 | const auto numThroats = gridView.size(0); | |
61 | 24 | throatInscribedRadius_.resize(numThroats); | |
62 | 24 | throatLength_.resize(numThroats); | |
63 | 24 | throatLabel_.resize(numThroats); | |
64 | 24 | throatCrossSectionalArea_.resize(numThroats); | |
65 | 24 | throatShapeFactor_.resize(numThroats); | |
66 | |||
67 | 24 | useSameGeometryForAllPores_ = true; | |
68 | 24 | useSameShapeForAllThroats_ = true; | |
69 | 24 | overwriteGridDataWithShapeSpecificValues_ = false; | |
70 | |||
71 | // first check if the same geometry shall be used for all entities ... | ||
72 |
9/16✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 24 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 24 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 20 times.
✓ Branch 15 taken 4 times.
✓ Branch 16 taken 20 times.
✓ Branch 17 taken 4 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
120 | if (hasParamInGroup(gridData.paramGroup(), "Grid.ThroatCrossSectionShape")) |
73 | { | ||
74 | 41 | const auto throatGeometryInput = getParamFromGroup<std::string>(gridData.paramGroup(), "Grid.ThroatCrossSectionShape"); | |
75 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | const auto throatGeometry = Throat::shapeFromString(throatGeometryInput); |
76 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | throatGeometry_.resize(1); |
77 | 20 | throatGeometry_[0] = throatGeometry; | |
78 |
2/7✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
21 | overwriteGridDataWithShapeSpecificValues_ = getParamFromGroup<bool>(gridData.paramGroup(), "Grid.OverwriteGridDataWithShapeSpecificValues", true); |
79 | |||
80 |
3/6✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 20 times.
|
60 | std::cout << "Using '" << throatGeometryInput << "' as cross-sectional shape for all throats." << std::endl; |
81 | } | ||
82 | else // .. otherwise, get the corresponding parameter index from the grid data and resize the respective vector | ||
83 | { | ||
84 | 8 | std::cout << "Reading shape factors for throats from grid data." << std::endl; | |
85 | 4 | useSameShapeForAllThroats_ = false; | |
86 | 4 | throatGeometry_.resize(numThroats); | |
87 | } | ||
88 | |||
89 | // get the vertex parameters | ||
90 | 24 | const auto numPores = gridView.size(dim); | |
91 | 24 | poreInscribedRadius_.resize(numPores); | |
92 | 24 | poreLabel_.resize(numPores); | |
93 | 24 | poreVolume_.resize(numPores); | |
94 | |||
95 | // first check if the same geometry shall be used for all entities ... | ||
96 |
10/17✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 19 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 19 times.
✓ Branch 12 taken 5 times.
✓ Branch 13 taken 19 times.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 5 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
120 | if (hasParamInGroup(gridData.paramGroup(), "Grid.PoreGeometry")) |
97 | { | ||
98 |
0/3✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
53 | const auto poreGeometryInput = getParamFromGroup<std::string>(gridData.paramGroup(), "Grid.PoreGeometry"); |
99 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | poreGeometry_.resize(1); |
100 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | poreGeometry_[0] = Pore::shapeFromString(poreGeometryInput);; |
101 | |||
102 |
3/6✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 24 times.
|
72 | std::cout << "Using '" << poreGeometryInput << "' as geometry for all pores." << std::endl; |
103 | } | ||
104 | else // .. otherwise, get the corresponding parameter index from the grid data and resize the respective vector | ||
105 | { | ||
106 | ✗ | std::cout << "Reading pore shapes from grid data." << std::endl; | |
107 | ✗ | useSameGeometryForAllPores_ = false; | |
108 | ✗ | poreGeometry_.resize(numPores); | |
109 | } | ||
110 | |||
111 | |||
112 |
6/6✓ Branch 1 taken 18847 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 18847 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 18826 times.
|
37718 | for (const auto& vertex : vertices(gridView)) |
113 | { | ||
114 |
7/14✓ Branch 0 taken 21 times.
✓ Branch 1 taken 18826 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 21 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 21 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
18889 | static const auto poreInscribedRadiusIdx = gridData.parameterIndex("PoreInscribedRadius"); |
115 |
7/14✓ Branch 0 taken 21 times.
✓ Branch 1 taken 18826 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 21 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 21 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
18847 | static const auto poreLabelIdx = gridData.parameterIndex("PoreLabel"); |
116 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18847 times.
|
18847 | const auto vIdx = gridView.indexSet().index(vertex); |
117 | 18847 | const auto& params = gridData.parameters(vertex); | |
118 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 18847 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18847 times.
|
37694 | poreInscribedRadius_[vIdx] = params[poreInscribedRadiusIdx]; |
119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18847 times.
|
18847 | assert(poreInscribedRadius_[vIdx] > 0.0); |
120 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 18847 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18847 times.
|
37694 | poreLabel_[vIdx] = params[poreLabelIdx]; |
121 | |||
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18847 times.
|
18847 | if (!useSameGeometryForAllPores()) |
123 | ✗ | poreGeometry_[vIdx] = getPoreGeometry_(gridData, vertex); | |
124 | |||
125 | 18847 | poreVolume_[vIdx] = getPoreVolume_(gridData, vertex, vIdx); | |
126 | } | ||
127 | |||
128 |
5/6✓ Branch 1 taken 42153 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 42153 times.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42153 times.
|
42177 | for (const auto& element : elements(gridView)) |
129 | { | ||
130 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42153 times.
|
42153 | const int eIdx = gridView.indexSet().index(element); |
131 | 42153 | const auto& params = gridData.parameters(element); | |
132 |
7/14✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42132 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 21 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 21 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
42195 | static const auto throatInscribedRadiusIdx = gridData.parameterIndex("ThroatInscribedRadius"); |
133 |
7/14✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42132 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 21 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 21 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
42153 | static const auto throatLengthIdx = gridData.parameterIndex("ThroatLength"); |
134 |
4/4✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42132 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 42132 times.
|
84306 | throatInscribedRadius_[eIdx] = params[throatInscribedRadiusIdx]; |
135 |
4/4✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42132 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 42132 times.
|
84306 | throatLength_[eIdx] = params[throatLengthIdx]; |
136 | |||
137 | // use a default value if no throat label is given by the grid | ||
138 |
6/10✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42132 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 21 times.
|
42153 | static const bool gridHasThroatLabel = gridData.gridHasElementParameter("ThroatLabel"); |
139 |
1/2✓ Branch 0 taken 42153 times.
✗ Branch 1 not taken.
|
42153 | if (gridHasThroatLabel) |
140 | { | ||
141 |
7/14✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42132 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 21 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 21 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
42153 | static const auto throatLabelIdx = gridData.parameterIndex("ThroatLabel"); |
142 | 126459 | throatLabel_[eIdx] = params[throatLabelIdx]; | |
143 | } | ||
144 | else | ||
145 | { | ||
146 | ✗ | const auto vIdx0 = gridView.indexSet().subIndex(element, 0, dim); | |
147 | ✗ | const auto vIdx1 = gridView.indexSet().subIndex(element, 1, dim); | |
148 | |||
149 | ✗ | const auto poreLabel0 = poreLabel(vIdx0); | |
150 | ✗ | const auto poreLabel1 = poreLabel(vIdx1); | |
151 | |||
152 | ✗ | if (poreLabel0 >= 0 && poreLabel1 >= 0) | |
153 | { | ||
154 | ✗ | std::cout << "\n Warning: Throat " | |
155 | << eIdx << " connects two boundary pores with different pore labels. Using the greater pore label as throat label.\n" | ||
156 | ✗ | << "Set the throat labels explicitly in your grid file, if needed." << std::endl; | |
157 | } | ||
158 | |||
159 | using std::max; | ||
160 | ✗ | throatLabel_[eIdx] = max(poreLabel0, poreLabel1); | |
161 | } | ||
162 | |||
163 |
2/2✓ Branch 0 taken 6382 times.
✓ Branch 1 taken 35771 times.
|
42153 | if (!useSameShapeForAllThroats()) |
164 | { | ||
165 |
7/14✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6381 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
6384 | static const auto throatShapeFactorIdx = gridData.parameterIndex("ThroatShapeFactor"); |
166 |
7/14✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6381 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
6384 | static const auto throatAreaIdx = gridData.parameterIndex("ThroatCrossSectionalArea"); |
167 |
4/4✓ Branch 0 taken 4122 times.
✓ Branch 1 taken 2260 times.
✓ Branch 2 taken 4122 times.
✓ Branch 3 taken 2260 times.
|
12764 | throatShapeFactor_[eIdx] = params[throatShapeFactorIdx]; |
168 |
2/2✓ Branch 0 taken 4122 times.
✓ Branch 1 taken 2260 times.
|
10504 | throatGeometry_[eIdx] = Throat::shape(throatShapeFactor_[eIdx]); |
169 | 19146 | throatCrossSectionalArea_[eIdx] = params[throatAreaIdx]; | |
170 | } | ||
171 | else | ||
172 | { | ||
173 | 35771 | throatCrossSectionalArea_[eIdx] = getThroatCrossSectionalArea_(gridData, element, eIdx); | |
174 | 35771 | throatShapeFactor_[eIdx] = getThroatShapeFactor_(gridData, element, eIdx); | |
175 | } | ||
176 | |||
177 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 42153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42153 times.
|
84306 | assert(throatInscribedRadius_[eIdx] > 0.0); |
178 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 42153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42153 times.
|
84306 | assert(throatLength_[eIdx] > 0.0); |
179 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 42153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42153 times.
|
84306 | assert(throatCrossSectionalArea_[eIdx] > 0.0); |
180 | |||
181 |
5/8✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42132 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
42153 | static const bool addThroatVolumeToPoreVolume = getParamFromGroup<bool>(gridData.paramGroup(), "Grid.AddThroatVolumeToPoreVolume", false); |
182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42153 times.
|
42153 | if (addThroatVolumeToPoreVolume) |
183 | { | ||
184 | ✗ | for (int vIdxLocal = 0; vIdxLocal < 2; ++vIdxLocal) | |
185 | { | ||
186 | ✗ | const auto vIdx = gridView.indexSet().subIndex(element, vIdxLocal, dim); | |
187 | ✗ | poreVolume_[vIdx] += 0.5 * throatCrossSectionalArea_[eIdx] * throatLength_[eIdx]; | |
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | 24 | maybeResizeContainers_(); | |
193 | 24 | } | |
194 | |||
195 | //! Returns the pore label (e.g. used for setting BCs) | ||
196 | Label poreLabel(const GridIndex dofIdxGlobal) const | ||
197 |
59/68✓ Branch 0 taken 49599 times.
✓ Branch 1 taken 1460415 times.
✓ Branch 2 taken 49599 times.
✓ Branch 3 taken 1460415 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1316 times.
✓ Branch 6 taken 17037 times.
✓ Branch 7 taken 62929 times.
✓ Branch 8 taken 18353 times.
✓ Branch 9 taken 61613 times.
✓ Branch 10 taken 265812 times.
✓ Branch 11 taken 2758432 times.
✓ Branch 12 taken 265495 times.
✓ Branch 13 taken 2758115 times.
✓ Branch 14 taken 7377 times.
✓ Branch 15 taken 5356 times.
✓ Branch 16 taken 7986 times.
✓ Branch 17 taken 5666 times.
✓ Branch 18 taken 21515 times.
✓ Branch 19 taken 20869 times.
✓ Branch 20 taken 27465 times.
✓ Branch 21 taken 123769 times.
✓ Branch 22 taken 65157 times.
✓ Branch 23 taken 742879 times.
✓ Branch 24 taken 117514 times.
✓ Branch 25 taken 829614 times.
✓ Branch 26 taken 87561 times.
✓ Branch 27 taken 551575 times.
✓ Branch 28 taken 27280 times.
✓ Branch 29 taken 354760 times.
✓ Branch 30 taken 7323 times.
✓ Branch 31 taken 28251 times.
✓ Branch 32 taken 4472 times.
✓ Branch 33 taken 19699 times.
✓ Branch 34 taken 44251 times.
✓ Branch 35 taken 382748 times.
✓ Branch 36 taken 44250 times.
✓ Branch 37 taken 382744 times.
✓ Branch 38 taken 1407 times.
✓ Branch 39 taken 5383 times.
✓ Branch 40 taken 1407 times.
✓ Branch 41 taken 5383 times.
✓ Branch 42 taken 1365 times.
✓ Branch 43 taken 4018 times.
✓ Branch 44 taken 805 times.
✓ Branch 45 taken 3213 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 6790 times.
✗ Branch 48 not taken.
✓ Branch 49 taken 6790 times.
✓ Branch 50 taken 1732252 times.
✓ Branch 51 taken 2101022 times.
✓ Branch 52 taken 1732252 times.
✓ Branch 53 taken 2101022 times.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✓ Branch 64 taken 82760 times.
✓ Branch 65 taken 715720 times.
✓ Branch 66 taken 82760 times.
✓ Branch 67 taken 715720 times.
✓ Branch 68 taken 195 times.
✓ Branch 69 taken 1819 times.
✓ Branch 70 taken 195 times.
✓ Branch 71 taken 1819 times.
|
24654985 | { return poreLabel_[dofIdxGlobal]; } |
198 | |||
199 | //! Returns the vector of pore labels | ||
200 | const std::vector<Label>& poreLabel() const | ||
201 |
2/4✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
20 | { return poreLabel_; } |
202 | |||
203 | //! Returns the inscribed radius of the pore | ||
204 | Scalar poreInscribedRadius(const GridIndex dofIdxGlobal) const | ||
205 |
13/24✓ Branch 0 taken 2522976 times.
✓ Branch 1 taken 41563 times.
✓ Branch 2 taken 2522976 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2564539 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2522976 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2522976 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2522976 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1092264 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1092264 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1092264 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1092264 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1092264 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1092264 times.
✗ Branch 23 not taken.
|
42478828 | { return poreInscribedRadius_[dofIdxGlobal]; } |
206 | |||
207 | //! Returns the vector of inscribed pore radii | ||
208 | const std::vector<Scalar>& poreInscribedRadius() const | ||
209 | { return poreInscribedRadius_; } | ||
210 | |||
211 | //! Returns the volume of the pore | ||
212 | Scalar poreVolume(const GridIndex dofIdxGlobal) const | ||
213 | 15824760 | { return poreVolume_[dofIdxGlobal]; } | |
214 | |||
215 | //! Returns the vector of pore volumes | ||
216 | const std::vector<Scalar>& poreVolume() const | ||
217 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
3 | { return poreVolume_; } |
218 | |||
219 | //! Returns the inscribed radius of the throat | ||
220 | Scalar throatInscribedRadius(const GridIndex eIdx) const | ||
221 |
2/4✓ Branch 0 taken 722 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 722 times.
✗ Branch 3 not taken.
|
84730822 | { return throatInscribedRadius_[eIdx]; } |
222 | |||
223 | //! Returns the vector of inscribed throat radii | ||
224 | const std::vector<Scalar>& throatInscribedRadius() const | ||
225 | { return throatInscribedRadius_; } | ||
226 | |||
227 | //! Returns the length of the throat | ||
228 | Scalar throatLength(const GridIndex eIdx) const | ||
229 | 80928576 | { return throatLength_[eIdx]; } | |
230 | |||
231 | //! Returns the vector of throat lengths | ||
232 | const std::vector<Scalar>& throatLength() const | ||
233 | { return throatLength_; } | ||
234 | |||
235 | //! Returns an index indicating if a throat is touching the domain boundary | ||
236 | Label throatLabel(const GridIndex eIdx) const | ||
237 | 1444 | { return throatLabel_[eIdx]; } | |
238 | |||
239 | //! Returns the vector of throat labels | ||
240 | const std::vector<Label>& throatLabel() const | ||
241 |
2/4✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
20 | { return throatLabel_; } |
242 | |||
243 | //! Returns the number of throats connected to a pore (coordination number) | ||
244 | SmallLocalIndex coordinationNumber(const GridIndex dofIdxGlobal) const | ||
245 | 15813316 | { return coordinationNumber_[dofIdxGlobal]; } | |
246 | |||
247 | //! Returns the vector of coordination numbers | ||
248 | const std::vector<SmallLocalIndex>& coordinationNumber() const | ||
249 |
2/4✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
1368799 | { return coordinationNumber_; } |
250 | |||
251 | //! the geometry of the pore | ||
252 | Pore::Shape poreGeometry(const GridIndex vIdx) const | ||
253 |
2/4✓ Branch 0 taken 83320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2979476 times.
✗ Branch 3 not taken.
|
3063616 | { return useSameGeometryForAllPores() ? poreGeometry_[0] : poreGeometry_[vIdx]; } |
254 | |||
255 | //! Returns the vector of pore geometries | ||
256 | 3062796 | const std::vector<Pore::Shape>& poreGeometry() const | |
257 | { | ||
258 |
1/2✓ Branch 0 taken 3062796 times.
✗ Branch 1 not taken.
|
3062796 | if (useSameGeometryForAllPores()) |
259 | { | ||
260 | // if a vector of pore geometries is requested (e.g., for vtk output), | ||
261 | // resize the container and fill it with the same value everywhere | ||
262 | 3062796 | const auto poreGeo = poreGeometry_[0]; | |
263 | 6125592 | poreGeometry_.resize(poreInscribedRadius_.size(), poreGeo); | |
264 | } | ||
265 | |||
266 | 3062796 | return poreGeometry_; | |
267 | } | ||
268 | |||
269 | //! Returns the throat's cross-sectional shape | ||
270 | Throat::Shape throatCrossSectionShape(const GridIndex eIdx) const | ||
271 |
6/10✓ Branch 0 taken 2910328 times.
✓ Branch 1 taken 35427936 times.
✓ Branch 2 taken 1092264 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 92457 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 959946 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 959820 times.
✗ Branch 9 not taken.
|
41514293 | { return useSameShapeForAllThroats() ? throatGeometry_[0] : throatGeometry_[eIdx]; } |
272 | |||
273 | //! Returns the vector of cross-sectional shapes | ||
274 | const std::vector<Throat::Shape>& throatCrossSectionShape() const | ||
275 | { | ||
276 | if (useSameShapeForAllThroats()) | ||
277 | { | ||
278 | // if a vector of throat cross section shapes is requested (e.g., for vtk output), | ||
279 | // resize the container and fill it with the same value everywhere | ||
280 | const auto throatShape = throatGeometry_[0]; | ||
281 | throatGeometry_.resize(throatInscribedRadius_.size(), throatShape); | ||
282 | } | ||
283 | |||
284 | return throatGeometry_; | ||
285 | } | ||
286 | |||
287 | //! Returns the throat's cross-sectional area | ||
288 | Scalar throatCrossSectionalArea(const GridIndex eIdx) const | ||
289 |
4/4✓ Branch 0 taken 153993 times.
✓ Branch 1 taken 867363 times.
✓ Branch 2 taken 153993 times.
✓ Branch 3 taken 867363 times.
|
89019842 | { return throatCrossSectionalArea_[eIdx]; } |
290 | |||
291 | //! Returns the vector of throat cross-sectional areas | ||
292 | const std::vector<Scalar>& throatCrossSectionalArea() const | ||
293 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
3 | { return throatCrossSectionalArea_; } |
294 | |||
295 | //! Returns the throat's shape factor | ||
296 | Scalar throatShapeFactor(const GridIndex eIdx) const | ||
297 |
4/6✓ Branch 0 taken 1409717 times.
✓ Branch 1 taken 35427936 times.
✓ Branch 2 taken 3482796 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1092264 times.
✗ Branch 5 not taken.
|
41412713 | { return useSameShapeForAllThroats() ? throatShapeFactor_[0] : throatShapeFactor_[eIdx]; } |
298 | |||
299 | //! Returns the vector of throat shape factors | ||
300 | 2 | const std::vector<Scalar>& throatShapeFactor() const | |
301 | { | ||
302 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (useSameShapeForAllThroats()) |
303 | { | ||
304 | // if a vector of throat shape factors is requested (e.g., for vtk output), | ||
305 | // resize the container and fill it with the same value everywhere | ||
306 | 2 | const auto shapeFactor = throatShapeFactor_[0]; | |
307 | 4 | throatShapeFactor_.resize(throatInscribedRadius_.size(), shapeFactor); | |
308 | } | ||
309 | |||
310 | 2 | return throatShapeFactor_; | |
311 | } | ||
312 | |||
313 | //! Returns whether all pores feature the same shape | ||
314 | ✗ | bool useSameGeometryForAllPores() const | |
315 | ✗ | { return useSameGeometryForAllPores_; } | |
316 | |||
317 | //! Returns whether all throats feature the same cross-sectional shape | ||
318 | ✗ | bool useSameShapeForAllThroats() const | |
319 | ✗ | { return useSameShapeForAllThroats_; } | |
320 | |||
321 | private: | ||
322 | |||
323 | //! determine the pore geometry provided as scalar value by the grid file | ||
324 | template<class GridData> | ||
325 | ✗ | Pore::Shape getPoreGeometry_(const GridData& gridData, const Vertex& vertex) const | |
326 | { | ||
327 | ✗ | static const auto poreGeometryIdx = gridData.parameterIndex("PoreGeometry"); | |
328 | using T = std::underlying_type_t<Pore::Shape>; | ||
329 | ✗ | const auto poreGeometryValue = static_cast<T>(gridData.parameters(vertex)[poreGeometryIdx]); | |
330 | ✗ | return static_cast<Pore::Shape>(poreGeometryValue); | |
331 | } | ||
332 | |||
333 | //! automatically determine the pore volume if not provided by the grid file | ||
334 | template<class GridData> | ||
335 | 18847 | Scalar getPoreVolume_(const GridData& gridData, const Vertex& vertex, const std::size_t vIdx) const | |
336 | { | ||
337 |
6/10✓ Branch 0 taken 21 times.
✓ Branch 1 taken 18826 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 21 times.
|
18847 | static const bool gridHasPoreVolume = gridData.gridHasVertexParameter("PoreVolume"); |
338 | |||
339 |
2/2✓ Branch 0 taken 18027 times.
✓ Branch 1 taken 820 times.
|
18847 | if (gridHasPoreVolume) |
340 | { | ||
341 |
7/14✓ Branch 0 taken 10 times.
✓ Branch 1 taken 18017 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
18027 | static const auto poreVolumeIdx = gridData.parameterIndex("PoreVolume"); |
342 | 18027 | return gridData.parameters(vertex)[poreVolumeIdx]; | |
343 | } | ||
344 | else | ||
345 | { | ||
346 |
2/4✓ Branch 0 taken 820 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 820 times.
|
1640 | if (poreGeometry(vIdx) == Pore::Shape::cylinder) |
347 | { | ||
348 | ✗ | static const Scalar fixedHeight = getParamFromGroup<Scalar>(gridData.paramGroup(), "Grid.PoreHeight", -1.0); | |
349 | ✗ | const Scalar h = fixedHeight > 0.0 ? fixedHeight : gridData.getParameter(vertex, "PoreHeight"); | |
350 | ✗ | return Pore::volume(Pore::Shape::cylinder, poreInscribedRadius(vIdx), h); | |
351 | } | ||
352 | else | ||
353 | 1640 | return Pore::volume(poreGeometry(vIdx), poreInscribedRadius(vIdx)); | |
354 | } | ||
355 | } | ||
356 | |||
357 | //! automatically determine throat cross-sectional area if not provided by the grid file | ||
358 | template<class GridData> | ||
359 | 35771 | Scalar getThroatCrossSectionalArea_(const GridData& gridData, const Element& element, const std::size_t eIdx) const | |
360 | { | ||
361 |
6/10✓ Branch 0 taken 20 times.
✓ Branch 1 taken 35751 times.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 20 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 20 times.
✗ Branch 14 not taken.
|
35811 | static const bool gridHasThroatCrossSectionalArea = gridData.gridHasElementParameter("ThroatCrossSectionalArea"); |
362 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 35771 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
35771 | if (gridHasThroatCrossSectionalArea && !overwriteGridDataWithShapeSpecificValues_) |
363 | { | ||
364 | ✗ | static const auto throatAreaIdx = gridData.parameterIndex("ThroatCrossSectionalArea"); | |
365 | ✗ | return gridData.parameters(element)[throatAreaIdx]; | |
366 | } | ||
367 | else | ||
368 | { | ||
369 |
2/4✓ Branch 0 taken 35771 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35771 times.
|
71542 | if (const auto shape = throatCrossSectionShape(eIdx); shape == Throat::Shape::rectangle) |
370 | { | ||
371 | ✗ | static const auto throatHeight = getParamFromGroup<Scalar>(gridData.paramGroup(), "Grid.ThroatHeight"); | |
372 | ✗ | return Throat::totalCrossSectionalAreaForRectangle(throatInscribedRadius_[eIdx], throatHeight); | |
373 | } | ||
374 | else | ||
375 | 71542 | return Throat::totalCrossSectionalArea(shape, throatInscribedRadius_[eIdx]); | |
376 | } | ||
377 | } | ||
378 | |||
379 | //! automatically determine throat shape factor if not provided by the grid file | ||
380 | template<class GridData> | ||
381 | 35771 | Scalar getThroatShapeFactor_(const GridData& gridData, const Element& element, const std::size_t eIdx) const | |
382 | { | ||
383 |
6/10✓ Branch 0 taken 20 times.
✓ Branch 1 taken 35751 times.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 20 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 20 times.
✗ Branch 14 not taken.
|
35811 | static const bool gridHasThroatShapeFactor = gridData.gridHasElementParameter("ThroatShapeFactor"); |
384 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 35771 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
35771 | if (gridHasThroatShapeFactor && !overwriteGridDataWithShapeSpecificValues_) |
385 | { | ||
386 | ✗ | static const auto throatShapeFactorIdx = gridData.parameterIndex("ThroatShapeFactor"); | |
387 | ✗ | return gridData.parameters(element)[throatShapeFactorIdx]; | |
388 | } | ||
389 | else | ||
390 | { | ||
391 |
2/4✓ Branch 0 taken 35771 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35771 times.
|
71542 | if (const auto shape = throatCrossSectionShape(eIdx); shape == Throat::Shape::rectangle) |
392 | { | ||
393 | ✗ | static const auto throatHeight = getParamFromGroup<Scalar>(gridData.paramGroup(), "Grid.ThroatHeight"); | |
394 | ✗ | return Throat::shapeFactorRectangle(throatInscribedRadius_[eIdx], throatHeight); | |
395 | } | ||
396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35771 times.
|
35771 | else if (shape == Throat::Shape::polygon || shape == Throat::Shape::scaleneTriangle) |
397 | { | ||
398 | ✗ | static const auto shapeFactor = getParamFromGroup<Scalar>(gridData.paramGroup(), "Grid.ThroatShapeFactor"); | |
399 | ✗ | return shapeFactor; | |
400 | } | ||
401 | else | ||
402 | 71542 | return Throat::shapeFactor<Scalar>(shape, throatInscribedRadius_[eIdx]); | |
403 | } | ||
404 | } | ||
405 | |||
406 | 24 | void maybeResizeContainers_() | |
407 | { | ||
408 | // check if all throat might have the same shape in order to save some memory | ||
409 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
|
24 | if (!useSameShapeForAllThroats() && |
410 |
6/12✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
|
24 | std::adjacent_find(throatGeometry_.begin(), throatGeometry_.end(), std::not_equal_to<Throat::Shape>() ) == throatGeometry_.end()) |
411 | { | ||
412 | ✗ | std::cout << "All throats feature the same shape, resizing containers" << std::endl; | |
413 | ✗ | useSameShapeForAllThroats_ = true; | |
414 | ✗ | const Scalar shapeFactor = throatShapeFactor_[0]; | |
415 | ✗ | const auto throatGeometry = throatGeometry_[0]; | |
416 | ✗ | throatShapeFactor_.resize(1); | |
417 | ✗ | throatGeometry_.resize(1); | |
418 | ✗ | throatShapeFactor_[0] = shapeFactor; | |
419 | ✗ | throatGeometry_[0] = throatGeometry; | |
420 | } | ||
421 | |||
422 | // check if all throat might have the same shape in order to save some memory | ||
423 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if (!useSameGeometryForAllPores() && |
424 | ✗ | std::adjacent_find(poreGeometry_.begin(), poreGeometry_.end(), std::not_equal_to<Pore::Shape>() ) == poreGeometry_.end()) | |
425 | { | ||
426 | ✗ | std::cout << "All pores feature the same shape, resizing containers" << std::endl; | |
427 | ✗ | useSameGeometryForAllPores_ = true; | |
428 | ✗ | const auto poreGeometry = poreGeometry_[0]; | |
429 | ✗ | poreGeometry_.resize(1); | |
430 | ✗ | poreGeometry_[0] = poreGeometry; | |
431 | } | ||
432 | 24 | } | |
433 | |||
434 | mutable std::vector<Pore::Shape> poreGeometry_; | ||
435 | std::vector<Scalar> poreInscribedRadius_; | ||
436 | std::vector<Scalar> poreVolume_; | ||
437 | std::vector<Label> poreLabel_; // 0:no, 1:general, 2:coupling1, 3:coupling2, 4:inlet, 5:outlet | ||
438 | std::vector<SmallLocalIndex> coordinationNumber_; | ||
439 | mutable std::vector<Throat::Shape> throatGeometry_; | ||
440 | mutable std::vector<Scalar> throatShapeFactor_; | ||
441 | std::vector<Scalar> throatInscribedRadius_; | ||
442 | std::vector<Scalar> throatLength_; | ||
443 | std::vector<Label> throatLabel_; // 0:no, 1:general, 2:coupling1, 3:coupling2, 4:inlet, 5:outlet | ||
444 | std::vector<Scalar> throatCrossSectionalArea_; | ||
445 | bool useSameGeometryForAllPores_; | ||
446 | bool useSameShapeForAllThroats_; | ||
447 | bool overwriteGridDataWithShapeSpecificValues_; | ||
448 | }; | ||
449 | |||
450 | /*! | ||
451 | * \ingroup PoreNetworkDiscretization | ||
452 | * \brief The default traits | ||
453 | * \tparam the grid view type | ||
454 | */ | ||
455 | template<class GridView, class MapperTraits = DefaultMapperTraits<GridView>> | ||
456 | struct PNMDefaultGridGeometryTraits | ||
457 | : public MapperTraits | ||
458 | { | ||
459 | using SubControlVolume = PNMSubControlVolume<GridView>; | ||
460 | using SubControlVolumeFace = PNMSubControlVolumeFace<GridView>; | ||
461 | |||
462 | template<class GridGeometry, bool enableCache> | ||
463 | using LocalView = PNMFVElementGeometry<GridGeometry, enableCache>; | ||
464 | |||
465 | using PNMData = DefaultPNMData<typename SubControlVolume::Traits::Scalar, GridView>; | ||
466 | }; | ||
467 | |||
468 | /*! | ||
469 | * \ingroup PoreNetworkDiscretization | ||
470 | * \brief Base class for the finite volume geometry for porenetwork models | ||
471 | * \note This class is specialized for versions with and without caching the fv geometries on the grid view | ||
472 | */ | ||
473 | template<class Scalar, | ||
474 | class GridView, | ||
475 | bool enableGridGeometryCache = false, | ||
476 | class Traits = PNMDefaultGridGeometryTraits<GridView> > | ||
477 | class GridGeometry; | ||
478 | |||
479 | /*! | ||
480 | * \ingroup PoreNetworkDiscretization | ||
481 | * \brief Base class for the finite volume geometry for porenetwork models | ||
482 | * \note For caching enabled we store the fv geometries for the whole grid view which is memory intensive but faster | ||
483 | */ | ||
484 | template<class Scalar, class GV, class Traits> | ||
485 | class GridGeometry<Scalar, GV, true, Traits> | ||
486 | : public BaseGridGeometry<GV, Traits> | ||
487 | , public Traits::PNMData | ||
488 | { | ||
489 | using ThisType = GridGeometry<Scalar, GV, true, Traits>; | ||
490 | using ParentType = BaseGridGeometry<GV, Traits>; | ||
491 | using GridIndexType = typename IndexTraits<GV>::GridIndex; | ||
492 | using LocalIndexType = typename IndexTraits<GV>::LocalIndex; | ||
493 | using PNMData = typename Traits::PNMData; | ||
494 | |||
495 | using Element = typename GV::template Codim<0>::Entity; | ||
496 | using CoordScalar = typename GV::ctype; | ||
497 | static const int dim = GV::dimension; | ||
498 | static const int dimWorld = GV::dimensionworld; | ||
499 | |||
500 | public: | ||
501 | //! export the discretization method this geometry belongs to | ||
502 | using DiscretizationMethod = DiscretizationMethods::Box; | ||
503 | static constexpr DiscretizationMethod discMethod{}; | ||
504 | |||
505 | //! export the type of the fv element geometry (the local view type) | ||
506 | using LocalView = typename Traits::template LocalView<ThisType, true>; | ||
507 | //! export the type of sub control volume | ||
508 | using SubControlVolume = typename Traits::SubControlVolume; | ||
509 | //! export the type of sub control volume | ||
510 | using SubControlVolumeFace = typename Traits::SubControlVolumeFace; | ||
511 | //! export the type of extrusion | ||
512 | using Extrusion = Extrusion_t<Traits>; | ||
513 | //! export dof mapper type | ||
514 | using DofMapper = typename Traits::VertexMapper; | ||
515 | //! export the finite element cache type | ||
516 | using FeCache = Dune::LagrangeLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; | ||
517 | //! export the grid view type | ||
518 | using GridView = GV; | ||
519 | |||
520 | //! Constructor | ||
521 | template<class GridData> | ||
522 | GridGeometry(const GridView& gridView, const GridData& gridData) | ||
523 | : ParentType(gridView) | ||
524 | { | ||
525 | static_assert(GridView::dimension == 1, "Porenetwork model only allow GridView::dimension == 1!"); | ||
526 | update_(gridData); | ||
527 | } | ||
528 | |||
529 | //! the vertex mapper is the dofMapper | ||
530 | //! this is convenience to have better chance to have the same main files for box/tpfa/mpfa... | ||
531 | const DofMapper& dofMapper() const | ||
532 | { return this->vertexMapper(); } | ||
533 | |||
534 | //! The total number of sub control volumes | ||
535 | std::size_t numScv() const | ||
536 | { return numScv_; } | ||
537 | |||
538 | //! The total number of sun control volume faces | ||
539 | std::size_t numScvf() const | ||
540 | { return numScvf_; } | ||
541 | |||
542 | //! The total number of boundary sub control volume faces | ||
543 | //! For compatibility reasons with cc methods | ||
544 | std::size_t numBoundaryScvf() const | ||
545 | { return 0; } | ||
546 | |||
547 | //! The total number of degrees of freedom | ||
548 | std::size_t numDofs() const | ||
549 | { return this->vertexMapper().size(); } | ||
550 | |||
551 | //! update all fvElementGeometries (call this after grid adaption) | ||
552 | template<class GridData> | ||
553 | void update(const GridView& gridView, const GridData& gridData) | ||
554 | { | ||
555 | ParentType::update(gridView); | ||
556 | update_(gridData); | ||
557 | } | ||
558 | |||
559 | //! update all fvElementGeometries (call this after grid adaption) | ||
560 | template<class GridData> | ||
561 | void update(GridView&& gridView, const GridData& gridData) | ||
562 | { | ||
563 | ParentType::update(std::move(gridView)); | ||
564 | update_(gridData); | ||
565 | } | ||
566 | |||
567 | //! The finite element cache for creating local FE bases | ||
568 | const FeCache& feCache() const | ||
569 | { return feCache_; } | ||
570 | |||
571 | //! Get the local scvs for an element | ||
572 | const std::array<SubControlVolume, 2>& scvs(GridIndexType eIdx) const | ||
573 | { return scvs_[eIdx]; } | ||
574 | |||
575 | //! Get the local scvfs for an element | ||
576 | const std::array<SubControlVolumeFace, 1>& scvfs(GridIndexType eIdx) const | ||
577 | { return scvfs_[eIdx]; } | ||
578 | |||
579 | //! If a vertex / d.o.f. is on the boundary | ||
580 | bool dofOnBoundary(GridIndexType dofIdx) const | ||
581 | { return boundaryDofIndices_[dofIdx]; } | ||
582 | |||
583 | //! If a vertex / d.o.f. is on a periodic boundary (not implemented) | ||
584 | bool dofOnPeriodicBoundary(GridIndexType dofIdx) const | ||
585 | { return false; } | ||
586 | |||
587 | //! The index of the vertex / d.o.f. on the other side of the periodic boundary | ||
588 | GridIndexType periodicallyMappedDof(GridIndexType dofIdx) const | ||
589 | { DUNE_THROW(Dune::NotImplemented, "Periodic boundaries"); } | ||
590 | |||
591 | //! Returns the map between dofs across periodic boundaries | ||
592 | [[deprecated("Will be removed after release 3.9. Implement periodicDofMap() if periodic bcs are supported.")]] | ||
593 | std::unordered_map<GridIndexType, GridIndexType> periodicVertexMap() const | ||
594 | { return std::unordered_map<GridIndexType, GridIndexType>{}; } | ||
595 | |||
596 | //! Returns whether one of the geometry's scvfs lies on a boundary | ||
597 | bool hasBoundaryScvf(GridIndexType eIdx) const | ||
598 | { return hasBoundaryScvf_[eIdx]; } | ||
599 | |||
600 | private: | ||
601 | |||
602 | template<class GridData> | ||
603 | void update_(const GridData& gridData) | ||
604 | { | ||
605 | PNMData::update(this->gridView(), gridData); | ||
606 | |||
607 | scvs_.clear(); | ||
608 | scvfs_.clear(); | ||
609 | |||
610 | auto numElements = this->gridView().size(0); | ||
611 | scvs_.resize(numElements); | ||
612 | scvfs_.resize(numElements); | ||
613 | hasBoundaryScvf_.resize(numElements, false); | ||
614 | |||
615 | boundaryDofIndices_.assign(numDofs(), false); | ||
616 | |||
617 | numScvf_ = numElements; | ||
618 | numScv_ = 2*numElements; | ||
619 | |||
620 | // Build the SCV and SCV faces | ||
621 | for (const auto& element : elements(this->gridView())) | ||
622 | { | ||
623 | // get the element geometry | ||
624 | auto eIdx = this->elementMapper().index(element); | ||
625 | auto elementGeometry = element.geometry(); | ||
626 | |||
627 | // construct the sub control volumes | ||
628 | for (LocalIndexType scvLocalIdx = 0; scvLocalIdx < elementGeometry.corners(); ++scvLocalIdx) | ||
629 | { | ||
630 | const auto dofIdxGlobal = this->vertexMapper().subIndex(element, scvLocalIdx, dim); | ||
631 | |||
632 | // get the corners | ||
633 | auto corners = std::array{elementGeometry.corner(scvLocalIdx), elementGeometry.center()}; | ||
634 | |||
635 | // get the fractional volume associated with the scv | ||
636 | const auto volume = this->poreVolume(dofIdxGlobal) / this->coordinationNumber(dofIdxGlobal); | ||
637 | |||
638 | scvs_[eIdx][scvLocalIdx] = SubControlVolume(dofIdxGlobal, | ||
639 | scvLocalIdx, | ||
640 | eIdx, | ||
641 | std::move(corners), | ||
642 | volume); | ||
643 | |||
644 | if (this->poreLabel(dofIdxGlobal) > 0) | ||
645 | { | ||
646 | if (boundaryDofIndices_[dofIdxGlobal]) | ||
647 | continue; | ||
648 | |||
649 | boundaryDofIndices_[dofIdxGlobal] = true; | ||
650 | hasBoundaryScvf_[eIdx] = true; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | // construct the inner sub control volume face | ||
655 | auto unitOuterNormal = elementGeometry.corner(1)-elementGeometry.corner(0); | ||
656 | unitOuterNormal /= unitOuterNormal.two_norm(); | ||
657 | LocalIndexType scvfLocalIdx = 0; | ||
658 | scvfs_[eIdx][0] = SubControlVolumeFace(elementGeometry.center(), | ||
659 | std::move(unitOuterNormal), | ||
660 | this->throatCrossSectionalArea(this->elementMapper().index(element)), | ||
661 | scvfLocalIdx++, | ||
662 | std::array<LocalIndexType, 2>({0, 1})); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | const FeCache feCache_; | ||
667 | |||
668 | std::vector<std::array<SubControlVolume, 2>> scvs_; | ||
669 | std::vector<std::array<SubControlVolumeFace, 1>> scvfs_; | ||
670 | |||
671 | std::size_t numScv_; | ||
672 | std::size_t numScvf_; | ||
673 | |||
674 | // vertices on the boundary | ||
675 | std::vector<bool> boundaryDofIndices_; | ||
676 | std::vector<bool> hasBoundaryScvf_; | ||
677 | }; | ||
678 | |||
679 | /*! | ||
680 | * \ingroup PoreNetworkDiscretization | ||
681 | * \brief Base class for the finite volume geometry for porenetwork models | ||
682 | * \note For caching disabled we store only some essential index maps to build up local systems on-demand in | ||
683 | * the corresponding FVElementGeometry | ||
684 | */ | ||
685 | template<class Scalar, class GV, class Traits> | ||
686 | class GridGeometry<Scalar, GV, false, Traits> | ||
687 | : public BaseGridGeometry<GV, Traits> | ||
688 | , public Traits::PNMData | ||
689 | { | ||
690 | using ThisType = GridGeometry<Scalar, GV, false, Traits>; | ||
691 | using ParentType = BaseGridGeometry<GV, Traits>; | ||
692 | using GridIndexType = typename IndexTraits<GV>::GridIndex; | ||
693 | using LocalIndexType = typename IndexTraits<GV>::LocalIndex; | ||
694 | using PNMData = typename Traits::PNMData; | ||
695 | |||
696 | static const int dim = GV::dimension; | ||
697 | static const int dimWorld = GV::dimensionworld; | ||
698 | |||
699 | using Element = typename GV::template Codim<0>::Entity; | ||
700 | using CoordScalar = typename GV::ctype; | ||
701 | |||
702 | public: | ||
703 | //! export the discretization method this geometry belongs to | ||
704 | using DiscretizationMethod = DiscretizationMethods::Box; | ||
705 | static constexpr DiscretizationMethod discMethod{}; | ||
706 | |||
707 | //! export the type of the fv element geometry (the local view type) | ||
708 | using LocalView = typename Traits::template LocalView<ThisType, false>; | ||
709 | //! export the type of sub control volume | ||
710 | using SubControlVolume = typename Traits::SubControlVolume; | ||
711 | //! export the type of sub control volume | ||
712 | using SubControlVolumeFace = typename Traits::SubControlVolumeFace; | ||
713 | //! export the type of extrusion | ||
714 | using Extrusion = Extrusion_t<Traits>; | ||
715 | //! export dof mapper type | ||
716 | using DofMapper = typename Traits::VertexMapper; | ||
717 | //! export the finite element cache type | ||
718 | using FeCache = Dune::LagrangeLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; | ||
719 | //! export the grid view type | ||
720 | using GridView = GV; | ||
721 | |||
722 | //! Constructor | ||
723 | template<class GridData> | ||
724 | 22 | GridGeometry(const GridView& gridView, const GridData& gridData) | |
725 |
2/6✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
22 | : ParentType(gridView) |
726 | { | ||
727 | static_assert(GridView::dimension == 1, "Porenetwork model only allow GridView::dimension == 1!"); | ||
728 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | update_(gridData); |
729 | 22 | } | |
730 | |||
731 | |||
732 | //! the vertex mapper is the dofMapper | ||
733 | //! this is convenience to have better chance to have the same main files for box/tpfa/mpfa... | ||
734 | const DofMapper& dofMapper() const | ||
735 |
9/32✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 501 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 501 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4880 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4880 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 2 times.
✓ Branch 24 taken 3 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 5 times.
✗ Branch 27 not taken.
✓ Branch 29 taken 6 times.
✗ Branch 30 not taken.
✓ Branch 32 taken 6 times.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
|
21720024 | { return this->vertexMapper(); } |
736 | |||
737 | //! The total number of sub control volumes | ||
738 | std::size_t numScv() const | ||
739 | { return numScv_; } | ||
740 | |||
741 | //! The total number of sun control volume faces | ||
742 | std::size_t numScvf() const | ||
743 | { return numScvf_; } | ||
744 | |||
745 | //! The total number of boundary sub control volume faces | ||
746 | //! For compatibility reasons with cc methods | ||
747 | std::size_t numBoundaryScvf() const | ||
748 | { return 0; } | ||
749 | |||
750 | //! The total number of degrees of freedom | ||
751 | std::size_t numDofs() const | ||
752 |
55/99✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✓ Branch 17 taken 7 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✓ Branch 20 taken 5 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✓ Branch 23 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✓ Branch 29 taken 2 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✓ Branch 35 taken 140 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 140 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 140 times.
✓ Branch 41 taken 1 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 1 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 1 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 3 times.
✗ Branch 51 not taken.
✓ Branch 53 taken 4 times.
✗ Branch 54 not taken.
✓ Branch 56 taken 4 times.
✗ Branch 57 not taken.
✓ Branch 59 taken 4 times.
✗ Branch 60 not taken.
✓ Branch 62 taken 4 times.
✗ Branch 63 not taken.
✓ Branch 65 taken 4 times.
✗ Branch 66 not taken.
✓ Branch 68 taken 2 times.
✗ Branch 69 not taken.
✓ Branch 71 taken 2 times.
✗ Branch 72 not taken.
✓ Branch 74 taken 2 times.
✗ Branch 75 not taken.
✓ Branch 77 taken 1 times.
✗ Branch 78 not taken.
✓ Branch 80 taken 1 times.
✗ Branch 81 not taken.
✓ Branch 83 taken 1 times.
✗ Branch 84 not taken.
✓ Branch 86 taken 1 times.
✗ Branch 87 not taken.
✓ Branch 89 taken 1 times.
✗ Branch 90 not taken.
✓ Branch 92 taken 1 times.
✗ Branch 93 not taken.
✓ Branch 95 taken 1 times.
✗ Branch 96 not taken.
✓ Branch 98 taken 1 times.
✗ Branch 99 not taken.
✓ Branch 101 taken 1 times.
✗ Branch 102 not taken.
✓ Branch 104 taken 1 times.
✗ Branch 105 not taken.
✓ Branch 107 taken 1 times.
✗ Branch 108 not taken.
✓ Branch 110 taken 1 times.
✗ Branch 111 not taken.
✓ Branch 113 taken 1 times.
✗ Branch 114 not taken.
✓ Branch 116 taken 1 times.
✗ Branch 117 not taken.
✓ Branch 119 taken 1 times.
✗ Branch 120 not taken.
✓ Branch 122 taken 1 times.
✗ Branch 123 not taken.
✓ Branch 125 taken 1 times.
✗ Branch 126 not taken.
✓ Branch 128 taken 1 times.
✗ Branch 129 not taken.
✓ Branch 131 taken 1 times.
✗ Branch 132 not taken.
|
708 | { return this->vertexMapper().size(); } |
753 | |||
754 | //! update all fvElementGeometries (call this after grid adaption) | ||
755 | template<class GridData> | ||
756 | void update(const GridView& gridView, const GridData& gridData) | ||
757 | { | ||
758 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | ParentType::update(gridView); |
759 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | update_(gridData); |
760 | } | ||
761 | |||
762 | //! update all fvElementGeometries (call this after grid adaption) | ||
763 | template<class GridData> | ||
764 | void update(GridView&& gridView, const GridData& gridData) | ||
765 | { | ||
766 | ParentType::update(std::move(gridView)); | ||
767 | update_(gridData); | ||
768 | } | ||
769 | |||
770 | //! The finite element cache for creating local FE bases | ||
771 | const FeCache& feCache() const | ||
772 | 5427310 | { return feCache_; } | |
773 | |||
774 | //! If a vertex / d.o.f. is on the boundary | ||
775 | bool dofOnBoundary(GridIndexType dofIdx) const | ||
776 |
12/12✓ Branch 0 taken 222602 times.
✓ Branch 1 taken 2132830 times.
✓ Branch 2 taken 222602 times.
✓ Branch 3 taken 2132830 times.
✓ Branch 4 taken 85052 times.
✓ Branch 5 taken 855798 times.
✓ Branch 6 taken 85052 times.
✓ Branch 7 taken 855798 times.
✓ Branch 8 taken 496 times.
✓ Branch 9 taken 480 times.
✓ Branch 10 taken 496 times.
✓ Branch 11 taken 480 times.
|
6594516 | { return boundaryDofIndices_[dofIdx]; } |
777 | |||
778 | //! If a vertex / d.o.f. is on a periodic boundary (not implemented) | ||
779 | ✗ | bool dofOnPeriodicBoundary(GridIndexType dofIdx) const | |
780 | ✗ | { return false; } | |
781 | |||
782 | //! The index of the vertex / d.o.f. on the other side of the periodic boundary | ||
783 | ✗ | GridIndexType periodicallyMappedDof(GridIndexType dofIdx) const | |
784 | ✗ | { DUNE_THROW(Dune::NotImplemented, "Periodic boundaries"); } | |
785 | |||
786 | //! Returns the map between dofs across periodic boundaries | ||
787 | [[deprecated("Will be removed after release 3.9. Implement periodicDofMap() if periodic bcs are supported.")]] | ||
788 | std::unordered_map<GridIndexType, GridIndexType> periodicVertexMap() const | ||
789 | { return std::unordered_map<GridIndexType, GridIndexType>{}; } | ||
790 | |||
791 | private: | ||
792 | |||
793 | template<class GridData> | ||
794 | 24 | void update_(const GridData& gridData) | |
795 | { | ||
796 | 48 | PNMData::update(this->gridView(), gridData); | |
797 | |||
798 | 48 | boundaryDofIndices_.assign(numDofs(), false); | |
799 | |||
800 | // save global data on the grid's scvs and scvfs | ||
801 | 48 | numScvf_ = this->gridView().size(0); | |
802 | 24 | numScv_ = 2*numScvf_; | |
803 | |||
804 |
4/4✓ Branch 2 taken 42153 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 42153 times.
✓ Branch 5 taken 24 times.
|
42201 | for (const auto& element : elements(this->gridView())) |
805 | { | ||
806 | // treat boundaries | ||
807 |
2/2✓ Branch 0 taken 84306 times.
✓ Branch 1 taken 42153 times.
|
126459 | for (LocalIndexType vIdxLocal = 0; vIdxLocal < 2; ++vIdxLocal) |
808 | { | ||
809 | 168612 | const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdxLocal, dim); | |
810 |
4/4✓ Branch 0 taken 14154 times.
✓ Branch 1 taken 70152 times.
✓ Branch 2 taken 14154 times.
✓ Branch 3 taken 70152 times.
|
168612 | if (this->poreLabel(vIdxGlobal) > 0) |
811 | { | ||
812 |
6/6✓ Branch 0 taken 4762 times.
✓ Branch 1 taken 9392 times.
✓ Branch 2 taken 4762 times.
✓ Branch 3 taken 9392 times.
✓ Branch 4 taken 4762 times.
✓ Branch 5 taken 9392 times.
|
42462 | if (boundaryDofIndices_[vIdxGlobal]) |
813 | continue; | ||
814 | |||
815 | 14286 | boundaryDofIndices_[vIdxGlobal] = true; | |
816 | } | ||
817 | } | ||
818 | } | ||
819 | 24 | } | |
820 | |||
821 | const FeCache feCache_; | ||
822 | |||
823 | // Information on the global number of geometries | ||
824 | std::size_t numScv_; | ||
825 | std::size_t numScvf_; | ||
826 | |||
827 | // vertices on the boundary | ||
828 | std::vector<bool> boundaryDofIndices_; | ||
829 | }; | ||
830 | |||
831 | } // end namespace Dumux::PoreNetwork | ||
832 | |||
833 | #endif | ||
834 |