Line | Branch | Exec | Source |
---|---|---|---|
1 | // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||
2 | // vi: set et ts=4 sw=4 sts=4: | ||
3 | // | ||
4 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup Assembly | ||
10 | * \ingroup CVFEDiscretization | ||
11 | * \ingroup MultiDomain | ||
12 | * \brief An assembler for Jacobian and residual contribution per element (CVFE methods) for multidomain problems | ||
13 | */ | ||
14 | #ifndef DUMUX_MULTIDOMAIN_SUBDOMAIN_CVFE_LOCAL_ASSEMBLER_HH | ||
15 | #define DUMUX_MULTIDOMAIN_SUBDOMAIN_CVFE_LOCAL_ASSEMBLER_HH | ||
16 | |||
17 | #include <type_traits> | ||
18 | |||
19 | #include <dune/common/reservedvector.hh> | ||
20 | #include <dune/common/indices.hh> | ||
21 | #include <dune/common/hybridutilities.hh> | ||
22 | #include <dune/grid/common/gridenums.hh> // for GhostEntity | ||
23 | #include <dune/istl/matrixindexset.hh> | ||
24 | |||
25 | #include <dumux/common/reservedblockvector.hh> | ||
26 | #include <dumux/common/properties.hh> | ||
27 | #include <dumux/common/parameters.hh> | ||
28 | #include <dumux/common/numericdifferentiation.hh> | ||
29 | #include <dumux/common/numeqvector.hh> | ||
30 | #include <dumux/assembly/numericepsilon.hh> | ||
31 | #include <dumux/assembly/diffmethod.hh> | ||
32 | #include <dumux/assembly/cvfelocalassembler.hh> | ||
33 | #include <dumux/discretization/extrusion.hh> | ||
34 | |||
35 | namespace Dumux { | ||
36 | |||
37 | /*! | ||
38 | * \ingroup Assembly | ||
39 | * \ingroup CVFEDiscretization | ||
40 | * \ingroup MultiDomain | ||
41 | * \brief A base class for all CVFE subdomain local assemblers | ||
42 | * \tparam id the id of the sub domain | ||
43 | * \tparam TypeTag the TypeTag | ||
44 | * \tparam Assembler the assembler type | ||
45 | * \tparam Implementation the actual implementation type | ||
46 | * \tparam implicit Specifies whether the time discretization is implicit or not not (i.e. explicit) | ||
47 | */ | ||
48 | template<std::size_t id, class TypeTag, class Assembler, class Implementation, DiffMethod dm, bool implicit> | ||
49 | 6616770 | class SubDomainCVFELocalAssemblerBase : public CVFELocalAssembler<TypeTag, Assembler, dm, implicit, Implementation> | |
50 | { | ||
51 | using ParentType = CVFELocalAssembler<TypeTag, Assembler, dm, implicit, Implementation>; | ||
52 | |||
53 | using Problem = GetPropType<TypeTag, Properties::Problem>; | ||
54 | using LocalResidualValues = Dumux::NumEqVector<GetPropType<TypeTag, Properties::PrimaryVariables>>; | ||
55 | using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>; | ||
56 | using SolutionVector = typename Assembler::SolutionVector; | ||
57 | using ElementBoundaryTypes = GetPropType<TypeTag, Properties::ElementBoundaryTypes>; | ||
58 | |||
59 | using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; | ||
60 | using GridVolumeVariables = typename GridVariables::GridVolumeVariables; | ||
61 | using ElementVolumeVariables = typename GridVolumeVariables::LocalView; | ||
62 | using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView; | ||
63 | using Scalar = typename GridVariables::Scalar; | ||
64 | |||
65 | using GridGeometry = typename GridVariables::GridGeometry; | ||
66 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
67 | using SubControlVolume = typename GridGeometry::SubControlVolume; | ||
68 | using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace; | ||
69 | using Extrusion = Extrusion_t<GridGeometry>; | ||
70 | using GridView = typename GridGeometry::GridView; | ||
71 | using Element = typename GridView::template Codim<0>::Entity; | ||
72 | |||
73 | using CouplingManager = typename Assembler::CouplingManager; | ||
74 | |||
75 | static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq(); | ||
76 | |||
77 | public: | ||
78 | //! export the domain id of this sub-domain | ||
79 | static constexpr auto domainId = typename Dune::index_constant<id>(); | ||
80 | //! pull up constructor of parent class | ||
81 | using ParentType::ParentType; | ||
82 | //! export element residual vector type | ||
83 | using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector; | ||
84 | |||
85 | // the constructor | ||
86 | 5585931 | explicit SubDomainCVFELocalAssemblerBase( | |
87 | const Assembler& assembler, | ||
88 | const Element& element, | ||
89 | const SolutionVector& curSol, | ||
90 | CouplingManager& couplingManager | ||
91 | ) | ||
92 | : ParentType(assembler, | ||
93 | element, | ||
94 | curSol, | ||
95 | localView(assembler.gridGeometry(domainId)), | ||
96 |
2/4✓ Branch 1 taken 1295090 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
|
12987915 | localView(assembler.gridVariables(domainId).curGridVolVars()), |
97 |
3/6✓ Branch 1 taken 1295090 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 40 times.
✗ Branch 8 not taken.
|
13729075 | localView(assembler.gridVariables(domainId).prevGridVolVars()), |
98 |
4/8✓ Branch 1 taken 1295090 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 40 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 40 times.
✗ Branch 11 not taken.
|
14470235 | localView(assembler.gridVariables(domainId).gridFluxVarsCache()), |
99 | assembler.localResidual(domainId), | ||
100 | 11035803 | (element.partitionType() == Dune::GhostEntity)) | |
101 |
26/44✓ Branch 0 taken 1238886 times.
✓ Branch 1 taken 68041 times.
✓ Branch 2 taken 1239836 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 68041 times.
✓ Branch 5 taken 1239836 times.
✓ Branch 6 taken 712307 times.
✓ Branch 7 taken 55254 times.
✓ Branch 8 taken 1252623 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 55254 times.
✓ Branch 11 taken 1239836 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 55234 times.
✓ Branch 14 taken 1239816 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 55234 times.
✓ Branch 17 taken 1239816 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 55234 times.
✓ Branch 20 taken 1239816 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 55234 times.
✓ Branch 23 taken 1239816 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 55234 times.
✓ Branch 26 taken 1239816 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 55234 times.
✓ Branch 29 taken 1239816 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 55234 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 1239816 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 1295050 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 55234 times.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
|
6946241 | , couplingManager_(couplingManager) |
102 | 5585891 | {} | |
103 | |||
104 | /*! | ||
105 | * \brief Computes the derivatives with respect to the given element and adds them | ||
106 | * to the global matrix. The element residual is written into the right hand side. | ||
107 | */ | ||
108 | template<class JacobianMatrixRow, class SubResidualVector, class GridVariablesTuple> | ||
109 | void assembleJacobianAndResidual(JacobianMatrixRow& jacRow, SubResidualVector& res, GridVariablesTuple& gridVariables) | ||
110 | { | ||
111 | 4719964 | auto assembleCouplingBlocks = [&](const auto& residual) | |
112 | { | ||
113 | // assemble the coupling blocks | ||
114 | using namespace Dune::Hybrid; | ||
115 | 1345982 | forEach(integralRange(Dune::Hybrid::size(jacRow)), [&](auto&& i) | |
116 | { | ||
117 | 2359982 | if constexpr (std::decay_t<decltype(i)>{} != id) | |
118 |
0/6✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
1337883 | this->assembleJacobianCoupling(i, jacRow, residual, gridVariables); |
119 | }); | ||
120 | }; | ||
121 | |||
122 | // the coupled model does not support partial reassembly yet | ||
123 | 2359982 | const DefaultPartialReassembler* noReassembler = nullptr; | |
124 |
16/32✓ Branch 1 taken 801611 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 801611 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 801611 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 801611 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 536663 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 536663 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 536663 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 536663 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 57708 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 57708 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 57708 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 57708 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 964000 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 964000 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 964000 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 964000 times.
✗ Branch 47 not taken.
|
9439928 | ParentType::assembleJacobianAndResidual(jacRow[domainId], res, *std::get<domainId>(gridVariables), noReassembler, assembleCouplingBlocks); |
125 | } | ||
126 | |||
127 | /*! | ||
128 | * \brief Assemble the entries in a coupling block of the jacobian. | ||
129 | * There is no coupling block between a domain and itself. | ||
130 | */ | ||
131 | template<std::size_t otherId, class JacRow, class GridVariables, | ||
132 | typename std::enable_if_t<(otherId == id), int> = 0> | ||
133 | void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacRow& jacRow, | ||
134 | const ElementResidualVector& res, GridVariables& gridVariables) | ||
135 | {} | ||
136 | |||
137 | /*! | ||
138 | * \brief Assemble the entries in a coupling block of the jacobian. | ||
139 | */ | ||
140 | template<std::size_t otherId, class JacRow, class GridVariables, | ||
141 | typename std::enable_if_t<(otherId != id), int> = 0> | ||
142 | ✗ | void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacRow& jacRow, | |
143 | const ElementResidualVector& res, GridVariables& gridVariables) | ||
144 | { | ||
145 |
0/79✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ 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.
✗ 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.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
|
9407532 | this->asImp_().assembleJacobianCoupling(domainJ, jacRow[domainJ], res, *std::get<domainId>(gridVariables)); |
146 | ✗ | } | |
147 | |||
148 | /*! | ||
149 | * \brief Evaluates the local source term for an element and given element volume variables | ||
150 | */ | ||
151 | 218701 | ElementResidualVector evalLocalSourceResidual(const Element& element, const ElementVolumeVariables& elemVolVars) const | |
152 | { | ||
153 | // initialize the residual vector for all scvs in this element | ||
154 | 656103 | ElementResidualVector residual(this->fvGeometry().numScv()); | |
155 | |||
156 | // evaluate the volume terms (storage + source terms) | ||
157 | // forward to the local residual specialized for the discretization methods | ||
158 |
4/4✓ Branch 0 taken 694440 times.
✓ Branch 1 taken 142542 times.
✓ Branch 2 taken 545808 times.
✓ Branch 3 taken 68226 times.
|
2074471 | for (const auto& scv : scvs(this->fvGeometry())) |
159 | { | ||
160 |
1/2✓ Branch 0 taken 545808 times.
✗ Branch 1 not taken.
|
857816 | const auto& curVolVars = elemVolVars[scv]; |
161 |
2/4✓ Branch 0 taken 545808 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 545808 times.
✗ Branch 3 not taken.
|
1418368 | auto source = this->localResidual().computeSource(problem(), element, this->fvGeometry(), elemVolVars, scv); |
162 | 1715632 | source *= -Extrusion::volume(this->fvGeometry(), scv)*curVolVars.extrusionFactor(); | |
163 | 1715632 | residual[scv.localDofIndex()] = std::move(source); | |
164 | } | ||
165 | |||
166 | 218701 | return residual; | |
167 | } | ||
168 | |||
169 | /*! | ||
170 | * \brief Evaluates the local source term depending on time discretization scheme | ||
171 | */ | ||
172 | ElementResidualVector evalLocalSourceResidual(const Element& neighbor) const | ||
173 | 285084 | { return this->evalLocalSourceResidual(neighbor, implicit ? this->curElemVolVars() : this->prevElemVolVars()); } | |
174 | |||
175 | /*! | ||
176 | * \brief Prepares all local views necessary for local assembly. | ||
177 | */ | ||
178 | 5592810 | void bindLocalViews() | |
179 | { | ||
180 | // get some references for convenience | ||
181 | 5592810 | const auto& element = this->element(); | |
182 | 11185620 | const auto& curSol = this->curSol(domainId); | |
183 | 11185620 | auto&& fvGeometry = this->fvGeometry(); | |
184 | 5592810 | auto&& curElemVolVars = this->curElemVolVars(); | |
185 | 5592810 | auto&& elemFluxVarsCache = this->elemFluxVarsCache(); | |
186 | |||
187 | // bind the caches | ||
188 | 5592810 | couplingManager_.bindCouplingContext(domainId, element, this->assembler()); | |
189 | 5592810 | fvGeometry.bind(element); | |
190 | |||
191 | if constexpr (implicit) | ||
192 | { | ||
193 | 3564810 | curElemVolVars.bind(element, fvGeometry, curSol); | |
194 | 3564810 | elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); | |
195 |
4/4✓ Branch 0 taken 873254 times.
✓ Branch 1 taken 1421131 times.
✓ Branch 2 taken 873254 times.
✓ Branch 3 taken 1421131 times.
|
7129620 | if (!this->assembler().isStationaryProblem()) |
196 | 4160816 | this->prevElemVolVars().bindElement(element, fvGeometry, this->assembler().prevSol()[domainId]); | |
197 | } | ||
198 | else | ||
199 | { | ||
200 | 2028000 | auto& prevElemVolVars = this->prevElemVolVars(); | |
201 | 4056000 | const auto& prevSol = this->assembler().prevSol()[domainId]; | |
202 | |||
203 | 2028000 | curElemVolVars.bindElement(element, fvGeometry, curSol); | |
204 | 2028000 | prevElemVolVars.bind(element, fvGeometry, prevSol); | |
205 | 2028000 | elemFluxVarsCache.bind(element, fvGeometry, prevElemVolVars); | |
206 | } | ||
207 | |||
208 | 11185620 | this->elemBcTypes().update(problem(), this->element(), this->fvGeometry()); | |
209 | 5592810 | } | |
210 | |||
211 | //! return reference to the underlying problem | ||
212 | template<std::size_t i = domainId> | ||
213 | ✗ | const Problem& problem(Dune::index_constant<i> dId = domainId) const | |
214 |
32/48✓ Branch 0 taken 531064 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27418 times.
✓ Branch 3 taken 12745 times.
✓ Branch 4 taken 1318 times.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 25 times.
✓ Branch 9 taken 10 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 23 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 5 times.
✓ Branch 14 taken 4 times.
✓ Branch 15 taken 22 times.
✓ Branch 16 taken 7 times.
✓ Branch 17 taken 1 times.
✓ Branch 18 taken 24 times.
✓ Branch 19 taken 7 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 22 times.
✓ Branch 22 taken 2 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 4 times.
✓ Branch 25 taken 2 times.
✗ Branch 26 not taken.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 1 times.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 35 taken 1 times.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✓ Branch 38 taken 2 times.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✓ Branch 41 taken 2 times.
✗ Branch 42 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 1 times.
✗ Branch 50 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
|
17595775 | { return this->assembler().problem(domainId); } |
215 | |||
216 | //! return reference to the underlying problem | ||
217 | template<std::size_t i = domainId> | ||
218 | ✗ | const auto& curSol(Dune::index_constant<i> dId = domainId) const | |
219 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 1795 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10531 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 8736 times.
|
11336734 | { return ParentType::curSol()[dId]; } |
220 | |||
221 | //! return reference to the coupling manager | ||
222 | ✗ | CouplingManager& couplingManager() | |
223 | ✗ | { return couplingManager_; } | |
224 | |||
225 | private: | ||
226 | CouplingManager& couplingManager_; //!< the coupling manager | ||
227 | }; | ||
228 | |||
229 | /*! | ||
230 | * \ingroup Assembly | ||
231 | * \ingroup CVFEDiscretization | ||
232 | * \ingroup MultiDomain | ||
233 | * \brief The CVFE scheme multidomain local assembler | ||
234 | * \tparam id the id of the sub domain | ||
235 | * \tparam TypeTag the TypeTag | ||
236 | * \tparam Assembler the assembler type | ||
237 | * \tparam DM the numeric differentiation method | ||
238 | * \tparam implicit whether the assembler is explicit or implicit in time | ||
239 | */ | ||
240 | template<std::size_t id, class TypeTag, class Assembler, DiffMethod DM = DiffMethod::numeric, bool implicit = true> | ||
241 | class SubDomainCVFELocalAssembler; | ||
242 | |||
243 | /*! | ||
244 | * \ingroup Assembly | ||
245 | * \ingroup CVFEDiscretization | ||
246 | * \ingroup MultiDomain | ||
247 | * \brief CVFE scheme multi domain local assembler using numeric differentiation and implicit time discretization | ||
248 | */ | ||
249 | template<std::size_t id, class TypeTag, class Assembler> | ||
250 |
4/16✓ Branch 0 taken 442618 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 394194 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 232108 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 232108 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
3595413 | class SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true> |
251 | : public SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler, | ||
252 | SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, true>, DiffMethod::numeric, true > | ||
253 | { | ||
254 | using ThisType = SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>; | ||
255 | using ParentType = SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler, ThisType, DiffMethod::numeric, /*implicit=*/true>; | ||
256 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
257 | using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>; | ||
258 | |||
259 | using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView; | ||
260 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
261 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
262 | using SubControlVolume = typename GridGeometry::SubControlVolume; | ||
263 | using GridView = typename GridGeometry::GridView; | ||
264 | using Element = typename GridView::template Codim<0>::Entity; | ||
265 | using Problem = GetPropType<TypeTag, Properties::Problem>; | ||
266 | |||
267 | static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq(); | ||
268 | static constexpr int dim = GridView::dimension; | ||
269 | |||
270 | static constexpr bool enableGridFluxVarsCache = GetPropType<TypeTag, Properties::GridVariables>::GridFluxVariablesCache::cachingEnabled; | ||
271 | static constexpr bool enableGridVolVarsCache = GetPropType<TypeTag, Properties::GridVariables>::GridVolumeVariables::cachingEnabled; | ||
272 | static constexpr auto domainI = Dune::index_constant<id>(); | ||
273 | |||
274 | public: | ||
275 |
2/4✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
|
2294425 | using ParentType::ParentType; |
276 | //! export element residual vector type | ||
277 | using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector; | ||
278 | |||
279 | /*! | ||
280 | * \brief Update the coupling context for coupled models. | ||
281 | */ | ||
282 | template<class ElemSol> | ||
283 | 92 | void maybeUpdateCouplingContext(const SubControlVolume& scv, ElemSol& elemSol, const int pvIdx) | |
284 | { | ||
285 |
6/10✗ Branch 0 not taken.
✓ Branch 1 taken 37792 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 37712 times.
✓ Branch 5 taken 80 times.
✓ Branch 9 taken 18528 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 18528 times.
✗ Branch 13 not taken.
|
47944476 | this->couplingManager().updateCouplingContext(domainI, *this, domainI, scv.dofIndex(), elemSol[scv.localDofIndex()], pvIdx); |
286 | 92 | } | |
287 | |||
288 | /*! | ||
289 | * \brief Update the additional domain derivatives for coupled models. | ||
290 | */ | ||
291 | template<class JacobianMatrixDiagBlock, class GridVariables> | ||
292 | ✗ | void maybeEvalAdditionalDomainDerivatives(const ElementResidualVector& origResiduals, JacobianMatrixDiagBlock& A, GridVariables& gridVariables) | |
293 | { | ||
294 | 1345982 | this->couplingManager().evalAdditionalDomainDerivatives(domainI, *this, origResiduals, A, gridVariables); | |
295 | ✗ | } | |
296 | |||
297 | /*! | ||
298 | * \brief Computes the derivatives with respect to the given element and adds them | ||
299 | * to the global matrix. | ||
300 | */ | ||
301 | template<std::size_t otherId, class JacobianBlock, class GridVariables> | ||
302 | 2168412 | void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A, | |
303 | const ElementResidualVector& res, GridVariables& gridVariables) | ||
304 | { | ||
305 | //////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
306 | // Calculate derivatives of all dofs in the element with respect to all dofs in the coupling stencil. // | ||
307 | //////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
308 | |||
309 | // get some aliases for convenience | ||
310 | 2168412 | const auto& element = this->element(); | |
311 | 2168412 | const auto& fvGeometry = this->fvGeometry(); | |
312 | 2168412 | auto&& curElemVolVars = this->curElemVolVars(); | |
313 | 2168412 | auto&& elemFluxVarsCache = this->elemFluxVarsCache(); | |
314 | |||
315 | // convenience lambda for call to update self | ||
316 | 10616539 | auto updateCoupledVariables = [&] () | |
317 | { | ||
318 | // Update ourself after the context has been modified. Depending on the | ||
319 | // type of caching, other objects might have to be updated. All ifs can be optimized away. | ||
320 | if constexpr (enableGridFluxVarsCache) | ||
321 | { | ||
322 | if constexpr (enableGridVolVarsCache) | ||
323 | 7541069 | this->couplingManager().updateCoupledVariables(domainI, *this, gridVariables.curGridVolVars(), gridVariables.gridFluxVarsCache()); | |
324 | else | ||
325 | this->couplingManager().updateCoupledVariables(domainI, *this, curElemVolVars, gridVariables.gridFluxVarsCache()); | ||
326 | } | ||
327 | else | ||
328 | { | ||
329 | if constexpr (enableGridVolVarsCache) | ||
330 | this->couplingManager().updateCoupledVariables(domainI, *this, gridVariables.curGridVolVars(), elemFluxVarsCache); | ||
331 | else | ||
332 | 907358 | this->couplingManager().updateCoupledVariables(domainI, *this, curElemVolVars, elemFluxVarsCache); | |
333 | } | ||
334 | }; | ||
335 | |||
336 | // get element stencil information | ||
337 | 2168412 | const auto& stencil = this->couplingManager().couplingStencil(domainI, element, domainJ); | |
338 | 2168412 | const auto& curSolJ = this->curSol(domainJ); | |
339 |
4/4✓ Branch 0 taken 2485238 times.
✓ Branch 1 taken 1354081 times.
✓ Branch 2 taken 2484938 times.
✓ Branch 3 taken 1353781 times.
|
11654223 | for (const auto globalJ : stencil) |
340 | { | ||
341 | // undeflected privars and privars to be deflected | ||
342 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 2485238 times.
✗ Branch 2 not taken.
|
4669271 | const auto origPriVarsJ = curSolJ[globalJ]; |
343 | 4669271 | auto priVarsJ = origPriVarsJ; | |
344 | |||
345 | // the undeflected coupling residual | ||
346 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 2485238 times.
✗ Branch 2 not taken.
|
4669271 | const auto origResidual = this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ); |
347 | |||
348 |
2/2✓ Branch 0 taken 3779456 times.
✓ Branch 1 taken 2485238 times.
|
11926978 | for (int pvIdx = 0; pvIdx < JacobianBlock::block_type::cols; ++pvIdx) |
349 | { | ||
350 | 20019752 | auto evalCouplingResidual = [&](Scalar priVar) | |
351 | { | ||
352 | 3202984 | priVarsJ[pvIdx] = priVar; | |
353 | 3779456 | this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, priVarsJ, pvIdx); | |
354 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
|
3777152 | updateCoupledVariables(); |
355 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
|
3779456 | return this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ); |
356 | }; | ||
357 | |||
358 | // derive the residuals numerically | ||
359 |
4/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 1509392 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 1509392 times.
|
14515414 | ElementResidualVector partialDerivs(fvGeometry.numScv()); |
360 | |||
361 |
4/4✓ Branch 0 taken 72 times.
✓ Branch 1 taken 3779384 times.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 3779384 times.
|
14515414 | const auto& paramGroup = this->assembler().problem(domainJ).paramGroup(); |
362 |
4/6✓ Branch 0 taken 72 times.
✓ Branch 1 taken 3779384 times.
✓ Branch 3 taken 72 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 72 times.
✗ Branch 7 not taken.
|
7257707 | static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod"); |
363 |
4/6✓ Branch 0 taken 72 times.
✓ Branch 1 taken 3779384 times.
✓ Branch 3 taken 72 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 72 times.
✗ Branch 7 not taken.
|
7257707 | static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup); |
364 | |||
365 |
2/4✓ Branch 1 taken 3779456 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2547784 times.
✗ Branch 5 not taken.
|
12353275 | NumericDifferentiation::partialDerivative(evalCouplingResidual, origPriVarsJ[pvIdx], partialDerivs, origResidual, |
366 | 12353275 | epsCoupl(origPriVarsJ[pvIdx], pvIdx), numDiffMethod); | |
367 | |||
368 | // update the global stiffness matrix with the current partial derivatives | ||
369 |
4/4✓ Branch 0 taken 13468670 times.
✓ Branch 1 taken 3779456 times.
✓ Branch 2 taken 12858114 times.
✓ Branch 3 taken 3474178 times.
|
40147092 | for (const auto& scv : scvs(fvGeometry)) |
370 | { | ||
371 |
2/2✓ Branch 0 taken 18329838 times.
✓ Branch 1 taken 13468670 times.
|
60442076 | for (int eqIdx = 0; eqIdx < numEq; eqIdx++) |
372 | { | ||
373 | // A[i][col][eqIdx][pvIdx] is the rate of change of | ||
374 | // the residual of equation 'eqIdx' at dof 'i' | ||
375 | // depending on the primary variable 'pvIdx' at dof | ||
376 | // 'col'. | ||
377 |
9/13✓ Branch 1 taken 18329838 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18329838 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18329838 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 8730880 times.
✓ Branch 10 taken 9598958 times.
✓ Branch 11 taken 7845680 times.
✓ Branch 12 taken 802958 times.
✓ Branch 13 taken 8794160 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 648240 times.
|
122259688 | A[scv.dofIndex()][globalJ][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx]; |
378 | |||
379 | // If the dof is coupled by a Dirichlet condition, | ||
380 | // set the derived value only once (i.e. overwrite existing values). | ||
381 |
4/4✓ Branch 0 taken 9367534 times.
✓ Branch 1 taken 8962304 times.
✓ Branch 2 taken 9367534 times.
✓ Branch 3 taken 8962304 times.
|
69620796 | if (this->elemBcTypes().hasDirichlet()) |
382 | { | ||
383 | 2579468 | const auto bcTypes = this->elemBcTypes().get(fvGeometry, scv); | |
384 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 689598 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 689598 times.
|
2580332 | if (bcTypes.isCouplingDirichlet(eqIdx)) |
385 | ✗ | A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = partialDerivs[scv.localDofIndex()][eqIdx]; | |
386 |
2/2✓ Branch 0 taken 293608 times.
✓ Branch 1 taken 395990 times.
|
1290166 | else if (bcTypes.isDirichlet(eqIdx)) |
387 |
2/4✓ Branch 1 taken 293608 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293608 times.
✗ Branch 5 not taken.
|
1129744 | A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = 0.0; |
388 | } | ||
389 | |||
390 | // enforce internal Dirichlet constraints | ||
391 | if constexpr (Problem::enableInternalDirichletConstraints()) | ||
392 | { | ||
393 |
2/4✓ Branch 1 taken 115200 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 115200 times.
✗ Branch 5 not taken.
|
460800 | const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv); |
394 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 115200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 115200 times.
|
460800 | if (internalDirichletConstraints[eqIdx]) |
395 | ✗ | A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = 0.0; | |
396 | } | ||
397 | |||
398 | } | ||
399 | } | ||
400 | |||
401 | // restore the current element solution | ||
402 |
2/4✓ Branch 1 taken 340524 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 340524 times.
✗ Branch 5 not taken.
|
12353275 | priVarsJ[pvIdx] = origPriVarsJ[pvIdx]; |
403 | |||
404 | // restore the undeflected state of the coupling context | ||
405 |
1/2✓ Branch 1 taken 1423644 times.
✗ Branch 2 not taken.
|
11823587 | this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, priVarsJ, pvIdx); |
406 | } | ||
407 | |||
408 | // Restore original state of the flux vars cache and/or vol vars. | ||
409 | // This has to be done in case they depend on variables of domainJ before | ||
410 | // we continue with the numeric derivative w.r.t the next globalJ. Otherwise, | ||
411 | // the next "origResidual" will be incorrect. | ||
412 |
1/2✓ Branch 1 taken 300 times.
✗ Branch 2 not taken.
|
4669271 | updateCoupledVariables(); |
413 | } | ||
414 | 2168412 | } | |
415 | }; | ||
416 | |||
417 | /*! | ||
418 | * \ingroup Assembly | ||
419 | * \ingroup CVFEDiscretization | ||
420 | * \ingroup MultiDomain | ||
421 | * \brief CVFE scheme multi domain local assembler using numeric differentiation and explicit time discretization | ||
422 | */ | ||
423 | template<std::size_t id, class TypeTag, class Assembler> | ||
424 | 1014000 | class SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false> | |
425 | : public SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler, | ||
426 | SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, false>, DiffMethod::numeric, false > | ||
427 | { | ||
428 | using ThisType = SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false>; | ||
429 | using ParentType = SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler, ThisType, DiffMethod::numeric, /*implicit=*/false>; | ||
430 | |||
431 | public: | ||
432 | 1014000 | using ParentType::ParentType; | |
433 | //! export element residual vector type | ||
434 | using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector; | ||
435 | |||
436 | /*! | ||
437 | * \brief Computes the coupling derivatives with respect to the given element and adds them | ||
438 | * to the global matrix. | ||
439 | * \note Since the coupling can only enter sources or fluxes and these are evaluated on | ||
440 | * the old time level (explicit scheme), the coupling blocks are empty. | ||
441 | */ | ||
442 | template<std::size_t otherId, class JacobianBlock, class GridVariables> | ||
443 | ✗ | void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A, | |
444 | const ElementResidualVector& res, GridVariables& gridVariables) | ||
445 | ✗ | {} | |
446 | }; | ||
447 | |||
448 | } // end namespace Dumux | ||
449 | |||
450 | #endif | ||
451 |