GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/multidomain/newtonsolver.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 44 52 84.6%
Functions: 548 1181 46.4%
Branches: 35 158 22.2%

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 Nonlinear
10 * \ingroup MultiDomain
11 * \copydoc Dumux::MultiDomainNewtonSolver
12 */
13 #ifndef DUMUX_MULTIDOMAIN_NEWTON_SOLVER_HH
14 #define DUMUX_MULTIDOMAIN_NEWTON_SOLVER_HH
15
16 #include <memory>
17 #include <dumux/nonlinear/newtonsolver.hh>
18
19 namespace Dumux {
20 namespace Detail {
21
22 template<class Assembler, class Index>
23 using DetectPVSwitchMultiDomain = typename Assembler::template GridVariables<Index::value>::VolumeVariables::PrimaryVariableSwitch;
24
25 } // end namespace Detail
26
27 /*!
28 * \ingroup Nonlinear
29 * \ingroup MultiDomain
30 * \brief Newton solver for coupled problems
31 */
32 template <class Assembler, class LinearSolver, class CouplingManager,
33 class Reassembler = DefaultPartialReassembler,
34 class Comm = Dune::Communication<Dune::MPIHelper::MPICommunicator> >
35 class MultiDomainNewtonSolver: public NewtonSolver<Assembler, LinearSolver, Reassembler, Comm>
36 {
37 using ParentType = NewtonSolver<Assembler, LinearSolver, Reassembler, Comm>;
38 using typename ParentType::Backend;
39 using typename ParentType::SolutionVector;
40
41 static constexpr bool assemblerExportsVariables = Detail::PDESolver::assemblerExportsVariables<Assembler>;
42
43 template<std::size_t i>
44 using PrimaryVariableSwitch =
45 Dune::Std::detected_or_t<int, Detail::DetectPVSwitchMultiDomain, Assembler, Dune::index_constant<i>>;
46
47 template<std::size_t i>
48 using HasPriVarsSwitch =
49 Dune::Std::is_detected<Detail::DetectPVSwitchMultiDomain, Assembler, Dune::index_constant<i>>; // std::true_type or std::false_type
50
51 template<std::size_t i>
52 using PrivarSwitchPtr = std::unique_ptr<PrimaryVariableSwitch<i>>;
53 using PriVarSwitchPtrTuple = typename Assembler::Traits::template Tuple<PrivarSwitchPtr>;
54
55 public:
56 using typename ParentType::Variables;
57
58 /*!
59 * \brief The constructor
60 */
61 169 MultiDomainNewtonSolver(std::shared_ptr<Assembler> assembler,
62 std::shared_ptr<LinearSolver> linearSolver,
63 std::shared_ptr<CouplingManager> couplingManager,
64
3/8
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
155 const Comm& comm = Dune::MPIHelper::getCommunication(),
65 const std::string& paramGroup = "")
66 : ParentType(assembler, linearSolver, comm, paramGroup)
67
7/22
✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 155 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 155 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 155 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 155 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 155 times.
✓ Branch 20 taken 155 times.
✗ Branch 21 not taken.
✗ 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 30 not taken.
✗ Branch 31 not taken.
676 , couplingManager_(couplingManager)
68 {
69 using namespace Dune::Hybrid;
70
1/2
✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
2817 forEach(std::make_index_sequence<Assembler::Traits::numSubDomains>{}, [&](auto&& id)
71 {
72
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
345 const int priVarSwitchVerbosity = getParamFromGroup<int>(paramGroup, "PrimaryVariableSwitch.Verbosity", 1);
73 using PVSwitch = PrimaryVariableSwitch<std::decay_t<decltype(id)>::value>;
74
13/24
✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 148 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 148 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 38 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 38 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 5 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 5 times.
✓ Branch 20 taken 2 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
345 elementAt(priVarSwitches_, id) = std::make_unique<PVSwitch>(priVarSwitchVerbosity);
75 });
76
77 169 priVarsSwitchedInLastIteration_.fill(false);
78 169 }
79
80 /*!
81 * \brief Indicates the beginning of a Newton iteration.
82 */
83 2921 void newtonBeginStep(const Variables& varsCurrentIter) override
84 {
85
2/2
✓ Branch 0 taken 1022 times.
✓ Branch 1 taken 1861 times.
2921 ParentType::newtonBeginStep(varsCurrentIter);
86 5842 couplingManager_->updateSolution(Backend::dofs(varsCurrentIter));
87 2921 }
88
89 /*!
90 *
91 * \brief Called before the Newton method is applied to an
92 * non-linear system of equations.
93 *
94 * \param vars The variables representing the initial solution
95 */
96 1035 void newtonBegin(Variables& vars) override
97 {
98 1035 ParentType::newtonBegin(vars);
99
100 using namespace Dune::Hybrid;
101 3105 forEach(std::make_index_sequence<Assembler::Traits::numSubDomains>{}, [&](auto&& id)
102 {
103
0/8
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2228 this->initPriVarSwitch_(vars, id, HasPriVarsSwitch<std::decay_t<decltype(id)>::value>{});
104 });
105 1035 }
106
107 /*!
108 * \brief Returns true if the error of the solution is below the
109 * tolerance.
110 */
111 3950 bool newtonConverged() const override
112 {
113
2/2
✓ Branch 0 taken 3885 times.
✓ Branch 1 taken 14 times.
7900 if (Dune::any_true(priVarsSwitchedInLastIteration_))
114 return false;
115
116 3936 return ParentType::newtonConverged();
117 }
118
119
120 /*!
121 * \brief Indicates that one Newton iteration was finished.
122 *
123 * \param varsCurrentIter The variables after the current Newton iteration
124 * \param uLastIter The solution at the beginning of the current Newton iteration
125 */
126 2918 void newtonEndStep(Variables& varsCurrentIter, const SolutionVector& uLastIter) override
127 {
128 using namespace Dune::Hybrid;
129 2918 forEach(std::make_index_sequence<Assembler::Traits::numSubDomains>{}, [&](auto&& id)
130 {
131
0/14
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
6557 auto& uCurrentIter = Backend::dofs(varsCurrentIter)[id];
132 if constexpr (!assemblerExportsVariables)
133
0/42
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
19671 this->invokePriVarSwitch_(this->assembler().gridVariables(id),
134 uCurrentIter, id, HasPriVarsSwitch<std::decay_t<decltype(id)>::value>{});
135 else
136 this->invokePriVarSwitch_(varsCurrentIter[id], uCurrentIter, id, HasPriVarsSwitch<std::decay_t<decltype(id)>::value>{});
137 });
138
139 2918 ParentType::newtonEndStep(varsCurrentIter, uLastIter);
140 5836 couplingManager_->updateSolution(Backend::dofs(varsCurrentIter));
141 2918 }
142
143 protected:
144 /*!
145 * \brief Update solution-depended quantities like grid variables after the solution has changed.
146 */
147 2962 void solutionChanged_(Variables& vars, const SolutionVector& uCurrentIter) override
148 {
149 5924 couplingManager_->updateSolution(uCurrentIter);
150 2962 ParentType::solutionChanged_(vars, uCurrentIter);
151 2962 }
152
153 private:
154
155 /*!
156 * \brief Reset the privar switch state, noop if there is no priVarSwitch
157 */
158 template<std::size_t i>
159 void initPriVarSwitch_(Variables&, Dune::index_constant<i> id, std::false_type) {}
160
161 /*!
162 * \brief Switch primary variables if necessary
163 */
164 template<std::size_t i>
165 void initPriVarSwitch_(Variables& vars, Dune::index_constant<i> id, std::true_type)
166 {
167 using namespace Dune::Hybrid;
168
0/12
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
158 auto& priVarSwitch = *elementAt(priVarSwitches_, id);
169
0/6
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
79 auto& sol = Backend::dofs(vars)[id];
170
171
0/6
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
79 priVarSwitch.reset(sol.size());
172 priVarsSwitchedInLastIteration_[i] = false;
173
174 const auto& problem = this->assembler().problem(id);
175 const auto& gridGeometry = this->assembler().gridGeometry(id);
176 if constexpr (!assemblerExportsVariables)
177 priVarSwitch.updateDirichletConstraints(problem, gridGeometry, this->assembler().gridVariables(id), sol);
178 else // This expects usage of MultiDomainGridVariables
179 priVarSwitch.updateDirichletConstraints(problem, gridGeometry, vars[id], sol[id]);
180 }
181
182 /*!
183 * \brief Switch primary variables if necessary, noop if there is no priVarSwitch
184 */
185 template<class SubVars, class SubSol, std::size_t i>
186 void invokePriVarSwitch_(SubVars&, SubSol&, Dune::index_constant<i> id, std::false_type) {}
187
188 /*!
189 * \brief Switch primary variables if necessary
190 */
191 template<class SubVars, class SubSol, std::size_t i>
192 304 void invokePriVarSwitch_(SubVars& subVars, SubSol& uCurrentIter, Dune::index_constant<i> id, std::true_type)
193 {
194 // update the variable switch (returns true if the pri vars at at least one dof were switched)
195 // for disabled grid variable caching
196 608 const auto& gridGeometry = this->assembler().gridGeometry(id);
197 608 const auto& problem = this->assembler().problem(id);
198
199 using namespace Dune::Hybrid;
200 608 auto& priVarSwitch = *elementAt(priVarSwitches_, id);
201
202 // invoke the primary variable switch
203
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 290 times.
304 priVarsSwitchedInLastIteration_[i] = priVarSwitch.update(uCurrentIter, subVars, problem, gridGeometry);
204
205
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 290 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 290 times.
608 if (priVarsSwitchedInLastIteration_[i])
206 {
207
1/2
✓ Branch 2 taken 910 times.
✗ Branch 3 not taken.
938 for (const auto& element : elements(gridGeometry.gridView()))
208 {
209 // if the volume variables are cached globally, we need to update those where the primary variables have been switched
210 896 priVarSwitch.updateSwitchedVolVars(problem, element, gridGeometry, subVars, uCurrentIter);
211
212 // if the flux variables are cached globally, we need to update those where the primary variables have been switched
213 896 priVarSwitch.updateSwitchedFluxVarsCache(problem, element, gridGeometry, subVars, uCurrentIter);
214 }
215 }
216 304 }
217
218 //! the coupling manager
219 std::shared_ptr<CouplingManager> couplingManager_;
220
221 //! the class handling the primary variable switch
222 PriVarSwitchPtrTuple priVarSwitches_;
223 //! if we switched primary variables in the last iteration
224 std::array<bool, Assembler::Traits::numSubDomains> priVarsSwitchedInLastIteration_;
225 };
226
227 } // end namespace Dumux
228
229 #endif
230