GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/freeflow/navierstokes/momentum/problem.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 90 104 86.5%
Functions: 55 82 67.1%
Branches: 101 174 58.0%

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 NavierStokesModel
10 * \copydoc Dumux::NavierStokesMomentumProblem
11 */
12 #ifndef DUMUX_NAVIERSTOKES_MOMENTUM_PROBLEM_HH
13 #define DUMUX_NAVIERSTOKES_MOMENTUM_PROBLEM_HH
14
15 #include <dune/common/exceptions.hh>
16 #include <dune/common/fvector.hh>
17 #include <dune/common/typetraits.hh>
18 #include <dumux/common/numeqvector.hh>
19 #include <dumux/common/properties.hh>
20 #include <dumux/common/fvproblemwithspatialparams.hh>
21 #include <dumux/discretization/method.hh>
22 #include <dumux/freeflow/navierstokes/momentum/boundarytypes.hh>
23
24 namespace Dumux {
25
26 template<class TypeTag, class DiscretizationMethod>
27 class NavierStokesMomentumProblemImpl;
28
29 template<class TypeTag>
30 class NavierStokesMomentumProblemImpl<TypeTag, DiscretizationMethods::FCStaggered>
31 : public FVProblemWithSpatialParams<TypeTag>
32 {
33 using ParentType = FVProblemWithSpatialParams<TypeTag>;
34 using Implementation = GetPropType<TypeTag, Properties::Problem>;
35
36 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
37 using GridView = typename GridGeometry::GridView;
38 using Element = typename GridView::template Codim<0>::Entity;
39
40 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
41 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
42 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
43 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
44
45 using FVElementGeometry = typename GridGeometry::LocalView;
46 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
47 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
48 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
49
50 enum {
51 dim = GridView::dimension,
52 dimWorld = GridView::dimensionworld
53 };
54
55 using GlobalPosition = typename SubControlVolumeFace::GlobalPosition;
56 using VelocityVector = Dune::FieldVector<Scalar, dimWorld>;
57 using GravityVector = Dune::FieldVector<Scalar, dimWorld>;
58 using CouplingManager = GetPropType<TypeTag, Properties::CouplingManager>;
59 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
60
61 static constexpr bool isCoupled_ = !std::is_empty_v<CouplingManager>;
62
63
64 public:
65 //! These types are used in place of the typical NumEqVector type.
66 //! In the numeqvector assembly type, only one equation per DOF (face) is considered
67 //! while the type here provides one entry for each world dimension.
68 using InitialValues = Dune::FieldVector<Scalar, dimWorld>;
69 using Sources = Dune::FieldVector<Scalar, dimWorld>;
70 using DirichletValues = Dune::FieldVector<Scalar, dimWorld>;
71 using BoundaryFluxes = Dune::FieldVector<Scalar, dimWorld>;
72
73 using MomentumFluxType = Dune::FieldVector<Scalar, dimWorld>;
74
75 //! Export the boundary types.
76 using BoundaryTypes = NavierStokesMomentumBoundaryTypes<ModelTraits::dim()>;
77
78 //! This problem is used for the momentum balance model.
79 static constexpr bool isMomentumProblem() { return true; }
80
81 /*!
82 * \brief The constructor
83 * \param gridGeometry The finite volume grid geometry
84 * \param couplingManager The coupling manager (couples mass and momentum equations)
85 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
86 */
87 71 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
88 std::shared_ptr<CouplingManager> couplingManager,
89 const std::string& paramGroup = "")
90 : ParentType(gridGeometry, paramGroup)
91 141 , gravity_(0.0)
92
1/2
✓ Branch 2 taken 71 times.
✗ Branch 3 not taken.
212 , couplingManager_(couplingManager)
93 {
94
3/4
✓ Branch 1 taken 71 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 66 times.
71 if (getParamFromGroup<bool>(paramGroup, "Problem.EnableGravity"))
95 5 gravity_[dim-1] = -9.81;
96
97
1/2
✓ Branch 1 taken 71 times.
✗ Branch 2 not taken.
71 enableInertiaTerms_ = getParamFromGroup<bool>(paramGroup, "Problem.EnableInertiaTerms");
98 71 }
99
100 /*!
101 * \brief The constructor for usage without a coupling manager
102 * \param gridGeometry The finite volume grid geometry
103 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
104 */
105 5 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
106 const std::string& paramGroup = "")
107
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
10 : NavierStokesMomentumProblemImpl(gridGeometry, {}, paramGroup)
108 5 {}
109
110 /*!
111 * \brief Evaluate the source term for all phases within a given
112 * sub-control-volume.
113 *
114 * This is the method for the case where the source term is
115 * potentially solution dependent and requires some quantities that
116 * are specific to the fully-implicit method.
117 *
118 * \param element The finite element
119 * \param fvGeometry The finite-volume geometry
120 * \param elemVolVars All volume variables for the element
121 * \param scv The sub control volume
122 *
123 * For this method, the return parameter stores the conserved quantity rate
124 * generated or annihilate per volume unit. Positive values mean
125 * that the conserved quantity is created, negative ones mean that it vanishes.
126 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
127 */
128 96362830 Sources source(const Element& element,
129 const FVElementGeometry& fvGeometry,
130 const ElementVolumeVariables& elemVolVars,
131 const SubControlVolume& scv) const
132 {
133 // forward to solution independent, fully-implicit specific interface
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34273600 times.
96362830 return asImp_().sourceAtPos(scv.dofPosition());
135 }
136
137 /*!
138 * \brief Evaluate the source term for all phases within a given
139 * sub-control-volume.
140 *
141 * \param globalPos The position of the center of the finite volume
142 * for which the source term ought to be
143 * specified in global coordinates
144 *
145 * For this method, the values parameter stores the conserved quantity rate
146 * generated or annihilate per volume unit. Positive values mean
147 * that the conserved quantity is created, negative ones mean that it vanishes.
148 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
149 */
150 45849870 Sources sourceAtPos(const GlobalPosition& globalPos) const
151 {
152 //! As a default, i.e. if the user's problem does not overload any source method
153 //! return 0.0 (no source terms)
154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45849870 times.
91699740 return Sources(0.0);
155 }
156
157 /*!
158 * \brief Adds contribution of point sources for a specific sub control volume
159 * to the values.
160 * Caution: Only overload this method in the implementation if you know
161 * what you are doing.
162 */
163 Sources scvPointSources(const Element& element,
164 const FVElementGeometry& fvGeometry,
165 const ElementVolumeVariables& elemVolVars,
166 const SubControlVolume& scv) const
167 {
168 if (!this->pointSourceMap().empty())
169 DUNE_THROW(Dune::NotImplemented, "scvPointSources not implemented");
170
171 return Sources(0.0);
172 }
173
174 /*!
175 * \brief Specifies which kind of boundary condition should be
176 * used for which equation on a given boundary segment.
177 *
178 * \param element The finite element
179 * \param scvf The sub control volume face
180 */
181
1/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1455352 auto boundaryTypes(const Element& element,
182 const SubControlVolumeFace& scvf) const
183 {
184 // Forward it to the method which only takes the global coordinate.
185 // We evaluate the boundary type at the center of the sub control volume face
186 // in order to avoid ambiguities at domain corners.
187
16/16
✓ Branch 0 taken 180806 times.
✓ Branch 1 taken 253344 times.
✓ Branch 2 taken 197992 times.
✓ Branch 3 taken 268588 times.
✓ Branch 4 taken 26900 times.
✓ Branch 5 taken 165396 times.
✓ Branch 6 taken 59296 times.
✓ Branch 7 taken 82880 times.
✓ Branch 8 taken 108992 times.
✓ Branch 9 taken 45632 times.
✓ Branch 10 taken 36172 times.
✓ Branch 11 taken 23876 times.
✓ Branch 12 taken 2436 times.
✓ Branch 13 taken 1500 times.
✓ Branch 14 taken 240 times.
✓ Branch 15 taken 1302 times.
1455352 return asImp_().boundaryTypesAtPos(scvf.center());
188 }
189
190 /*!
191 * \brief Evaluate the boundary conditions for a dirichlet
192 * control volume face.
193 *
194 * \param element The finite element
195 * \param scvf the sub control volume face
196 * \note used for cell-centered discretization schemes
197 */
198
6/14
✓ Branch 0 taken 61740 times.
✓ Branch 1 taken 185220 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3136 times.
✓ Branch 9 taken 9408 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 6630 times.
✓ Branch 13 taken 19482 times.
1326644 DirichletValues dirichlet(const Element& element, const SubControlVolumeFace& scvf) const
199 {
200
9/15
✓ Branch 0 taken 61740 times.
✓ Branch 1 taken 191266 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 5600 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 920 times.
✓ Branch 9 taken 3136 times.
✓ Branch 10 taken 9408 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 6630 times.
✓ Branch 14 taken 19482 times.
✓ Branch 2 taken 6046 times.
1600646 return asImp_().dirichletAtPos(scvf.ipGlobal());
201 }
202
203 /*!
204 * \brief Evaluates the boundary conditions for a Neumann control volume.
205 *
206 * \param element The element for which the Neumann boundary condition is set
207 * \param fvGeometry The fvGeometry
208 * \param elemVolVars The element volume variables
209 * \param elemFluxVarsCache The element flux variables cache
210 * \param scvf The boundary sub control volume face
211 */
212 template<class ElementFluxVariablesCache>
213 BoundaryFluxes neumann(const Element& element,
214 const FVElementGeometry& fvGeometry,
215 const ElementVolumeVariables& elemVolVars,
216 const ElementFluxVariablesCache& elemFluxVarsCache,
217 const SubControlVolumeFace& scvf) const
218 { return asImp_().neumannAtPos(scvf.ipGlobal()); }
219
220 /*!
221 * \brief Returns the neumann flux at a given position.
222 */
223 BoundaryFluxes neumannAtPos(const GlobalPosition& globalPos) const
224 { return BoundaryFluxes(0.0); } //! A default, i.e. if the user's does not overload any neumann method
225
226 /*!
227 * \brief Returns the acceleration due to gravity.
228 *
229 * If the <tt>Problem.EnableGravity</tt> parameter is true, this means
230 * \f$\boldsymbol{g} = ( 0,\dots,\ -9.81)^T \f$, else \f$\boldsymbol{g} = ( 0,\dots, 0)^T \f$
231 */
232 const GravityVector& gravity() const
233 104220774 { return gravity_; }
234
235 /*!
236 * \brief Returns whether inertia terms should be considered.
237 */
238 343077434 bool enableInertiaTerms() const
239
8/10
✓ Branch 0 taken 106164576 times.
✓ Branch 1 taken 201463822 times.
✓ Branch 2 taken 118980 times.
✓ Branch 3 taken 192034 times.
✓ Branch 4 taken 34371500 times.
✓ Branch 5 taken 634630 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 65984 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 65908 times.
343077434 { return enableInertiaTerms_; }
240
241 /*!
242 * \brief Returns the pressure at a given sub control volume face.
243 * \note Overload this if a fixed pressure shall be prescribed (e.g., given by an analytical solution).
244 */
245 104054148 Scalar pressure(const Element& element,
246 const FVElementGeometry& fvGeometry,
247 const SubControlVolumeFace& scvf) const
248 {
249 if constexpr (isCoupled_)
250 103819484 return couplingManager_->pressure(element, fvGeometry, scvf);
251 else
252 234664 return asImp_().pressureAtPos(scvf.ipGlobal());
253 }
254
255 /*!
256 * \brief Returns the pressure at a given position.
257 */
258 Scalar pressureAtPos(const GlobalPosition&) const
259 {
260 DUNE_THROW(Dune::NotImplemented, "pressureAtPos not implemented");
261 }
262
263 /*!
264 * \brief Returns a reference pressure at a given sub control volume face.
265 * This pressure is subtracted from the actual pressure for the momentum balance
266 * which potentially helps to improve numerical accuracy by avoiding issues related do floating point arithmetic.
267 * \note Overload this for reference pressures other than zero.
268 */
269 Scalar referencePressure(const Element& element,
270 const FVElementGeometry& fvGeometry,
271 const SubControlVolumeFace& scvf) const
272 { return 0.0; }
273
274 /*!
275 * \brief Returns the density at a given sub control volume face.
276 * \note Overload this if a fixed density shall be prescribed.
277 */
278 67194798 Scalar density(const Element& element,
279 const FVElementGeometry& fvGeometry,
280 const SubControlVolumeFace& scvf) const
281 {
282 if constexpr (isCoupled_)
283
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 7355627 times.
67194798 return couplingManager_->density(element, fvGeometry, scvf);
284 else
285 return asImp_().densityAtPos(scvf.ipGlobal());
286 }
287
288 /*!
289 * \brief Returns the density at a given sub control volume.
290 * \note Overload this if a fixed density shall be prescribed.
291 */
292 226036228 Scalar density(const Element& element,
293 const SubControlVolume& scv,
294 const bool isPreviousTimeStep = false) const
295 {
296 if constexpr (isCoupled_)
297
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
226036228 return couplingManager_->density(element, scv, isPreviousTimeStep);
298 else
299 return asImp_().densityAtPos(scv.dofPosition());
300 }
301
302
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
132768324 auto insideAndOutsideDensity(const Element& element,
303 const FVElementGeometry& fvGeometry,
304 const SubControlVolumeFace& scvf,
305 const bool isPreviousTimeStep = false) const
306 {
307 if constexpr (isCoupled_)
308
4/7
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 14538917 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 6 taken 30437 times.
132768324 return couplingManager_->insideAndOutsideDensity(element, fvGeometry, scvf, isPreviousTimeStep);
309 else
310 {
311 const auto rho = asImp_().densityAtPos(scvf.ipGlobal());
312 return std::make_pair(rho, rho);
313 }
314 }
315
316 /*!
317 * \brief Returns the density at a given position.
318 */
319 Scalar densityAtPos(const GlobalPosition&) const
320 {
321 DUNE_THROW(Dune::NotImplemented, "densityAtPos not implemented");
322 }
323
324 /*!
325 * \brief Returns the effective dynamic viscosity at a given sub control volume face.
326 * \note Overload this if a fixed viscosity shall be prescribed.
327 */
328 309689520 Scalar effectiveViscosity(const Element& element,
329 const FVElementGeometry& fvGeometry,
330 const SubControlVolumeFace& scvf) const
331 {
332 if constexpr (isCoupled_)
333
4/5
✓ Branch 5 taken 217488 times.
✓ Branch 6 taken 192552 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 65908 times.
✓ Branch 7 taken 66968 times.
309682152 return couplingManager_->effectiveViscosity(element, fvGeometry, scvf);
334 else
335 return asImp_().effectiveViscosityAtPos(scvf.ipGlobal());
336 }
337
338 /*!
339 * \brief Returns the effective dynamic viscosity at a given sub control volume.
340 * \note Overload this if a fixed viscosity shall be prescribed.
341 */
342 90344 Scalar effectiveViscosity(const Element& element,
343 const FVElementGeometry& fvGeometry,
344 const SubControlVolume& scv) const
345 {
346 if constexpr (isCoupled_)
347 90344 return couplingManager_->effectiveViscosity(element, fvGeometry, scv);
348 else
349 return asImp_().effectiveViscosityAtPos(scv.dofPosition());
350 }
351
352 /*!
353 * \brief Returns the effective dynamic viscosity at a given position.
354 */
355 Scalar effectiveViscosityAtPos(const GlobalPosition&) const
356 {
357 DUNE_THROW(Dune::NotImplemented, "effectiveViscosityAtPos not implemented");
358 }
359
360 /*!
361 * \brief Applies the initial solution for all degrees of freedom of the grid.
362 * \param sol the initial solution vector
363 */
364 template<class SolutionVector>
365 33 void applyInitialSolution(SolutionVector& sol) const
366 {
367 33 sol.resize(this->gridGeometry().numDofs());
368
1/2
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
33 std::vector<bool> dofHandled(this->gridGeometry().numDofs(), false);
369
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
33 auto fvGeometry = localView(this->gridGeometry());
370
3/6
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 199255 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1250 times.
✗ Branch 9 not taken.
597732 for (const auto& element : elements(this->gridGeometry().gridView()))
371 {
372
1/2
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
199222 fvGeometry.bindElement(element);
373
4/4
✓ Branch 0 taken 402729 times.
✓ Branch 1 taken 394159 times.
✓ Branch 2 taken 796888 times.
✓ Branch 3 taken 199222 times.
996110 for (const auto& scv : scvs(fvGeometry))
374 {
375 796888 const auto dofIdx = scv.dofIndex();
376
2/2
✓ Branch 0 taken 402729 times.
✓ Branch 1 taken 394159 times.
796888 if (!dofHandled[dofIdx])
377 {
378
2/3
✓ Branch 1 taken 81250 times.
✗ Branch 2 not taken.
✓ Branch 0 taken 5150 times.
402729 dofHandled[dofIdx] = true;
379
1/2
✓ Branch 1 taken 10200 times.
✗ Branch 2 not taken.
478929 sol[dofIdx] = asImp_().initial(scv)[scv.dofAxis()];
380 }
381 }
382 }
383 33 }
384
385 /*!
386 * \brief Evaluate the initial value at a sub control volume
387 */
388
2/2
✓ Branch 0 taken 5150 times.
✓ Branch 1 taken 71050 times.
323205 InitialValues initial(const SubControlVolume& scv) const
389 {
390
2/2
✓ Branch 0 taken 5150 times.
✓ Branch 1 taken 71050 times.
466869 return asImp_().initialAtPos(scv.dofPosition());
391 }
392
393 //! Convenience function for staggered grid implementation.
394 7368 Scalar pseudo3DWallFriction(const Element& element,
395 const FVElementGeometry& fvGeometry,
396 const ElementVolumeVariables& elemVolVars,
397 const SubControlVolume& scv,
398 const Scalar height,
399 const Scalar factor = 8.0) const
400 {
401 7368 const Scalar velocity = elemVolVars[scv].velocity();
402 7368 const auto scvf = scvfs(fvGeometry, scv).begin();
403 7368 const Scalar viscosity = effectiveViscosity(element, fvGeometry, *scvf);
404 7368 return pseudo3DWallFriction(velocity, viscosity, height, factor);
405 }
406
407 /*!
408 * \brief An additional drag term can be included as source term for the momentum balance
409 * to mimic 3D flow behavior in 2D:
410 * \f[
411 * f_{drag} = -(8 \mu / h^2)v
412 * \f]
413 * Here, \f$h\f$ corresponds to the extruded height that is
414 * bounded by the imaginary walls. See Flekkoy et al. (1995) \cite flekkoy1995a<BR>
415 * A value of 8.0 is used as a default factor, corresponding
416 * to the velocity profile at the center plane
417 * of the virtual height (maximum velocity). Setting this value to 12.0 corresponds
418 * to an depth-averaged velocity (Venturoli and Boek, 2006) \cite venturoli2006a.
419 */
420 7368 Scalar pseudo3DWallFriction(const Scalar velocity,
421 const Scalar viscosity,
422 const Scalar height,
423 const Scalar factor = 8.0) const
424 {
425 static_assert(dim == 2, "Pseudo 3D wall friction may only be used in 2D");
426 7368 return -factor * velocity * viscosity / (height*height);
427 }
428
429 /*!
430 * \brief Returns true if the scvf is located on a boundary with a slip condition.
431 * \note This member function must be overloaded in the problem implementation.
432 * Make sure to use scvf.center() for querying the spatial location.
433 */
434 bool onSlipBoundary(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf) const
435 338484 { return asImp_().onSlipBoundaryAtPos(scvf.center()); }
436
437 /*!
438 * \brief Returns true if the scvf is located on a boundary with a slip condition.
439 * \note This member function must be overloaded in the problem implementation.
440 */
441 bool onSlipBoundaryAtPos(const GlobalPosition& pos) const
442 { return false; }
443
444 const CouplingManager& couplingManager() const
445 {
446 if constexpr (isCoupled_)
447 return *couplingManager_;
448 else
449 DUNE_THROW(Dune::InvalidStateException,
450 "Accessing coupling manager of an uncoupled problem is not possible."
451 );
452 }
453
454 private:
455 //! Returns the implementation of the problem (i.e. static polymorphism)
456 Implementation& asImp_()
457 { return *static_cast<Implementation *>(this); }
458
459 //! \copydoc asImp_()
460 const Implementation& asImp_() const
461 { return *static_cast<const Implementation *>(this); }
462
463 GravityVector gravity_;
464 bool enableInertiaTerms_;
465 std::shared_ptr<CouplingManager> couplingManager_;
466 };
467
468 /*!
469 * \brief Navier-Stokes default problem implementation for CVFE discretizations
470 */
471 template<class TypeTag, class DM>
472 class NavierStokesMomentumProblemImpl<TypeTag, DiscretizationMethods::CVFE<DM>>
473 : public FVProblemWithSpatialParams<TypeTag>
474 {
475 using ParentType = FVProblemWithSpatialParams<TypeTag>;
476 using Implementation = GetPropType<TypeTag, Properties::Problem>;
477
478 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
479 using GridView = typename GridGeometry::GridView;
480 using Element = typename GridView::template Codim<0>::Entity;
481
482 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
483 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
484 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
485 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
486
487 using FVElementGeometry = typename GridGeometry::LocalView;
488 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
489 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
490 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
491
492 static constexpr int dim = GridView::dimension;
493 static constexpr int dimWorld = GridView::dimensionworld;
494
495 using GlobalPosition = typename SubControlVolumeFace::GlobalPosition;
496 using VelocityVector = Dune::FieldVector<Scalar, dimWorld>;
497 using GravityVector = Dune::FieldVector<Scalar, dimWorld>;
498 using CouplingManager = GetPropType<TypeTag, Properties::CouplingManager>;
499 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
500
501 public:
502 //! These types are used in place of the typical NumEqVector type.
503 //! In the numeqvector assembly type, only one equation per DOF (face) is considered
504 //! while the type here provides one entry for each world dimension.
505 using InitialValues = Dune::FieldVector<Scalar, dimWorld>;
506 using Sources = Dune::FieldVector<Scalar, dimWorld>;
507 using DirichletValues = Dune::FieldVector<Scalar, dimWorld>;
508 using BoundaryFluxes = Dune::FieldVector<Scalar, dimWorld>;
509
510 //! Export the boundary types.
511 using BoundaryTypes = NavierStokesMomentumBoundaryTypes<ModelTraits::dim()>;
512
513 //! This problem is used for the momentum balance model.
514 static constexpr bool isMomentumProblem() { return true; }
515
516 /*!
517 * \brief The constructor
518 * \param gridGeometry The finite volume grid geometry
519 * \param couplingManager A coupling manager (in case this problem is a coupled "mass-momentum"/full Navier-Stokes problem)
520 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
521 */
522 30 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
523 std::shared_ptr<CouplingManager> couplingManager,
524 const std::string& paramGroup = "")
525 : ParentType(gridGeometry, paramGroup)
526 60 , gravity_(0.0)
527
1/2
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
90 , couplingManager_(couplingManager)
528 {
529
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
30 if (getParamFromGroup<bool>(paramGroup, "Problem.EnableGravity"))
530 gravity_[dim-1] = -9.81;
531
532
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 enableInertiaTerms_ = getParamFromGroup<bool>(paramGroup, "Problem.EnableInertiaTerms");
533 30 }
534
535 /*!
536 * \brief The constructor for usage without a coupling manager
537 * \param gridGeometry The finite volume grid geometry
538 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
539 */
540 18 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
541 const std::string& paramGroup = "")
542
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
36 : NavierStokesMomentumProblemImpl(gridGeometry, {}, paramGroup)
543 18 {}
544
545 /*!
546 * \brief Evaluate the source term for all phases within a given
547 * sub-control-volume.
548 *
549 * This is the method for the case where the source term is
550 * potentially solution dependent and requires some quantities that
551 * are specific to the fully-implicit method.
552 *
553 * \param element The finite element
554 * \param fvGeometry The finite-volume geometry
555 * \param elemVolVars All volume variables for the element
556 * \param scv The sub control volume
557 *
558 * For this method, the return parameter stores the conserved quantity rate
559 * generated or annihilate per volume unit. Positive values mean
560 * that the conserved quantity is created, negative ones mean that it vanishes.
561 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
562 */
563 template<class ElementVolumeVariables>
564 31591694 Sources source(const Element &element,
565 const FVElementGeometry& fvGeometry,
566 const ElementVolumeVariables& elemVolVars,
567 const SubControlVolume &scv) const
568 {
569 // forward to solution independent, fully-implicit specific interface
570 31591694 return asImp_().sourceAtPos(scv.center());
571 }
572
573 /*!
574 * \brief Evaluate the source term for all phases at a given position
575 *
576 * \param globalPos The position of the center of the finite volume
577 * for which the source term ought to be
578 * specified in global coordinates
579 *
580 * For this method, the values parameter stores the conserved quantity rate
581 * generated or annihilate per volume unit. Positive values mean
582 * that the conserved quantity is created, negative ones mean that it vanishes.
583 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
584 */
585 30436494 Sources sourceAtPos(const GlobalPosition &globalPos) const
586 {
587 //! As a default, i.e. if the user's problem does not overload any source method
588 //! return 0.0 (no source terms)
589
2/2
✓ Branch 0 taken 5976666 times.
✓ Branch 1 taken 1992222 times.
66849654 return Sources(0.0);
590 }
591
592 /*!
593 * \brief Specifies which kind of boundary condition should be
594 * used for which equation on a given boundary segment.
595 *
596 * \param element The finite element
597 * \param scv The sub control volume
598 */
599 72813 BoundaryTypes boundaryTypes(const Element& element,
600 const SubControlVolume& scv) const
601 {
602 // forward it to the method which only takes the global coordinate
603
2/2
✓ Branch 0 taken 47412 times.
✓ Branch 1 taken 21130 times.
72813 return asImp_().boundaryTypesAtPos(scv.dofPosition());
604 }
605
606 /*!
607 * \brief Specifies which kind of boundary condition should be
608 * used for which equation on a given boundary segment.
609 *
610 * \param element The finite element
611 * \param scvf The sub control volume face
612 */
613 BoundaryTypes boundaryTypes(const Element& element,
614 const SubControlVolumeFace& scvf) const
615 {
616 DUNE_THROW(Dune::InvalidStateException, "boundaryTypes(..., scvf) called for a CVFE method.");
617 }
618
619 /*!
620 * \brief Evaluate the boundary conditions for a Dirichlet
621 * control volume.
622 *
623 * \param element The finite element
624 * \param scv the sub control volume
625 */
626 86156 DirichletValues dirichlet(const Element& element, const SubControlVolume& scv) const
627 {
628 // forward it to the method which only takes the global coordinate
629
4/4
✓ Branch 0 taken 47274 times.
✓ Branch 1 taken 15758 times.
✓ Branch 2 taken 35556 times.
✓ Branch 3 taken 11852 times.
197676 return asImp_().dirichletAtPos(scv.dofPosition());
630 }
631
632 /*!
633 * \brief Evaluate the boundary conditions for a Dirichlet
634 * control volume face.
635 *
636 * \param element The finite element
637 * \param scvf the sub control volume face
638 */
639 DirichletValues dirichlet(const Element& element, const SubControlVolumeFace& scvf) const
640 {
641 // forward it to the method which only takes the global coordinate
642 DUNE_THROW(Dune::InvalidStateException, "dirichlet(scvf) called for CVFE method.");
643 }
644
645 /*!
646 * \brief Returns the acceleration due to gravity.
647 *
648 * If the <tt>Problem.EnableGravity</tt> parameter is true, this means
649 * \f$\boldsymbol{g} = ( 0,\dots,\ -9.81)^T \f$, else \f$\boldsymbol{g} = ( 0,\dots, 0)^T \f$
650 */
651 const GravityVector& gravity() const
652 32455694 { return gravity_; }
653
654 /*!
655 * \brief Returns whether inertia terms should be considered.
656 */
657 46901758 bool enableInertiaTerms() const
658
6/6
✓ Branch 0 taken 17582868 times.
✓ Branch 1 taken 29298040 times.
✓ Branch 2 taken 17370 times.
✓ Branch 3 taken 3474 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
46901758 { return enableInertiaTerms_; }
659
660 /*!
661 * \brief Returns a reference pressure
662 * This pressure is subtracted from the actual pressure for the momentum balance
663 * which potentially helps to improve numerical accuracy by avoiding issues related do floating point arithmetic.
664 * \note Overload this for reference pressures other than zero.
665 */
666 Scalar referencePressure() const
667 { return 0.0; }
668
669 /*!
670 * \brief Returns the pressure at a given sub control volume face.
671 * \note Overload this if a fixed pressure shall be prescribed (e.g., given by an analytical solution).
672 */
673 46921262 Scalar pressure(const Element& element,
674 const FVElementGeometry& fvGeometry,
675 const SubControlVolumeFace& scvf) const
676 {
677 if constexpr (std::is_empty_v<CouplingManager>)
678 6334400 return asImp_().pressureAtPos(scvf.ipGlobal());
679 else
680
1/2
✓ Branch 2 taken 40354 times.
✗ Branch 3 not taken.
40586862 return couplingManager_->pressure(element, fvGeometry, scvf);
681 }
682
683 /*!
684 * \brief Returns the pressure at a given sub control volume.
685 * \note Overload this if a fixed pressure shall be prescribed (e.g., given by an analytical solution).
686 */
687 3822000 Scalar pressure(const Element& element,
688 const FVElementGeometry& fvGeometry,
689 const SubControlVolume& scv,
690 const bool isPreviousTimeStep = false) const
691 {
692 if constexpr (std::is_empty_v<CouplingManager>)
693 3822000 return asImp_().pressureAtPos(scv.dofPosition());
694 else
695 return couplingManager_->pressure(element, fvGeometry, scv, isPreviousTimeStep);
696 }
697
698 /*!
699 * \brief Returns the pressure at a given position.
700 */
701 Scalar pressureAtPos(const GlobalPosition&) const
702 {
703 DUNE_THROW(Dune::NotImplemented, "pressureAtPos not implemented");
704 }
705
706 /*!
707 * \brief Returns the density at a given sub control volume face.
708 * \note Overload this if a fixed density shall be prescribed.
709 */
710 Scalar density(const Element& element,
711 const FVElementGeometry& fvGeometry,
712 const SubControlVolumeFace& scvf) const
713 {
714 if constexpr (std::is_empty_v<CouplingManager>)
715 return asImp_().densityAtPos(scvf.ipGlobal());
716 else
717 return couplingManager_->density(element, fvGeometry, scvf);
718 }
719
720 /*!
721 * \brief Returns the density at a given sub control volume.
722 * \note Overload this if a fixed density shall be prescribed.
723 */
724 5292054 Scalar density(const Element& element,
725 const FVElementGeometry& fvGeometry,
726 const SubControlVolume& scv,
727 const bool isPreviousTimeStep = false) const
728 {
729 if constexpr (std::is_empty_v<CouplingManager>)
730 3822000 return asImp_().densityAtPos(scv.dofPosition());
731 else
732 1470054 return couplingManager_->density(element, fvGeometry, scv, isPreviousTimeStep);
733 }
734
735
736 /*!
737 * \brief Returns the density at a given position.
738 */
739 Scalar densityAtPos(const GlobalPosition&) const
740 {
741 DUNE_THROW(Dune::NotImplemented, "densityAtPos not implemented");
742 }
743
744 /*!
745 * \brief Returns the effective dynamic viscosity at a given sub control volume face.
746 * \note Overload this if a fixed viscosity shall be prescribed.
747 */
748
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5207990 times.
7471188 Scalar effectiveViscosity(const Element& element,
749 const FVElementGeometry& fvGeometry,
750 const SubControlVolumeFace& scvf) const
751 {
752 if constexpr (std::is_empty_v<CouplingManager>)
753
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5207990 times.
5208000 return asImp_().effectiveViscosityAtPos(scvf.ipGlobal());
754 else
755 2263188 return couplingManager_->effectiveViscosity(element, fvGeometry, scvf);
756 }
757
758 /*!
759 * \brief Returns the effective dynamic viscosity at a given sub control volume.
760 * \note Overload this if a fixed viscosity shall be prescribed.
761 */
762 4066500 Scalar effectiveViscosity(const Element& element,
763 const FVElementGeometry& fvGeometry,
764 const SubControlVolume& scv,
765 const bool isPreviousTimeStep = false) const
766 {
767 if constexpr (std::is_empty_v<CouplingManager>)
768 3822000 return asImp_().effectiveViscosityAtPos(scv.dofPosition());
769 else
770 244500 return couplingManager_->effectiveViscosity(element, fvGeometry, scv, isPreviousTimeStep);
771 }
772
773 /*!
774 * \brief Returns the effective dynamic viscosity at a given position.
775 */
776 Scalar effectiveViscosityAtPos(const GlobalPosition&) const
777 {
778 DUNE_THROW(Dune::NotImplemented, "effectiveViscosityAtPos not implemented");
779 }
780
781 /*!
782 * \brief Applies the initial solution for all degrees of freedom of the grid.
783 * \param sol the initial solution vector
784 */
785 template<class SolutionVector>
786 void applyInitialSolution(SolutionVector& sol) const
787 {
788 static_assert(GridGeometry::discMethod == DiscretizationMethods::CVFE<DM>{});
789 sol.resize(this->gridGeometry().numDofs());
790 std::vector<bool> dofHandled(this->gridGeometry().numDofs(), false);
791 auto fvGeometry = localView(this->gridGeometry());
792 for (const auto& element : elements(this->gridGeometry().gridView()))
793 {
794 fvGeometry.bindElement(element);
795 for (const auto& scv : scvs(fvGeometry))
796 {
797 const auto dofIdx = scv.dofIndex();
798 if (!dofHandled[dofIdx])
799 {
800 dofHandled[dofIdx] = true;
801 sol[dofIdx] = asImp_().initial(scv);
802 }
803 }
804 }
805 }
806
807 /*!
808 * \brief Evaluate the initial value at an sub control volume
809 */
810 InitialValues initial(const SubControlVolume& scv) const
811 {
812 static_assert(GridGeometry::discMethod == DiscretizationMethods::CVFE<DM>{});
813 return asImp_().initialAtPos(scv.dofPosition());
814 }
815
816 private:
817 //! Returns the implementation of the problem (i.e. static polymorphism)
818 Implementation &asImp_()
819 { return *static_cast<Implementation *>(this); }
820
821 //! \copydoc asImp_()
822 const Implementation &asImp_() const
823 { return *static_cast<const Implementation *>(this); }
824
825 GravityVector gravity_;
826 bool enableInertiaTerms_;
827 std::shared_ptr<CouplingManager> couplingManager_ = {};
828 };
829
830 /*!
831 * \ingroup NavierStokesModel
832 * \brief Navier-Stokes momentum problem class
833 *
834 * Inherit from this problem to implement Navier-Stokes momentum problems
835 */
836 template<class TypeTag>
837 using NavierStokesMomentumProblem = NavierStokesMomentumProblemImpl<
838 TypeTag, typename GetPropType<TypeTag, Properties::GridGeometry>::DiscretizationMethod
839 >;
840
841 } // end namespace Dumux
842
843 #endif
844