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 | /*! | ||
9 | * \file | ||
10 | * \ingroup PNMTwoPModel | ||
11 | * \brief A (quasi-) static two-phase pore-network model for drainage processes. | ||
12 | */ | ||
13 | #ifndef DUMUX_PNM_TWOP_STATIC_DRAINAGE_HH | ||
14 | #define DUMUX_PNM_TWOP_STATIC_DRAINAGE_HH | ||
15 | |||
16 | #include <stack> | ||
17 | #include <vector> | ||
18 | |||
19 | namespace Dumux::PoreNetwork { | ||
20 | |||
21 | /*! | ||
22 | * \ingroup PNMTwoPModel | ||
23 | * | ||
24 | * \brief A (quasi-) static two-phase pore-network model for drainage processes. | ||
25 | * This assumes that there are no pressure gradients within the phases and thus, no flow. | ||
26 | */ | ||
27 | template<class GridGeometry, class Scalar> | ||
28 | class TwoPStaticDrainage | ||
29 | { | ||
30 | using GridView = typename GridGeometry::GridView; | ||
31 | |||
32 | public: | ||
33 | |||
34 | 1 | TwoPStaticDrainage(const GridGeometry& gridGeometry, | |
35 | const std::vector<Scalar>& pcEntry, | ||
36 | const std::vector<int>& throatLabel, | ||
37 | const int inletPoreLabel, | ||
38 | const int outletPoreLabel, | ||
39 | const bool allowDraingeOfOutlet = false) | ||
40 | : gridView_(gridGeometry.gridView()) | ||
41 | , pcEntry_(pcEntry) | ||
42 | , throatLabel_(throatLabel) | ||
43 | , inletThroatLabel_(inletPoreLabel) | ||
44 | , outletThroatLabel_(outletPoreLabel) | ||
45 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | , allowDraingeOfOutlet_(allowDraingeOfOutlet) |
46 | {} | ||
47 | |||
48 | /*! | ||
49 | * \brief Updates the invasion state of the network for the given global capillary pressure. | ||
50 | * | ||
51 | * \param elementIsInvaded A vector storing the invasion state of the network. | ||
52 | * \param pcGlobal The global capillary pressure to be applied. | ||
53 | */ | ||
54 | 51 | void updateInvasionState(std::vector<bool>& elementIsInvaded, const Scalar pcGlobal) | |
55 | { | ||
56 | // iterate over all elements (throats) | ||
57 |
5/6✓ Branch 1 taken 36822 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 36822 times.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36822 times.
|
36873 | for (const auto& element : elements(gridView_)) |
58 | { | ||
59 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 36822 times.
✓ Branch 2 taken 16642 times.
✓ Branch 3 taken 20180 times.
|
36822 | const auto eIdx = gridView_.indexSet().index(element); |
60 | |||
61 | // if the throat is already invaded, do nothing and continue | ||
62 |
6/6✓ Branch 0 taken 16642 times.
✓ Branch 1 taken 20180 times.
✓ Branch 2 taken 16642 times.
✓ Branch 3 taken 20180 times.
✓ Branch 4 taken 16642 times.
✓ Branch 5 taken 20180 times.
|
110466 | if (elementIsInvaded[eIdx]) |
63 | continue; | ||
64 | |||
65 | // try to find a seed from which to start the search process | ||
66 | 16642 | bool isSeed = false; | |
67 | |||
68 | // start at the inlet boundary | ||
69 |
8/8✓ Branch 0 taken 1030 times.
✓ Branch 1 taken 15612 times.
✓ Branch 2 taken 1030 times.
✓ Branch 3 taken 15612 times.
✓ Branch 4 taken 40 times.
✓ Branch 5 taken 990 times.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 990 times.
|
33284 | if (throatLabel_[eIdx] == inletThroatLabel_ && pcGlobal >= pcEntry_[eIdx]) |
70 | { | ||
71 | 40 | ++numThroatsInvaded_; | |
72 | 40 | isSeed = true; | |
73 | } | ||
74 | |||
75 | // if no throat gets invaded at the inlet, search the interior domain | ||
76 | if (!isSeed) | ||
77 | { | ||
78 | // find a throat which is not invaded yet but has an invaded neighbor (invasion-percolation) | ||
79 |
4/6✓ Branch 3 taken 90477 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 69278 times.
✓ Branch 6 taken 4805 times.
✓ Branch 8 taken 73875 times.
✗ Branch 9 not taken.
|
226163 | for (const auto& intersection : intersections(gridView_, element)) |
80 | { | ||
81 |
4/4✓ Branch 0 taken 69278 times.
✓ Branch 1 taken 4805 times.
✓ Branch 2 taken 69278 times.
✓ Branch 3 taken 4805 times.
|
148166 | if (intersection.neighbor()) |
82 | { | ||
83 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 69278 times.
|
69278 | const auto& neighborElement = intersection.outside(); |
84 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 69278 times.
✓ Branch 2 taken 3476 times.
✓ Branch 3 taken 65802 times.
|
69278 | const auto nIdx = gridView_.indexSet().index(neighborElement); |
85 |
15/16✓ Branch 0 taken 3476 times.
✓ Branch 1 taken 65802 times.
✓ Branch 2 taken 3476 times.
✓ Branch 3 taken 65802 times.
✓ Branch 4 taken 3476 times.
✓ Branch 5 taken 65802 times.
✓ Branch 6 taken 1927 times.
✓ Branch 7 taken 1549 times.
✓ Branch 8 taken 1927 times.
✓ Branch 9 taken 1549 times.
✓ Branch 10 taken 1927 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 208 times.
✓ Branch 13 taken 1719 times.
✓ Branch 14 taken 208 times.
✓ Branch 15 taken 1719 times.
|
207834 | if (elementIsInvaded[nIdx] && pcGlobal >= pcEntry_[eIdx] && (allowDraingeOfOutlet_ || throatLabel_[eIdx] != outletThroatLabel_)) |
86 | { | ||
87 | 208 | ++numThroatsInvaded_; | |
88 | 208 | isSeed = true; | |
89 | break; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // if an invaded throat is found, continue the search for neighboring invaded throats | ||
96 |
2/2✓ Branch 0 taken 248 times.
✓ Branch 1 taken 16394 times.
|
16642 | if (isSeed) |
97 | { | ||
98 | 496 | elementIsInvaded[eIdx] = true; | |
99 | |||
100 | // use iteration instead of recursion here because the recursion can get too deep | ||
101 | using Element = typename GridView::template Codim<0>::Entity; | ||
102 | 496 | std::stack<Element> elementStack; | |
103 |
1/2✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
|
248 | elementStack.push(element); |
104 |
4/4✓ Branch 0 taken 686 times.
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 686 times.
✓ Branch 3 taken 248 times.
|
1868 | while (!elementStack.empty()) |
105 | { | ||
106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 686 times.
|
686 | auto e = elementStack.top(); |
107 | 686 | elementStack.pop(); | |
108 | |||
109 |
5/8✓ Branch 1 taken 686 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3916 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 3072 times.
✓ Branch 11 taken 158 times.
✓ Branch 13 taken 3230 times.
✗ Branch 14 not taken.
|
9732 | for (const auto& intersection : intersections(gridView_, e)) |
110 | { | ||
111 |
4/4✓ Branch 0 taken 3072 times.
✓ Branch 1 taken 158 times.
✓ Branch 2 taken 3072 times.
✓ Branch 3 taken 158 times.
|
6460 | if (intersection.neighbor()) |
112 | { | ||
113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3072 times.
|
3072 | const auto& neighborElement = intersection.outside(); |
114 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 3072 times.
✓ Branch 2 taken 1358 times.
✓ Branch 3 taken 1714 times.
|
3072 | const auto nIdx = gridView_.indexSet().index(neighborElement); |
115 |
15/16✓ Branch 0 taken 1358 times.
✓ Branch 1 taken 1714 times.
✓ Branch 2 taken 1358 times.
✓ Branch 3 taken 1714 times.
✓ Branch 4 taken 1358 times.
✓ Branch 5 taken 1714 times.
✓ Branch 6 taken 486 times.
✓ Branch 7 taken 872 times.
✓ Branch 8 taken 486 times.
✓ Branch 9 taken 872 times.
✓ Branch 10 taken 486 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 438 times.
✓ Branch 13 taken 48 times.
✓ Branch 14 taken 438 times.
✓ Branch 15 taken 48 times.
|
9216 | if (!elementIsInvaded[nIdx] && pcGlobal >= pcEntry_[nIdx] && (allowDraingeOfOutlet_ || throatLabel_[nIdx] != outletThroatLabel_)) |
116 | { | ||
117 | 438 | ++numThroatsInvaded_; | |
118 |
2/4✓ Branch 0 taken 438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 438 times.
✗ Branch 3 not taken.
|
876 | elementIsInvaded[nIdx] = true; |
119 |
1/2✓ Branch 0 taken 438 times.
✗ Branch 1 not taken.
|
438 | elementStack.push(neighborElement); |
120 | } | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | 51 | } | |
127 | |||
128 | /*! | ||
129 | * \brief Returns the number of invaded throats. | ||
130 | */ | ||
131 | ✗ | std::size_t numThroatsInvaded() const | |
132 | ✗ | { return numThroatsInvaded_; } | |
133 | |||
134 | private: | ||
135 | const GridView& gridView_; | ||
136 | const std::vector<Scalar>& pcEntry_; | ||
137 | const std::vector<int>& throatLabel_; | ||
138 | const int inletThroatLabel_; | ||
139 | const int outletThroatLabel_; | ||
140 | const int allowDraingeOfOutlet_; | ||
141 | std::size_t numThroatsInvaded_ = 0; | ||
142 | }; | ||
143 | |||
144 | } // namespace Dumux::PoreNetwork | ||
145 | |||
146 | #endif | ||
147 |