GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/test/multidomain/boundary/freeflowporenetwork/1p_1p/problem_freeflow.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 79 83 95.2%
Functions: 9 9 100.0%
Branches: 65 92 70.7%

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-FileCopyrightText: 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 BoundaryTests
10 * \brief Free-flow sub-problem for the coupled 1p_1p free-flow/pore-network-model test
11 */
12
13 #ifndef DUMUX_TEST_MULTIDOMAIN_BOUNDARY_FREEFLOW_PORE_NETWORK_PROBLEM_FREEFLOW_HH
14 #define DUMUX_TEST_MULTIDOMAIN_BOUNDARY_FREEFLOW_PORE_NETWORK_PROBLEM_FREEFLOW_HH
15
16 #include <dumux/common/properties.hh>
17
18 #include <dumux/freeflow/navierstokes/boundarytypes.hh>
19 #include <dumux/freeflow/navierstokes/momentum/fluxhelper.hh>
20 #include <dumux/freeflow/navierstokes/scalarfluxhelper.hh>
21 #include <dumux/freeflow/navierstokes/mass/1p/advectiveflux.hh>
22
23 namespace Dumux {
24
25 /*!
26 * \ingroup BoundaryTests
27 * \brief Free-flow sub-problem for the coupled 1p_1p free-flow/pore-network-model test
28 * A two-dimensional Stokes flow region coupled to a pore-network model.
29 */
30 template <class TypeTag, class BaseProblem>
31 class FreeFlowOnePTestProblem : public BaseProblem
32 {
33 using ParentType = BaseProblem;
34
35 using BoundaryTypes = typename ParentType::BoundaryTypes;
36 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
37 using FVElementGeometry = typename GridGeometry::LocalView;
38 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
39 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
40 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
41 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
42 using InitialValues = typename ParentType::InitialValues;
43 using Sources = typename ParentType::Sources;
44 using DirichletValues = typename ParentType::DirichletValues;
45 using BoundaryFluxes = typename ParentType::BoundaryFluxes;
46 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
47 using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
48
49 static constexpr auto dimWorld = GridGeometry::GridView::dimensionworld;
50 using Element = typename GridGeometry::GridView::template Codim<0>::Entity;
51 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
52 using VelocityVector = Dune::FieldVector<Scalar, dimWorld>;
53
54 using CouplingManager = GetPropType<TypeTag, Properties::CouplingManager>;
55
56 public:
57 12 FreeFlowOnePTestProblem(std::shared_ptr<const GridGeometry> gridGeometry, std::shared_ptr<CouplingManager> couplingManager)
58 : ParentType(gridGeometry, couplingManager, "FreeFlow")
59
2/6
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
48 , couplingManager_(couplingManager)
60 {
61
3/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
24 problemName_ = getParam<std::string>("Vtk.OutputName") + "_" + getParamFromGroup<std::string>(this->paramGroup(), "Problem.Name");
62
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 initialPressure_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.InitialPressure", 1e5);
63
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 inletPressure_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.InletPressure", 1.01e5);
64
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 outletPressure_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.OutletPressure", 1e5);
65
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 verticalFlow_ = getParamFromGroup<bool>(this->paramGroup(), "Problem.VerticalFlow", false);
66 #if !ISOTHERMAL
67
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 initialTemperature_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.InitialTemperature", 273.15 + 20.0);
68
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 inletTemperature_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.InletTemperature", 273.15 + 20.0);
69
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 outletTemperature_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.OutletTemperature", 273.15 + 20.0);
70 #endif
71 12 }
72
73 /*!
74 * \name Problem parameters
75 */
76 // \{
77
78 3 const std::string& name() const
79
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 { return problemName_; }
80
81 // \}
82
83 /*!
84 * \name Boundary conditions
85 */
86 // \{
87
88 /*!
89 * \brief Specifies which kind of boundary condition should be
90 * used for which equation on a given boundary segment.
91 *
92 * \param element The finite element
93 * \param scvf The sub control volume face
94 */
95 98056 BoundaryTypes boundaryTypes(const Element& element,
96 const SubControlVolumeFace& scvf) const
97 {
98 98056 BoundaryTypes values;
99 98056 const auto& globalPos = scvf.center(); //avoid ambiguities at corners
100
101 if constexpr (ParentType::isMomentumProblem())
102 {
103
2/2
✓ Branch 1 taken 861 times.
✓ Branch 2 taken 12541 times.
26804 if (couplingManager_->isCoupled(CouplingManager::freeFlowMomentumIndex, CouplingManager::poreNetworkIndex, scvf))
104 {
105 1722 values.setCouplingNeumann(Indices::momentumXBalanceIdx);
106 1722 values.setCouplingNeumann(Indices::momentumYBalanceIdx);
107 }
108
2/2
✓ Branch 0 taken 9103 times.
✓ Branch 1 taken 3438 times.
25082 else if (onInlet_(globalPos) || onOutlet_(globalPos))
109 26804 values.setAllNeumann();
110 else
111 26804 values.setAllDirichlet(); //e.g. fixed velocities at walls
112 }
113 else
114 {
115 76530 if (couplingManager_->isCoupled(CouplingManager::freeFlowMassIndex, CouplingManager::poreNetworkIndex, scvf))
116 71252 values.setAllCouplingNeumann(); //mass and energy coupling
117 65506 else if (onInlet_(globalPos))
118 58260 values.setAllDirichlet();
119
2/2
✓ Branch 0 taken 19200 times.
✓ Branch 1 taken 8000 times.
65506 else if (onOutlet_(globalPos))
120 58260 values.setAllNeumann();
121 else
122 58260 values.setAllNeumann(); //outflow or zero flux BCs for p,T
123 }
124 98056 return values;
125 }
126
127 /*!
128 * \brief Returns Dirichlet boundary values at a given position.
129 *
130 * \param globalPos The global position
131 */
132 54 DirichletValues dirichletAtPos(const GlobalPosition& globalPos) const
133 {
134 54 DirichletValues values(0.0); //velocity is 0.0
135
136 if constexpr (!ParentType::isMomentumProblem())
137 {
138 54 if (onInlet_(globalPos))
139 {
140 54 values[Indices::pressureIdx] = inletPressure_;
141 #if !ISOTHERMAL
142 values[Indices::temperatureIdx] = inletTemperature_;
143 #endif
144 }
145 else if (onOutlet_(globalPos))
146 {
147 values[Indices::pressureIdx] = outletPressure_;
148 #if !ISOTHERMAL
149 values[Indices::temperatureIdx] = outletTemperature_;
150 #endif
151 }
152 }
153 54 return values;
154 }
155
156 /*!
157 * \brief Evaluates the boundary conditions for a Neumann
158 * boundary segment/ control volume.
159 *
160 * This is the method for the case where the Neumann condition is
161 * potentially solution dependent
162 *
163 * \param element The finite element
164 * \param fvGeometry The finite-volume geometry
165 * \param elemVolVars All volume variables for the element
166 * \param elemFluxVarsCache Flux variables caches for all faces in stencil
167 * \param scvf The sub control volume face
168 *
169 * Negative values mean influx.
170 * E.g. for the mass balance that would be the mass flux in \f$ [ kg / (m^2 \cdot s)] \f$.
171 */
172 template<class ElementVolumeVariables, class ElementFluxVariablesCache>
173 173038 BoundaryFluxes neumann(const Element& element,
174 const FVElementGeometry& fvGeometry,
175 const ElementVolumeVariables& elemVolVars,
176 const ElementFluxVariablesCache& elemFluxVarsCache,
177 const SubControlVolumeFace& scvf) const
178 {
179 173038 BoundaryFluxes values(0.0);
180 173038 const auto& globalPos = scvf.ipGlobal();
181 using SlipVelocityPolicy = NavierStokesSlipVelocity<typename GridGeometry::DiscretizationMethod, NavierStokes::SlipConditions::BJ>;
182 using FluxHelper = NavierStokesMomentumBoundaryFlux<typename GridGeometry::DiscretizationMethod, SlipVelocityPolicy>;
183
184 if constexpr (ParentType::isMomentumProblem())
185 {
186
187
2/2
✓ Branch 1 taken 27289 times.
✓ Branch 2 taken 32236 times.
119050 if (couplingManager_->isCoupled(CouplingManager::freeFlowMomentumIndex, CouplingManager::poreNetworkIndex, scvf))
188 {
189 54578 values[scvf.normalAxis()] += couplingManager_->momentumCouplingCondition(
190 CouplingManager::freeFlowMomentumIndex, CouplingManager::poreNetworkIndex,
191 fvGeometry, scvf, elemVolVars
192 );
193
194 109156 values += FluxHelper::slipVelocityMomentumFlux(
195 *this, fvGeometry, scvf, elemVolVars, elemFluxVarsCache
196 );
197 }
198 66008 else if (onInlet_(globalPos))
199 {
200 1536 values = FluxHelper::fixedPressureMomentumFlux(
201 *this, fvGeometry, scvf, elemVolVars,
202 1536 elemFluxVarsCache, inletPressure_, true /*zeroNormalVelocityGradient*/
203 );
204 }
205
1/2
✓ Branch 0 taken 31468 times.
✗ Branch 1 not taken.
62936 else if (onOutlet_(globalPos))
206 {
207 62936 values = FluxHelper::fixedPressureMomentumFlux(
208 *this, fvGeometry, scvf, elemVolVars,
209 62936 elemFluxVarsCache, outletPressure_, true /*zeroNormalVelocityGradient*/
210 );
211 }
212 }
213 else
214 {
215 53988 if (couplingManager_->isCoupled(CouplingManager::freeFlowMassIndex, CouplingManager::poreNetworkIndex, scvf))
216 {
217 4226 values[Indices::conti0EqIdx] = couplingManager_->massCouplingCondition(
218 CouplingManager::freeFlowMassIndex, CouplingManager::poreNetworkIndex,
219 fvGeometry, scvf, elemVolVars);
220 #if !ISOTHERMAL
221 3080 values[Indices::energyEqIdx] = couplingManager_->energyCouplingCondition(CouplingManager::freeFlowMassIndex, CouplingManager::poreNetworkIndex,
222 fvGeometry, scvf, elemVolVars);
223 #endif
224 }
225
2/2
✓ Branch 0 taken 6851 times.
✓ Branch 1 taken 18030 times.
49762 else if (onOutlet_(globalPos))
226 {
227 using FluxHelper = NavierStokesScalarBoundaryFluxHelper<AdvectiveFlux<ModelTraits>>;
228 13702 DirichletValues outsideBoundaryPriVars = initialAtPos(globalPos);
229 13702 values = FluxHelper::scalarOutflowFlux(
230 *this, element, fvGeometry, scvf, elemVolVars, std::move(outsideBoundaryPriVars)
231 );
232 }
233 }
234
235 173038 return values;
236 }
237
238 /*!
239 * \brief Evaluates the source term for all phases within a given
240 * sub-control volume
241 */
242 template<class ElementVolumeVariables>
243 Sources source(const Element& element,
244 const FVElementGeometry& fvGeometry,
245 const ElementVolumeVariables& elemVolVars,
246 const SubControlVolume& scv) const
247 {
248 auto source = Sources(0.0);
249 return source;
250 }
251
252 // The following function defines the initial conditions
253 7351 InitialValues initialAtPos(const GlobalPosition &globalPos) const
254 {
255 7351 InitialValues values(0.0); //velocity is 0.0
256
257 if constexpr (!ParentType::isMomentumProblem())
258 {
259 7351 values[Indices::pressureIdx] = initialPressure_;
260 #if !ISOTHERMAL
261 6550 values[Indices::temperatureIdx] = initialTemperature_;
262 #endif
263 }
264 return values;
265 }
266
267 /*!
268 * \brief Returns true if the scvf lies on a porous slip boundary
269 */
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34494 times.
34494 bool onSlipBoundary(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf) const
271 {
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34494 times.
34494 assert(scvf.isFrontal());
273
3/4
✓ Branch 0 taken 34494 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 12600 times.
✓ Branch 4 taken 21894 times.
34494 return scvf.boundary() && couplingManager_->isCoupled(CouplingManager::freeFlowMomentumIndex, CouplingManager::poreNetworkIndex, scvf);
274 }
275
276 /*!
277 * \brief Returns the beta value
278 */
279 21894 Scalar betaBJ(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf, const GlobalPosition& tangentialVector) const
280 {
281 21894 const Scalar radius = couplingManager_->coupledPoreInscribedRadius(fvGeometry, scvf);
282 21894 return 5.73 / radius; // this value is only an approximation of wall friction is considered
283 }
284
285 /*!
286 * \brief Returns the velocity in the porous medium (which is 0 by default according to Saffmann).
287 */
288 21894 VelocityVector porousMediumVelocity(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf) const
289 {
290 21894 return couplingManager_->interfaceThroatVelocity(fvGeometry, scvf);
291 }
292
293 // \}
294
295 private:
296
297 77818 bool onInlet_(const GlobalPosition &globalPos) const
298 {
299
7/8
✓ Branch 0 taken 1536 times.
✓ Branch 1 taken 30700 times.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3477 times.
✓ Branch 5 taken 29510 times.
✓ Branch 6 taken 1711 times.
✓ Branch 7 taken 10830 times.
77818 if (verticalFlow_)
300 return 0;
301 else
302
7/8
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 768 times.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3243 times.
✓ Branch 5 taken 234 times.
✓ Branch 6 taken 1597 times.
✓ Branch 7 taken 114 times.
6778 return onLeftBoundary_(globalPos);
303 }
304
305 95976 bool onOutlet_(const GlobalPosition &globalPos) const
306 {
307
8/10
✓ Branch 0 taken 30700 times.
✓ Branch 1 taken 768 times.
✓ Branch 2 taken 20570 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1815 times.
✓ Branch 5 taken 2496 times.
✓ Branch 6 taken 28292 times.
✓ Branch 7 taken 1597 times.
✓ Branch 8 taken 9738 times.
✗ Branch 9 not taken.
95976 if (verticalFlow_)
308 91115 return onUpperBoundary_(globalPos);
309 else
310 10414 return onRightBoundary_(globalPos);
311 }
312
313
7/8
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 768 times.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3243 times.
✓ Branch 5 taken 234 times.
✓ Branch 6 taken 1597 times.
✓ Branch 7 taken 114 times.
6778 bool onLeftBoundary_(const GlobalPosition &globalPos) const
314
7/8
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 768 times.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3243 times.
✓ Branch 5 taken 234 times.
✓ Branch 6 taken 1597 times.
✓ Branch 7 taken 114 times.
6778 { return globalPos[0] < this->gridGeometry().bBoxMin()[0] + eps_; }
315
316 4861 bool onRightBoundary_(const GlobalPosition &globalPos) const
317 10414 { return globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; }
318
319 91115 bool onUpperBoundary_(const GlobalPosition &globalPos) const
320 91115 { return globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_; }
321
322 std::string problemName_;
323 static constexpr Scalar eps_ = 1e-6;
324 Scalar initialPressure_;
325 Scalar inletPressure_;
326 Scalar outletPressure_;
327 bool verticalFlow_;
328 #if !ISOTHERMAL
329 Scalar initialTemperature_;
330 Scalar inletTemperature_;
331 Scalar outletTemperature_;
332 #endif
333
334 std::shared_ptr<CouplingManager> couplingManager_;
335 };
336 } // end namespace Dumux
337
338 #endif
339