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 |