3.1-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
test/porousmediumflow/richards/implicit/analytical/problem.hh
Go to the documentation of this file.
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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
29#ifndef DUMUX_RICHARDS_ANALYTICALPROBLEM_HH
30#define DUMUX_RICHARDS_ANALYTICALPROBLEM_HH
31
32#include <cmath>
33#include <dune/geometry/quadraturerules.hh>
34#include <dune/grid/yaspgrid.hh>
35
39
43
44#include "spatialparams.hh"
45
46namespace Dumux {
47
56template <class TypeTag>
57class RichardsAnalyticalProblem;
58
60// Specify the properties for the analytical problem
62namespace Properties {
63// Create new type tags
64namespace TTag {
65struct RichardsAnalytical { using InheritsFrom = std::tuple<Richards>; };
66struct RichardsAnalyticalBox { using InheritsFrom = std::tuple<RichardsAnalytical, BoxModel>; };
67struct RichardsAnalyticalCC { using InheritsFrom = std::tuple<RichardsAnalytical, CCTpfaModel>; };
68} // end namespace TTag
69
70// Use 2d YaspGrid
71template<class TypeTag>
72struct Grid<TypeTag, TTag::RichardsAnalytical> { using type = Dune::YaspGrid<2>; };
73
74// Set the physical problem to be solved
75template<class TypeTag>
76struct Problem<TypeTag, TTag::RichardsAnalytical> { using type = RichardsAnalyticalProblem<TypeTag>; };
77
78// Set the spatial parameters
79template<class TypeTag>
80struct SpatialParams<TypeTag, TTag::RichardsAnalytical>
81{
85};
86} // end namespace Properties
87
103template <class TypeTag>
105{
115 enum {
116 // copy some indices for convenience
117 pwIdx = Indices::pressureIdx,
118 bothPhases = Indices::bothPhases,
119 };
120 // Grid and world dimension
121 static const int dimWorld = GridView::dimensionworld;
122 static const int dim = GridView::dimension;
123 using Element = typename GridView::template Codim<0>::Entity;
124 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
125 using Geometry = typename GridView::template Codim<0>::Entity::Geometry;
126
127public:
128 RichardsAnalyticalProblem(std::shared_ptr<const GridGeometry> gridGeometry)
130 {
131 pnRef_ = 1e5; // air pressure
132 name_ = getParam<std::string>("Problem.Name");
133 time_ = 0.0;
134 }
135
139 // \{
140
146 const std::string name() const
147 { return name_; }
148
149 void setTime(Scalar time)
150 { time_ = time; }
151
157 Scalar temperature() const
158 { return 273.15 + 10; } // -> 10°C
159
167 { return pnRef_; }
168
180 NumEqVector sourceAtPos(const GlobalPosition &globalPos) const
181 {
182 NumEqVector values(0.0);
183 const Scalar time = time_;
184 const Scalar pwTop = 98942.8;
185 const Scalar pwBottom = 95641.1;
186
187 // linear model with complex solution
188 // calculated with Matlab script "Richards.m"
189 using std::pow;
190 using std::tanh;
191
192 values = (pow(tanh(globalPos[1]*5.0+time*(1.0/1.0E1)-1.5E1),2.0)*(1.0/1.0E1)
193 -1.0/1.0E1)*(pwBottom*(1.0/2.0)-pwTop*(1.0/2.0))*4.0E-8-((pow(tanh(globalPos[1]
194 *5.0+time*(1.0/1.0E1)-1.5E1),2.0)*5.0-5.0)*(pwBottom*(1.0/2.0)-pwTop*(1.0/2.0))-1.0E3)
195 *(pow(tanh(globalPos[1]*5.0+time*(1.0/1.0E1)-1.5E1),2.0)*5.0-5.0)*(pwBottom
196 *(1.0/2.0)-pwTop*(1.0/2.0))*5.0E-16+tanh(globalPos[1]*5.0+time*(1.0/1.0E1)-1.5E1)
197 *(pow(tanh(globalPos[1]*5.0+time*(1.0/1.0E1)-1.5E1),2.0)*5.0-5.0)*(pwBottom
198 *(1.0/2.0)-pwTop*(1.0/2.0))*(pwBottom*5.0E-16-(tanh(globalPos[1]*5.0+time*(1.0/1.0E1)
199 -1.5E1)+1.0)*(pwBottom*(1.0/2.0)-pwTop*(1.0/2.0))*5.0E-16+4.99995E-6)*1.0E1;
200 return values;
201 }
202
203 // \}
204
208 // \{
209
216 BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
217 {
218 BoundaryTypes bcTypes;
219 if (onLowerBoundary_(globalPos) ||
220 onUpperBoundary_(globalPos))
221 {
222 bcTypes.setAllDirichlet();
223 }
224 else
225 bcTypes.setAllNeumann();
226 return bcTypes;
227 }
228
236 PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
237 {
238 PrimaryVariables values(0.0);
239 values.setState(bothPhases);
240 const Scalar time = time_;
241 const Scalar pwTop = 98942.8;
242 const Scalar pwBottom = 95641.1;
243 using std::tanh;
244 Scalar pw = pwBottom
245 + 0.5 * (tanh( (5.0 * globalPos[1]) - 15.0 + time/10.0) + 1.0) * (pwTop - pwBottom);
246
247 values[pwIdx] = pw;
248 return values;
249 }
250
259 NumEqVector neumannAtPos(const GlobalPosition &globalPos) const
260 {
261 NumEqVector values(0.0);
262 return values;
263 }
264
268 // \{
269
278 PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
279 {
280 PrimaryVariables values(0.0);
281 values.setState(bothPhases);
282 analyticalSolution(values, time_, globalPos);
283 return values;
284 }
285
286 // \}
287
297 void analyticalSolution(PrimaryVariables &values,
298 const Scalar time,
299 const GlobalPosition &globalPos) const
300 {
301
302 const Scalar pwTop = 98942.8;
303 const Scalar pwBottom = 95641.1;
304 using std::tanh;
305 Scalar pw = pwBottom
306 + 0.5 * (tanh( (5.0 * globalPos[1]) - 15.0 + time/10.0) + 1.0) * (pwTop - pwBottom);
307
308 values[pwIdx] = pw;
309 }
310
321 Scalar calculateL2Error(const SolutionVector& curSol)
322 {
323 const unsigned int qOrder = 4;
324 Scalar l2error = 0.0;
325 Scalar l2analytic = 0.0;
326 const Scalar time = time_;
327
328 for (const auto& element :elements(this->gridGeometry().gridView()))
329 {
330 int eIdx = this->gridGeometry().elementMapper().index(element);
331 // value from numerical approximation
332 Scalar numericalSolution = curSol[eIdx];
333
334 // integrate over element using a quadrature rule
335 Geometry geometry = element.geometry();
336 Dune::GeometryType gt = geometry.type();
337 Dune::QuadratureRule<Scalar, dim> rule =
338 Dune::QuadratureRules<Scalar, dim>::rule(gt, qOrder);
339
340 for (auto qIt = rule.begin(); qIt != rule.end(); ++qIt)
341 {
342 // evaluate analytical solution
343 Dune::FieldVector<Scalar, dim> globalPos = geometry.global(qIt->position());
344 PrimaryVariables values(0.0);
345 analyticalSolution(values, time, globalPos);
346 // add contributino of current quadrature point
347 l2error += (numericalSolution - values[0]) * (numericalSolution - values[0]) *
348 qIt->weight() * geometry.integrationElement(qIt->position());
349 l2analytic += values[0] * values[0] *
350 qIt->weight() * geometry.integrationElement(qIt->position());
351 }
352 }
353 using std::sqrt;
354 return sqrt(l2error/l2analytic);
355 }
356
361 void writeOutput(const SolutionVector& curSol)
362 {
363
364 Scalar l2error = calculateL2Error(curSol);
365
366 // compute L2 error if analytical solution is available
367 std::cout.precision(8);
368 std::cout << "L2 error for "
369 << std::setw(6) << this->gridGeometry().gridView().size(0)
370 << " elements: "
371 << std::scientific
372 << l2error
373 << std::endl;
374 }
375
376private:
377
378 // evaluates if global position is at lower boundary
379 bool onLowerBoundary_(const GlobalPosition &globalPos) const
380 {
381 return globalPos[1] < this->gridGeometry().bBoxMin()[1] + eps_;
382 }
383
384 // evaluates if global position is at upper boundary
385 bool onUpperBoundary_(const GlobalPosition &globalPos) const
386 {
387 return globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_;
388 }
389
390 static constexpr Scalar eps_ = 3e-6;
391 Scalar pnRef_;
392 std::string name_;
393 Scalar time_;
394};
395} // end namespace Dumux
396
397#endif
Defines a type tag and some properties for models using the box scheme.
Properties for all models using cell-centered finite volume scheme with TPFA.
A much simpler (and thus potentially less buggy) version of pure water.
A liquid phase consisting of a single component.
make the local view function available whenever we use the grid geometry
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:149
Base class for all finite-volume problems.
Definition: common/fvproblem.hh:50
const GridGeometry & gridGeometry() const
The finite volume grid geometry.
Definition: common/fvproblem.hh:588
The DUNE grid type.
Definition: common/properties.hh:57
Property to specify the type of a problem which has to be solved.
Definition: common/properties.hh:69
The type of the spatial parameters object.
Definition: common/properties.hh:221
Base class for all fully implicit porous media problems.
Definition: dumux/porousmediumflow/problem.hh:39
A one-dimensional infiltration problem with a smooth, given solution.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:105
Scalar calculateL2Error(const SolutionVector &curSol)
Calculate the L2 error between the solution given by dirichletAtPos and the numerical approximation.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:321
Scalar temperature() const
Returns the temperature [K] within a finite volume.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:157
void setTime(Scalar time)
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:149
PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
Evaluates the boundary conditions for a Dirichlet boundary segment.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:236
RichardsAnalyticalProblem(std::shared_ptr< const GridGeometry > gridGeometry)
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:128
NumEqVector neumannAtPos(const GlobalPosition &globalPos) const
Evaluates the boundary conditions for a Neumann boundary segment.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:259
PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
Evaluates the initial values for a control volume.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:278
void analyticalSolution(PrimaryVariables &values, const Scalar time, const GlobalPosition &globalPos) const
Evaluates the analytical solution.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:297
Scalar nonWettingReferencePressure() const
Returns the reference pressure [Pa] of the non-wetting fluid phase within a finite volume.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:166
NumEqVector sourceAtPos(const GlobalPosition &globalPos) const
Evaluates the source values for a control volume.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:180
void writeOutput(const SolutionVector &curSol)
Writes the relevant secondary variables of the current solution into an VTK output file.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:361
BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
Specifies which kind of boundary condition should be used for which equation on a given boundary segm...
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:216
const std::string name() const
The problem name.
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:146
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:65
std::tuple< Richards > InheritsFrom
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:65
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:66
std::tuple< RichardsAnalytical, BoxModel > InheritsFrom
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:66
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:67
std::tuple< RichardsAnalytical, CCTpfaModel > InheritsFrom
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:67
Dune::YaspGrid< 2 > type
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:72
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:83
GetPropType< TypeTag, Properties::GridGeometry > GridGeometry
Definition: test/porousmediumflow/richards/implicit/analytical/problem.hh:82
The spatial parameters for the RichardsAnalyticalProblem.
Definition: porousmediumflow/richards/implicit/analytical/spatialparams.hh:48
This model implements a variant of the Richards' equation for quasi-twophase flow.
Base class for all porous media problems.
Definition of the spatial parameters for the MaxwellStefan problem.