GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/freeflow/navierstokes/momentum/problem.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 64 103 62.1%
Functions: 49 252 19.4%
Branches: 71 163 43.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 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/typetraits.hh>
17 #include <dumux/common/numeqvector.hh>
18 #include <dumux/common/properties.hh>
19 #include <dumux/common/fvproblemwithspatialparams.hh>
20 #include <dumux/discretization/method.hh>
21 #include <dumux/freeflow/navierstokes/momentum/boundarytypes.hh>
22
23 namespace Dumux {
24
25 template<class TypeTag, class DiscretizationMethod>
26 class NavierStokesMomentumProblemImpl;
27
28 template<class TypeTag>
29 class NavierStokesMomentumProblemImpl<TypeTag, DiscretizationMethods::FCStaggered>
30 : public FVProblemWithSpatialParams<TypeTag>
31 {
32 using ParentType = FVProblemWithSpatialParams<TypeTag>;
33 using Implementation = GetPropType<TypeTag, Properties::Problem>;
34
35 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
36 using GridView = typename GridGeometry::GridView;
37 using Element = typename GridView::template Codim<0>::Entity;
38
39 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
40 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
41 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
42 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
43
44 using FVElementGeometry = typename GridGeometry::LocalView;
45 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
46 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
47 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
48
49 enum {
50 dim = GridView::dimension,
51 dimWorld = GridView::dimensionworld
52 };
53
54 using GlobalPosition = typename SubControlVolumeFace::GlobalPosition;
55 using VelocityVector = Dune::FieldVector<Scalar, dimWorld>;
56 using GravityVector = Dune::FieldVector<Scalar, dimWorld>;
57 using CouplingManager = GetPropType<TypeTag, Properties::CouplingManager>;
58 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
59
60 static constexpr bool isCoupled_ = !std::is_empty_v<CouplingManager>;
61
62
63 public:
64 //! These types are used in place of the typical NumEqVector type.
65 //! In the numeqvector assembly type, only one equation per DOF (face) is considered
66 //! while the type here provides one entry for each world dimension.
67 using InitialValues = Dune::FieldVector<Scalar, dimWorld>;
68 using Sources = Dune::FieldVector<Scalar, dimWorld>;
69 using DirichletValues = Dune::FieldVector<Scalar, dimWorld>;
70 using BoundaryFluxes = Dune::FieldVector<Scalar, dimWorld>;
71
72 using MomentumFluxType = Dune::FieldVector<Scalar, dimWorld>;
73
74 //! Export the boundary types.
75 using BoundaryTypes = NavierStokesMomentumBoundaryTypes<ModelTraits::dim()>;
76
77 //! This problem is used for the momentum balance model.
78 static constexpr bool isMomentumProblem() { return true; }
79
80 /*!
81 * \brief The constructor
82 * \param gridGeometry The finite volume grid geometry
83 * \param couplingManager The coupling manager (couples mass and momentum equations)
84 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
85 */
86 60 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
87 std::shared_ptr<CouplingManager> couplingManager,
88 const std::string& paramGroup = "")
89 : ParentType(gridGeometry, paramGroup)
90 , gravity_(0.0)
91
2/10
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
180 , couplingManager_(couplingManager)
92 {
93
3/4
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 58 times.
60 if (getParamFromGroup<bool>(paramGroup, "Problem.EnableGravity"))
94 4 gravity_[dim-1] = -9.81;
95
96
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 enableInertiaTerms_ = getParamFromGroup<bool>(paramGroup, "Problem.EnableInertiaTerms");
97 60 }
98
99 /*!
100 * \brief The constructor for usage without a coupling manager
101 * \param gridGeometry The finite volume grid geometry
102 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
103 */
104 5 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
105 const std::string& paramGroup = "")
106
3/10
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
15 : NavierStokesMomentumProblemImpl(gridGeometry, {}, paramGroup)
107 5 {}
108
109 /*!
110 * \brief Evaluate the source term for all phases within a given
111 * sub-control-volume.
112 *
113 * This is the method for the case where the source term is
114 * potentially solution dependent and requires some quantities that
115 * are specific to the fully-implicit method.
116 *
117 * \param element The finite element
118 * \param fvGeometry The finite-volume geometry
119 * \param elemVolVars All volume variables for the element
120 * \param scv The sub control volume
121 *
122 * For this method, the return parameter stores the conserved quantity rate
123 * generated or annihilate per volume unit. Positive values mean
124 * that the conserved quantity is created, negative ones mean that it vanishes.
125 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
126 */
127 Sources source(const Element& element,
128 const FVElementGeometry& fvGeometry,
129 const ElementVolumeVariables& elemVolVars,
130 const SubControlVolume& scv) const
131 {
132 // forward to solution independent, fully-implicit specific interface
133
0/4
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
43185200 return asImp_().sourceAtPos(scv.dofPosition());
134 }
135
136 /*!
137 * \brief Evaluate the source term for all phases within a given
138 * sub-control-volume.
139 *
140 * \param globalPos The position of the center of the finite volume
141 * for which the source term ought to be
142 * specified in global coordinates
143 *
144 * For this method, the values parameter stores the conserved quantity rate
145 * generated or annihilate per volume unit. Positive values mean
146 * that the conserved quantity is created, negative ones mean that it vanishes.
147 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
148 */
149 Sources sourceAtPos(const GlobalPosition& globalPos) const
150 {
151 //! As a default, i.e. if the user's problem does not overload any source method
152 //! return 0.0 (no source terms)
153 86370400 return Sources(0.0);
154 }
155
156 /*!
157 * \brief Specifies which kind of boundary condition should be
158 * used for which equation on a given boundary segment.
159 *
160 * \param element The finite element
161 * \param scvf The sub control volume face
162 */
163 auto boundaryTypes(const Element& element,
164 const SubControlVolumeFace& scvf) const
165 {
166 // Forward it to the method which only takes the global coordinate.
167 // We evaluate the boundary type at the center of the sub control volume face
168 // in order to avoid ambiguities at domain corners.
169
2/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2526472 return asImp_().boundaryTypesAtPos(scvf.center());
170 }
171
172 /*!
173 * \brief Evaluate the boundary conditions for a dirichlet
174 * control volume face.
175 *
176 * \param element The finite element
177 * \param scvf the sub control volume face
178 * \note used for cell-centered discretization schemes
179 */
180 DirichletValues dirichlet(const Element& element, const SubControlVolumeFace& scvf) const
181 {
182
0/5
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3781190 return asImp_().dirichletAtPos(scvf.ipGlobal());
183 }
184
185 /*!
186 * \brief Evaluates the boundary conditions for a Neumann control volume.
187 *
188 * \param element The element for which the Neumann boundary condition is set
189 * \param fvGeometry The fvGeometry
190 * \param elemVolVars The element volume variables
191 * \param elemFluxVarsCache The element flux variables cache
192 * \param scvf The boundary sub control volume face
193 */
194 template<class ElementFluxVariablesCache>
195 BoundaryFluxes neumann(const Element& element,
196 const FVElementGeometry& fvGeometry,
197 const ElementVolumeVariables& elemVolVars,
198 const ElementFluxVariablesCache& elemFluxVarsCache,
199 const SubControlVolumeFace& scvf) const
200 { return asImp_().neumannAtPos(scvf.ipGlobal()); }
201
202 /*!
203 * \brief Returns the neumann flux at a given position.
204 */
205 BoundaryFluxes neumannAtPos(const GlobalPosition& globalPos) const
206 { return BoundaryFluxes(0.0); } //! A default, i.e. if the user's does not overload any neumann method
207
208 /*!
209 * \brief Returns the acceleration due to gravity.
210 *
211 * If the <tt>Problem.EnableGravity</tt> parameter is true, this means
212 * \f$\boldsymbol{g} = ( 0,\dots,\ -9.81)^T \f$, else \f$\boldsymbol{g} = ( 0,\dots, 0)^T \f$
213 */
214 const GravityVector& gravity() const
215
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
43559688 { return gravity_; }
216
217 /*!
218 * \brief Returns whether inertia terms should be considered.
219 */
220 bool enableInertiaTerms() const
221 { return enableInertiaTerms_; }
222
223 /*!
224 * \brief Returns the pressure at a given sub control volume face.
225 * \note Overload this if a fixed pressure shall be prescribed (e.g., given by an analytical solution).
226 */
227 Scalar pressure(const Element& element,
228 const FVElementGeometry& fvGeometry,
229 const SubControlVolumeFace& scvf) const
230 {
231 if constexpr (isCoupled_)
232 188716296 return couplingManager_->pressure(element, fvGeometry, scvf);
233 else
234 685632 return asImp_().pressureAtPos(scvf.ipGlobal());
235 }
236
237 /*!
238 * \brief Returns the pressure at a given position.
239 */
240 Scalar pressureAtPos(const GlobalPosition&) const
241 {
242 DUNE_THROW(Dune::NotImplemented, "pressureAtPos not implemented");
243 }
244
245 /*!
246 * \brief Returns a reference pressure at a given sub control volume face.
247 * This pressure is subtracted from the actual pressure for the momentum balance
248 * which potentially helps to improve numerical accuracy by avoiding issues related do floating point arithmetic.
249 * \note Overload this for reference pressures other than zero.
250 */
251 Scalar referencePressure(const Element& element,
252 const FVElementGeometry& fvGeometry,
253 const SubControlVolumeFace& scvf) const
254 { return 0.0; }
255
256 /*!
257 * \brief Returns the density at a given sub control volume face.
258 * \note Overload this if a fixed density shall be prescribed.
259 */
260 Scalar density(const Element& element,
261 const FVElementGeometry& fvGeometry,
262 const SubControlVolumeFace& scvf) const
263 {
264 if constexpr (isCoupled_)
265
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 7355627 times.
130725212 return couplingManager_->density(element, fvGeometry, scvf);
266 else
267 return asImp_().densityAtPos(scvf.ipGlobal());
268 }
269
270 /*!
271 * \brief Returns the density at a given sub control volume.
272 * \note Overload this if a fixed density shall be prescribed.
273 */
274 Scalar density(const Element& element,
275 const SubControlVolume& scv,
276 const bool isPreviousTimeStep = false) const
277 {
278 if constexpr (isCoupled_)
279
0/14
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
300535372 return couplingManager_->density(element, scv, isPreviousTimeStep);
280 else
281 return asImp_().densityAtPos(scv.dofPosition());
282 }
283
284 auto insideAndOutsideDensity(const Element& element,
285 const FVElementGeometry& fvGeometry,
286 const SubControlVolumeFace& scvf,
287 const bool isPreviousTimeStep = false) const
288 {
289 if constexpr (isCoupled_)
290
4/8
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 14538917 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 30437 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
258729224 return couplingManager_->insideAndOutsideDensity(element, fvGeometry, scvf, isPreviousTimeStep);
291 else
292 {
293 const auto rho = asImp_().densityAtPos(scvf.ipGlobal());
294 return std::make_pair(rho, rho);
295 }
296 }
297
298 /*!
299 * \brief Returns the density at a given position.
300 */
301 Scalar densityAtPos(const GlobalPosition&) const
302 {
303 DUNE_THROW(Dune::NotImplemented, "densityAtPos not implemented");
304 }
305
306 /*!
307 * \brief Returns the effective dynamic viscosity at a given sub control volume face.
308 * \note Overload this if a fixed viscosity shall be prescribed.
309 */
310 Scalar effectiveViscosity(const Element& element,
311 const FVElementGeometry& fvGeometry,
312 const SubControlVolumeFace& scvf) const
313 {
314 if constexpr (isCoupled_)
315
6/7
✓ Branch 8 taken 1400 times.
✓ Branch 9 taken 2742 times.
✓ Branch 10 taken 1240 times.
✓ Branch 11 taken 66968 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1744 times.
✓ Branch 16 taken 1770 times.
561807512 return couplingManager_->effectiveViscosity(element, fvGeometry, scvf);
316 else
317 1350928 return asImp_().effectiveViscosityAtPos(scvf.ipGlobal());
318 }
319
320 /*!
321 * \brief Returns the effective dynamic viscosity at a given sub control volume.
322 * \note Overload this if a fixed viscosity shall be prescribed.
323 */
324 Scalar effectiveViscosity(const Element& element,
325 const FVElementGeometry& fvGeometry,
326 const SubControlVolume& scv) const
327 {
328 if constexpr (isCoupled_)
329 180688 return couplingManager_->effectiveViscosity(element, fvGeometry, scv);
330 else
331 return asImp_().effectiveViscosityAtPos(scv.dofPosition());
332 }
333
334 /*!
335 * \brief Returns the effective dynamic viscosity at a given position.
336 */
337 Scalar effectiveViscosityAtPos(const GlobalPosition&) const
338 {
339 DUNE_THROW(Dune::NotImplemented, "effectiveViscosityAtPos not implemented");
340 }
341
342 /*!
343 * \brief Applies the initial solution for all degrees of freedom of the grid.
344 * \param sol the initial solution vector
345 */
346 template<class SolutionVector>
347 26 void applyInitialSolution(SolutionVector& sol) const
348 {
349 52 sol.resize(this->gridGeometry().numDofs());
350
5/10
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 26 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 25 times.
✗ Branch 14 not taken.
78 std::vector<bool> dofHandled(this->gridGeometry().numDofs(), false);
351
2/4
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
52 auto fvGeometry = localView(this->gridGeometry());
352
5/10
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 186968 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 1250 times.
✗ Branch 14 not taken.
373988 for (const auto& element : elements(this->gridGeometry().gridView()))
353 {
354
1/2
✓ Branch 1 taken 1250 times.
✗ Branch 2 not taken.
186942 fvGeometry.bindElement(element);
355
5/5
✓ Branch 0 taken 5000 times.
✓ Branch 1 taken 744018 times.
✓ Branch 2 taken 185692 times.
✓ Branch 3 taken 742768 times.
✓ Branch 4 taken 185692 times.
934710 for (const auto& scv : scvs(fvGeometry))
356 {
357 747768 const auto dofIdx = scv.dofIndex();
358
6/6
✓ Branch 0 taken 377655 times.
✓ Branch 1 taken 370113 times.
✓ Branch 2 taken 377655 times.
✓ Branch 3 taken 370113 times.
✓ Branch 4 taken 377655 times.
✓ Branch 5 taken 370113 times.
2243304 if (!dofHandled[dofIdx])
359 {
360
5/6
✓ Branch 0 taken 5150 times.
✓ Branch 1 taken 60950 times.
✓ Branch 2 taken 5150 times.
✓ Branch 3 taken 50750 times.
✓ Branch 4 taken 10200 times.
✗ Branch 5 not taken.
755310 dofHandled[dofIdx] = true;
361
1/2
✓ Branch 1 taken 10200 times.
✗ Branch 2 not taken.
1359570 sol[dofIdx] = asImp_().initial(scv)[scv.dofAxis()];
362 }
363 }
364 }
365 26 }
366
367 /*!
368 * \brief Evaluate the initial value at a sub control volume
369 */
370 InitialValues initial(const SubControlVolume& scv) const
371 {
372
4/4
✓ Branch 0 taken 5150 times.
✓ Branch 1 taken 50750 times.
✓ Branch 2 taken 5150 times.
✓ Branch 3 taken 50750 times.
855360 return asImp_().initialAtPos(scv.dofPosition());
373 }
374
375 //! Convenience function for staggered grid implementation.
376 30728 Scalar pseudo3DWallFriction(const Element& element,
377 const FVElementGeometry& fvGeometry,
378 const ElementVolumeVariables& elemVolVars,
379 const SubControlVolume& scv,
380 const Scalar height,
381 const Scalar factor = 8.0) const
382 {
383 30728 const Scalar velocity = elemVolVars[scv].velocity();
384 30728 const auto scvf = scvfs(fvGeometry, scv).begin();
385 30728 const Scalar viscosity = effectiveViscosity(element, fvGeometry, *scvf);
386 61456 return pseudo3DWallFriction(velocity, viscosity, height, factor);
387 }
388
389 /*!
390 * \brief An additional drag term can be included as source term for the momentum balance
391 * to mimic 3D flow behavior in 2D:
392 * \f[
393 * f_{drag} = -(8 \mu / h^2)v
394 * \f]
395 * Here, \f$h\f$ corresponds to the extruded height that is
396 * bounded by the imaginary walls. See Flekkoy et al. (1995) \cite flekkoy1995a<BR>
397 * A value of 8.0 is used as a default factor, corresponding
398 * to the velocity profile at the center plane
399 * of the virtual height (maximum velocity). Setting this value to 12.0 corresponds
400 * to an depth-averaged velocity (Venturoli and Boek, 2006) \cite venturoli2006a.
401 */
402 Scalar pseudo3DWallFriction(const Scalar velocity,
403 const Scalar viscosity,
404 const Scalar height,
405 const Scalar factor = 8.0) const
406 {
407 static_assert(dim == 2, "Pseudo 3D wall friction may only be used in 2D");
408 30728 return -factor * velocity * viscosity / (height*height);
409 }
410
411 /*!
412 * \brief Returns true if the scvf is located on a boundary with a slip condition.
413 * \note This member function must be overloaded in the problem implementation.
414 * Make sure to use scvf.center() for querying the spatial location.
415 */
416 bool onSlipBoundary(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf) const
417 591592 { return asImp_().onSlipBoundaryAtPos(scvf.center()); }
418
419 /*!
420 * \brief Returns true if the scvf is located on a boundary with a slip condition.
421 * \note This member function must be overloaded in the problem implementation.
422 */
423 bool onSlipBoundaryAtPos(const GlobalPosition& pos) const
424 { return false; }
425
426 /*!
427 * \brief Returns the intrinsic permeability of required as input parameter for the Beavers-Joseph-Saffman boundary condition
428 * This member function must be overloaded in the problem implementation, if the BJS boundary condition is used.
429 */
430 [[deprecated("Will be removed after release 3.9.")]]
431 Scalar permeability(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf) const
432 {
433 DUNE_THROW(Dune::NotImplemented,
434 "When using the Beavers-Joseph-Saffman boundary condition, "
435 "the permeability must be returned in the actual problem"
436 );
437 }
438
439 /*!
440 * \brief Returns the alpha value required as input parameter for the Beavers-Joseph-Saffman boundary condition
441 * This member function must be overloaded in the problem implementation, if the BJS boundary condition is used.
442 */
443 [[deprecated("Will be removed after release 3.9. Implement betaBJ instead. ")]]
444 Scalar alphaBJ(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf) const
445 {
446 DUNE_THROW(Dune::NotImplemented,
447 "When using the Beavers-Joseph-Saffman boundary condition, "
448 "the alpha value must be returned in the actual problem"
449 );
450 }
451
452 /*!
453 * \brief Returns the beta value which is the alpha value divided by the square root of the (scalar-valued) interface permeability.
454 */
455 [[deprecated("Needs to be implemented in test problem. Will be removed after release 3.9.")]]
456 Scalar betaBJ(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf, const GlobalPosition& tangentialVector) const
457 {
458 const auto& K = asImp_().permeability(fvGeometry, scvf);
459 const auto interfacePermeability = vtmv(tangentialVector, K, tangentialVector);
460 using std::sqrt;
461 return asImp_().alphaBJ(fvGeometry, scvf) / sqrt(interfacePermeability);
462 }
463
464 /*!
465 * \brief Returns the velocity in the porous medium (which is 0 by default according to Saffmann).
466 */
467 [[deprecated("Needs to be implemented in test problem. Will be removed after release 3.9.")]]
468 VelocityVector porousMediumVelocity(const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf) const
469 {
470 return VelocityVector(0.0);
471 }
472
473 /*!
474 * \brief Returns the slip velocity at a porous boundary based on the Beavers-Joseph(-Saffman) condition.
475 * \note This only returns a vector filled with one component of the slip velocity (corresponding to the dof axis of the scv the scvf belongs to)
476 */
477 [[deprecated("Will be removed after release 3.9.")]]
478 const VelocityVector beaversJosephVelocity(const FVElementGeometry& fvGeometry,
479 const SubControlVolumeFace& scvf,
480 const ElementVolumeVariables& elemVolVars,
481 Scalar tangentialVelocityGradient) const
482 {
483 assert(scvf.isLateral());
484 assert(scvf.boundary());
485
486 const auto& scv = fvGeometry.scv(scvf.insideScvIdx());
487
488 // create a unit normal vector oriented in positive coordinate direction
489 GlobalPosition orientation(0.0);
490 orientation[scv.dofAxis()] = 1.0;
491
492 // du/dy + dv/dx = beta * (u_boundary-uPM)
493 // beta = alpha/sqrt(K)
494 const Scalar betaBJ = asImp_().betaBJ(fvGeometry, scvf, orientation);
495 const Scalar distanceNormalToBoundary = (scvf.ipGlobal() - scv.dofPosition()).two_norm();
496
497 static const bool onlyNormalGradient = getParamFromGroup<bool>(this->paramGroup(), "FreeFlow.EnableUnsymmetrizedVelocityGradientForBeaversJoseph", false);
498 if (onlyNormalGradient)
499 tangentialVelocityGradient = 0.0;
500
501 const Scalar scalarSlipVelocity = (tangentialVelocityGradient*distanceNormalToBoundary
502 + asImp_().porousMediumVelocity(fvGeometry, scvf) * orientation * betaBJ * distanceNormalToBoundary
503 + elemVolVars[scv].velocity()) / (betaBJ*distanceNormalToBoundary + 1.0);
504
505 orientation *= scalarSlipVelocity;
506 return orientation;
507 }
508
509 const CouplingManager& couplingManager() const
510 {
511 if constexpr (isCoupled_)
512 return *couplingManager_;
513 else
514 DUNE_THROW(Dune::InvalidStateException,
515 "Accessing coupling manager of an uncoupled problem is not possible."
516 );
517 }
518
519 private:
520 //! Returns the implementation of the problem (i.e. static polymorphism)
521 Implementation& asImp_()
522 { return *static_cast<Implementation *>(this); }
523
524 //! \copydoc asImp_()
525 const Implementation& asImp_() const
526 { return *static_cast<const Implementation *>(this); }
527
528 GravityVector gravity_;
529 bool enableInertiaTerms_;
530 std::shared_ptr<CouplingManager> couplingManager_;
531 };
532
533 /*!
534 * \brief Navier-Stokes default problem implementation for FCDiamond discretizations
535 */
536 template<class TypeTag, class DM>
537 class NavierStokesMomentumProblemImpl<TypeTag, DiscretizationMethods::CVFE<DM>>
538 : public FVProblemWithSpatialParams<TypeTag>
539 {
540 using ParentType = FVProblemWithSpatialParams<TypeTag>;
541 using Implementation = GetPropType<TypeTag, Properties::Problem>;
542
543 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
544 using GridView = typename GridGeometry::GridView;
545 using Element = typename GridView::template Codim<0>::Entity;
546
547 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
548 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
549 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
550 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
551
552 using FVElementGeometry = typename GridGeometry::LocalView;
553 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
554 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
555 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
556
557 static constexpr int dim = GridView::dimension;
558 static constexpr int dimWorld = GridView::dimensionworld;
559
560 using GlobalPosition = typename SubControlVolumeFace::GlobalPosition;
561 using VelocityVector = Dune::FieldVector<Scalar, dimWorld>;
562 using GravityVector = Dune::FieldVector<Scalar, dimWorld>;
563 using CouplingManager = GetPropType<TypeTag, Properties::CouplingManager>;
564 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
565
566 static constexpr bool isCVFE = DiscretizationMethods::isCVFE<
567 typename GridGeometry::DiscretizationMethod
568 >;
569
570 public:
571 //! These types are used in place of the typical NumEqVector type.
572 //! In the numeqvector assembly type, only one equation per DOF (face) is considered
573 //! while the type here provides one entry for each world dimension.
574 using InitialValues = Dune::FieldVector<Scalar, dimWorld>;
575 using Sources = Dune::FieldVector<Scalar, dimWorld>;
576 using DirichletValues = Dune::FieldVector<Scalar, dimWorld>;
577 using BoundaryFluxes = Dune::FieldVector<Scalar, dimWorld>;
578
579 //! Export the boundary types.
580 using BoundaryTypes = NavierStokesMomentumBoundaryTypes<ModelTraits::dim()>;
581
582 //! This problem is used for the momentum balance model.
583 static constexpr bool isMomentumProblem() { return true; }
584
585 /*!
586 * \brief The constructor
587 * \param gridGeometry The finite volume grid geometry
588 * \param couplingManager A coupling manager (in case this problem is a coupled "mass-momentum"/full Navier-Stokes problem)
589 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
590 */
591 27 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
592 std::shared_ptr<CouplingManager> couplingManager,
593 const std::string& paramGroup = "")
594 : ParentType(gridGeometry, paramGroup)
595 , gravity_(0.0)
596
2/8
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
81 , couplingManager_(couplingManager)
597 {
598
2/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
27 if (getParamFromGroup<bool>(paramGroup, "Problem.EnableGravity"))
599 gravity_[dim-1] = -9.81;
600
601
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 enableInertiaTerms_ = getParamFromGroup<bool>(paramGroup, "Problem.EnableInertiaTerms");
602 27 }
603
604 /*!
605 * \brief The constructor for usage without a coupling manager
606 * \param gridGeometry The finite volume grid geometry
607 * \param paramGroup The parameter group in which to look for runtime parameters first (default is "")
608 */
609 18 NavierStokesMomentumProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry,
610 const std::string& paramGroup = "")
611
3/10
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
54 : NavierStokesMomentumProblemImpl(gridGeometry, {}, paramGroup)
612 18 {}
613
614 /*!
615 * \brief Evaluate the source term for all phases within a given
616 * sub-control-volume.
617 *
618 * This is the method for the case where the source term is
619 * potentially solution dependent and requires some quantities that
620 * are specific to the fully-implicit method.
621 *
622 * \param element The finite element
623 * \param fvGeometry The finite-volume geometry
624 * \param elemVolVars All volume variables for the element
625 * \param scv The sub control volume
626 *
627 * For this method, the return parameter stores the conserved quantity rate
628 * generated or annihilate per volume unit. Positive values mean
629 * that the conserved quantity is created, negative ones mean that it vanishes.
630 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
631 */
632 template<class ElementVolumeVariables>
633 Sources source(const Element &element,
634 const FVElementGeometry& fvGeometry,
635 const ElementVolumeVariables& elemVolVars,
636 const SubControlVolume &scv) const
637 {
638 // forward to solution independent, fully-implicit specific interface
639 29669328 return asImp_().sourceAtPos(scv.center());
640 }
641
642 /*!
643 * \brief Evaluate the source term for all phases at a given position
644 *
645 * \param globalPos The position of the center of the finite volume
646 * for which the source term ought to be
647 * specified in global coordinates
648 *
649 * For this method, the values parameter stores the conserved quantity rate
650 * generated or annihilate per volume unit. Positive values mean
651 * that the conserved quantity is created, negative ones mean that it vanishes.
652 * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$.
653 */
654 Sources sourceAtPos(const GlobalPosition &globalPos) const
655 {
656 //! As a default, i.e. if the user's problem does not overload any source method
657 //! return 0.0 (no source terms)
658 53082088 return Sources(0.0);
659 }
660
661 /*!
662 * \brief Specifies which kind of boundary condition should be
663 * used for which equation on a given boundary segment.
664 *
665 * \param element The finite element
666 * \param scv The sub control volume
667 */
668 BoundaryTypes boundaryTypes(const Element& element,
669 const SubControlVolume& scv) const
670 {
671 if (!isCVFE)
672 DUNE_THROW(Dune::InvalidStateException,
673 "boundaryTypes(..., scv) called for for a non CVFE method.");
674
675 // forward it to the method which only takes the global coordinate
676 116916 return asImp_().boundaryTypesAtPos(scv.dofPosition());
677 }
678
679 /*!
680 * \brief Specifies which kind of boundary condition should be
681 * used for which equation on a given boundary segment.
682 *
683 * \param element The finite element
684 * \param scvf The sub control volume face
685 */
686 BoundaryTypes boundaryTypes(const Element& element,
687 const SubControlVolumeFace& scvf) const
688 {
689 if (isCVFE)
690 DUNE_THROW(Dune::InvalidStateException,
691 "boundaryTypes(..., scvf) called for a CVFE method.");
692
693 // forward it to the method which only takes the global coordinate
694 return asImp_().boundaryTypesAtPos(scvf.ipGlobal());
695 }
696
697 /*!
698 * \brief Evaluate the boundary conditions for a Dirichlet
699 * control volume.
700 *
701 * \param element The finite element
702 * \param scv the sub control volume
703 */
704 DirichletValues dirichlet(const Element& element, const SubControlVolume& scv) const
705 {
706 // forward it to the method which only takes the global coordinate
707 if (!isCVFE)
708 DUNE_THROW(Dune::InvalidStateException, "dirichlet(scv) called for a non CVFE method.");
709 else
710 155328 return asImp_().dirichletAtPos(scv.dofPosition());
711 }
712
713 /*!
714 * \brief Evaluate the boundary conditions for a Dirichlet
715 * control volume face.
716 *
717 * \param element The finite element
718 * \param scvf the sub control volume face
719 */
720 DirichletValues dirichlet(const Element& element, const SubControlVolumeFace& scvf) const
721 {
722 // forward it to the method which only takes the global coordinate
723 if (isCVFE)
724 DUNE_THROW(Dune::InvalidStateException, "dirichlet(scvf) called for CVFE method.");
725 else
726 return asImp_().dirichletAtPos(scvf.ipGlobal());
727 }
728
729 /*!
730 * \brief Returns the acceleration due to gravity.
731 *
732 * If the <tt>Problem.EnableGravity</tt> parameter is true, this means
733 * \f$\boldsymbol{g} = ( 0,\dots,\ -9.81)^T \f$, else \f$\boldsymbol{g} = ( 0,\dots, 0)^T \f$
734 */
735 const GravityVector& gravity() const
736 29378128 { return gravity_; }
737
738 /*!
739 * \brief Returns whether inertia terms should be considered.
740 */
741 bool enableInertiaTerms() const
742 { return enableInertiaTerms_; }
743
744 /*!
745 * \brief Returns a reference pressure
746 * This pressure is subtracted from the actual pressure for the momentum balance
747 * which potentially helps to improve numerical accuracy by avoiding issues related do floating point arithmetic.
748 * \note Overload this for reference pressures other than zero.
749 */
750 Scalar referencePressure() const
751 { return 0.0; }
752
753 /*!
754 * \brief Returns the pressure at a given sub control volume face.
755 * \note Overload this if a fixed pressure shall be prescribed (e.g., given by an analytical solution).
756 */
757 Scalar pressure(const Element& element,
758 const FVElementGeometry& fvGeometry,
759 const SubControlVolumeFace& scvf) const
760 {
761 if constexpr (std::is_empty_v<CouplingManager>)
762 19003200 return asImp_().pressureAtPos(scvf.ipGlobal());
763 else
764
2/4
✓ Branch 3 taken 38754 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 38754 times.
✗ Branch 7 not taken.
72453012 return couplingManager_->pressure(element, fvGeometry, scvf);
765 }
766
767 /*!
768 * \brief Returns the pressure at a given sub control volume.
769 * \note Overload this if a fixed pressure shall be prescribed (e.g., given by an analytical solution).
770 */
771 Scalar pressure(const Element& element,
772 const FVElementGeometry& fvGeometry,
773 const SubControlVolume& scv,
774 const bool isPreviousTimeStep = false) const
775 {
776 if constexpr (std::is_empty_v<CouplingManager>)
777 11466000 return asImp_().pressureAtPos(scv.dofPosition());
778 else
779 return couplingManager_->pressure(element, fvGeometry, scv, isPreviousTimeStep);
780 }
781
782 /*!
783 * \brief Returns the pressure at a given position.
784 */
785 Scalar pressureAtPos(const GlobalPosition&) const
786 {
787 DUNE_THROW(Dune::NotImplemented, "pressureAtPos not implemented");
788 }
789
790 /*!
791 * \brief Returns the density at a given sub control volume face.
792 * \note Overload this if a fixed density shall be prescribed.
793 */
794 Scalar density(const Element& element,
795 const FVElementGeometry& fvGeometry,
796 const SubControlVolumeFace& scvf) const
797 {
798 if constexpr (std::is_empty_v<CouplingManager>)
799 return asImp_().densityAtPos(scvf.ipGlobal());
800 else
801 return couplingManager_->density(element, fvGeometry, scvf);
802 }
803
804 /*!
805 * \brief Returns the density at a given sub control volume.
806 * \note Overload this if a fixed density shall be prescribed.
807 */
808 Scalar density(const Element& element,
809 const FVElementGeometry& fvGeometry,
810 const SubControlVolume& scv,
811 const bool isPreviousTimeStep = false) const
812 {
813 if constexpr (std::is_empty_v<CouplingManager>)
814 9455200 return asImp_().densityAtPos(scv.dofPosition());
815 else
816 2227200 return couplingManager_->density(element, fvGeometry, scv, isPreviousTimeStep);
817 }
818
819
820 /*!
821 * \brief Returns the density at a given position.
822 */
823 Scalar densityAtPos(const GlobalPosition&) const
824 {
825 DUNE_THROW(Dune::NotImplemented, "densityAtPos not implemented");
826 }
827
828 /*!
829 * \brief Returns the effective dynamic viscosity at a given sub control volume face.
830 * \note Overload this if a fixed viscosity shall be prescribed.
831 */
832 Scalar effectiveViscosity(const Element& element,
833 const FVElementGeometry& fvGeometry,
834 const SubControlVolumeFace& scvf) const
835 {
836 if constexpr (std::is_empty_v<CouplingManager>)
837
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 6334366 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 6334366 times.
12668800 return asImp_().effectiveViscosityAtPos(scvf.ipGlobal());
838 else
839 3100560 return couplingManager_->effectiveViscosity(element, fvGeometry, scvf);
840 }
841
842 /*!
843 * \brief Returns the effective dynamic viscosity at a given sub control volume.
844 * \note Overload this if a fixed viscosity shall be prescribed.
845 */
846 Scalar effectiveViscosity(const Element& element,
847 const FVElementGeometry& fvGeometry,
848 const SubControlVolume& scv,
849 const bool isPreviousTimeStep = false) const
850 {
851 if constexpr (std::is_empty_v<CouplingManager>)
852 7644000 return asImp_().effectiveViscosityAtPos(scv.dofPosition());
853 else
854 489000 return couplingManager_->effectiveViscosity(element, fvGeometry, scv, isPreviousTimeStep);
855 }
856
857 /*!
858 * \brief Returns the effective dynamic viscosity at a given position.
859 */
860 Scalar effectiveViscosityAtPos(const GlobalPosition&) const
861 {
862 DUNE_THROW(Dune::NotImplemented, "effectiveViscosityAtPos not implemented");
863 }
864
865 /*!
866 * \brief Applies the initial solution for all degrees of freedom of the grid.
867 * \param sol the initial solution vector
868 */
869 template<class SolutionVector>
870 void applyInitialSolution(SolutionVector& sol) const
871 {
872 static_assert(GridGeometry::discMethod == DiscretizationMethods::CVFE<DM>{});
873 sol.resize(this->gridGeometry().numDofs());
874 std::vector<bool> dofHandled(this->gridGeometry().numDofs(), false);
875 auto fvGeometry = localView(this->gridGeometry());
876 for (const auto& element : elements(this->gridGeometry().gridView()))
877 {
878 fvGeometry.bindElement(element);
879 for (const auto& scv : scvs(fvGeometry))
880 {
881 const auto dofIdx = scv.dofIndex();
882 if (!dofHandled[dofIdx])
883 {
884 dofHandled[dofIdx] = true;
885 sol[dofIdx] = asImp_().initial(scv);
886 }
887 }
888 }
889 }
890
891 /*!
892 * \brief Evaluate the initial value at an sub control volume
893 */
894 InitialValues initial(const SubControlVolume& scv) const
895 {
896 static_assert(GridGeometry::discMethod == DiscretizationMethods::CVFE<DM>{});
897 return asImp_().initialAtPos(scv.dofPosition());
898 }
899
900 private:
901 //! Returns the implementation of the problem (i.e. static polymorphism)
902 Implementation &asImp_()
903 { return *static_cast<Implementation *>(this); }
904
905 //! \copydoc asImp_()
906 const Implementation &asImp_() const
907 { return *static_cast<const Implementation *>(this); }
908
909 GravityVector gravity_;
910 bool enableInertiaTerms_;
911 std::shared_ptr<CouplingManager> couplingManager_ = {};
912 };
913
914 /*!
915 * \ingroup NavierStokesModel
916 * \brief Navier-Stokes momentum problem class
917 *
918 * Inherit from this problem to implement Navier-Stokes momentum problems
919 */
920 template<class TypeTag>
921 using NavierStokesMomentumProblem = NavierStokesMomentumProblemImpl<
922 TypeTag, typename GetPropType<TypeTag, Properties::GridGeometry>::DiscretizationMethod
923 >;
924
925 } // end namespace Dumux
926
927 #endif
928