GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/examples/diffusion/main.cc
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 66 72 91.7%
Functions: 3 7 42.9%
Branches: 117 260 45.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-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7
8 // In the file `main.cc`, we use the previously defined model to
9 // setup the simulation. The setup consists of four steps:
10 // 1. Define the problem setting boundary conditions and the diffusion coefficient
11 // 2. Configure the property system reusing the model defined in Part 1
12 // 3. Define a function for setting the random initial condition
13 // 4. The main program defining all steps of the program
14 //
15 // __Table of contents__
16 //
17 // [TOC]
18 //
19 // We start in `main.cc` with the necessary header includes:
20 // [[details]] includes
21 #include <config.h>
22
23 // Include the header containing std::true_type and std::false_type
24 #include <type_traits>
25
26 // Include the headers useful for the random initial solution
27 #include <random>
28 #include <dumux/common/random.hh>
29
30 // As Dune grid interface implementation we will use
31 // the structured parallel grid manager YaspGrid
32 #include <dune/grid/yaspgrid.hh>
33
34 // Common includes for problem and main
35 // [[codeblock]]
36 #include <dumux/common/initialize.hh>
37 #include <dumux/common/properties.hh>
38 #include <dumux/common/parameters.hh>
39 #include <dumux/common/numeqvector.hh>
40 #include <dumux/common/boundarytypes.hh>
41 #include <dumux/common/fvproblem.hh>
42
43 // VTK output functionality
44 #include <dumux/io/vtkoutputmodule.hh>
45 #include <dumux/io/grid/gridmanager_yasp.hh>
46
47 // the discretization method
48 #include <dumux/discretization/box.hh>
49
50 // assembly and solver
51 #include <dumux/linear/linearsolvertraits.hh>
52 #include <dumux/linear/linearalgebratraits.hh>
53 #include <dumux/linear/istlsolvers.hh>
54 #include <dumux/linear/pdesolver.hh>
55 #include <dumux/assembly/fvassembler.hh>
56 // [[/codeblock]]
57 //
58 // Finally, we include the model defined in Part 1.
59 #include "model.hh"
60 // [[/details]]
61
62 //
63 // ## 1. The problem class
64 //
65 // The problem class implements the boundary conditions. It also provides
66 // an interface that is used by the local residual (see Part 1) to obtain the diffusion
67 // coefficient. The value is read from the parameter configuration tree.
68 // [[content]]
69 namespace Dumux {
70 template<class TypeTag>
71 3 class DiffusionTestProblem : public FVProblem<TypeTag>
72 {
73 // [[details]] boilerplate code
74 using ParentType = FVProblem<TypeTag>;
75 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
76 using GlobalPosition = typename GridGeometry::LocalView::Element::Geometry::GlobalCoordinate;
77 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
78 using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
79 using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
80 using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
81 // [[/details]]
82 // In the constructor, we read the diffusion coefficient constant from the
83 // parameter tree (which is initialized with the content of `params.input`).
84 public:
85 3 DiffusionTestProblem(std::shared_ptr<const GridGeometry> gridGeometry)
86
6/16
✓ 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 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
9 : ParentType(gridGeometry)
87 {
88
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 diffusionCoefficient_ = getParam<Scalar>("Problem.DiffusionCoefficient");
89 3 }
90
91 // As boundary conditions, we specify Neumann everywhere. This means, we
92 // have to prescribe a flux at each boundary sub control volume face
93 BoundaryTypes boundaryTypesAtPos(const GlobalPosition& globalPos) const
94 {
95
1/2
✓ Branch 0 taken 4488 times.
✗ Branch 1 not taken.
4488 BoundaryTypes values;
96
1/2
✓ Branch 0 taken 4488 times.
✗ Branch 1 not taken.
4488 values.setAllNeumann();
97 return values;
98 }
99
100 // We prescribe zero flux over all of the boundary
101 NumEqVector neumannAtPos(const GlobalPosition& globalPos) const
102 5280 { return NumEqVector(0.0); }
103
104 // The diffusion coefficient interface is used in the local residual (see Part 1).
105 // We can name this interface however we want as long as we adapt the calling site
106 // in the `LocalResidual` class in `model.hh`.
107 Scalar diffusionCoefficient() const
108 { return diffusionCoefficient_; }
109
110 private:
111 Scalar diffusionCoefficient_;
112 };
113 } // end namespace Dumux
114 // [[/content]]
115
116 //
117 // ## 2. Property tag and specializations
118 //
119 // We create a new tag `DiffusionTest` that inherits all properties
120 // specialized for the tag `DiffusionModel` (we created this in Part 1)
121 // and the tag `BoxModel` which provides types relevant for the spatial
122 // discretization scheme (see [dumux/discretization/box.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/discretization/box.hh)).
123 //
124 // Here we choose a short form of specializing properties. The property
125 // system also recognizes an alias (`using`) with the property name being
126 // a member of the specified type tag. Note that we could also use the same mechanism
127 // as in (Part 1), for example:
128 // ```code
129 // template<class TypeTag>
130 // struct Scalar<TypeTag, TTag::DiffusionTest>
131 // { using type = double; };
132 //```
133 // which has the same effect as having an alias `Scalar = double;`
134 // as member of the type tag `DiffusionTest`.
135 // This mechanism allows for a terser code expression.
136 // In case both definitions are present for the same type tag, the explicit
137 // specialization (long form) takes precedence.
138 //
139 // [[content]]
140 namespace Dumux::Properties::TTag {
141
142 struct DiffusionTest
143 {
144 using InheritsFrom = std::tuple<DiffusionModel, BoxModel>;
145
146 using Scalar = double;
147 using Grid = Dune::YaspGrid<2>;
148
149 template<class TypeTag>
150 using Problem = DiffusionTestProblem<TypeTag>;
151
152 using EnableGridVolumeVariablesCache = std::true_type;
153 using EnableGridFluxVariablesCache = std::true_type;
154 using EnableGridGeometryCache = std::true_type;
155 };
156
157 } // end namespace Dumux::Properties::TTag
158 // [[/content]]
159
160 //
161 // ## 3. Creating the initial solution
162 //
163 // We want to initialize the entries of the solution vector $c_{h,B}$
164 // with a random field such that $c_{h,B} \sim U(0,1)$. When running
165 // with MPI in parallel this requires communication. With just one
166 // processor (`gg.gridView().comm().size() == 1`), we can just iterate
167 // over all entries of the solution vector and assign a uniformly
168 // distributed random number. However, with multiple processes, the
169 // solution vector only contains a subset of the degrees of freedom
170 // living on the processor. Moreover, some degrees of freedom exist
171 // on multiple processes. Each processor generates their own random
172 // number which means we might generate different numbers for the
173 // same degree of freedom. Therefore, we communicate the number.
174 // The idea is that each process adds its rank number (processes are
175 // numbered starting from 0) to its value. Then we take the minimum
176 // over all processes which will take return the value of the processor
177 // with the lowest rank. Afterwards, we subtract the added rank offset.
178 //
179 // [[content]]
180 // [[codeblock]]
181 template<class SolutionVector, class GridGeometry>
182 3 SolutionVector createInitialSolution(const GridGeometry& gg)
183 {
184 6 SolutionVector sol(gg.numDofs());
185
186 // Generate random number and add processor offset
187 // For sequential run, `rank` always returns `0`.
188 3 std::mt19937 gen(0); // seed is 0 for deterministic results
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 Dumux::SimpleUniformDistribution<> dis(0.0, 1.0);
190
191
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
6 const auto rank = gg.gridView().comm().rank();
192
2/2
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 3 times.
108 for (int n = 0; n < sol.size(); ++n)
193 105 sol[n] = dis(gen) + rank;
194
195 // We take the value of the processor with the minimum rank
196 // and subtract the rank offset
197
6/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
6 if (gg.gridView().comm().size() > 1)
198 {
199 Dumux::VectorCommDataHandleMin<
200 typename GridGeometry::VertexMapper,
201 SolutionVector,
202 GridGeometry::GridView::dimension
203
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 > minHandle(gg.vertexMapper(), sol);
204
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 gg.gridView().communicate(minHandle, Dune::All_All_Interface, Dune::ForwardCommunication);
205
206 // remove processor offset
207
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 2 times.
58 for (int n = 0; n < sol.size(); ++n)
208 112 sol[n][0] -= std::floor(sol[n][0]);
209 }
210
211 3 return sol;
212 }
213 // [[/codeblock]]
214 // [[/content]]
215 //
216 // ## 4. The main program
217 //
218 // [[content]]
219 3 int main(int argc, char** argv)
220 {
221 3 using namespace Dumux;
222
223 // First, we initialize MPI and the multithreading backend.
224 // This convenience function takes care that everything is setup in the right order and
225 // has to be called for every Dumux simulation. `Dumux::initialize` also respects
226 // the environment variable `DUMUX_NUM_THREADS` to restrict to amount of available cores
227 // for multi-threaded code parts (for example the assembly).
228 3 Dumux::initialize(argc, argv);
229
230 // We initialize parameter tree including command line arguments.
231 // This will, per default, read all parameters from the configuration file `params.input`
232 // if such as file exists. Then it will look for command line arguments. For example
233 // `./example_diffusion -TimeLoop.TEnd 10` will set the end time to $10$ seconds.
234 // Command line arguments overwrite settings in the parameter file.
235
9/24
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
12 Parameters::init(argc, argv);
236
237 // We specify an alias for the model type tag.
238 // We will configure the assembler with this type tag that
239 // we specialized all these properties for above and in the model definition (Part 1).
240 // We can extract type information through properties specialized for the type tag
241 // using `GetPropType`.
242 3 using TypeTag = Properties::TTag::DiffusionTest;
243
244 3 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
245 3 using Grid = GetPropType<TypeTag, Properties::Grid>;
246 3 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
247 3 using Problem = GetPropType<TypeTag, Properties::Problem>;
248 3 using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
249 3 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
250
251 // First, we initialize the grid. Grid parameters are taken from the input file
252 // from the group `[Grid]` if it exists. You can also pass any other parameter
253 // group (e.g. `"MyGroup"`) to `init` and then it will look in `[MyGroup.Grid]`.
254 6 GridManager<Grid> gridManager;
255
5/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
6 gridManager.init();
256
257 // We, create the finite volume grid geometry from the (leaf) grid view,
258 // the problem for the boundary conditions, a solution vector and a grid variables instance.
259
3/8
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
6 auto gridGeometry = std::make_shared<GridGeometry>(gridManager.grid().leafGridView());
260
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6 auto problem = std::make_shared<Problem>(gridGeometry);
261
3/8
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
9 auto sol = createInitialSolution<SolutionVector>(*gridGeometry);
262
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6 auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
263
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 gridVariables->init(sol);
264
265 // We initialize the VTK output module and write out the initial concentration field
266
8/16
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
12 VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name());
267
7/18
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 17 taken 3 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
9 vtkWriter.addVolumeVariable([](const auto& vv){ return vv.priVar(0); }, "c");
268
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 vtkWriter.write(0.0);
269
270 // We instantiate time loop using start and end time as well as
271 // the time step size from the parameter tree (`params.input`)
272 3 auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>(
273 getParam<Scalar>("TimeLoop.TStart", 0.0),
274
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 getParam<Scalar>("TimeLoop.Dt"),
275
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 getParam<Scalar>("TimeLoop.TEnd")
276
1/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6 );
277
278 // Next, we choose the type of assembler, linear solver and PDE solver
279 // and construct instances of these classes.
280 3 using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
281 3 using LinearSolver = SSORCGIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>;
282 3 using Solver = Dumux::LinearPDESolver<Assembler, LinearSolver>;
283
284
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6 auto oldSol = sol; // copy the vector to store state of previous time step
285
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6 auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, oldSol);
286
6/14
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
18 auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper());
287
8/20
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 3 times.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
15 Solver solver(assembler, linearSolver);
288
289 // We tell the assembler to create the system matrix and vector objects. Then we
290 // assemble the system matrix once and then tell the solver to reuse in every time step.
291 // Since we have a linear problem, the matrix is not going to change.
292
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 assembler->setLinearSystem();
293
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 assembler->assembleJacobian(sol);
294
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 solver.reuseMatrix();
295
296 // The time loop is where most of the actual computations happen.
297 // We assemble and solve the linear system of equations, update the solution,
298 // write the solution to a VTK file and continue until the we reach the
299 // final simulation time.
300 //
301 // [[codeblock]]
302
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 timeLoop->start(); do
303 {
304 // assemble & solve
305
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 solver.solve(sol);
306
307 // make the new solution the old solution
308
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 oldSol = sol;
309
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
300 gridVariables->advanceTimeStep();
310
311 // advance to the time loop to the next step
312
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
300 timeLoop->advanceTimeStep();
313
314 // write VTK output (writes out the concentration field)
315
3/6
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
450 vtkWriter.write(timeLoop->time());
316
317 // report statistics of this time step
318
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
300 timeLoop->reportTimeStep();
319
320
4/6
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 147 times.
✓ Branch 7 taken 3 times.
300 } while (!timeLoop->finished());
321
322
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
12 timeLoop->finalize(gridGeometry->gridView().comm());
323
324 3 return 0;
325 }
326 // [[/codeblock]]
327 // [[/content]]
328