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 | // # Cahn-Hilliard equation main program | ||
9 | // | ||
10 | // The file [`main.cc`](main.cc) contains the problem class `CahnHilliardTestProblem`, | ||
11 | // properties and traits specific to the test case as well as the `main` function. | ||
12 | // The setup consists of four steps: | ||
13 | // 1. Define the problem setting boundary conditions and the diffusion coefficient | ||
14 | // 2. Configure the property system reusing the model defined in Part 1 | ||
15 | // 3. Define a function for setting the random initial condition | ||
16 | // 4. The main program defining all steps of the program | ||
17 | // | ||
18 | // __Table of contents__ | ||
19 | // | ||
20 | // [TOC] | ||
21 | // | ||
22 | // We start in `main.cc` with the necessary header includes: | ||
23 | // [[details]] includes | ||
24 | #include <config.h> | ||
25 | #include <type_traits> | ||
26 | #include <random> | ||
27 | |||
28 | #include <dumux/common/initialize.hh> | ||
29 | #include <dumux/common/properties.hh> | ||
30 | #include <dumux/common/parameters.hh> | ||
31 | #include <dumux/common/numeqvector.hh> | ||
32 | #include <dumux/common/boundarytypes.hh> | ||
33 | #include <dumux/common/fvproblem.hh> | ||
34 | |||
35 | #include <dumux/discretization/box.hh> | ||
36 | #include <dumux/linear/linearsolvertraits.hh> | ||
37 | #include <dumux/linear/linearalgebratraits.hh> | ||
38 | #include <dumux/linear/istlsolvers.hh> | ||
39 | #include <dumux/nonlinear/newtonsolver.hh> | ||
40 | #include <dumux/assembly/fvassembler.hh> | ||
41 | |||
42 | #include <dune/grid/yaspgrid.hh> | ||
43 | #include <dumux/io/chrono.hh> | ||
44 | #include <dumux/io/vtkoutputmodule.hh> | ||
45 | #include <dumux/io/grid/gridmanager_yasp.hh> | ||
46 | |||
47 | #include "model.hh" | ||
48 | // [[/details]] | ||
49 | |||
50 | // | ||
51 | // ## 1. The problem class | ||
52 | // | ||
53 | // The problem class implements boundary conditions and the source term. | ||
54 | // It also provides an interface that is used by the local residual (see Part 1) to obtain | ||
55 | // the mobility and surface tension. The values are read from the parameter configuration tree. | ||
56 | // [[content]] | ||
57 | namespace Dumux { | ||
58 | template<class TypeTag> | ||
59 | 3 | class CahnHilliardTestProblem : public FVProblem<TypeTag> | |
60 | { | ||
61 | // [[details]] boilerplate code | ||
62 | using ParentType = FVProblem<TypeTag>; | ||
63 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
64 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
65 | using SubControlVolume = typename GridGeometry::SubControlVolume; | ||
66 | using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView; | ||
67 | using Element = typename GridView::template Codim<0>::Entity; | ||
68 | using GlobalPosition = typename Element::Geometry::GlobalCoordinate; | ||
69 | |||
70 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
71 | using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>; | ||
72 | using NumEqVector = Dumux::NumEqVector<PrimaryVariables>; | ||
73 | using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>; | ||
74 | using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices; | ||
75 | // [[/details]] | ||
76 | // In the constructor, we read the parameter constants from the | ||
77 | // parameter tree (which is initialized with the content of `params.input`). | ||
78 | public: | ||
79 | 3 | CahnHilliardTestProblem(std::shared_ptr<const GridGeometry> gridGeometry) | |
80 |
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) |
81 | { | ||
82 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | mobility_ = getParam<Scalar>("Problem.Mobility"); |
83 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | surfaceTension_ = getParam<Scalar>("Problem.SurfaceTension"); |
84 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | energyScale_ = getParam<Scalar>("Problem.EnergyScale"); |
85 | 3 | } | |
86 | |||
87 | // In the `source` function, we implement the derivative of the free energy. | ||
88 | // This demonstrates how parts of the local residual can be split into model specific | ||
89 | // parts (see `CahnHilliardModelLocalResidual`) and parts that might change from scenario to scenario. | ||
90 | template<class ElementVolumeVariables> | ||
91 | 3672800 | NumEqVector source(const Element &element, | |
92 | const FVElementGeometry& fvGeometry, | ||
93 | const ElementVolumeVariables& elemVolVars, | ||
94 | const SubControlVolume &scv) const | ||
95 | { | ||
96 | 3672800 | NumEqVector values(0.0); | |
97 | 11018400 | const auto& c = elemVolVars[scv].concentration(); | |
98 | 7345600 | values[Indices::chemicalPotentialEqIdx] = -energyScale_*2.0*c*(2.0*c*c - 3*c + 1); | |
99 | 3672800 | return values; | |
100 | } | ||
101 | |||
102 | // We choose boundary flux (or Neumann) conditions for all equations on the entire boundary, | ||
103 | // while specifying zero flux for both equations. | ||
104 | // [[codeblock]] | ||
105 | ✗ | BoundaryTypes boundaryTypesAtPos(const GlobalPosition& globalPos) const | |
106 | { | ||
107 | 72560 | BoundaryTypes values; | |
108 |
1/2✓ Branch 0 taken 72560 times.
✗ Branch 1 not taken.
|
72560 | values.setAllNeumann(); |
109 | ✗ | return values; | |
110 | } | ||
111 | |||
112 | ✗ | NumEqVector neumannAtPos(const GlobalPosition& globalPos) const | |
113 | 1335104 | { return { 0.0, 0.0 }; } | |
114 | // [[/codeblock]] | ||
115 | |||
116 | // The parameters interfaces are used in the local residual (see Part 1). | ||
117 | // We can name this interface however we want as long as we adapt the calling site | ||
118 | // in the `CahnHilliardModelLocalResidual` class in `model.hh`. | ||
119 | // [[codeblock]] | ||
120 | ✗ | Scalar mobility() const | |
121 | ✗ | { return mobility_; } | |
122 | |||
123 | ✗ | Scalar surfaceTension() const | |
124 | ✗ | { return surfaceTension_; } | |
125 | |||
126 | private: | ||
127 | Scalar mobility_; | ||
128 | Scalar surfaceTension_; | ||
129 | Scalar energyScale_; | ||
130 | }; | ||
131 | } // end namespace Dumux | ||
132 | // [[/codeblock]] | ||
133 | // [[/content]] | ||
134 | |||
135 | // | ||
136 | // ## 2. Property tag and specializations | ||
137 | // | ||
138 | // We create a new tag `DiffusionTest` that inherits all properties | ||
139 | // specialized for the tag `DiffusionModel` (we created this in Part 1) | ||
140 | // and the tag `BoxModel` which provides types relevant for the spatial | ||
141 | // discretization scheme (see [dumux/discretization/box.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/discretization/box.hh)). | ||
142 | // | ||
143 | // [[content]] | ||
144 | namespace Dumux::Properties::TTag { | ||
145 | struct CahnHilliardTest | ||
146 | { | ||
147 | using InheritsFrom = std::tuple<CahnHilliardModel, BoxModel>; | ||
148 | |||
149 | using Grid = Dune::YaspGrid<2>; | ||
150 | |||
151 | template<class TypeTag> | ||
152 | using Problem = CahnHilliardTestProblem<TypeTag>; | ||
153 | |||
154 | using EnableGridGeometryCache = std::true_type; | ||
155 | using EnableGridVolumeVariablesCache = std::true_type; | ||
156 | using EnableGridFluxVariablesCache = std::true_type; | ||
157 | }; | ||
158 | } // end namespace Dumux::Properties | ||
159 | // [[/content]] | ||
160 | // | ||
161 | // ## 3. Creating the initial solution | ||
162 | // | ||
163 | // To initialize with a random field in parallel, where each processor | ||
164 | // creates its own random number sequence, we need to communicate the | ||
165 | // resulting values on the processor border and overlap. | ||
166 | // See [Diffusion equation example](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/docs/main.md). | ||
167 | // for details. Here in addition, we need to provide a custom scatter operation | ||
168 | // that handles vector types. We only need to communicate the first entry (concentration). | ||
169 | // | ||
170 | // [[content]] | ||
171 | // [[codeblock]] | ||
172 | // functor for data communication with MPI | ||
173 | struct MinScatter | ||
174 | { | ||
175 | template<class A, class B> | ||
176 | static void apply(A& a, const B& b) | ||
177 | ✗ | { a[0] = std::min(a[0], b[0]); } | |
178 | }; | ||
179 | |||
180 | // create the random initial solution | ||
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 runs `rank` always returns `0`. | ||
188 | 3 | std::mt19937 gen(0); // seed is 0 for deterministic results | |
189 | 3 | std::uniform_real_distribution<> dis(0.0, 1.0); | |
190 |
2/2✓ Branch 0 taken 297 times.
✓ Branch 1 taken 3 times.
|
300 | for (int n = 0; n < sol.size(); ++n) |
191 | { | ||
192 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 297 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 297 times.
|
297 | sol[n][0] = 0.42 + 0.02*(0.5-dis(gen)) + gg.gridView().comm().rank(); |
193 | 594 | sol[n][1] = 0.0; | |
194 | } | ||
195 | |||
196 | // We take the value of the processor with the minimum rank | ||
197 | // and subtract the rank offset | ||
198 |
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) |
199 | { | ||
200 | Dumux::VectorCommDataHandle< | ||
201 | typename GridGeometry::VertexMapper, | ||
202 | SolutionVector, | ||
203 | GridGeometry::GridView::dimension, | ||
204 | MinScatter | ||
205 |
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); |
206 |
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); |
207 | |||
208 | // Remove processor offset | ||
209 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 2 times.
|
178 | for (int n = 0; n < sol.size(); ++n) |
210 | 704 | sol[n][0] -= std::floor(sol[n][0]); | |
211 | } | ||
212 | 3 | return sol; | |
213 | } | ||
214 | // [[/codeblock]] | ||
215 | // [[/content]] | ||
216 | // | ||
217 | // ## 4. The main program | ||
218 | // | ||
219 | // The `main` function sets up the simulation framework, initializes runtime parameters, | ||
220 | // creates the grid and storage vectors | ||
221 | // for the variables, primary and secondary. It specifies and constructs and assembler, which | ||
222 | // assembles the discretized residual and system matrix (Jacobian of the model residual), as well as | ||
223 | // a linear solver. A Newton method is used to solve the nonlinear equations where in each Newton iteration | ||
224 | // the Jacobian and the residual needs to be reassembled and the resulting linear system is solved. | ||
225 | // The time loop controls the time stepping. Here, we let the Newton solver suggest an adaption of | ||
226 | // the time step size based on the convergence history of the nonlinear solver. | ||
227 | // | ||
228 | // [[content]] | ||
229 | 3 | int main(int argc, char** argv) | |
230 | { | ||
231 | 3 | using namespace Dumux; | |
232 | |||
233 | // We initialize MPI and/or multithreading backend. When not running | ||
234 | // in parallel the MPI setup is skipped. | ||
235 | 3 | Dumux::initialize(argc, argv); | |
236 | |||
237 | // Then we initialize parameter tree. | ||
238 |
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); |
239 | |||
240 | // We create an alias for the type tag for this problem | ||
241 | // and extract type information through properties. | ||
242 | 3 | using TypeTag = Properties::TTag::CahnHilliardTest; | |
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 | // We initialize the grid, grid geometry, problem, solution vector, and grid variables. | ||
252 | 6 | GridManager<Grid> gridManager; | |
253 |
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(); |
254 | |||
255 |
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()); |
256 |
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); |
257 |
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); |
258 |
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); |
259 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
6 | gridVariables->init(sol); |
260 | |||
261 | // We initialize the VTK output module and write out the initial concentration and chemical potential | ||
262 |
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()); |
263 |
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.concentration(); }, "c"); |
264 |
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.chemicalPotential(); }, "mu"); |
265 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | vtkWriter.write(0.0); |
266 | |||
267 | // We instantiate time loop using start and end time as well as | ||
268 | // the time step size from the parameter tree (`params.input`) | ||
269 | 3 | auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>( | |
270 |
1/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
3 | Chrono::toSeconds(getParam("TimeLoop.TStart", "0")), |
271 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
|
6 | Chrono::toSeconds(getParam("TimeLoop.InitialTimeStepSize")), |
272 |
4/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 9 not taken.
✓ Branch 10 taken 3 times.
|
6 | Chrono::toSeconds(getParam("TimeLoop.TEnd")) |
273 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
6 | ); |
274 | |||
275 | // We set the maximum time step size allowed in the adaptive time stepping scheme. | ||
276 |
5/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 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
6 | timeLoop->setMaxTimeStepSize(Chrono::toSeconds(getParam("TimeLoop.MaxTimeStepSize"))); |
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 = SSORBiCGSTABIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>; | |
282 | 3 | using Solver = Dumux::NewtonSolver<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; |
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 |
12/28✓ 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 18 taken 3 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 3 times.
✗ Branch 26 not taken.
✓ Branch 27 taken 3 times.
✓ Branch 28 taken 3 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 3 times.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
|
15 | Solver solver(assembler, linearSolver); |
288 | |||
289 | // The time loop is where most of the actual computations happen. | ||
290 | // We assemble and solve the linear system of equations, update the solution, | ||
291 | // write the solution to a VTK file and continue until the we reach the | ||
292 | // final simulation time. | ||
293 | // | ||
294 | // [[codeblock]] | ||
295 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | timeLoop->start(); do |
296 | { | ||
297 | // Assemble & solve | ||
298 | // Passing the time loop enables the solver to repeat the time step | ||
299 | // with a reduced time step size if the Newton solver does not converge. | ||
300 |
2/4✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 306 times.
✗ Branch 5 not taken.
|
612 | solver.solve(sol, *timeLoop); |
301 | |||
302 | // make the new solution the old solution | ||
303 |
1/2✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
|
306 | oldSol = sol; |
304 |
2/4✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 306 times.
✗ Branch 5 not taken.
|
612 | gridVariables->advanceTimeStep(); |
305 | |||
306 | // advance to the time loop to the next step | ||
307 |
2/4✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 306 times.
✗ Branch 5 not taken.
|
612 | timeLoop->advanceTimeStep(); |
308 | |||
309 | // write VTK output (concentration field and chemical potential) | ||
310 |
3/6✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 306 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 306 times.
✗ Branch 8 not taken.
|
918 | vtkWriter.write(timeLoop->time()); |
311 | |||
312 | // report statistics of this time step | ||
313 |
2/4✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 306 times.
✗ Branch 5 not taken.
|
612 | timeLoop->reportTimeStep(); |
314 | |||
315 | // set new dt as suggested by the Newton solver | ||
316 |
5/10✗ Branch 0 not taken.
✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 306 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 306 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 306 times.
✓ Branch 9 taken 306 times.
✗ Branch 10 not taken.
|
1530 | timeLoop->setTimeStepSize(solver.suggestTimeStepSize(timeLoop->timeStepSize())); |
317 | |||
318 |
4/6✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 306 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 303 times.
✓ Branch 7 taken 3 times.
|
612 | } while (!timeLoop->finished()); |
319 | |||
320 | // print the final report | ||
321 |
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()); |
322 | 3 | return 0; | |
323 | } | ||
324 | // [[/codeblock]] | ||
325 | // [[/content]] | ||
326 |