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 EmbeddedCoupling | ||
10 | * \brief Extended source stencil helper class for coupling managers | ||
11 | */ | ||
12 | |||
13 | #ifndef DUMUX_MULTIDOMAIN_EMBEDDED_EXTENDEDSOURCESTENCIL_HH | ||
14 | #define DUMUX_MULTIDOMAIN_EMBEDDED_EXTENDEDSOURCESTENCIL_HH | ||
15 | |||
16 | #include <vector> | ||
17 | |||
18 | #include <dune/common/indices.hh> | ||
19 | |||
20 | #include <dumux/common/properties.hh> | ||
21 | #include <dumux/common/parameters.hh> | ||
22 | #include <dumux/common/numericdifferentiation.hh> | ||
23 | #include <dumux/assembly/numericepsilon.hh> | ||
24 | |||
25 | #include <dumux/discretization/method.hh> | ||
26 | |||
27 | namespace Dumux::EmbeddedCoupling { | ||
28 | |||
29 | /*! | ||
30 | * \ingroup EmbeddedCoupling | ||
31 | * \brief A class managing an extended source stencil | ||
32 | * \tparam CouplingManager the coupling manager type | ||
33 | */ | ||
34 | template<class CouplingManager> | ||
35 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
34 | class ExtendedSourceStencil |
36 | { | ||
37 | using MDTraits = typename CouplingManager::MultiDomainTraits; | ||
38 | using Scalar = typename MDTraits::Scalar; | ||
39 | |||
40 | template<std::size_t id> using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag; | ||
41 | template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; | ||
42 | template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; | ||
43 | template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; | ||
44 | |||
45 | static constexpr auto bulkIdx = typename MDTraits::template SubDomain<0>::Index(); | ||
46 | static constexpr auto lowDimIdx = typename MDTraits::template SubDomain<1>::Index(); | ||
47 | |||
48 | template<std::size_t id> | ||
49 | static constexpr bool isBox() | ||
50 | { return GridGeometry<id>::discMethod == DiscretizationMethods::box; } | ||
51 | public: | ||
52 | /*! | ||
53 | * \brief extend the jacobian pattern of the diagonal block of domain i | ||
54 | * by those entries that are not already in the uncoupled pattern | ||
55 | * \note Such additional dependencies can arise from the coupling, e.g. if a coupling source | ||
56 | * term depends on a non-local average of a quantity of the same domain | ||
57 | */ | ||
58 | template<std::size_t id, class JacobianPattern> | ||
59 | 92 | void extendJacobianPattern(const CouplingManager& couplingManager, Dune::index_constant<id> domainI, JacobianPattern& pattern) const | |
60 | { | ||
61 | // add additional dof dependencies | ||
62 |
6/8✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✓ Branch 3 taken 954038 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 11662 times.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8424 times.
|
3792832 | for (const auto& element : elements(couplingManager.gridView(domainI))) |
63 | { | ||
64 | 1924800 | const auto& dofs = extendedSourceStencil_(couplingManager, domainI, element); | |
65 | if constexpr (isBox<domainI>()) | ||
66 | { | ||
67 |
5/5✓ Branch 0 taken 80 times.
✓ Branch 1 taken 123608 times.
✓ Branch 2 taken 15526 times.
✓ Branch 3 taken 123608 times.
✓ Branch 4 taken 15446 times.
|
278348 | for (int i = 0; i < element.subEntities(GridView<domainI>::dimension); ++i) |
68 |
4/4✓ Branch 0 taken 45776 times.
✓ Branch 1 taken 123648 times.
✓ Branch 2 taken 45776 times.
✓ Branch 3 taken 123648 times.
|
924992 | for (const auto globalJ : dofs) |
69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45776 times.
|
91552 | pattern.add(couplingManager.problem(domainI).gridGeometry().vertexMapper().subIndex(element, i, GridView<domainI>::dimension), globalJ); |
70 | } | ||
71 | else | ||
72 | { | ||
73 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 930106 times.
|
1910756 | const auto globalI = couplingManager.problem(domainI).gridGeometry().elementMapper().index(element); |
74 |
4/4✓ Branch 0 taken 67718 times.
✓ Branch 1 taken 938530 times.
✓ Branch 2 taken 67718 times.
✓ Branch 3 taken 938530 times.
|
5902052 | for (const auto globalJ : dofs) |
75 | 135436 | pattern.add(globalI, globalJ); | |
76 | } | ||
77 | } | ||
78 | 92 | } | |
79 | |||
80 | /*! | ||
81 | * \brief evaluate additional derivatives of the element residual of a domain with respect | ||
82 | * to dofs in the same domain that are not in the regular stencil (per default this is not the case) | ||
83 | * \note Such additional dependencies can arise from the coupling, e.g. if a coupling source | ||
84 | * term depends on a non-local average of a quantity of the same domain | ||
85 | * \note This is the same for box and cc | ||
86 | */ | ||
87 | template<std::size_t i, class LocalAssemblerI, class JacobianMatrixDiagBlock, class GridVariables> | ||
88 | 13157336 | void evalAdditionalDomainDerivatives(CouplingManager& couplingManager, | |
89 | Dune::index_constant<i> domainI, | ||
90 | const LocalAssemblerI& localAssemblerI, | ||
91 | JacobianMatrixDiagBlock& A, | ||
92 | GridVariables& gridVariables) const | ||
93 | { | ||
94 |
1/2✓ Branch 0 taken 856990 times.
✗ Branch 1 not taken.
|
13157336 | const auto& curSolI = couplingManager.curSol(domainI); |
95 | 13157336 | constexpr auto numEq = std::decay_t<decltype(curSolI[0])>::size(); | |
96 | 13157336 | const auto& elementI = localAssemblerI.element(); | |
97 | |||
98 | // only do something if we have an extended stencil | ||
99 |
5/5✓ Branch 0 taken 856990 times.
✓ Branch 1 taken 5516791 times.
✓ Branch 2 taken 204887 times.
✓ Branch 3 taken 5516791 times.
✓ Branch 4 taken 204887 times.
|
13157336 | if (extendedSourceStencil_(couplingManager, domainI, elementI).empty()) |
100 | 12747562 | return; | |
101 | |||
102 | // compute the undeflected residual (source only!) | ||
103 | 409774 | const auto origResidual = localAssemblerI.evalLocalSourceResidual(elementI); | |
104 | |||
105 | // compute derivate for all additional dofs in the circle stencil | ||
106 |
4/5✗ Branch 0 not taken.
✓ Branch 1 taken 654492 times.
✓ Branch 2 taken 204887 times.
✓ Branch 3 taken 654492 times.
✓ Branch 4 taken 204887 times.
|
1718758 | for (const auto dofIndex : extendedSourceStencil_(couplingManager, domainI, elementI)) |
107 | { | ||
108 | 1308984 | auto partialDerivs = origResidual; | |
109 | 1308984 | const auto origPriVars = curSolI[dofIndex]; | |
110 | 1308984 | auto priVars = origPriVars; | |
111 | |||
112 | // calculate derivatives w.r.t to the privars at the dof at hand | ||
113 |
2/2✓ Branch 0 taken 684582 times.
✓ Branch 1 taken 654492 times.
|
2678148 | for (int pvIdx = 0; pvIdx < numEq; pvIdx++) |
114 | { | ||
115 | // reset partial derivatives | ||
116 | 1369164 | partialDerivs = 0.0; | |
117 | |||
118 | 2738328 | const auto evalResiduals = [&](const Scalar priVar) | |
119 | { | ||
120 | // update the coupling context (solution vector and recompute element residual) | ||
121 | 1308984 | priVars[pvIdx] = priVar; | |
122 | 684582 | couplingManager.updateCouplingContext(domainI, localAssemblerI, domainI, dofIndex, priVars, pvIdx); | |
123 | 684582 | return localAssemblerI.evalLocalSourceResidual(elementI); | |
124 | }; | ||
125 | |||
126 | // derive the residuals numerically | ||
127 |
7/10✓ Branch 0 taken 25 times.
✓ Branch 1 taken 684557 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 23 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
|
1369164 | static const NumericEpsilon<Scalar, numEq> eps_{localAssemblerI.problem().paramGroup()}; |
128 |
7/10✓ Branch 0 taken 25 times.
✓ Branch 1 taken 684557 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 23 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
|
1369164 | static const int numDiffMethod = getParamFromGroup<int>(localAssemblerI.problem().paramGroup(), "Assembly.NumericDifferenceMethod"); |
129 | 4107492 | NumericDifferentiation::partialDerivative( | |
130 |
3/5✓ Branch 2 taken 624402 times.
✓ Branch 3 taken 60180 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 60180 times.
✗ Branch 7 not taken.
|
1489524 | evalResiduals, priVars[pvIdx], partialDerivs, origResidual, eps_(priVars[pvIdx], pvIdx), numDiffMethod |
131 | ); | ||
132 | |||
133 | // update the global stiffness matrix with the current partial derivatives | ||
134 |
4/4✓ Branch 0 taken 1116622 times.
✓ Branch 1 taken 684582 times.
✓ Branch 2 taken 1116622 times.
✓ Branch 3 taken 684582 times.
|
6340736 | for (const auto& scvJ : scvs(localAssemblerI.fvGeometry())) |
135 | { | ||
136 |
2/2✓ Branch 0 taken 1176802 times.
✓ Branch 1 taken 1116622 times.
|
4586848 | for (int eqIdx = 0; eqIdx < numEq; eqIdx++) |
137 | { | ||
138 | // A[i][col][eqIdx][pvIdx] is the rate of change of | ||
139 | // the residual of equation 'eqIdx' at dof 'i' | ||
140 | // depending on the primary variable 'pvIdx' at dof | ||
141 | // 'col'. | ||
142 |
5/10✓ Branch 1 taken 1176802 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1176802 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1176802 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 683042 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 120360 times.
✗ Branch 14 not taken.
|
8667616 | A[scvJ.dofIndex()][dofIndex][eqIdx][pvIdx] += partialDerivs[scvJ.indexInElement()][eqIdx]; |
143 | } | ||
144 | } | ||
145 | |||
146 | // restore the current element solution | ||
147 | 1489524 | priVars[pvIdx] = origPriVars[pvIdx]; | |
148 | |||
149 | // restore the original coupling context | ||
150 | 2738328 | couplingManager.updateCouplingContext(domainI, localAssemblerI, domainI, dofIndex, origPriVars, pvIdx); | |
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | //! clear the internal data | ||
156 | 12 | void clear() { sourceStencils_.clear(); } | |
157 | |||
158 | //! return a reference to the stencil | ||
159 | typename CouplingManager::template CouplingStencils<bulkIdx>& stencil() | ||
160 |
4/6✓ Branch 1 taken 67865 times.
✓ Branch 2 taken 48640 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 67865 times.
✓ Branch 5 taken 48640 times.
✗ Branch 6 not taken.
|
443517 | { return sourceStencils_; } |
161 | |||
162 | //! return a const reference to the stencil | ||
163 | const typename CouplingManager::template CouplingStencils<bulkIdx>& stencil() const | ||
164 | 1875744 | { return sourceStencils_; } | |
165 | |||
166 | private: | ||
167 | //! the extended source stencil due to the source average (always empty for lowdim, but may be filled for bulk) | ||
168 | template<std::size_t id> | ||
169 | 6872117 | const auto& extendedSourceStencil_(const CouplingManager& couplingManager, Dune::index_constant<id> domainId, const Element<id>& element) const | |
170 | { | ||
171 | if constexpr (domainId == bulkIdx) | ||
172 | { | ||
173 | 6872117 | const auto bulkElementIdx = couplingManager.problem(bulkIdx).gridGeometry().elementMapper().index(element); | |
174 | 20616351 | if (auto stencil = sourceStencils_.find(bulkElementIdx); stencil != sourceStencils_.end()) | |
175 | 10863430 | return stencil->second; | |
176 | } | ||
177 | |||
178 |
4/8✓ Branch 0 taken 856990 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 856990 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8424 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 8424 times.
|
4611632 | return couplingManager.emptyStencil(domainId); |
179 | } | ||
180 | |||
181 | //! the additional stencil for the kernel evaluations / circle averages | ||
182 | typename CouplingManager::template CouplingStencils<bulkIdx> sourceStencils_; | ||
183 | }; | ||
184 | |||
185 | } // end namespace Dumux::EmbeddedCoupling | ||
186 | |||
187 | #endif | ||
188 |