GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/porenetwork/2p/spatialparams.hh
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 31 43 72.1%
Functions: 16 34 47.1%
Branches: 39 116 33.6%

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 PNMTwoPModel
10 * \ingroup SpatialParameters
11 * \brief The two-phase spatial parameters for pore-network models.
12 */
13 #ifndef DUMUX_PNM_2P_SPATIAL_PARAMS_HH
14 #define DUMUX_PNM_2P_SPATIAL_PARAMS_HH
15
16 #include <dumux/material/fluidmatrixinteractions/fluidmatrixinteraction.hh>
17 #include <dumux/material/fluidmatrixinteractions/porenetwork/throat/thresholdcapillarypressures.hh>
18
19 #include <dumux/porenetwork/common/spatialparams.hh>
20 #include <dumux/porenetwork/common/poreproperties.hh>
21 #include <dumux/porenetwork/common/throatproperties.hh>
22
23 namespace Dumux::PoreNetwork {
24
25 /*!
26 * \ingroup PNMTwoPModel
27 * \ingroup SpatialParameters
28 * \brief The base class for spatial parameters for pore-network models.
29 */
30 template<class GridGeometry, class Scalar, class LocalRules, class Implementation>
31 class TwoPSpatialParams
32 : public SpatialParams<GridGeometry, Scalar, Implementation>
33 {
34 using ParentType = SpatialParams<GridGeometry, Scalar, Implementation>;
35 using GridView = typename GridGeometry::GridView;
36 using SubControlVolume = typename GridGeometry::SubControlVolume;
37 using Element = typename GridView::template Codim<0>::Entity;
38 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
39
40 public:
41
42 4 TwoPSpatialParams(std::shared_ptr<const GridGeometry> gridGeometry)
43
3/12
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
8 : ParentType(gridGeometry)
44 {
45
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
8 if (!gridGeometry->useSameGeometryForAllPores() && LocalRules::supportsMultipleGeometries())
46 DUNE_THROW(Dune::InvalidStateException, "Your MaterialLaw does not support multiple pore body shapes.");
47
48
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 if (this->gridGeometry().useSameShapeForAllThroats())
49 {
50
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 cornerHalfAngles_.resize(1);
51
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 const auto& shape = this->gridGeometry().throatCrossSectionShape(/*eIdx*/0);
52
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 cornerHalfAngles_[0] = Throat::cornerHalfAngles<Scalar>(shape);
53 }
54 else
55 {
56 cornerHalfAngles_.resize(this->gridGeometry().gridView().size(0));
57 for (auto&& element : elements(this->gridGeometry().gridView()))
58 {
59 const auto eIdx = this->gridGeometry().elementMapper().index(element);
60 const auto& shape = this->gridGeometry().throatCrossSectionShape(eIdx);
61 cornerHalfAngles_[eIdx] = Throat::cornerHalfAngles<Scalar>(shape);
62 }
63 }
64 4 }
65
66 /*!
67 * \brief The index of the wetting phase within a pore throat
68 */
69 template<class FS, class ElementVolumeVariables>
70 int wettingPhase(const Element& element,
71 const ElementVolumeVariables& elemVolVars) const
72
7/10
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 417 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 417 times.
✓ Branch 8 taken 959820 times.
✓ Branch 9 taken 959820 times.
✓ Branch 10 taken 959820 times.
✓ Branch 11 taken 959820 times.
2879877 { return this->asImp_().template wettingPhaseAtPos<FS>(element.geometry().center()); }
73
74 /*!
75 * \brief The index of the wetting phase within a pore body
76 */
77 template<class FS, class ElementSolutionVector>
78 int wettingPhase(const Element& element,
79 const SubControlVolume& scv,
80 const ElementSolutionVector& elemSol) const
81
5/6
✓ Branch 0 taken 2401 times.
✓ Branch 1 taken 1528997 times.
✓ Branch 2 taken 2401 times.
✓ Branch 3 taken 39259 times.
✓ Branch 4 taken 1489738 times.
✗ Branch 5 not taken.
3062796 { return this->asImp_().template wettingPhaseAtPos<FS>(scv.center()); }
82
83 /*!
84 * \brief Function for defining which phase is to be considered as the wetting phase.
85 *
86 * \return the wetting phase index
87 * \param globalPos The global position
88 */
89 template<class FluidSystem>
90 int wettingPhaseAtPos(const GlobalPosition& globalPos) const
91 {
92 DUNE_THROW(Dune::InvalidStateException,
93 "The spatial parameters do not provide "
94 "a wettingPhaseAtPos() method.");
95 }
96
97 /*!
98 * \brief The contact angle within a pore throat \f$[rad]\f$.
99 * \note Overload for solution-dependent values.
100 *
101 * \param element The element
102 * \param elemVolVars The element volume variables
103 */
104 template<class ElementVolumeVariables>
105 Scalar contactAngle(const Element& element,
106 const ElementVolumeVariables& elemVolVars) const
107 5852211 { return this->asImp_().contactAngleAtPos(element.geometry().center()); }
108
109 /*!
110 * \brief The contact angle within a pore body \f$[rad]\f$.
111 * \note Overload for solution-dependent values.
112 *
113 * \param element The element
114 * \param scv The sub-control volume
115 * \param elemSol The element solution
116 */
117 template<class ElementSolutionVector>
118 Scalar contactAngle(const Element& element,
119 const SubControlVolume& scv,
120 const ElementSolutionVector& elemSol) const
121 { return this->asImp_().contactAngleAtPos(scv.center()); }
122
123 //! \brief Function for defining the Contact Angle
124 int contactAngleAtPos(const GlobalPosition& globalPos) const
125 {
126 DUNE_THROW(Dune::InvalidStateException,
127 "The spatial parameters do not provide "
128 "a contactAngleAtPos() method.");
129 }
130
131 /*!
132 * \brief Returns the surface tension \f$ [N/m] \f$
133 *
134 * \param element The current element
135 * \param scv The sub-control volume inside the element.
136 * \param elemSol The solution at the dofs connected to the element.
137 */
138 template<class ElementSolution>
139 Scalar surfaceTension(const Element& element,
140 const SubControlVolume& scv,
141 const ElementSolution& elemSol) const
142 9188362 { return this->asImp_().surfaceTensionAtPos(scv.center()); }
143
144 //! \brief Function for defining the surface Tension
145 Scalar surfaceTensionAtPos(const GlobalPosition& globalPos) const
146 {
147 DUNE_THROW(Dune::InvalidStateException,
148 "The spatial parameters do not provide "
149 "a surfaceTensionAtPos() method.");
150 }
151
152 /*!
153 * \brief Return the element (throat) specific entry capillary pressure \f$ Pa\f$
154 * \param element The current element
155 * \param elemVolVars The element volume variables
156 */
157 template<class ElementVolumeVariables>
158 960111 const Scalar pcEntry(const Element& element,
159 const ElementVolumeVariables& elemVolVars) const
160 {
161 2880333 const auto eIdx = this->gridGeometry().elementMapper().index(element);
162 // take the average of both adjacent pores TODO: is this correct?
163
2/4
✓ Branch 0 taken 960111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 960111 times.
✗ Branch 3 not taken.
1920222 const Scalar surfaceTension = 0.5*(elemVolVars[0].surfaceTension() + elemVolVars[1].surfaceTension());
164 960111 return ThresholdCapillaryPressures::pcEntry(surfaceTension,
165 960111 this->asImp_().contactAngle(element, elemVolVars),
166 960111 this->asImp_().throatInscribedRadius(element, elemVolVars),
167
2/4
✓ Branch 0 taken 960111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 960111 times.
✗ Branch 3 not taken.
1920222 this->gridGeometry().throatShapeFactor(eIdx));
168 }
169
170 /*!
171 * \brief Return the element (throat) specific snap-off capillary pressure \f$ Pa\f$
172 * \param element The current element
173 * \param elemVolVars The element volume variables
174 */
175 template<class ElementVolumeVariables>
176 959946 const Scalar pcSnapoff(const Element& element,
177 const ElementVolumeVariables& elemVolVars) const
178 {
179 // take the average of both adjacent pores TODO: is this correct?
180
2/4
✓ Branch 0 taken 959946 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 959946 times.
✗ Branch 3 not taken.
1919892 const Scalar surfaceTension = 0.5*(elemVolVars[0].surfaceTension() + elemVolVars[1].surfaceTension());
181 959946 return ThresholdCapillaryPressures::pcSnapoff(surfaceTension,
182 959946 this->asImp_().contactAngle(element, elemVolVars),
183 959946 this->asImp_().throatInscribedRadius(element, elemVolVars),
184
2/4
✓ Branch 0 taken 959946 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 959946 times.
✗ Branch 3 not taken.
1919892 this->gridGeometry().throatCrossSectionShape(/*eIdx*/ 0));
185 }
186
187 /*!
188 * \brief Returns the parameter object for the pore-local pc-Sw law
189 *
190 * \param element The current element
191 * \param scv The sub-control volume inside the element.
192 * \param elemSol The solution at the dofs connected to the element.
193 * \return The material parameters object
194 */
195 template<class ElementSolution>
196 6042272 auto fluidMatrixInteraction(const Element& element,
197 const SubControlVolume& scv,
198 const ElementSolution& elemSol) const
199 {
200
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
6042272 const auto params = typename LocalRules::BasicParams(*this, element, scv, elemSol);
201
6/14
✓ Branch 1 taken 3062796 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3062796 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3062796 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 3062796 times.
✓ Branch 13 taken 3062796 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3062796 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
24169088 return makeFluidMatrixInteraction(LocalRules(params, "SpatialParams"));
202 }
203
204 2879460 const Dune::ReservedVector<Scalar, 4>& cornerHalfAngles(const Element& element) const
205 {
206
2/4
✓ Branch 0 taken 2879460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2879460 times.
✗ Branch 3 not taken.
5758920 if (this->gridGeometry().useSameShapeForAllThroats())
207 2879460 return cornerHalfAngles_[0];
208 else
209 {
210 const auto eIdx = this->gridGeometry().gridView().indexSet().index(element);
211 return cornerHalfAngles_[eIdx];
212 }
213 }
214
215 private:
216 std::vector<Dune::ReservedVector<Scalar, 4>> cornerHalfAngles_;
217 };
218
219 /*!
220 * \ingroup PNMTwoPModel
221 * \ingroup SpatialParameters
222 * \brief The default class for spatial parameters for two-phase pore-network models.
223 */
224 template<class GridGeometry, class Scalar, class LocalRules>
225 class TwoPDefaultSpatialParams
226 : public TwoPSpatialParams<GridGeometry, Scalar, LocalRules, TwoPDefaultSpatialParams<GridGeometry, Scalar, LocalRules>>
227 {
228 using ParentType = TwoPSpatialParams<GridGeometry, Scalar, LocalRules,
229 TwoPDefaultSpatialParams<GridGeometry, Scalar, LocalRules>>;
230 using GridView = typename GridGeometry::GridView;
231 using Element = typename GridView::template Codim<0>::Entity;
232 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
233 public:
234 using ParentType::ParentType;
235
236 TwoPDefaultSpatialParams(std::shared_ptr<const GridGeometry> gridGeometry)
237 : ParentType(gridGeometry)
238 { }
239
240 /*!
241 * \brief Function for defining which phase is to be considered as the wetting phase.
242 *
243 * \return the wetting phase index
244 * \param globalPos The global position
245 */
246 template<class FluidSystem>
247 int wettingPhaseAtPos(const GlobalPosition& globalPos) const
248 { return FluidSystem::phase0Idx; }
249
250 /*!
251 * \brief Function for defining the Contact Angle
252 *
253 * \return the contact angle
254 * \param globalPos The global position
255 */
256 int contactAngleAtPos(const GlobalPosition& globalPos) const
257 {
258 static const Scalar theta = getParam<Scalar>("SpatialParams.ContactAngle", 0.0);
259 return theta;
260 }
261
262 /*!
263 * \brief Function for defining the surface Tension
264 *
265 * \return the surface tension
266 * \param globalPos The global position
267 */
268 Scalar surfaceTensionAtPos(const GlobalPosition& globalPos) const
269 {
270 static const Scalar gamma = getParam<Scalar>("SpatialParams.SurfaceTension", 0.0725); // default to surface tension of water/air
271 return gamma;
272 }
273
274 };
275
276 } // namespace Dumux::PoreNetwork
277
278 #endif
279