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 | #ifndef DUMUX_EXAMPLE_SHALLOWWATER_FRICTION_PROBLEM_HH | ||
9 | #define DUMUX_EXAMPLE_SHALLOWWATER_FRICTION_PROBLEM_HH | ||
10 | |||
11 | // ## The problem file (`problem.hh`) | ||
12 | // | ||
13 | // This file contains the __problem class__ which defines the initial and boundary | ||
14 | // conditions for the shallow water flow simulation with bottom friction. | ||
15 | // In addition, the analytical solution is defined here. | ||
16 | // | ||
17 | // [[content]] | ||
18 | // | ||
19 | // ### Include files | ||
20 | // [[details]] includes | ||
21 | // | ||
22 | // The first include we need here is the `ShallowWaterProblem` class, the base | ||
23 | // class from which we will derive. | ||
24 | #include <dumux/freeflow/shallowwater/problem.hh> | ||
25 | // In addition, we need the boundaryflux header, which handles the flux over | ||
26 | // the model boundaries. | ||
27 | #include <dumux/freeflow/shallowwater/boundaryfluxes.hh> | ||
28 | // Include the `BoundaryTypes` class which specifies the boundary types set in this problem. | ||
29 | #include <dumux/common/boundarytypes.hh> | ||
30 | // Include the `NumEqVector` class which specifies a field vector with size number of equations in this problem. | ||
31 | #include <dumux/common/numeqvector.hh> | ||
32 | // [[/details]] | ||
33 | |||
34 | // | ||
35 | // ### The problem class | ||
36 | // | ||
37 | // We enter the problem class where all necessary boundary conditions and initial conditions are set for our simulation. | ||
38 | // In addition the analytical solution of the problem is calculated. | ||
39 | // As this is a shallow water problem, we inherit from the basic ShallowWaterProblem. | ||
40 | // [[codeblock]] | ||
41 | namespace Dumux { | ||
42 | |||
43 | template <class TypeTag> | ||
44 | class RoughChannelProblem : public ShallowWaterProblem<TypeTag> | ||
45 | { | ||
46 | // [[/codeblock]] | ||
47 | // [[details]] convenience aliases | ||
48 | using ParentType = ShallowWaterProblem<TypeTag>; | ||
49 | using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>; | ||
50 | using BoundaryTypes = Dumux::BoundaryTypes<PrimaryVariables::size()>; | ||
51 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
52 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
53 | using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView; | ||
54 | using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; | ||
55 | using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView; | ||
56 | using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView; | ||
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 | using NumEqVector = Dumux::NumEqVector<PrimaryVariables>; | ||
62 | using NeumannFluxes = NumEqVector; | ||
63 | using SubControlVolume = typename FVElementGeometry::SubControlVolume; | ||
64 | using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices; | ||
65 | // [[/details]] | ||
66 | |||
67 | // In the constructor, we retrieve all required parameters from the input file | ||
68 | // [[codeblock]] | ||
69 | public: | ||
70 | 1 | RoughChannelProblem(std::shared_ptr<const GridGeometry> gridGeometry) | |
71 |
8/22✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
|
3 | : ParentType(gridGeometry) |
72 | { | ||
73 | // We read the parameters from the params.input file. | ||
74 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | constManningN_ = getParam<Scalar>("Problem.ManningN"); |
75 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | bedSlope_ = getParam<Scalar>("Problem.BedSlope"); |
76 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | discharge_ = getParam<Scalar>("Problem.Discharge"); |
77 | // We calculate the outflow boundary condition using the Gauckler-Manning-Strickler formula. | ||
78 | 1 | hBoundary_ = this->gaucklerManningStrickler(discharge_,constManningN_,bedSlope_); | |
79 | // We initialize the analytic solution to a vector of the appropriate size filled with zeros. | ||
80 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
2 | exactWaterDepth_.resize(gridGeometry->numDofs(), 0.0); |
81 |
3/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
2 | exactVelocityX_.resize(gridGeometry->numDofs(), 0.0); |
82 | 1 | } | |
83 | // [[/codeblock]] | ||
84 | |||
85 | // #### Analytical Solution | ||
86 | // | ||
87 | // The analytical solution is calculated using the equation of Gauckler, Manning and Strickler. | ||
88 | // [[codeblock]] | ||
89 | |||
90 | // Equation of Gauckler, Manning and Strickler | ||
91 | ✗ | Scalar gaucklerManningStrickler(Scalar discharge, Scalar manningN, Scalar bedSlope) | |
92 | { | ||
93 | using std::pow; | ||
94 | using std::abs; | ||
95 | using std::sqrt; | ||
96 | |||
97 | ✗ | return pow(abs(discharge)*manningN/sqrt(bedSlope), 0.6); | |
98 | } | ||
99 | |||
100 | // Calculate the analytical solution | ||
101 | 1 | void analyticalSolution() | |
102 | { | ||
103 | using std::abs; | ||
104 | |||
105 |
1/2✓ Branch 3 taken 2501 times.
✗ Branch 4 not taken.
|
5003 | for (const auto& element : elements(this->gridGeometry().gridView())) |
106 | { | ||
107 | 2500 | const Scalar h = this->gaucklerManningStrickler(discharge_,constManningN_,bedSlope_); | |
108 | 2500 | const Scalar u = abs(discharge_)/h; | |
109 | |||
110 | 7500 | const auto eIdx = this->gridGeometry().elementMapper().index(element); | |
111 | 5000 | exactWaterDepth_[eIdx] = h; | |
112 | 5000 | exactVelocityX_[eIdx] = u; | |
113 | } | ||
114 | 1 | } | |
115 | |||
116 | // [[exclude]] | ||
117 | // Getter function for the analytical solution of the water depth | ||
118 | const std::vector<Scalar>& getExactWaterDepth() | ||
119 | { | ||
120 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | return exactWaterDepth_; |
121 | } | ||
122 | |||
123 | // Getter function for the analytical solution of the velocity in x-direction | ||
124 | const std::vector<Scalar>& getExactVelocityX() | ||
125 | { | ||
126 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | return exactVelocityX_; |
127 | } | ||
128 | // [[/exclude]] | ||
129 | // [[/codeblock]] | ||
130 | |||
131 | // #### Bottom friction | ||
132 | // | ||
133 | // The bottom friction is a source term and therefore handled by the `source` function. | ||
134 | // [[codeblock]] | ||
135 | 863061 | NumEqVector source(const Element& element, | |
136 | const FVElementGeometry& fvGeometry, | ||
137 | const ElementVolumeVariables& elemVolVars, | ||
138 | const SubControlVolume &scv) const | ||
139 | { | ||
140 | |||
141 | 863061 | NumEqVector source (0.0); | |
142 | |||
143 | // Since the bed slope source term is handles within the flux computation, | ||
144 | // in this model the bottom friction is the only source term. | ||
145 | 863061 | source += bottomFrictionSource(element, fvGeometry, elemVolVars, scv); | |
146 | |||
147 | 863061 | return source; | |
148 | } | ||
149 | // [[/codeblock]] | ||
150 | |||
151 | // The calculation of the source term due to bottom friction needs the bottom shear stess. | ||
152 | // This is the force per area, which works between the flow and the channel bed | ||
153 | // (1D vector with two entries) and is calculated within the `FrictionLaw` class. | ||
154 | // The bottom friction causes a loss of momentum. Thus, the first entry of the `bottomFrictionSource`, | ||
155 | // which is related to the mass balance equation is zero. | ||
156 | // The second entry of the `bottomFricitonSource` corresponds to the momentum equation in x-direction | ||
157 | // and is therefore equal to the first, the x-component, of the `bottomShearStress`. | ||
158 | // Accordingly, the third entry of the `bottomFrictionSource` is equal to the second component of the `bottomShearStress`. | ||
159 | // [[codeblock]] | ||
160 | 863061 | NumEqVector bottomFrictionSource(const Element& element, | |
161 | const FVElementGeometry& fvGeometry, | ||
162 | const ElementVolumeVariables& elemVolVars, | ||
163 | const SubControlVolume &scv) const | ||
164 | { | ||
165 | 863061 | NumEqVector bottomFrictionSource(0.0); | |
166 | 863061 | const auto& volVars = elemVolVars[scv]; | |
167 | |||
168 | // bottom shear stress vector | ||
169 | 2589183 | Dune::FieldVector<Scalar, 2> bottomShearStress = this->spatialParams().frictionLaw(element, scv).bottomShearStress(volVars); | |
170 | |||
171 | // source term due to bottom friction | ||
172 | 1726122 | bottomFrictionSource[Indices::massBalanceIdx] = 0.0; | |
173 | 3452244 | bottomFrictionSource[Indices::momentumXBalanceIdx] = -bottomShearStress[0] / volVars.density(); | |
174 | 3452244 | bottomFrictionSource[Indices::momentumYBalanceIdx] = -bottomShearStress[1] / volVars.density(); | |
175 | |||
176 | 863061 | return bottomFrictionSource; | |
177 | } | ||
178 | // [[/codeblock]] | ||
179 | |||
180 | // #### Boundary conditions | ||
181 | // | ||
182 | // We use Neumann boundary conditions on the entire boundary. | ||
183 | // [[codeblock]] | ||
184 | ✗ | BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const | |
185 | { | ||
186 | 439683 | BoundaryTypes bcTypes; | |
187 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 90900 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 348783 times.
|
439683 | bcTypes.setAllNeumann(); |
188 | ✗ | return bcTypes; | |
189 | } | ||
190 | // [[/codeblock]] | ||
191 | |||
192 | // In the following function we implement the __Neumann boundary conditions__. | ||
193 | // Due to the weak imposition we calculate the flux at the boundary with a Riemann solver. | ||
194 | // This needs the state of a virtual cell outside of the boundary (`boundaryStateVariables`), | ||
195 | // which is calculated with the Riemann invariants | ||
196 | // (see: Yoon and Kang, "Finite Volume Model for Two-Dimensional Shallow Water Flows on Unstructured Grids"). | ||
197 | // [[codeblock]] | ||
198 | 348783 | NeumannFluxes neumann(const Element& element, | |
199 | const FVElementGeometry& fvGeometry, | ||
200 | const ElementVolumeVariables& elemVolVars, | ||
201 | const ElementFluxVariablesCache& elemFluxVarsCache, | ||
202 | const SubControlVolumeFace& scvf) const | ||
203 | { | ||
204 | 348783 | NeumannFluxes values(0.0); | |
205 | |||
206 | 697566 | const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx()); | |
207 | 348783 | const auto& insideVolVars = elemVolVars[insideScv]; | |
208 |
2/2✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 346983 times.
|
348783 | const auto& nxy = scvf.unitOuterNormal(); |
209 |
4/4✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 346983 times.
✓ Branch 2 taken 1800 times.
✓ Branch 3 taken 346983 times.
|
697566 | const auto gravity = this->spatialParams().gravity(scvf.center()); |
210 | std::array<Scalar, 3> boundaryStateVariables; | ||
211 | |||
212 | // Calculate the Riemann invariants for imposed discharge at the left side. | ||
213 |
12/12✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 346983 times.
✓ Branch 2 taken 1800 times.
✓ Branch 3 taken 346983 times.
✓ Branch 4 taken 1800 times.
✓ Branch 5 taken 346983 times.
✓ Branch 6 taken 1800 times.
✓ Branch 7 taken 346983 times.
✓ Branch 8 taken 1800 times.
✓ Branch 9 taken 346983 times.
✓ Branch 10 taken 1800 times.
✓ Branch 11 taken 346983 times.
|
2092698 | if (scvf.center()[0] < this->gridGeometry().bBoxMin()[0] + eps_) |
214 | { | ||
215 | 7200 | boundaryStateVariables = ShallowWater::fixedDischargeBoundary(discharge_, | |
216 | insideVolVars.waterDepth(), | ||
217 | insideVolVars.velocity(0), | ||
218 | insideVolVars.velocity(1), | ||
219 | gravity, | ||
220 | nxy); | ||
221 | } | ||
222 | // Calculate the Riemann invariants for imposed water depth at the right side. | ||
223 |
12/12✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 345183 times.
✓ Branch 2 taken 1800 times.
✓ Branch 3 taken 345183 times.
✓ Branch 4 taken 1800 times.
✓ Branch 5 taken 345183 times.
✓ Branch 6 taken 1800 times.
✓ Branch 7 taken 345183 times.
✓ Branch 8 taken 1800 times.
✓ Branch 9 taken 345183 times.
✓ Branch 10 taken 1800 times.
✓ Branch 11 taken 345183 times.
|
2081898 | else if (scvf.center()[0] > this->gridGeometry().bBoxMax()[0] - eps_) |
224 | { | ||
225 | 7200 | boundaryStateVariables = ShallowWater::fixedWaterDepthBoundary(hBoundary_, | |
226 | insideVolVars.waterDepth(), | ||
227 | insideVolVars.velocity(0), | ||
228 | insideVolVars.velocity(1), | ||
229 | gravity, | ||
230 | nxy); | ||
231 | } | ||
232 | // Calculate the Riemann invariants for the no-flow boundary. | ||
233 | else | ||
234 | { | ||
235 | 690366 | boundaryStateVariables[0] = insideVolVars.waterDepth(); | |
236 | 690366 | boundaryStateVariables[1] = -insideVolVars.velocity(0); | |
237 | 1035549 | boundaryStateVariables[2] = -insideVolVars.velocity(1); | |
238 | } | ||
239 | // Calculate the boundary fluxes based on a Riemann problem. | ||
240 | 348783 | auto riemannFlux = ShallowWater::riemannProblem(insideVolVars.waterDepth(), | |
241 | 697566 | boundaryStateVariables[0], | |
242 | insideVolVars.velocity(0), | ||
243 | 697566 | boundaryStateVariables[1], | |
244 | insideVolVars.velocity(1), | ||
245 | 697566 | boundaryStateVariables[2], | |
246 | insideVolVars.bedSurface(), | ||
247 | insideVolVars.bedSurface(), | ||
248 | gravity, | ||
249 | nxy); | ||
250 | |||
251 | 1046349 | values[Indices::massBalanceIdx] = riemannFlux[0]; | |
252 | 1046349 | values[Indices::velocityXIdx] = riemannFlux[1]; | |
253 | 1046349 | values[Indices::velocityYIdx] = riemannFlux[2]; | |
254 | |||
255 | 348783 | return values; | |
256 | } | ||
257 | // [[/codeblock]] | ||
258 | |||
259 | // #### Initial conditions | ||
260 | // | ||
261 | // We specify the initial conditions for the primary variables (water depth, velocity in y-direction | ||
262 | // and velocity in x-direction). In this example constant initial conditions are used. Therefore the | ||
263 | //argument `globalPos` is not needed. If you want to impose spatial variable initial conditions, | ||
264 | // you have to use the `globalPos` argument. | ||
265 | // [[codeblock]] | ||
266 | ✗ | PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const | |
267 | { | ||
268 | 2500 | PrimaryVariables initialValues(0.0); | |
269 | 2500 | initialValues[Indices::waterdepthIdx] = 1.0; | |
270 | 2500 | initialValues[Indices::velocityXIdx] = 0.0; | |
271 | 5000 | initialValues[Indices::velocityYIdx] = 0.0; | |
272 | ✗ | return initialValues; | |
273 | } | ||
274 | // [[/codeblock]] | ||
275 | |||
276 | // [[details]] private variables | ||
277 | // [[codeblock]] | ||
278 | private: | ||
279 | // variables for the analytic solution. | ||
280 | std::vector<Scalar> exactWaterDepth_; | ||
281 | std::vector<Scalar> exactVelocityX_; | ||
282 | // constant friction value (an analytic solution is only available for const friction). | ||
283 | Scalar constManningN_; | ||
284 | // The constant channel bed slope. | ||
285 | Scalar bedSlope_; | ||
286 | // The water depth at the outflow boundary. | ||
287 | Scalar hBoundary_; | ||
288 | // The discharge at the inflow boundary. | ||
289 | Scalar discharge_; | ||
290 | // We assign a private global variable for the epsilon: | ||
291 | static constexpr Scalar eps_ = 1.0e-6; | ||
292 | |||
293 | }; // end class definition RoughChannelProblem | ||
294 | } // end namespace Dumux | ||
295 | // [[/codeblock]] | ||
296 | // [[/details]] | ||
297 | // [[/content]] | ||
298 | #endif | ||
299 |