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 FacetCoupling | ||
10 | * \copydoc Dumux::FacetCouplingManager | ||
11 | */ | ||
12 | #ifndef DUMUX_CCMPFA_FACETCOUPLING_MANAGER_HH | ||
13 | #define DUMUX_CCMPFA_FACETCOUPLING_MANAGER_HH | ||
14 | |||
15 | #include <algorithm> | ||
16 | #include <cassert> | ||
17 | |||
18 | #include <dumux/common/properties.hh> | ||
19 | #include <dumux/common/indextraits.hh> | ||
20 | #include <dumux/common/numericdifferentiation.hh> | ||
21 | #include <dumux/common/numeqvector.hh> | ||
22 | #include <dumux/assembly/numericepsilon.hh> | ||
23 | |||
24 | #include <dumux/discretization/method.hh> | ||
25 | #include <dumux/discretization/elementsolution.hh> | ||
26 | #include <dumux/multidomain/couplingmanager.hh> | ||
27 | #include <dumux/multidomain/facet/cellcentered/tpfa/couplingmanager.hh> | ||
28 | |||
29 | namespace Dumux { | ||
30 | |||
31 | /*! | ||
32 | * \ingroup FacetCoupling | ||
33 | * \brief Manages the coupling between bulk elements and lower dimensional elements | ||
34 | * where the coupling occurs across the facets of the bulk grid. This implementation | ||
35 | * is to be used in conjunction with models using the cell-centered mpfa scheme. | ||
36 | * | ||
37 | * \tparam MDTraits The multidomain traits containing the types on all sub-domains | ||
38 | * \tparam CouplingMapper Class containing maps on the coupling between dofs of different grids | ||
39 | * \tparam bulkDomainId The domain id of the bulk problem | ||
40 | * \tparam lowDimDomainId The domain id of the lower-dimensional problem | ||
41 | */ | ||
42 | template<class MDTraits, class CouplingMapper, std::size_t bulkDomainId, std::size_t lowDimDomainId> | ||
43 | class FacetCouplingManager<MDTraits, CouplingMapper, bulkDomainId, lowDimDomainId, DiscretizationMethods::CCMpfa> | ||
44 | : public FacetCouplingManager<MDTraits, CouplingMapper, bulkDomainId, lowDimDomainId, DiscretizationMethods::CCTpfa> | ||
45 | { | ||
46 | using ParentType = FacetCouplingManager<MDTraits, CouplingMapper, bulkDomainId, lowDimDomainId, DiscretizationMethods::CCTpfa>; | ||
47 | |||
48 | // domain id instances | ||
49 | using BulkIdType = typename MDTraits::template SubDomain<bulkDomainId>::Index; | ||
50 | using LowDimIdType = typename MDTraits::template SubDomain<lowDimDomainId>::Index; | ||
51 | static constexpr auto bulkId = BulkIdType(); | ||
52 | static constexpr auto lowDimId = LowDimIdType(); | ||
53 | |||
54 | // the sub-domain type tags | ||
55 | template<std::size_t id> using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag; | ||
56 | |||
57 | // further types specific to the sub-problems | ||
58 | template<std::size_t id> using Scalar = GetPropType<SubDomainTypeTag<id>, Properties::Scalar>; | ||
59 | template<std::size_t id> using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>; | ||
60 | template<std::size_t id> using NumEqVector = Dumux::NumEqVector<GetPropType<SubDomainTypeTag<id>, Properties::PrimaryVariables>>; | ||
61 | template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; | ||
62 | template<std::size_t id> using FVElementGeometry = typename GridGeometry<id>::LocalView; | ||
63 | template<std::size_t id> using SubControlVolume = typename GridGeometry<id>::SubControlVolume; | ||
64 | template<std::size_t id> using SubControlVolumeFace = typename GridGeometry<id>::SubControlVolumeFace; | ||
65 | template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; | ||
66 | template<std::size_t id> using GridIndexType = typename IndexTraits< GridView<id> >::GridIndex; | ||
67 | template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; | ||
68 | template<std::size_t id> using LocalResidual = typename MDTraits::template SubDomain<id>::LocalResidual; | ||
69 | |||
70 | template<std::size_t id> using GridVariables = GetPropType<SubDomainTypeTag<id>, Properties::GridVariables>; | ||
71 | template<std::size_t id> using GridVolumeVariables = typename GridVariables<id>::GridVolumeVariables; | ||
72 | template<std::size_t id> using ElementVolumeVariables = typename GridVolumeVariables<id>::LocalView; | ||
73 | |||
74 | // grid ids | ||
75 | static constexpr int bulkDim = GridView<bulkDomainId>::dimension; | ||
76 | static constexpr int lowDimDim = GridView<lowDimDomainId>::dimension; | ||
77 | static constexpr auto bulkGridId = CouplingMapper::template gridId<bulkDim>(); | ||
78 | static constexpr auto lowDimGridId = CouplingMapper::template gridId<lowDimDim>(); | ||
79 | |||
80 | static constexpr bool lowDimUsesBox = GridGeometry<lowDimId>::discMethod == DiscretizationMethods::box; | ||
81 | |||
82 | public: | ||
83 | |||
84 | //! the type of the solution vector | ||
85 | using SolutionVector = typename MDTraits::SolutionVector; | ||
86 | |||
87 | /*! | ||
88 | * \brief Initialize the coupling manager. | ||
89 | * | ||
90 | * \param bulkProblem The problem to be solved on the bulk domain | ||
91 | * \param lowDimProblem The problem to be solved on the lower-dimensional domain | ||
92 | * \param couplingMapper The mapper object containing the connectivity between the domains | ||
93 | * \param curSol The current solution | ||
94 | */ | ||
95 | 15 | void init(std::shared_ptr< Problem<bulkId> > bulkProblem, | |
96 | std::shared_ptr< Problem<lowDimId> > lowDimProblem, | ||
97 | std::shared_ptr< CouplingMapper > couplingMapper, | ||
98 | const SolutionVector& curSol) | ||
99 | { | ||
100 | // Initialize the parent class | ||
101 |
4/14✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ 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.
|
45 | ParentType::init(bulkProblem, lowDimProblem, couplingMapper, curSol); |
102 | |||
103 | // determine all bulk scvfs that coincide with low dim elements | ||
104 | 60 | bulkScvfIsOnFacetElement_.assign(bulkProblem->gridGeometry().numScvf(), false); | |
105 | 30 | const auto& bulkMap = couplingMapper->couplingMap(bulkGridId, lowDimGridId); | |
106 |
2/2✓ Branch 0 taken 1405 times.
✓ Branch 1 taken 13 times.
|
2278 | for (const auto& entry : bulkMap) |
107 |
2/2✓ Branch 0 taken 940 times.
✓ Branch 1 taken 1405 times.
|
8039 | for (const auto& couplingEntry : entry.second.elementToScvfMap) |
108 |
4/4✓ Branch 0 taken 1880 times.
✓ Branch 1 taken 940 times.
✓ Branch 2 taken 1880 times.
✓ Branch 3 taken 940 times.
|
9380 | for (const auto& scvfIdx : couplingEntry.second) |
109 | 8040 | bulkScvfIsOnFacetElement_[scvfIdx] = true; | |
110 | |||
111 | // store pointer to mapper | ||
112 | 15 | couplingMapperPtr_ = couplingMapper; | |
113 | 15 | } | |
114 | |||
115 | /*! | ||
116 | * \brief returns true if a bulk scvf coincides with a facet element. | ||
117 | */ | ||
118 | ✗ | bool isOnInteriorBoundary(const Element<bulkId>& element, | |
119 | const SubControlVolumeFace<bulkId>& scvf) const | ||
120 |
28/28✓ Branch 0 taken 1193848 times.
✓ Branch 1 taken 29111180 times.
✓ Branch 2 taken 1193848 times.
✓ Branch 3 taken 29111180 times.
✓ Branch 4 taken 801240 times.
✓ Branch 5 taken 22047585 times.
✓ Branch 6 taken 801240 times.
✓ Branch 7 taken 22047585 times.
✓ Branch 8 taken 664172 times.
✓ Branch 9 taken 15646684 times.
✓ Branch 10 taken 664172 times.
✓ Branch 11 taken 15646684 times.
✓ Branch 12 taken 416424 times.
✓ Branch 13 taken 10414704 times.
✓ Branch 14 taken 416424 times.
✓ Branch 15 taken 10414704 times.
✓ Branch 16 taken 829000 times.
✓ Branch 17 taken 17504000 times.
✓ Branch 18 taken 829000 times.
✓ Branch 19 taken 17504000 times.
✓ Branch 20 taken 6632 times.
✓ Branch 21 taken 140032 times.
✓ Branch 22 taken 6632 times.
✓ Branch 23 taken 140032 times.
✓ Branch 24 taken 400 times.
✓ Branch 25 taken 11062 times.
✓ Branch 26 taken 400 times.
✓ Branch 27 taken 11062 times.
|
197573926 | { return bulkScvfIsOnFacetElement_[scvf.index()]; } |
121 | |||
122 | using ParentType::evalCouplingResidual; | ||
123 | /*! | ||
124 | * \brief Evaluates the coupling element residual of a lower-dimensional domain element | ||
125 | * with respect to a dof in the bulk domain (dofIdxGlobalJ). This is essentially | ||
126 | * the fluxes across the facets of the neighboring bulk elements. | ||
127 | * \note The coupling residual is independent of w.r.t. which bulk dof it is computed | ||
128 | */ | ||
129 | template< class LowDimLocalAssembler > | ||
130 | typename LocalResidual<lowDimId>::ElementResidualVector | ||
131 | ✗ | evalCouplingResidual(LowDimIdType, | |
132 | const LowDimLocalAssembler& lowDimLocalAssembler, | ||
133 | BulkIdType, | ||
134 | GridIndexType<bulkId> dofIdxGlobalJ) | ||
135 |
1/2✓ Branch 2 taken 22194 times.
✗ Branch 3 not taken.
|
69504 | { return evalCouplingResidual(lowDimId, lowDimLocalAssembler, bulkId); } |
136 | |||
137 | /*! | ||
138 | * \brief Evaluates the coupling element residual of a lower-dimensional domain element | ||
139 | * with respect to a dof in the bulk domain (dofIdxGlobalJ). This is essentially | ||
140 | * the fluxes across the facets of the neighboring bulk elements. | ||
141 | */ | ||
142 | template< class LowDimLocalAssembler > | ||
143 | typename LocalResidual<lowDimId>::ElementResidualVector | ||
144 | 87437 | evalCouplingResidual(LowDimIdType, const LowDimLocalAssembler& lowDimLocalAssembler, BulkIdType) | |
145 | { | ||
146 | // make sure this is called for the element for which the context was set | ||
147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 87437 times.
|
87437 | assert(this->lowDimCouplingContext().isSet); |
148 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 87437 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 87437 times.
|
87437 | assert(this->problem(lowDimId).gridGeometry().elementMapper().index(lowDimLocalAssembler.element()) == this->lowDimCouplingContext().elementIdx); |
149 | |||
150 | // fill element residual vector with the sources | ||
151 | 262311 | typename LowDimLocalAssembler::LocalResidual::ElementResidualVector res(lowDimLocalAssembler.fvGeometry().numScv()); | |
152 | 87437 | res = 0.0; | |
153 |
2/2✓ Branch 0 taken 87437 times.
✓ Branch 1 taken 87437 times.
|
349748 | for (const auto& scv : scvs(lowDimLocalAssembler.fvGeometry())) |
154 | 246660 | res[scv.localDofIndex()] -= evalSourcesFromBulk(lowDimLocalAssembler.element(), | |
155 | lowDimLocalAssembler.fvGeometry(), | ||
156 | lowDimLocalAssembler.curElemVolVars(), | ||
157 | scv); | ||
158 | 87437 | return res; | |
159 | } | ||
160 | |||
161 | /*! | ||
162 | * \brief Computes the sources in a lower-dimensional sub-control volume stemming from the bulk domain. | ||
163 | */ | ||
164 | 206393 | NumEqVector<lowDimId> evalSourcesFromBulk(const Element<lowDimId>& element, | |
165 | const FVElementGeometry<lowDimId>& fvGeometry, | ||
166 | const ElementVolumeVariables<lowDimId>& elemVolVars, | ||
167 | const SubControlVolume<lowDimId>& scv) const | ||
168 | { | ||
169 | // make sure the this is called for the element of the context | ||
170 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 148629 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 148629 times.
|
206393 | assert(this->problem(lowDimId).gridGeometry().elementMapper().index(element) == this->lowDimCouplingContext().elementIdx); |
171 | |||
172 | 206393 | NumEqVector<lowDimId> sources(0.0); | |
173 | |||
174 | 412786 | const auto& map = couplingMapperPtr_->couplingMap(lowDimGridId, bulkGridId); | |
175 | 206393 | auto it = map.find(this->lowDimCouplingContext().elementIdx); | |
176 |
4/4✓ Branch 0 taken 54208 times.
✓ Branch 1 taken 94421 times.
✓ Branch 2 taken 54208 times.
✓ Branch 3 taken 94421 times.
|
412786 | if (it == map.end()) |
177 | ✗ | return sources; | |
178 | |||
179 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 148629 times.
|
206393 | assert(this->lowDimCouplingContext().isSet); |
180 |
4/4✓ Branch 0 taken 296376 times.
✓ Branch 1 taken 148629 times.
✓ Branch 2 taken 296376 times.
✓ Branch 3 taken 148629 times.
|
1649380 | for (const auto& embedment : it->second.embedments) |
181 | { | ||
182 | // list of scvfs in the bulk domain whose fluxes enter this scv | ||
183 | // if low dim domain uses a cc scheme, this is all scvfs lying on this element | ||
184 | // if it uses box, it is the one scvf coinciding with the given scv | ||
185 | 411904 | const auto& coincidingScvfs = embedment.second; | |
186 |
1/4✓ Branch 1 taken 296376 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
823808 | const auto& scvfList = lowDimUsesBox ? std::vector<GridIndexType<lowDimId>>{ coincidingScvfs[scv.localDofIndex()] } |
187 | : coincidingScvfs; | ||
188 | |||
189 |
4/10✓ Branch 1 taken 296376 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 296376 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 296376 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 296376 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
986224 | sources += this->evalBulkFluxes(this->problem(bulkId).gridGeometry().element(embedment.first), |
190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 296376 times.
|
411904 | *this->lowDimCouplingContext().bulkFvGeometry, |
191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 296376 times.
|
411904 | *this->lowDimCouplingContext().bulkElemVolVars, |
192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 296376 times.
|
411904 | *this->lowDimCouplingContext().bulkElemFluxVarsCache, |
193 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 296376 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 296376 times.
|
823808 | *this->lowDimCouplingContext().bulkLocalResidual, |
194 | scvfList); | ||
195 | } | ||
196 | |||
197 | 152185 | return sources; | |
198 | } | ||
199 | |||
200 | /*! | ||
201 | * \brief Extend the jacobian pattern of the diagonal block of the lowdim domain | ||
202 | * by the elements that are in the coupling stencil of the neighboring bulk elements | ||
203 | */ | ||
204 | template<class JacobianPattern> | ||
205 | 15 | void extendJacobianPattern(LowDimIdType, JacobianPattern& pattern) const | |
206 | { | ||
207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
15 | const auto& lowDimFVGridGeometry = this->problem(lowDimId).gridGeometry(); |
208 |
4/4✓ Branch 2 taken 480 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 480 times.
✓ Branch 5 taken 13 times.
|
710 | for (const auto& element : elements(lowDimFVGridGeometry.gridView())) |
209 | { | ||
210 | |||
211 | 1360 | const auto eIdx = lowDimFVGridGeometry.elementMapper().index(element); | |
212 | 1360 | const auto& map = couplingMapperPtr_->couplingMap(lowDimGridId, bulkGridId); | |
213 | 680 | auto it = map.find(eIdx); | |
214 | |||
215 | // if element is coupled, take one of the neighbors and add coupling stencil to pattern | ||
216 |
2/4✓ Branch 0 taken 480 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 480 times.
✗ Branch 3 not taken.
|
1360 | if (it != map.end()) |
217 | { | ||
218 | // coupling stencil of the first neighbor | ||
219 | 680 | const auto bulkElemIdx = it->second.embedments[0].first; | |
220 | 2040 | const auto& bulkMapEntry = couplingMapperPtr_->couplingMap(bulkGridId, lowDimGridId).at(bulkElemIdx); | |
221 | 680 | const auto& couplingStencil = bulkMapEntry.couplingStencil; | |
222 | |||
223 |
4/4✓ Branch 0 taken 1458 times.
✓ Branch 1 taken 480 times.
✓ Branch 2 taken 1458 times.
✓ Branch 3 taken 480 times.
|
6236 | for (auto globalJ : couplingStencil) |
224 | { | ||
225 | if (lowDimUsesBox) | ||
226 | { | ||
227 | for (int i = 0; i < element.subEntities(lowDimDim); ++i) | ||
228 | pattern.add(lowDimFVGridGeometry.vertexMapper().subIndex(element, i, lowDimDim), globalJ); | ||
229 | } | ||
230 | else | ||
231 | 2098 | pattern.add(eIdx, globalJ); | |
232 | } | ||
233 | } | ||
234 | } | ||
235 | 15 | } | |
236 | |||
237 | //! The bulk domain has no extended jacobian pattern | ||
238 | template<class JacobianPattern> | ||
239 | ✗ | void extendJacobianPattern(BulkIdType, JacobianPattern& pattern) const | |
240 | ✗ | {} | |
241 | |||
242 | /*! | ||
243 | * \brief evaluate additional derivatives of the element residual of the low-dim domain with respect | ||
244 | * to dofs in the same domain that are not in the regular stencil (see extendJacobianPattern) | ||
245 | * \note Here, this is the change of the source term with respect to changes in the variables of the | ||
246 | * other elements in the coupling stencil of the neighboring bulk elements. | ||
247 | */ | ||
248 | template<class LowDimLocalAssembler, class JacobianMatrixDiagBlock, class GridVariables> | ||
249 | 3503 | void evalAdditionalDomainDerivatives(LowDimIdType, | |
250 | const LowDimLocalAssembler& lowDimLocalAssembler, | ||
251 | const typename LowDimLocalAssembler::LocalResidual::ElementResidualVector&, | ||
252 | JacobianMatrixDiagBlock& A, | ||
253 | GridVariables& gridVariables) | ||
254 | { | ||
255 | // Since coupling only occurs via the fluxes, there are no | ||
256 | // additional derivatives for explicit time integration schemes | ||
257 | if (!LowDimLocalAssembler::isImplicit()) | ||
258 | return; | ||
259 | |||
260 | // lambda to update the coupling context for a given lowDim element/dofIdx | ||
261 | 176663 | auto updateContext = [&] (auto elemIdx, auto dofIdx, auto priVars, auto pvIdx) | |
262 | { | ||
263 | // deflect the solution | ||
264 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
|
28860 | auto& ldSol = this->curSol(lowDimId); |
265 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25272 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25272 times.
|
79404 | ldSol[dofIdx][pvIdx] = priVars[pvIdx]; |
266 | |||
267 | // update the corresponding vol vars in the bulk context | ||
268 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
|
28860 | assert(this->bulkCouplingContext().isSet); |
269 | 57720 | const auto& bulkMap = couplingMapperPtr_->couplingMap(bulkGridId, lowDimGridId); | |
270 | 57720 | const auto& couplingElementStencil = bulkMap.find(this->bulkCouplingContext().elementIdx)->second.couplingElementStencil; | |
271 | |||
272 | 86580 | auto it = std::find(couplingElementStencil.begin(), couplingElementStencil.end(), elemIdx); | |
273 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28860 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 28860 times.
|
86580 | assert(it != couplingElementStencil.end()); |
274 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28860 times.
|
57720 | const auto idxInContext = std::distance(couplingElementStencil.begin(), it); |
275 | |||
276 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
|
28860 | auto& volVars = this->bulkCouplingContext().lowDimVolVars[idxInContext]; |
277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
|
28860 | const auto& fvGeom = this->bulkCouplingContext().lowDimFvGeometries[idxInContext]; |
278 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
✓ Branch 2 taken 25272 times.
✓ Branch 3 taken 3588 times.
✓ Branch 4 taken 25272 times.
✓ Branch 5 taken 3588 times.
|
28860 | const auto& element = this->problem(lowDimId).gridGeometry().element(elemIdx); |
279 | |||
280 | // if low dim domain uses the box scheme, we have to create interpolated vol vars | ||
281 | if (lowDimUsesBox) | ||
282 | { | ||
283 | const auto elemGeom = element.geometry(); | ||
284 | FacetCoupling::makeInterpolatedVolVars(volVars, this->problem(lowDimId), ldSol, fvGeom, element, elemGeom, elemGeom.center()); | ||
285 | } | ||
286 | // if low dim domain uses a cc scheme we can directly update the vol vars | ||
287 | else | ||
288 |
3/4✓ Branch 0 taken 25272 times.
✓ Branch 1 taken 3588 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28860 times.
|
54132 | volVars.update( elementSolution(element, ldSol, this->problem(lowDimId).gridGeometry()), |
289 | this->problem(lowDimId), | ||
290 | element, | ||
291 | fvGeom.scv(elemIdx) ); | ||
292 | |||
293 | // update the element flux variables cache (tij depend on low dim values in context) | ||
294 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28860 times.
|
57720 | const auto contextElem = this->problem(bulkId).gridGeometry().element(this->bulkCouplingContext().elementIdx); |
295 |
2/4✓ Branch 1 taken 28860 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28860 times.
✗ Branch 5 not taken.
|
57720 | this->lowDimCouplingContext().bulkElemFluxVarsCache->update(contextElem, |
296 |
1/2✓ Branch 1 taken 28860 times.
✗ Branch 2 not taken.
|
28860 | *this->lowDimCouplingContext().bulkFvGeometry, |
297 |
1/2✓ Branch 1 taken 28860 times.
✗ Branch 2 not taken.
|
28860 | *this->lowDimCouplingContext().bulkElemVolVars); |
298 | }; | ||
299 | |||
300 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3503 times.
|
3503 | const auto eIdx = this->problem(lowDimId).gridGeometry().elementMapper().index(lowDimLocalAssembler.element()); |
301 | |||
302 | // bug tracking | ||
303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3503 times.
|
3503 | assert(this->lowDimCouplingContext().isSet); |
304 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3503 times.
|
3503 | assert(this->lowDimCouplingContext().elementIdx == eIdx); |
305 | |||
306 | // if the element is coupled, evaluate additional source derivatives | ||
307 | 7006 | const auto& map = couplingMapperPtr_->couplingMap(lowDimGridId, bulkGridId); | |
308 | 3503 | auto it = map.find(eIdx); | |
309 |
2/4✓ Branch 0 taken 3503 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3503 times.
✗ Branch 3 not taken.
|
7006 | if (it != map.end()) |
310 | 3503 | evalLowDimSourceDerivatives_(updateContext, lowDimLocalAssembler, A); | |
311 | } | ||
312 | |||
313 | //! The bulk domain has no additional derivatives | ||
314 | template<class LocalAssemblerI, class JacobianMatrixDiagBlock, class GridVariables> | ||
315 | ✗ | void evalAdditionalDomainDerivatives(BulkIdType, | |
316 | const LocalAssemblerI& localAssemblerI, | ||
317 | const typename LocalAssemblerI::LocalResidual::ElementResidualVector& origResiduals, | ||
318 | JacobianMatrixDiagBlock& A, | ||
319 | GridVariables& gridVariables) | ||
320 | ✗ | {} | |
321 | |||
322 | private: | ||
323 | //! evaluates the additional source derivatives w.r.t. to neighboring elements | ||
324 | template<class UpdateContext, class LowDimLocalAssembler, class JacobianMatrixDiagBlock> | ||
325 | 3503 | void evalLowDimSourceDerivatives_(const UpdateContext& updateContext, | |
326 | const LowDimLocalAssembler& lowDimLocalAssembler, | ||
327 | JacobianMatrixDiagBlock& A) | ||
328 | { | ||
329 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3503 times.
|
3503 | const auto& lowDimFVGridGeometry = this->problem(lowDimId).gridGeometry(); |
330 | 7006 | const auto eIdx = lowDimFVGridGeometry.elementMapper().index(lowDimLocalAssembler.element()); | |
331 | |||
332 | // coupling stencil of the first neighbor | ||
333 | 3503 | const auto bulkElemIdx = this->bulkCouplingContext().elementIdx; | |
334 | 10509 | const auto& bulkMapEntry = couplingMapperPtr_->couplingMap(bulkGridId, lowDimGridId).at(bulkElemIdx); | |
335 | 3503 | const auto& couplingStencil = bulkMapEntry.couplingStencil; | |
336 | 3503 | const auto& couplingElementStencil = bulkMapEntry.couplingElementStencil; | |
337 | |||
338 | // compute the undeflected residual (reuse coupling residual function) | ||
339 | 3503 | const auto origResidual = evalCouplingResidual(lowDimId, lowDimLocalAssembler, bulkId); | |
340 | |||
341 | // container of dofs within this element | ||
342 |
2/4✓ Branch 1 taken 3503 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3503 times.
✗ Branch 4 not taken.
|
7006 | std::vector< std::decay_t<decltype(couplingStencil[0])> > elemDofs; |
343 |
3/6✓ Branch 1 taken 3503 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3503 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3503 times.
✗ Branch 8 not taken.
|
10509 | elemDofs.reserve(lowDimLocalAssembler.fvGeometry().numScv()); |
344 |
2/2✓ Branch 0 taken 3503 times.
✓ Branch 1 taken 3503 times.
|
14012 | for (const auto& scv : scvs(lowDimLocalAssembler.fvGeometry())) |
345 |
2/6✓ Branch 1 taken 3503 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3503 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
7006 | elemDofs.push_back(scv.dofIndex()); |
346 | |||
347 | // compute derivate for all additional dofs in the stencil | ||
348 |
4/4✓ Branch 0 taken 10159 times.
✓ Branch 1 taken 3503 times.
✓ Branch 2 taken 10159 times.
✓ Branch 3 taken 3503 times.
|
20668 | for (const auto couplingElemIdx : couplingElementStencil) |
349 | { | ||
350 | // skip the same element | ||
351 |
2/2✓ Branch 0 taken 3503 times.
✓ Branch 1 taken 6656 times.
|
10159 | if (couplingElemIdx == eIdx) |
352 | 3503 | continue; | |
353 | |||
354 | // container of dofs within the other element | ||
355 |
2/6✓ Branch 1 taken 6656 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6656 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
19968 | std::vector< std::decay_t<decltype(couplingStencil[0])> > elemDofsJ; |
356 | if (lowDimUsesBox) | ||
357 | { | ||
358 | const auto& elemJ = lowDimFVGridGeometry.element(couplingElemIdx); | ||
359 | for (int i = 0; i < elemJ.subEntities(lowDimDim); ++i) | ||
360 | elemDofsJ.push_back(lowDimFVGridGeometry.vertexMapper().subIndex(elemJ, i, lowDimDim)); | ||
361 | } | ||
362 | else | ||
363 |
1/2✓ Branch 1 taken 6656 times.
✗ Branch 2 not taken.
|
6656 | elemDofsJ.push_back(couplingElemIdx); |
364 | |||
365 |
4/4✓ Branch 0 taken 6656 times.
✓ Branch 1 taken 6656 times.
✓ Branch 2 taken 6656 times.
✓ Branch 3 taken 6656 times.
|
26624 | for (auto dofIndex : elemDofsJ) |
366 | { | ||
367 | 6656 | auto partialDerivs = origResidual; | |
368 | 13312 | const auto origPriVars = this->curSol(lowDimId)[dofIndex]; | |
369 | |||
370 | // calculate derivatives w.r.t to the privars at the dof at hand | ||
371 | static constexpr auto numEq = std::decay_t<decltype(origPriVars)>::dimension; | ||
372 |
2/2✓ Branch 0 taken 14430 times.
✓ Branch 1 taken 6656 times.
|
21086 | for (int pvIdx = 0; pvIdx < numEq; pvIdx++) |
373 | { | ||
374 | // reset partial derivatives | ||
375 | 14430 | partialDerivs = 0.0; | |
376 | |||
377 | 55926 | auto evalResiduals = [&](Scalar<lowDimId> priVar) | |
378 | { | ||
379 | 12636 | auto priVars = origPriVars; | |
380 | 14430 | priVars[pvIdx] = priVar; | |
381 | |||
382 | // Update context to deflected solution and reevaluate residual | ||
383 | 14430 | updateContext(couplingElemIdx, dofIndex, priVars, pvIdx); | |
384 | 14430 | return this->evalCouplingResidual(lowDimId, lowDimLocalAssembler, bulkId); | |
385 | }; | ||
386 | |||
387 |
6/10✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14418 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
|
14430 | static const int numDiffMethod = getParamFromGroup<int>(this->problem(lowDimId).paramGroup(), "Assembly.NumericDifferenceMethod"); |
388 |
6/10✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14418 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
|
14430 | static const NumericEpsilon< Scalar<lowDimId>, numEq > eps{this->problem(lowDimId).paramGroup()}; |
389 |
2/4✓ Branch 1 taken 14430 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12636 times.
✗ Branch 5 not taken.
|
27066 | NumericDifferentiation::partialDerivative(evalResiduals, origPriVars[pvIdx], partialDerivs, |
390 | 27066 | origResidual, eps(origPriVars[pvIdx], pvIdx), numDiffMethod); | |
391 | |||
392 | // update the global stiffness matrix with the current partial derivatives | ||
393 | // A[i][col][eqIdx][pvIdx] is the rate of change of the residual of equation | ||
394 | // 'eqIdx' at dof 'i' depending on the primary variable 'pvIdx' at dof 'col'. | ||
395 |
2/2✓ Branch 0 taken 14430 times.
✓ Branch 1 taken 14430 times.
|
28860 | for (const auto& scv : scvs(lowDimLocalAssembler.fvGeometry())) |
396 |
2/2✓ Branch 0 taken 35802 times.
✓ Branch 1 taken 14430 times.
|
50232 | for (int eqIdx = 0; eqIdx < numEq; eqIdx++) |
397 |
5/10✓ Branch 1 taken 35802 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35802 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 35802 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 35802 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 34008 times.
✗ Branch 14 not taken.
|
177216 | A[scv.dofIndex()][dofIndex][eqIdx][pvIdx] += partialDerivs[scv.indexInElement()][eqIdx]; |
398 | |||
399 | // restore the original coupling context | ||
400 |
1/2✓ Branch 1 taken 14430 times.
✗ Branch 2 not taken.
|
14430 | updateContext(couplingElemIdx, dofIndex, origPriVars, pvIdx); |
401 | } | ||
402 | } | ||
403 | } | ||
404 | 3503 | } | |
405 | |||
406 | //! store which scvfs coincide with facet element | ||
407 | std::vector<bool> bulkScvfIsOnFacetElement_; | ||
408 | |||
409 | //! store shared_ptr to coupling mapper | ||
410 | std::shared_ptr< CouplingMapper > couplingMapperPtr_; | ||
411 | }; | ||
412 | |||
413 | } // end namespace Dumux | ||
414 | |||
415 | #endif | ||
416 |