GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/test/freeflow/shallowwater/bowl/problem.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 59 63 93.7%
Functions: 4 6 66.7%
Branches: 38 82 46.3%

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 ShallowWaterTests
10 * \brief A test for the Shallow water model (bowl).
11 */
12 #ifndef DUMUX_BOWL_TEST_PROBLEM_HH
13 #define DUMUX_BOWL_TEST_PROBLEM_HH
14
15 #include <dumux/common/boundarytypes.hh>
16 #include <dumux/common/properties.hh>
17 #include <dumux/common/parameters.hh>
18 #include <dumux/common/numeqvector.hh>
19
20 #include <dumux/freeflow/shallowwater/problem.hh>
21 #include <dumux/freeflow/shallowwater/boundaryfluxes.hh>
22
23 namespace Dumux {
24
25 /*!
26 * \ingroup ShallowWaterTests
27 * \brief A wetting and drying test with sloshing water in a bowl.
28 *
29 * There is no flow over the boundaries and no friction is considered.
30 *
31 * This example is demanding for the implicit model if a high mesh resolution is applied
32 * (e.g. 150x150 cells) in combination with a large time step size. Using the new limiting
33 * (UpwindFluxLimiting = true) will help to improve the convergence for such cases.
34 *
35 * This test uses a low mesh resolution and only ensures that UpwindFluxLimiting for the mobility
36 * works. For low mesh resolution the solution is very diffusive so that the oscillation is dampened.
37 * This gets better with grid refinement (not tested here).
38 *
39 * The results are checked against a analytical solution which is based on the "Thacker-Solution"
40 * (William Thacker, "Some exact solutions to the nonlinear shallow-water wave equations", Journal
41 * of Fluid Mechanics, 107:499–508, 1981, doi: https://doi.org/10.1017/S0022112081001882).
42 * This implements the oscillating solution in a circular bowl (Section 4 in the paper).
43 * Further examples and details on the solution are given
44 * in SWASHES (Shallow Water Analytic Solutions for Hydraulic and Environmental Studies,
45 * https://www.idpoisson.fr/swashes/).
46 *
47 * This problem uses the \ref ShallowWaterModel.
48 */
49 template <class TypeTag>
50 class BowlProblem : public ShallowWaterProblem<TypeTag>
51 {
52 using ParentType = ShallowWaterProblem<TypeTag>;
53
54 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
55 using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
56 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
57 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
58 using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
59 using Element = typename GridView::template Codim<0>::Entity;
60 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
61
62 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
63 using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
64 using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
65
66 using NeumannFluxes = NumEqVector;
67 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
68 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
69 using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
70
71
72 public:
73 3 BowlProblem(std::shared_ptr<const GridGeometry> gridGeometry)
74
7/20
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✓ Branch 15 taken 3 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
9 : ParentType(gridGeometry)
75 {
76
77
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 name_ = getParam<std::string>("Problem.Name");
78
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 bowlDepthAtCenter_ = getParam<Scalar>("Problem.BowlDepthAtCenter");
79
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 bowlParaboloidRadius_ = getParam<Scalar>("Problem.BowlParaboloidRadius");
80
81 // Thacker (1981) Eq. (43)
82 using std::sqrt;
83
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 bowlAnalyticParameterOmega_ = sqrt(8.0 * getParam<Scalar>("Problem.Gravity") * bowlDepthAtCenter_) / bowlParaboloidRadius_;
84 3 std::cout << "One full oscillation period of the water table is: "
85
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 << oscillationPeriodInSeconds() << " seconds." << std::endl;
86
87 // Thacker (1981) Eq. (50)
88
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 const auto D0PlusEta = bowlDepthAtCenter_ + getParam<Scalar>("Problem.BowlInitialWaterElevationAtCenter");
89 3 const auto D0PlusEtaSquared = D0PlusEta*D0PlusEta;
90 3 const auto D0Squared = bowlDepthAtCenter_*bowlDepthAtCenter_;
91 3 bowlAnalyticParameterA_ = (D0PlusEtaSquared - D0Squared)/(D0PlusEtaSquared + D0Squared);
92
93 // check constraint Thacker (1981) text after Eq. (49)
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (bowlAnalyticParameterA_ >= 1.0)
95 DUNE_THROW(Dune::InvalidStateException, "Parameter A has to be smaller than unity!");
96 3 }
97
98 //! One oscillation period of the water table (analytically this goes on forever)
99 Scalar oscillationPeriodInSeconds() const
100
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 { return 2*M_PI/bowlAnalyticParameterOmega_; }
101
102 //! Get the analytical water depth at time t and position pos
103 439520 PrimaryVariables analyticalSolution(const Scalar t, const GlobalPosition& pos) const
104 {
105 using std::sqrt;
106 using std::cos;
107 using std::sin;
108
109 // see Thacker (1981) Eq. (51) for formula
110
8/8
✓ Branch 0 taken 213440 times.
✓ Branch 1 taken 226080 times.
✓ Branch 2 taken 213440 times.
✓ Branch 3 taken 226080 times.
✓ Branch 4 taken 213440 times.
✓ Branch 5 taken 226080 times.
✓ Branch 6 taken 213440 times.
✓ Branch 7 taken 226080 times.
1758080 const auto radiusSquared = pos[0]*pos[0] + pos[1]*pos[1];
111 439520 const auto LSquared = bowlParaboloidRadius_*bowlParaboloidRadius_;
112 439520 const auto A = bowlAnalyticParameterA_;
113 439520 const auto omega = bowlAnalyticParameterOmega_;
114 439520 const auto D0 = bowlDepthAtCenter_;
115
116 439520 const auto oneMinusASq = 1.0 - A*A;
117 439520 const auto oneMinusACosOmegaT = 1.0 - A*cos(omega*t);
118 439520 const auto ratioSq = oneMinusASq / (oneMinusACosOmegaT*oneMinusACosOmegaT);
119 439520 const auto localRadiusSq = radiusSquared / LSquared;
120 // bowl depth function (cf. D in Thacker (1981))
121 439520 const auto D = D0*(1.0 - localRadiusSq);
122 // height above equilibrium water level (cf. h in Thacker (1981))
123 439520 const auto h = D0*(sqrt(ratioSq) - 1.0 - localRadiusSq*(ratioSq - 1.0));
124 // see remark about total water depth in Thacker (1981) beginning section 2
125 439520 const auto analyticalWaterDepth = h + D;
126
127 439520 const auto halfOmegaASinOmegaT = 0.5*omega*A*sin(omega*t);
128
2/2
✓ Branch 0 taken 213440 times.
✓ Branch 1 taken 226080 times.
439520 const auto analyticalVelocityX = pos[0]*halfOmegaASinOmegaT/oneMinusACosOmegaT;
129
2/2
✓ Branch 0 taken 213440 times.
✓ Branch 1 taken 226080 times.
439520 const auto analyticalVelocityY = pos[1]*halfOmegaASinOmegaT/oneMinusACosOmegaT;
130
131 // The radius of the shoreline (where h + D = 0), Eq. (48)
132 439520 const auto h0 = D0*(sqrt(ratioSq) - 1.0); // h in the middle of the bowl (r=0)
133 439520 const auto shoreLineRadiusSquared = LSquared*(D0/(D0 + h0));
134
135 // outside shoreline the water height and velocity is zero
136
2/2
✓ Branch 0 taken 213440 times.
✓ Branch 1 taken 226080 times.
439520 if (radiusSquared > shoreLineRadiusSquared)
137 213440 return { 0.0, 0.0, 0.0 };
138 else
139 226080 return { analyticalWaterDepth, analyticalVelocityX, analyticalVelocityY };
140 }
141
142 /*!
143 * \name Problem parameters
144 */
145 // \{
146
147 /*!
148 * \brief The problem name
149 * This is used as a prefix for files generated by the simulation.
150 */
151 const std::string& name() const
152
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 { return name_; }
153
154 // \}
155
156 /*!
157 * \name Boundary conditions
158 */
159 // \{
160
161 /*!
162 * \brief Specifies which kind of boundary condition should be
163 * used for which equation on a given boundary segment.
164 */
165 BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
166 {
167 868320 BoundaryTypes bcTypes;
168
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 173664 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 694656 times.
868320 bcTypes.setAllNeumann();
169 return bcTypes;
170 }
171
172 /*!
173 * \brief Specifies the neumann boundary
174 *
175 * We need the Riemann invariants to compute the values depending of the boundary type.
176 * Since we use a weak imposition we do not have a dirichlet value. We impose fluxes
177 * based on q, h, etc. computed with the Riemann invariants
178 */
179 template<class ElementFluxVariablesCache>
180 694656 NeumannFluxes neumann(const Element& element,
181 const FVElementGeometry& fvGeometry,
182 const ElementVolumeVariables& elemVolVars,
183 const ElementFluxVariablesCache& elemFluxVarsCache,
184 const SubControlVolumeFace& scvf) const
185 {
186 694656 NeumannFluxes values(0.0);
187
188 1389312 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
189 694656 const auto& insideVolVars = elemVolVars[insideScv];
190 694656 const auto& nxy = scvf.unitOuterNormal();
191 1389312 const auto gravity = this->spatialParams().gravity(scvf.center());
192 std::array<Scalar, 3> boundaryStateVariables;
193
194 //no flow with zero normal velocity and tangential velocity
195 2778624 const auto vNormalGhost = -(nxy[0] * insideVolVars.velocity(0) + nxy[1] * insideVolVars.velocity(1));
196 2778624 const auto vTangentialGhost = -nxy[1] * insideVolVars.velocity(0) + nxy[0] * insideVolVars.velocity(1);
197
198 1389312 boundaryStateVariables[0] = insideVolVars.waterDepth();
199 2083968 boundaryStateVariables[1] = nxy[0] * vNormalGhost - nxy[1] * vTangentialGhost;
200 2083968 boundaryStateVariables[2] = nxy[1] * vNormalGhost + nxy[0] * vTangentialGhost;
201
202 const auto riemannFlux =
203 2083968 ShallowWater::riemannProblem(insideVolVars.waterDepth(), boundaryStateVariables[0],
204 1389312 insideVolVars.velocity(0), boundaryStateVariables[1],
205 1389312 insideVolVars.velocity(1), boundaryStateVariables[2],
206 insideVolVars.bedSurface(), insideVolVars.bedSurface(),
207 gravity, nxy);
208
209 2083968 values[Indices::massBalanceIdx] = riemannFlux[0];
210 2083968 values[Indices::velocityXIdx] = riemannFlux[1];
211 2083968 values[Indices::velocityYIdx] = riemannFlux[2];
212
213 694656 return values;
214 }
215
216 // \}
217
218 /*!
219 * \name Volume terms
220 */
221 // \{
222
223 /*!
224 * \brief Evaluate the initial values at position globalPos
225 */
226 3280 PrimaryVariables initialAtPos(const GlobalPosition& globalPos) const
227 {
228 using std::max; // regularize so that we are virtually dry but not completely dry
229
4/4
✓ Branch 1 taken 1844 times.
✓ Branch 2 taken 1436 times.
✓ Branch 3 taken 1844 times.
✓ Branch 4 taken 1436 times.
5124 return { max(analyticalSolution(0, globalPos)[0], 1e-5), 0.0, 0.0 };
230 };
231
232 // \}
233
234 private:
235 Scalar bowlDepthAtCenter_;
236 Scalar bowlParaboloidRadius_;
237 Scalar bowlAnalyticParameterOmega_;
238 Scalar bowlAnalyticParameterA_;
239 static constexpr Scalar eps_ = 1.0e-6;
240 std::string name_;
241 };
242
243 } //end namespace Dumux
244
245 #endif
246