GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/test/freeflow/navierstokesnc/channel/problem.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 48 55 87.3%
Functions: 11 20 55.0%
Branches: 62 88 70.5%

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 NavierStokesNCTests
10 * \brief Channel flow test for the multi-component staggered grid (Navier-)Stokes model.
11 */
12
13 #ifndef DUMUX_CHANNEL_NC_TEST_PROBLEM_HH
14 #define DUMUX_CHANNEL_NC_TEST_PROBLEM_HH
15
16 #include <dumux/common/parameters.hh>
17 #include <dumux/common/properties.hh>
18 #include <dumux/common/timeloop.hh>
19
20 #include <dumux/freeflow/navierstokes/boundarytypes.hh>
21
22 #include <dumux/freeflow/navierstokes/momentum/fluxhelper.hh>
23 #include <dumux/freeflow/navierstokes/scalarfluxhelper.hh>
24 #include <dumux/freeflow/navierstokes/mass/1pnc/advectiveflux.hh>
25
26 namespace Dumux {
27
28 /*!
29 * \ingroup NavierStokesNCTests
30 * \brief Test problem for the one-phase (Navier-)Stokes model.
31 *
32 * Flow from left to right in a channel is considered. A parabolic velocity
33 * profile is set at the left boundary, while the pressure is set to
34 * a fixed value on the right boundary. The top and bottom boundaries
35 * represent solid walls with no-slip/no-flow conditions.
36 */
37 template <class TypeTag, class BaseProblem>
38 class ChannelNCTestProblem : public BaseProblem
39 {
40 using ParentType = BaseProblem;
41 using BoundaryTypes = typename ParentType::BoundaryTypes;
42 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
43 using FVElementGeometry = typename GridGeometry::LocalView;
44 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
45 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
46 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
47 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
48 using InitialValues = typename ParentType::InitialValues;
49 using Sources = typename ParentType::Sources;
50 using DirichletValues = typename ParentType::DirichletValues;
51 using BoundaryFluxes = typename ParentType::BoundaryFluxes;
52 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
53 using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
54 using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
55
56 static constexpr auto dimWorld = GridGeometry::GridView::dimensionworld;
57 using Element = typename GridGeometry::GridView::template Codim<0>::Entity;
58 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
59 using VelocityVector = Dune::FieldVector<Scalar, dimWorld>;
60
61 using CouplingManager = GetPropType<TypeTag, Properties::CouplingManager>;
62
63 using TimeLoopPtr = std::shared_ptr<CheckPointTimeLoop<Scalar>>;
64
65 static constexpr bool useMoles = ModelTraits::useMoles();
66 static constexpr bool isNonisothermal = ModelTraits::enableEnergyBalance();
67 static constexpr auto compIdx = 1;
68
69 public:
70 24 ChannelNCTestProblem(std::shared_ptr<const GridGeometry> gridGeometry,
71 std::shared_ptr<CouplingManager> couplingManager)
72 : ParentType(gridGeometry, couplingManager)
73
8/24
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✓ Branch 18 taken 12 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 12 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
96 , eps_(1e-6)
74 {
75
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 FluidSystem::init();
76
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 inletVelocity_ = getParam<Scalar>("Problem.InletVelocity");
77 24 }
78
79 /*!
80 * \brief Returns a reference pressure at a given sub control volume face.
81 * This pressure is subtracted from the actual pressure for the momentum balance
82 * which potentially helps to improve numerical accuracy by avoiding issues related do floating point arithmetic.
83 */
84 Scalar referencePressure(const Element& element,
85 const FVElementGeometry& fvGeometry,
86 const SubControlVolumeFace& scvf) const
87 { return 1.1e5; }
88
89 /*!
90 * \brief Specifies which kind of boundary condition should be
91 * used for which equation on a given boundary control volume.
92 *
93 * \param globalPos The position of the center of the finite volume
94 */
95 1399076 BoundaryTypes boundaryTypesAtPos(const GlobalPosition& globalPos) const
96 {
97 1399076 BoundaryTypes values;
98
99 if constexpr (ParentType::isMomentumProblem())
100 {
101
2/2
✓ Branch 0 taken 152696 times.
✓ Branch 1 taken 130502 times.
566396 values.setDirichlet(Indices::velocityXIdx);
102
2/2
✓ Branch 0 taken 152696 times.
✓ Branch 1 taken 130502 times.
566396 values.setDirichlet(Indices::velocityYIdx);
103
104 1132792 if (isOutlet_(globalPos))
105 values.setAllNeumann();
106 }
107 else
108 {
109 832680 values.setAllNeumann();
110
111 1665360 if (isInlet_(globalPos))
112 {
113 97040 values.setDirichlet(Indices::pressureIdx);
114 97040 values.setDirichlet(Indices::conti0EqIdx + compIdx);
115 if constexpr (isNonisothermal)
116 39290 values.setDirichlet(Indices::temperatureIdx);
117 }
118 }
119
120 1399076 return values;
121 }
122
123 /*!
124 * \brief Evaluates the boundary conditions for a Dirichlet control volume.
125 *
126 * \param globalPos The center of the finite volume which ought to be set.
127 */
128 21440 DirichletValues dirichlet(const Element& element, const SubControlVolumeFace& scvf) const
129 {
130 541286 const auto& globalPos = scvf.ipGlobal();
131 562726 DirichletValues values = initialAtPos(globalPos);
132
133 if constexpr (!ParentType::isMomentumProblem()) // mass problem
134 {
135 // give the system some time so that the pressure can equilibrate, then start the injection of the tracer
136 42880 if (isInlet_(globalPos))
137 {
138 // With respect to implementation, pressure is treated as if it were a dirichlet condition.
139 // As we want to prescribe the velocity profile in the inlet, we cannot fix the pressure at the same time.
140 // Therefore, the coupling manager is used to get the pressure from the momentum problem and use it as
141 // entry for the dirichlet condition in the mass problem.
142
6/6
✓ Branch 0 taken 1420 times.
✓ Branch 1 taken 9300 times.
✓ Branch 2 taken 1420 times.
✓ Branch 3 taken 9300 times.
✓ Branch 4 taken 1420 times.
✓ Branch 5 taken 9300 times.
64320 values[Indices::pressureIdx] = this->couplingManager().cellPressure(element, scvf);
143
144
2/2
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 1000 times.
2840 if (time() >= 10.0 || inletVelocity_ < eps_)
145 {
146 19440 Scalar moleFracTransportedComp = 1e-3;
147 if constexpr (useMoles)
148 31060 values[Indices::conti0EqIdx+compIdx] = moleFracTransportedComp;
149 else
150 {
151 Scalar averageMolarMassPhase = moleFracTransportedComp * FluidSystem::molarMass(compIdx)
152 + (1. - moleFracTransportedComp) * FluidSystem::molarMass(1-compIdx);
153 values[Indices::conti0EqIdx+compIdx] = moleFracTransportedComp * FluidSystem::molarMass(compIdx)
154 / averageMolarMassPhase;
155 }
156
157 if constexpr (isNonisothermal)
158 15640 values[Indices::temperatureIdx] = 293.15;
159 }
160 }
161 }
162
163 541286 return values;
164 }
165
166 /*!
167 * \brief Evaluates the boundary conditions for a Neumann control volume.
168 *
169 * \param element The element for which the Neumann boundary condition is set
170 * \param fvGeometry The fvGeometry
171 * \param elemVolVars The element volume variables
172 * \param elemFaceVars The element face variables
173 * \param scvf The boundary sub control volume face
174 */
175 template<class ElementVolumeVariables, class ElementFluxVariablesCache>
176 571200 BoundaryFluxes neumann(const Element& element,
177 const FVElementGeometry& fvGeometry,
178 const ElementVolumeVariables& elemVolVars,
179 const ElementFluxVariablesCache& elemFluxVarsCache,
180 const SubControlVolumeFace& scvf) const
181 {
182 571200 BoundaryFluxes values(0.0);
183
184 if constexpr (ParentType::isMomentumProblem())
185 {
186 using FluxHelper = NavierStokesMomentumBoundaryFlux<typename GridGeometry::DiscretizationMethod>;
187 values = FluxHelper::fixedPressureMomentumFlux(*this, fvGeometry, scvf,
188 elemVolVars, elemFluxVarsCache,
189 referencePressure(element, fvGeometry, scvf), true /*zeroNormalVelocityGradient*/);
190 }
191 else
192 {
193 1142400 const auto insideDensity = elemVolVars[scvf.insideScvIdx()].density();
194
2/2
✓ Branch 2 taken 37800 times.
✓ Branch 3 taken 247800 times.
2284800 values[Indices::conti0EqIdx] = this->faceVelocity(element, fvGeometry, scvf) * insideDensity * scvf.unitOuterNormal();
195
196 using FluxHelper = NavierStokesScalarBoundaryFluxHelper<AdvectiveFlux<ModelTraits>>;
197
2/2
✓ Branch 0 taken 37800 times.
✓ Branch 1 taken 247800 times.
571200 if (isOutlet_(scvf.ipGlobal()))
198 75600 values = FluxHelper::scalarOutflowFlux( *this, element, fvGeometry, scvf, elemVolVars);
199 }
200
201 571200 return values;
202 }
203
204 /*!
205 * \brief Evaluates the initial value for a control volume.
206 *
207 * \param globalPos The global position
208 */
209 1061502 InitialValues initialAtPos(const GlobalPosition& globalPos) const
210 {
211 1073972 InitialValues values(0.0);
212
213 if constexpr (ParentType::isMomentumProblem())
214 {
215 // parabolic velocity profile
216 4246008 values[Indices::velocityXIdx] = parabolicProfile(globalPos[1], inletVelocity_);
217 }
218 else
219 {
220
1/2
✓ Branch 0 taken 10720 times.
✗ Branch 1 not taken.
12470 values[Indices::pressureIdx] = 1.1e+5;
221 if constexpr (isNonisothermal)
222
1/2
✓ Branch 0 taken 4285 times.
✗ Branch 1 not taken.
7785 values[Indices::temperatureIdx] = 283.15;
223 }
224
225 1067937 return values;
226 }
227
228 /*!
229 * \brief A parabolic velocity profile.
230 *
231 * \param y The position where the velocity is evaluated.
232 * \param vMax The profile's maximum velocity.
233 */
234 Scalar parabolicProfile(const Scalar y, const Scalar vMax) const
235 {
236 2123004 const Scalar yMin = this->gridGeometry().bBoxMin()[1];
237 2123004 const Scalar yMax = this->gridGeometry().bBoxMax()[1];
238 530751 return vMax * (y - yMin)*(yMax - y) / (0.25*(yMax - yMin)*(yMax - yMin));
239 }
240
241 void setTimeLoop(TimeLoopPtr timeLoop)
242
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 { timeLoop_ = timeLoop; }
243
244 Scalar time() const
245
6/6
✓ Branch 0 taken 1420 times.
✓ Branch 1 taken 9300 times.
✓ Branch 2 taken 1420 times.
✓ Branch 3 taken 9300 times.
✓ Branch 4 taken 1420 times.
✓ Branch 5 taken 9300 times.
32160 { return timeLoop_->time(); }
246
247 //! Enable internal Dirichlet constraints
248 static constexpr bool enableInternalDirichletConstraints()
249 { return !ParentType::isMomentumProblem(); }
250
251 /*!
252 * \brief Tag a degree of freedom to carry internal Dirichlet constraints.
253 * If true is returned for a dof, the equation for this dof is replaced
254 * by the constraint that its primary variable values must match the
255 * user-defined values obtained from the function internalDirichlet(),
256 * which must be defined in the problem.
257 *
258 * \param element The finite element
259 * \param scv The sub-control volume
260 */
261 std::bitset<DirichletValues::dimension> hasInternalDirichletConstraint(const Element& element, const SubControlVolume& scv) const
262 {
263 1273400 std::bitset<DirichletValues::dimension> values;
264 return values;
265 }
266
267 /*!
268 * \brief Define the values of internal Dirichlet constraints for a degree of freedom.
269 * \param element The finite element
270 * \param scv The sub-control volume
271 */
272 DirichletValues internalDirichlet(const Element& element, const SubControlVolume& scv) const
273 600000 { return DirichletValues(1.1e5); }
274
275 private:
276 bool isInlet_(const GlobalPosition& globalPos) const
277
6/8
✓ Branch 0 taken 10720 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10720 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48520 times.
✓ Branch 5 taken 367820 times.
✓ Branch 6 taken 48520 times.
✓ Branch 7 taken 367820 times.
854120 { return globalPos[0] < eps_; }
278
279 bool isOutlet_(const GlobalPosition& globalPos) const
280
20/20
✓ Branch 0 taken 37800 times.
✓ Branch 1 taken 247800 times.
✓ Branch 2 taken 37800 times.
✓ Branch 3 taken 247800 times.
✓ Branch 4 taken 37800 times.
✓ Branch 5 taken 247800 times.
✓ Branch 6 taken 37800 times.
✓ Branch 7 taken 247800 times.
✓ Branch 8 taken 37800 times.
✓ Branch 9 taken 247800 times.
✓ Branch 10 taken 152696 times.
✓ Branch 11 taken 130502 times.
✓ Branch 12 taken 152696 times.
✓ Branch 13 taken 130502 times.
✓ Branch 14 taken 152696 times.
✓ Branch 15 taken 130502 times.
✓ Branch 16 taken 152696 times.
✓ Branch 17 taken 130502 times.
✓ Branch 18 taken 152696 times.
✓ Branch 19 taken 130502 times.
2843990 { return globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; }
281
282 const Scalar eps_;
283 Scalar inletVelocity_;
284 TimeLoopPtr timeLoop_;
285 };
286 } // end namespace Dumux
287
288 #endif
289