GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/assembly/cvfelocalassembler.hh
Date: 2025-05-03 19:19:02
Exec Total Coverage
Lines: 199 202 98.5%
Functions: 889 1300 68.4%
Branches: 182 408 44.6%

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 Assembly
10 * \ingroup CVFEDiscretization
11 * \brief An assembler for Jacobian and residual contribution per element (CVFE methods)
12 */
13 #ifndef DUMUX_CVFE_LOCAL_ASSEMBLER_HH
14 #define DUMUX_CVFE_LOCAL_ASSEMBLER_HH
15
16 #include <dune/common/exceptions.hh>
17 #include <dune/common/hybridutilities.hh>
18 #include <dune/common/reservedvector.hh>
19 #include <dune/grid/common/gridenums.hh>
20 #include <dune/istl/matrixindexset.hh>
21 #include <dune/istl/bvector.hh>
22
23 #include <dumux/common/properties.hh>
24 #include <dumux/common/parameters.hh>
25 #include <dumux/common/numericdifferentiation.hh>
26 #include <dumux/common/typetraits/localdofs_.hh>
27
28 #include <dumux/assembly/numericepsilon.hh>
29 #include <dumux/assembly/diffmethod.hh>
30 #include <dumux/assembly/fvlocalassemblerbase.hh>
31 #include <dumux/assembly/partialreassembler.hh>
32 #include <dumux/assembly/entitycolor.hh>
33
34 #include <dumux/discretization/cvfe/elementsolution.hh>
35 #include <dumux/discretization/cvfe/localdof.hh>
36
37 #include "volvardeflectionhelper_.hh"
38
39 namespace Dumux {
40
41 #ifndef DOXYGEN
42 namespace Detail::CVFE {
43
44 struct NoOperator
45 {
46 template<class... Args>
47 constexpr void operator()(Args&&...) const {}
48 };
49
50 template<class X, class Y>
51 using Impl = std::conditional_t<!std::is_same_v<X, void>, X, Y>;
52
53 template<typename ElemVars, typename FVG>
54 using DefinesDeflectionHelperType = typename ElemVars::template DeflectionHelper<FVG>;
55
56 template<typename ElemVars, typename FVG>
57 constexpr inline bool definesVolVarsDeflectionHelperType()
58 { return Dune::Std::is_detected<DefinesDeflectionHelperType, ElemVars, FVG>::value; }
59
60 template<class GridVarsCache, class ElemVars, class FVG>
61 11097974 auto VolVarsDeflectionHelper(GridVarsCache& gridVarsCache, ElemVars& elemVars, const FVG& fvg, bool deflectAllVolVars)
62 {
63 if constexpr (definesVolVarsDeflectionHelperType<ElemVars, FVG>())
64 {
65 using DeflectionHelper = typename ElemVars::template DeflectionHelper<FVG>;
66 return DeflectionHelper(gridVarsCache, elemVars, fvg, deflectAllVolVars);
67 }
68 else
69 {
70 using DeflectionHelper = Detail::VolVarsDeflectionHelper<GridVarsCache, FVG>;
71 11097974 return DeflectionHelper(gridVarsCache, elemVars, fvg, deflectAllVolVars);
72 }
73 };
74
75 } // end namespace Detail
76 #endif // DOXYGEN
77
78 /*!
79 * \ingroup Assembly
80 * \ingroup CVFEDiscretization
81 * \brief A base class for all local CVFE assemblers
82 * \tparam TypeTag The TypeTag
83 * \tparam Assembler The assembler type
84 * \tparam Implementation The actual implementation
85 * \tparam implicit Specifies whether the time discretization is implicit or not not (i.e. explicit)
86 */
87 template<class TypeTag, class Assembler, class Implementation, bool implicit>
88 20302091 class CVFELocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>
89 {
90 using ParentType = FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>;
91 using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
92 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
93 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
94 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
95 using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>;
96 using SolutionVector = typename Assembler::SolutionVector;
97
98 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
99 static constexpr int dim = GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimension;
100
101 public:
102
103 16763452 using ParentType::ParentType;
104
105 13671128 void bindLocalViews()
106 {
107 13671128 ParentType::bindLocalViews();
108 13671128 this->elemBcTypes().update(this->asImp_().problem(), this->element(), this->fvGeometry());
109 13671128 }
110
111
112 /*!
113 * \brief Computes the derivatives with respect to the given element and adds them
114 * to the global matrix. The element residual is written into the right hand side.
115 */
116 template <class ResidualVector, class PartialReassembler = DefaultPartialReassembler, class CouplingFunction = Detail::CVFE::NoOperator>
117 15511202 void assembleJacobianAndResidual(JacobianMatrix& jac, ResidualVector& res, GridVariables& gridVariables,
118 const PartialReassembler* partialReassembler = nullptr,
119 const CouplingFunction& maybeAssembleCouplingBlocks = {})
120 {
121 15511202 this->asImp_().bindLocalViews();
122 15511202 const auto eIdxGlobal = this->asImp_().problem().gridGeometry().elementMapper().index(this->element());
123 if (partialReassembler
124
4/4
✓ Branch 0 taken 452312 times.
✓ Branch 1 taken 9483839 times.
✓ Branch 2 taken 101622 times.
✓ Branch 3 taken 350690 times.
11028415 && partialReassembler->elementColor(eIdxGlobal) == EntityColor::green)
125 {
126 101622 const auto residual = this->asImp_().evalLocalResidual(); // forward to the internal implementation
127
128
2/2
✓ Branch 0 taken 406488 times.
✓ Branch 1 taken 101622 times.
508110 for (const auto& localDof : localDofs(this->fvGeometry()))
129 812976 res[localDof.dofIndex()] += residual[localDof.index()];
130
131 // assemble the coupling blocks for coupled models (does nothing if not coupled)
132 maybeAssembleCouplingBlocks(residual);
133 }
134
2/2
✓ Branch 0 taken 12369707 times.
✓ Branch 1 taken 69504 times.
15409580 else if (!this->elementIsGhost())
135 {
136 15340076 const auto residual = this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler); // forward to the internal implementation
137
138
2/2
✓ Branch 0 taken 41857456 times.
✓ Branch 1 taken 12369707 times.
65681704 for (const auto& localDof : localDofs(this->fvGeometry()))
139 84390288 res[localDof.dofIndex()] += residual[localDof.index()];
140
141 // assemble the coupling blocks for coupled models (does nothing if not coupled)
142 4327926 maybeAssembleCouplingBlocks(residual);
143 }
144 else
145 {
146 // Treatment of ghost elements
147 69504 assert(this->elementIsGhost());
148
149 // handle dofs per codimension
150 69504 const auto& gridGeometry = this->asImp_().problem().gridGeometry();
151 419904 Dune::Hybrid::forEach(std::make_integer_sequence<int, dim>{}, [&](auto d)
152 {
153 139008 constexpr int codim = dim - d;
154 139008 const auto& localCoeffs = gridGeometry.feCache().get(this->element().type()).localCoefficients();
155
6/14
✓ Branch 0 taken 272592 times.
✓ Branch 1 taken 72696 times.
✓ Branch 2 taken 273948 times.
✓ Branch 3 taken 68148 times.
✓ Branch 4 taken 4548 times.
✓ Branch 5 taken 1356 times.
✗ 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 6 not taken.
✗ Branch 9 not taken.
828060 for (int idx = 0; idx < localCoeffs.size(); ++idx)
156 {
157
4/14
✓ Branch 0 taken 272592 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4548 times.
✓ Branch 3 taken 272592 times.
✓ Branch 4 taken 4548 times.
✗ 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 6 not taken.
✗ Branch 9 not taken.
554280 const auto& localKey = localCoeffs.localKey(idx);
158
159 // skip if we are not handling this codim right now
160
4/12
✓ Branch 0 taken 272592 times.
✓ Branch 1 taken 4548 times.
✓ Branch 2 taken 4548 times.
✓ Branch 3 taken 272592 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
554280 if (localKey.codim() != codim)
161 414792 continue;
162
163 // do not change the non-ghost entities
164
4/18
✓ Branch 1 taken 1356 times.
✓ Branch 2 taken 3192 times.
✓ Branch 4 taken 133416 times.
✓ Branch 5 taken 133416 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 0 not taken.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
277140 auto entity = this->element().template subEntity<codim>(localKey.subEntity());
165
7/32
✓ Branch 0 taken 3192 times.
✓ Branch 1 taken 1356 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 133416 times.
✓ Branch 4 taken 133416 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5760 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2880 times.
✓ Branch 9 taken 2880 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ 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 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
282900 if (entity.partitionType() == Dune::InteriorEntity || entity.partitionType() == Dune::BorderEntity)
166 2880 continue;
167
168 // WARNING: this only works if the mapping from codim+subEntity to
169 // global dofIndex is unique (on dof per entity of this codim).
170 // For more general mappings, we should use a proper local-global mapping here.
171 // For example through dune-functions.
172
0/11
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 6 not taken.
✗ Branch 3 not taken.
✗ Branch 7 not taken.
139488 const auto dofIndex = gridGeometry.dofMapper().index(entity);
173
174 // this might be a vector-valued dof
175 using BlockType = typename JacobianMatrix::block_type;
176
2/11
✓ Branch 1 taken 3192 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 133416 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 6 not taken.
139488 BlockType &J = jac[dofIndex][dofIndex];
177
4/12
✓ Branch 0 taken 6384 times.
✓ Branch 1 taken 3192 times.
✓ Branch 2 taken 332712 times.
✓ Branch 3 taken 136296 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
478584 for (int j = 0; j < BlockType::rows; ++j)
178 339096 J[j][j] = 1.0;
179
180 // set residual for the ghost dof
181
0/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
271776 res[dofIndex] = 0;
182 }
183 });
184 }
185
186 18608676 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
187 const auto& dirichletValues,
188 const auto eqIdx,
189 const auto pvIdx)
190 {
191 1548737 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
192
193 1548737 auto& row = jac[scvOrLocalDofI.dofIndex()];
194
9/12
✗ Branch 0 not taken.
✓ Branch 1 taken 11588324 times.
✓ Branch 2 taken 10202857 times.
✓ Branch 3 taken 1385467 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1497657 times.
✓ Branch 6 taken 1335331 times.
✓ Branch 7 taken 162326 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5656 times.
✓ Branch 10 taken 4712 times.
✓ Branch 11 taken 944 times.
13091637 for (auto col = row.begin(); col != row.end(); ++col)
195 21678045 row[col.index()][eqIdx] = 0.0;
196
197 1548737 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
198
199 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
200 2400293 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
201 {
202 4 const auto periodicDof = this->asImp_().problem().gridGeometry().periodicallyMappedDof(scvOrLocalDofI.dofIndex());
203 4 res[periodicDof][eqIdx] = this->asImp_().curSol()[periodicDof][pvIdx] - dirichletValues[pvIdx];
204
205 4 auto& rowP = jac[periodicDof];
206
3/12
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
30 for (auto col = rowP.begin(); col != rowP.end(); ++col)
207 26 rowP[col.index()][eqIdx] = 0.0;
208
209 4 rowP[periodicDof][eqIdx][pvIdx] = 1.0;
210 }
211 };
212
213 31022404 this->asImp_().enforceDirichletConstraints(applyDirichlet);
214 15511202 }
215
216 /*!
217 * \brief Computes the derivatives with respect to the given element and adds them
218 * to the global matrix.
219 */
220 1136 void assembleJacobian(JacobianMatrix& jac, GridVariables& gridVariables)
221 {
222 1136 this->asImp_().bindLocalViews();
223 1136 this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables); // forward to the internal implementation
224
225 1816 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
226 const auto& dirichletValues,
227 const auto eqIdx,
228 const auto pvIdx)
229 {
230 336 auto& row = jac[scvOrLocalDofI.dofIndex()];
231
3/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2416 times.
✓ Branch 2 taken 2080 times.
✓ Branch 3 taken 336 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2416 for (auto col = row.begin(); col != row.end(); ++col)
232 2080 row[col.index()][eqIdx] = 0.0;
233
234 336 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
235 };
236
237 2272 this->asImp_().enforceDirichletConstraints(applyDirichlet);
238 1136 }
239
240 /*!
241 * \brief Assemble the residual only
242 */
243 template <class ResidualVector>
244 4044075 void assembleResidual(ResidualVector& res)
245 {
246 4044075 this->asImp_().bindLocalViews();
247 4044075 const auto residual = this->evalLocalResidual();
248
249
2/2
✓ Branch 0 taken 13117866 times.
✓ Branch 1 taken 3521963 times.
19164069 for (const auto& localDof : localDofs(this->fvGeometry()))
250 27159964 res[localDof.dofIndex()] += residual[localDof.index()];
251
252 4606799 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
253 const auto& dirichletValues,
254 const auto eqIdx,
255 const auto pvIdx)
256 {
257 562724 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
258 };
259
260 8088150 this->asImp_().enforceDirichletConstraints(applyDirichlet);
261 4044075 }
262
263 //! Enforce Dirichlet constraints
264 template<typename ApplyFunction>
265 16063932 void enforceDirichletConstraints(const ApplyFunction& applyDirichlet)
266 {
267 // enforce Dirichlet boundary conditions
268 16063932 this->asImp_().evalDirichletBoundaries(applyDirichlet);
269 // take care of internal Dirichlet constraints (if enabled)
270 16057532 this->asImp_().enforceInternalDirichletConstraints(applyDirichlet);
271 }
272
273 /*!
274 * \brief Evaluates Dirichlet boundaries
275 */
276 template< typename ApplyDirichletFunctionType >
277 32110380 void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
278 {
279 // enforce Dirichlet boundaries by overwriting partial derivatives with 1 or 0
280 // and set the residual to (privar - dirichletvalue)
281
2/2
✓ Branch 0 taken 611278 times.
✓ Branch 1 taken 15452654 times.
32110380 if (this->elemBcTypes().hasDirichlet())
282 {
283
2/2
✓ Branch 0 taken 2162689 times.
✓ Branch 1 taken 611278 times.
5534148 for (const auto& scvI : scvs(this->fvGeometry()))
284 {
285
2/2
✓ Branch 1 taken 1042487 times.
✓ Branch 2 taken 1120202 times.
4313318 const auto bcTypes = this->elemBcTypes().get(this->fvGeometry(), scvI);
286
2/2
✓ Branch 0 taken 1042487 times.
✓ Branch 1 taken 1120202 times.
4313318 if (bcTypes.hasDirichlet())
287 {
288
2/3
✓ Branch 0 taken 252474 times.
✓ Branch 1 taken 359483 times.
✗ Branch 2 not taken.
2079046 const auto dirichletValues = this->asImp_().problem().dirichlet(this->element(), scvI);
289
290 // set the Dirichlet conditions in residual and jacobian
291
3/3
✓ Branch 0 taken 2083967 times.
✓ Branch 1 taken 1077335 times.
✓ Branch 2 taken 17424 times.
6345596 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
292 {
293
3/4
✓ Branch 0 taken 24454 times.
✓ Branch 1 taken 2111785 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24454 times.
4266550 if (bcTypes.isDirichlet(eqIdx))
294 {
295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2111785 times.
4217642 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2111785 times.
4217642 assert(0 <= pvIdx && pvIdx < numEq);
297
1/2
✓ Branch 1 taken 311512 times.
✗ Branch 2 not taken.
4217642 applyDirichlet(scvI, dirichletValues, eqIdx, pvIdx);
298 }
299 }
300 }
301 }
302 }
303 32110380 }
304
305 /*!
306 * \brief Update the coupling context for coupled models.
307 * \note This does nothing per default (not a coupled model).
308 */
309 template<class... Args>
310 void maybeUpdateCouplingContext(Args&&...) {}
311
312 /*!
313 * \brief Update the additional domain derivatives for coupled models.
314 * \note This does nothing per default (not a coupled model).
315 */
316 template<class... Args>
317 void maybeEvalAdditionalDomainDerivatives(Args&&...) {}
318
319 };
320
321 /*!
322 * \ingroup Assembly
323 * \ingroup CVFEDiscretization
324 * \brief An assembler for Jacobian and residual contribution per element (CVFE methods)
325 * \tparam TypeTag The TypeTag
326 * \tparam diffMethod The differentiation method to residual compute derivatives
327 * \tparam implicit Specifies whether the time discretization is implicit or not not (i.e. explicit)
328 * \tparam Implementation via CRTP
329 */
330 template<class TypeTag, class Assembler, DiffMethod diffMethod = DiffMethod::numeric, bool implicit = true, class Implementation = void>
331 class CVFELocalAssembler;
332
333 /*!
334 * \ingroup Assembly
335 * \ingroup CVFEDiscretization
336 * \brief Control volume finite element local assembler using numeric differentiation and implicit time discretization
337 */
338 template<class TypeTag, class Assembler, class Implementation>
339
4/16
✓ Branch 0 taken 2202672 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 503303 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 261128 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 261056 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
17018494 class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true, Implementation>
340 : public CVFELocalAssemblerBase<TypeTag, Assembler,
341 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>,
342 true>
343 {
344 using ThisType = CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>;
345 using ParentType = CVFELocalAssemblerBase<TypeTag, Assembler, Detail::CVFE::Impl<Implementation, ThisType>, true>;
346 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
347 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
348 using GridVolumeVariables = GetPropType<TypeTag, Properties::GridVolumeVariables>;
349 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
350 using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>;
351 using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
352
353 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
354 static constexpr int dim = GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimension;
355
356 static constexpr bool enableGridFluxVarsCache
357 = GridVariables::GridFluxVariablesCache::cachingEnabled;
358 static constexpr bool solutionDependentFluxVarsCache
359 = GridVariables::GridFluxVariablesCache::FluxVariablesCache::isSolDependent;
360
361 public:
362
363 using LocalResidual = typename ParentType::LocalResidual;
364 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
365
6/12
✓ Branch 2 taken 8603753 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1789368 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 72 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 1 taken 931296 times.
✓ Branch 5 taken 268160 times.
✓ Branch 9 taken 7708 times.
✗ Branch 4 not taken.
13783476 using ParentType::ParentType;
366
367 /*!
368 * \brief Computes the derivatives with respect to the given element and adds them
369 * to the global matrix.
370 *
371 * \return The element residual at the current solution.
372 */
373 template <class PartialReassembler = DefaultPartialReassembler>
374 11106086 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
375 const PartialReassembler* partialReassembler = nullptr)
376 {
377 // get some aliases for convenience
378 11106086 const auto& element = this->element();
379 11106086 const auto& fvGeometry = this->fvGeometry();
380 11106086 const auto& curSol = this->asImp_().curSol();
381
382 11106086 auto&& curElemVolVars = this->curElemVolVars();
383 11106086 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
384
385 // get the vector of the actual element residuals
386 11106086 const auto origResiduals = this->evalLocalResidual();
387
388 //////////////////////////////////////////////////////////////////////////////////////////////////
389 // //
390 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
391 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
392 // actual element. In the actual element we evaluate the derivative of the entire residual. //
393 // //
394 //////////////////////////////////////////////////////////////////////////////////////////////////
395
396 // if all volvars in the stencil have to be updated or if it's enough to only update the
397 // volVars for the scv whose associated dof has been deflected
398
5/6
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 9149538 times.
✓ Branch 3 taken 163 times.
✓ Branch 4 taken 16 times.
✓ Branch 6 taken 163 times.
✗ Branch 7 not taken.
11106086 static const bool updateAllVolVars = getParamFromGroup<bool>(
399
1/2
✓ Branch 1 taken 163 times.
✗ Branch 2 not taken.
452 this->asImp_().problem().paramGroup(), "Assembly.BoxVolVarsDependOnAllElementDofs", false
400 );
401
402 // create the element solution
403 12820952 auto elemSol = elementSolution(element, curSol, fvGeometry.gridGeometry());
404
405 // create the vector storing the partial derivatives
406 11106086 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
407
408 11163446 auto deflectionHelper = Detail::CVFE::VolVarsDeflectionHelper(
409 11106086 gridVariables.curGridVolVars(),
410 curElemVolVars,
411 fvGeometry,
412 updateAllVolVars
413 );
414
415 87315754 auto assembleDerivative = [&, this](const auto& localDof)
416 {
417 // dof index and corresponding actual pri vars
418 38104834 const auto dofIdx = localDof.dofIndex();
419 38104834 const auto localIdx = localDof.index();
420 38104834 deflectionHelper.setCurrent(localDof);
421
422 // calculate derivatives w.r.t to the privars at the dof at hand
423
6/6
✓ Branch 0 taken 79863440 times.
✓ Branch 1 taken 35132626 times.
✓ Branch 2 taken 5153172 times.
✓ Branch 3 taken 2941376 times.
✓ Branch 4 taken 30832 times.
✓ Branch 5 taken 30832 times.
123152278 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
424 {
425 85047444 partialDerivs = 0.0;
426
427 171440808 auto evalResiduals = [&](Scalar priVar)
428 {
429 // update the volume variables and compute element residual
430 86393364 elemSol[localIdx][pvIdx] = priVar;
431 86393364 deflectionHelper.deflect(elemSol, localDof, this->asImp_().problem());
432 if constexpr (solutionDependentFluxVarsCache)
433 {
434 3127718 elemFluxVarsCache.update(element, fvGeometry, curElemVolVars);
435 if constexpr (enableGridFluxVarsCache)
436 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
437 }
438 86393364 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
439 86393364 return this->evalLocalResidual();
440 };
441
442 // derive the residuals numerically
443
13/18
✓ Branch 0 taken 231 times.
✓ Branch 1 taken 79863209 times.
✓ Branch 3 taken 192 times.
✓ Branch 4 taken 39 times.
✓ Branch 6 taken 192 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 31 times.
✓ Branch 11 taken 5153141 times.
✓ Branch 13 taken 31 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 31 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 30831 times.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
85047444 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
444
13/18
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 79863171 times.
✓ Branch 3 taken 192 times.
✓ Branch 4 taken 77 times.
✓ Branch 6 taken 192 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 31 times.
✓ Branch 11 taken 5153141 times.
✓ Branch 13 taken 31 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 31 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 30831 times.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
85047444 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
445
3/6
✓ Branch 1 taken 72923888 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5153172 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30832 times.
✗ Branch 8 not taken.
85047444 NumericDifferentiation::partialDerivative(evalResiduals, elemSol[localIdx][pvIdx], partialDerivs, origResiduals,
446 85047444 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
447
448 // update the global stiffness matrix with the current partial derivatives
449
6/6
✓ Branch 0 taken 295096406 times.
✓ Branch 1 taken 79863440 times.
✓ Branch 2 taken 20341772 times.
✓ Branch 3 taken 5153172 times.
✓ Branch 4 taken 123328 times.
✓ Branch 5 taken 30832 times.
400608950 for (const auto& localDofJ : localDofs(fvGeometry))
450 {
451 // don't add derivatives for green dofs
452 279984942 if (!partialReassembler
453
5/8
✓ Branch 0 taken 11222080 times.
✓ Branch 1 taken 263288142 times.
✓ Branch 2 taken 10849608 times.
✓ Branch 3 taken 372472 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1230720 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
275740942 || partialReassembler->dofColor(localDofJ.dofIndex()) != EntityColor::green)
454 {
455
6/6
✓ Branch 0 taken 779281770 times.
✓ Branch 1 taken 294723934 times.
✓ Branch 2 taken 41745292 times.
✓ Branch 3 taken 20341772 times.
✓ Branch 4 taken 123328 times.
✓ Branch 5 taken 123328 times.
1136339424 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
456 {
457 // A[i][col][eqIdx][pvIdx] is the rate of change of
458 // the residual of equation 'eqIdx' at dof 'i'
459 // depending on the primary variable 'pvIdx' at dof
460 // 'col'.
461
3/6
✓ Branch 1 taken 728327754 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 41745292 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 123328 times.
✗ Branch 8 not taken.
821150390 A[localDofJ.dofIndex()][dofIdx][eqIdx][pvIdx] += partialDerivs[localDofJ.index()][eqIdx];
462 }
463 }
464 }
465
466 // restore the original state of the scv's volume variables
467 85047444 deflectionHelper.restore(localDof);
468
469 // restore the original element solution
470
2/4
✓ Branch 1 taken 38494 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18528 times.
✗ Branch 5 not taken.
85047444 elemSol[localIdx][pvIdx] = curSol[localDof.dofIndex()][pvIdx];
471
2/4
✓ Branch 1 taken 38494 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18528 times.
✗ Branch 5 not taken.
85103684 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
472 }
473 };
474
475 // calculation of the derivatives
476
2/2
✓ Branch 0 taken 32636598 times.
✓ Branch 1 taken 9149717 times.
49234856 for (const auto& localDof : localDofs(fvGeometry))
477 38128770 assembleDerivative(localDof);
478
479 // restore original state of the flux vars cache in case of global caching.
480 // In the case of local caching this is obsolete because the elemFluxVarsCache used here goes out of scope after this.
481 if constexpr (enableGridFluxVarsCache)
482 3850564 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
483
484 // evaluate additional derivatives that might arise from the coupling (no-op if not coupled)
485 9737059 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
486
487 11106086 return origResiduals;
488 }
489
490 }; // implicit CVFEAssembler with numeric Jacobian
491
492 /*!
493 * \ingroup Assembly
494 * \ingroup CVFEDiscretization
495 * \brief Control volume finite element local assembler using numeric differentiation and explicit time discretization
496 */
497 template<class TypeTag, class Assembler, class Implementation>
498 1014000 class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false, Implementation>
499 : public CVFELocalAssemblerBase<TypeTag, Assembler,
500 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>>,
501 false>
502 {
503 using ThisType = CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>;
504 using ParentType = CVFELocalAssemblerBase<TypeTag, Assembler, Detail::CVFE::Impl<Implementation, ThisType>, false>;
505 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
506 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
507 using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>;
508 using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
509
510 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
511 static constexpr int dim = GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimension;
512
513 public:
514
515 using LocalResidual = typename ParentType::LocalResidual;
516 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
517
2/4
✓ Branch 1 taken 50000 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 964000 times.
✗ Branch 6 not taken.
1014000 using ParentType::ParentType;
518
519 /*!
520 * \brief Computes the derivatives with respect to the given element and adds them
521 * to the global matrix.
522 *
523 * \return The element residual at the current solution.
524 */
525 template <class PartialReassembler = DefaultPartialReassembler>
526 1014000 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
527 const PartialReassembler* partialReassembler = nullptr)
528 {
529 1014000 if (partialReassembler)
530 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
531
532 // get some aliases for convenience
533 1014000 const auto& element = this->element();
534 1014000 const auto& fvGeometry = this->fvGeometry();
535 1014000 const auto& curSol = this->asImp_().curSol();
536 1014000 auto&& curElemVolVars = this->curElemVolVars();
537
538 // get the vecor of the actual element residuals
539 1014000 const auto origResiduals = this->evalLocalResidual();
540 1014000 const auto origStorageResiduals = this->evalLocalStorageResidual();
541
542 //////////////////////////////////////////////////////////////////////////////////////////////////
543 // //
544 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
545 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
546 // actual element. In the actual element we evaluate the derivative of the entire residual. //
547 // //
548 //////////////////////////////////////////////////////////////////////////////////////////////////
549
550 // create the element solution
551 2028000 auto elemSol = elementSolution(element, curSol, fvGeometry.gridGeometry());
552
553 // create the vector storing the partial derivatives
554 2028000 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
555
556 // calculation of the derivatives
557 4006000 for (const auto& scv : scvs(fvGeometry))
558 {
559 // dof index and corresponding actual pri vars
560 2992000 const auto localIdx = scv.localDofIndex();
561 2992000 const auto dofIdx = scv.dofIndex();
562 2992000 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
563 2992000 const VolumeVariables origVolVars(curVolVars);
564
565 // calculate derivatives w.r.t to the privars at the dof at hand
566 5984000 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
567 {
568 2992000 partialDerivs = 0.0;
569
570 5984000 auto evalStorage = [&](Scalar priVar)
571 {
572 // auto partialDerivsTmp = partialDerivs;
573 2992000 elemSol[localIdx][pvIdx] = priVar;
574 2992000 curVolVars.update(elemSol, this->asImp_().problem(), element, scv);
575 2992000 return this->evalLocalStorageResidual();
576 };
577
578 // derive the residuals numerically
579 2992000 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
580 2992000 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
581 2992000 NumericDifferentiation::partialDerivative(evalStorage, elemSol[localIdx][pvIdx], partialDerivs, origStorageResiduals,
582 2992000 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
583
584 // update the global stiffness matrix with the current partial derivatives
585 5984000 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
586 {
587 // A[i][col][eqIdx][pvIdx] is the rate of change of
588 // the residual of equation 'eqIdx' at dof 'i'
589 // depending on the primary variable 'pvIdx' at dof
590 // 'col'.
591 2992000 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[localIdx][eqIdx];
592 }
593
594 // restore the original state of the scv's volume variables
595 2992000 curVolVars = origVolVars;
596
597 // restore the original element solution
598 2992000 elemSol[localIdx][pvIdx] = curSol[dofIdx][pvIdx];
599 // TODO additional dof dependencies
600 }
601 }
602
603 1014000 return origResiduals;
604 }
605 }; // explicit CVFEAssembler with numeric Jacobian
606
607 /*!
608 * \ingroup Assembly
609 * \ingroup CVFEDiscretization
610 * \brief Control volume finite element local assembler using analytic differentiation and implicit time discretization
611 */
612 template<class TypeTag, class Assembler, class Implementation>
613
2/8
✓ Branch 0 taken 500000 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5000 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1259597 class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/true, Implementation>
614 : public CVFELocalAssemblerBase<TypeTag, Assembler,
615 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>>,
616 true>
617 {
618 using ThisType = CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>;
619 using ParentType = CVFELocalAssemblerBase<TypeTag, Assembler, Detail::CVFE::Impl<Implementation, ThisType>, true>;
620 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
621 using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
622
623 public:
624
625 using LocalResidual = typename ParentType::LocalResidual;
626 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
627
2/4
✓ Branch 2 taken 729133 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 25464 times.
✗ Branch 7 not taken.
754597 using ParentType::ParentType;
628
629 /*!
630 * \brief Computes the derivatives with respect to the given element and adds them
631 * to the global matrix.
632 *
633 * \return The element residual at the current solution.
634 */
635 template <class PartialReassembler = DefaultPartialReassembler>
636 253869 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
637 const PartialReassembler* partialReassembler = nullptr)
638 {
639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253869 times.
253869 if (partialReassembler)
640 DUNE_THROW(Dune::NotImplemented, "partial reassembly for analytic differentiation");
641
642 // get some aliases for convenience
643 253869 const auto& element = this->element();
644 253869 const auto& fvGeometry = this->fvGeometry();
645 253869 const auto& problem = this->asImp_().problem();
646 253869 const auto& curElemVolVars = this->curElemVolVars();
647 253869 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
648
649 // get the vecor of the actual element residuals
650 253869 const auto origResiduals = this->evalLocalResidual();
651
652 //////////////////////////////////////////////////////////////////////////////////////////////////
653 // //
654 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
655 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
656 // actual element. In the actual element we evaluate the derivative of the entire residual. //
657 // //
658 //////////////////////////////////////////////////////////////////////////////////////////////////
659
660 // calculation of the source and storage derivatives
661
4/4
✓ Branch 0 taken 611000 times.
✓ Branch 1 taken 134266 times.
✓ Branch 2 taken 745266 times.
✓ Branch 3 taken 253869 times.
999135 for (const auto& scv : scvs(fvGeometry))
662 {
663 // dof index and corresponding actual pri vars
664
2/2
✓ Branch 0 taken 611000 times.
✓ Branch 1 taken 134266 times.
745266 const auto dofIdx = scv.dofIndex();
665 745266 const auto& volVars = curElemVolVars[scv];
666
667 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
668 // only if the problem is instationary we add derivative of storage term
669 // TODO if e.g. porosity depends on all dofs in the element, we would have off-diagonal matrix entries!?
670
2/2
✓ Branch 0 taken 611000 times.
✓ Branch 1 taken 134266 times.
745266 if (!this->assembler().isStationaryProblem())
671 611000 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
672 problem,
673 element,
674 fvGeometry,
675 volVars,
676 scv);
677
678 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
679 // add source term derivatives
680 745266 this->localResidual().addSourceDerivatives(A[dofIdx][dofIdx],
681 problem,
682 element,
683 fvGeometry,
684 volVars,
685 scv);
686 }
687
688 // localJacobian[scvIdx][otherScvIdx][eqIdx][priVarIdx] of the fluxes
689
4/4
✓ Branch 0 taken 610161 times.
✓ Branch 1 taken 26963 times.
✓ Branch 2 taken 635914 times.
✓ Branch 3 taken 253264 times.
890388 for (const auto& scvf : scvfs(fvGeometry))
690 {
691
2/2
✓ Branch 0 taken 609556 times.
✓ Branch 1 taken 26358 times.
635914 if (!scvf.boundary())
692 {
693 // add flux term derivatives
694 610161 this->localResidual().addFluxDerivatives(A,
695 problem,
696 element,
697 fvGeometry,
698 curElemVolVars,
699 elemFluxVarsCache,
700 scvf);
701 }
702
703 // the boundary gets special treatment to simplify
704 // for the user
705 else
706 {
707 26358 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
708 26358 if (this->elemBcTypes().get(fvGeometry, insideScv).hasNeumann())
709 {
710 // add flux term derivatives
711 26358 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
712 problem,
713 element,
714 fvGeometry,
715 curElemVolVars,
716 elemFluxVarsCache,
717 scvf);
718 }
719 }
720 }
721
722 253869 return origResiduals;
723 }
724
725 }; // implicit CVFEAssembler with analytic Jacobian
726
727 /*!
728 * \ingroup Assembly
729 * \ingroup CVFEDiscretization
730 * \brief Control volume finite element local assembler using analytic differentiation and explicit time discretization
731 */
732 template<class TypeTag, class Assembler, class Implementation>
733
2/8
✓ Branch 0 taken 500000 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5000 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1010000 class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/false, Implementation>
734 : public CVFELocalAssemblerBase<TypeTag, Assembler,
735 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>>,
736 false>
737 {
738 using ThisType = CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>;
739 using ParentType = CVFELocalAssemblerBase<TypeTag, Assembler, Detail::CVFE::Impl<Implementation, ThisType>, false>;
740 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
741 using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
742
743 public:
744
745 using LocalResidual = typename ParentType::LocalResidual;
746 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
747
2/4
✓ Branch 2 taken 500000 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 5000 times.
✗ Branch 7 not taken.
505000 using ParentType::ParentType;
748
749 /*!
750 * \brief Computes the derivatives with respect to the given element and adds them
751 * to the global matrix.
752 *
753 * \return The element residual at the current solution.
754 */
755 template <class PartialReassembler = DefaultPartialReassembler>
756 5000 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
757 const PartialReassembler* partialReassembler = nullptr)
758 {
759
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5000 times.
5000 if (partialReassembler)
760 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
761
762 // get some aliases for convenience
763 5000 const auto& element = this->element();
764 5000 const auto& fvGeometry = this->fvGeometry();
765 5000 const auto& problem = this->asImp_().problem();
766 5000 const auto& curElemVolVars = this->curElemVolVars();
767
768 // get the vecor of the actual element residuals
769 5000 const auto origResiduals = this->evalLocalResidual();
770
771 //////////////////////////////////////////////////////////////////////////////////////////////////
772 // //
773 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
774 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
775 // actual element. In the actual element we evaluate the derivative of the entire residual. //
776 // //
777 //////////////////////////////////////////////////////////////////////////////////////////////////
778
779 // calculation of the source and storage derivatives
780
2/2
✓ Branch 1 taken 20000 times.
✓ Branch 2 taken 5000 times.
25000 for (const auto& scv : scvs(fvGeometry))
781 {
782 // dof index and corresponding actual pri vars
783 20000 const auto dofIdx = scv.dofIndex();
784 20000 const auto& volVars = curElemVolVars[scv];
785
786 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
787 // only if the problem is instationary we add derivative of storage term
788 20000 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
789 problem,
790 element,
791 fvGeometry,
792 volVars,
793 scv);
794 }
795
796 5000 return origResiduals;
797 }
798
799 }; // explicit CVFEAssembler with analytic Jacobian
800
801 } // end namespace Dumux
802
803 #endif
804