GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/multidomain/newtonsolver.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 47 47 100.0%
Functions: 601 619 97.1%
Branches: 18 26 69.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-FileCopyrightText: 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 Newton
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 Newton
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 194 MultiDomainNewtonSolver(std::shared_ptr<Assembler> assembler,
62 std::shared_ptr<LinearSolver> linearSolver,
63 std::shared_ptr<CouplingManager> couplingManager,
64 172 const Comm& comm = Dune::MPIHelper::getCommunication(),
65 const std::string& paramGroup = "")
66 : ParentType(assembler, linearSolver, comm, paramGroup)
67
3/8
✓ Branch 3 taken 172 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 172 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 172 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
776 , couplingManager_(couplingManager)
68 {
69 using namespace Dune::Hybrid;
70
1/2
✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
1642 forEach(std::make_index_sequence<Assembler::Traits::numSubDomains>{}, [&](auto&& id)
71 {
72 384 const int priVarSwitchVerbosity = getParamFromGroup<int>(paramGroup, "PrimaryVariableSwitch.Verbosity", 1);
73 using PVSwitch = PrimaryVariableSwitch<std::decay_t<decltype(id)>::value>;
74
7/8
✗ Branch 0 not taken.
✓ Branch 1 taken 159 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 159 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 49 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 11 times.
384 elementAt(priVarSwitches_, id) = std::make_unique<PVSwitch>(priVarSwitchVerbosity);
75 });
76
77 194 priVarsSwitchedInLastIteration_.fill(false);
78 194 }
79
80 /*!
81 * \brief Indicates the beginning of a Newton iteration.
82 */
83 3832 void newtonBeginStep(const Variables& varsCurrentIter) override
84 {
85
2/2
✓ Branch 0 taken 1369 times.
✓ Branch 1 taken 2409 times.
3832 ParentType::newtonBeginStep(varsCurrentIter);
86 3832 couplingManager_->updateSolution(Backend::dofs(varsCurrentIter));
87 3832 }
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 1390 void newtonBegin(Variables& vars) override
97 {
98 1390 ParentType::newtonBegin(vars);
99
100 using namespace Dune::Hybrid;
101 1390 forEach(std::make_index_sequence<Assembler::Traits::numSubDomains>{}, [&](auto&& id)
102 {
103 1390 this->initPriVarSwitch_(vars, id, HasPriVarsSwitch<std::decay_t<decltype(id)>::value>{});
104 });
105 1390 }
106
107 /*!
108 * \brief Returns true if the error of the solution is below the
109 * tolerance.
110 */
111 5214 bool newtonConverged() const override
112 {
113
2/2
✓ Branch 0 taken 5127 times.
✓ Branch 1 taken 12 times.
10428 if (Dune::any_true(priVarsSwitchedInLastIteration_))
114 return false;
115
116 5202 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 3828 void newtonEndStep(Variables& varsCurrentIter, const SolutionVector& uLastIter) override
127 {
128 using namespace Dune::Hybrid;
129 3828 forEach(std::make_index_sequence<Assembler::Traits::numSubDomains>{}, [&](auto&& id)
130 {
131 3828 auto& uCurrentIter = Backend::dofs(varsCurrentIter)[id];
132 if constexpr (!assemblerExportsVariables)
133 3828 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 3828 ParentType::newtonEndStep(varsCurrentIter, uLastIter);
140 3828 couplingManager_->updateSolution(Backend::dofs(varsCurrentIter));
141 3828 }
142
143 protected:
144 /*!
145 * \brief Update solution-depended quantities like grid variables after the solution has changed.
146 */
147 3920 void solutionChanged_(Variables& vars, const SolutionVector& uCurrentIter) override
148 {
149 3920 couplingManager_->updateSolution(uCurrentIter);
150 3920 ParentType::solutionChanged_(vars, uCurrentIter);
151 3920 }
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 79 void initPriVarSwitch_(Variables& vars, Dune::index_constant<i> id, std::true_type)
166 {
167 using namespace Dune::Hybrid;
168 79 auto& priVarSwitch = *elementAt(priVarSwitches_, id);
169 79 auto& sol = Backend::dofs(vars)[id];
170
171 79 priVarSwitch.reset(sol.size());
172 79 priVarsSwitchedInLastIteration_[i] = false;
173
174 79 const auto& problem = this->assembler().problem(id);
175 79 const auto& gridGeometry = this->assembler().gridGeometry(id);
176 if constexpr (!assemblerExportsVariables)
177 79 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 305 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 305 const auto& gridGeometry = this->assembler().gridGeometry(id);
197 305 const auto& problem = this->assembler().problem(id);
198
199 using namespace Dune::Hybrid;
200 305 auto& priVarSwitch = *elementAt(priVarSwitches_, id);
201
202 // invoke the primary variable switch
203 305 priVarsSwitchedInLastIteration_[i] = priVarSwitch.update(uCurrentIter, subVars, problem, gridGeometry);
204
205
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 293 times.
305 if (priVarsSwitchedInLastIteration_[i])
206 {
207
1/2
✓ Branch 1 taken 780 times.
✗ Branch 2 not taken.
1560 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 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 priVarSwitch.updateSwitchedFluxVarsCache(problem, element, gridGeometry, subVars, uCurrentIter);
214 }
215 }
216 305 }
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