GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/multidomain/subdomainstaggeredlocalassembler.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 302 316 95.6%
Functions: 838 903 92.8%
Branches: 232 335 69.3%

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 StaggeredDiscretization
11 * \ingroup MultiDomain
12 * \brief A multidomain assembler for Jacobian and residual contribution per element (staggered method)
13 */
14 #ifndef DUMUX_MULTIDOMAIN_STAGGERED_LOCAL_ASSEMBLER_HH
15 #define DUMUX_MULTIDOMAIN_STAGGERED_LOCAL_ASSEMBLER_HH
16
17 #include <dune/common/reservedvector.hh>
18 #include <dune/common/indices.hh>
19 #include <dune/common/hybridutilities.hh>
20 #include <dune/grid/common/gridenums.hh> // for GhostEntity
21
22 #include <dumux/common/reservedblockvector.hh>
23 #include <dumux/common/properties.hh>
24 #include <dumux/common/parameters.hh>
25 #include <dumux/common/numericdifferentiation.hh>
26 #include <dumux/common/typetraits/utility.hh>
27 #include <dumux/assembly/diffmethod.hh>
28 #include <dumux/assembly/fvlocalassemblerbase.hh>
29 #include <dumux/discretization/staggered/elementsolution.hh>
30
31 namespace Dumux {
32
33 /*!
34 * \ingroup Assembly
35 * \ingroup StaggeredDiscretization
36 * \ingroup MultiDomain
37 * \brief A base class for all multidomain local assemblers (staggered)
38 * \tparam id the id of the sub domain
39 * \tparam TypeTag the TypeTag
40 * \tparam Assembler the assembler type
41 * \tparam Implementation the actual assembler implementation
42 * \tparam implicit whether the assembly is explicit or implicit in time
43 */
44 template<std::size_t id, class TypeTag, class Assembler, class Implementation, bool isImplicit = true>
45 2721144 class SubDomainStaggeredLocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler,Implementation, isImplicit>
46 {
47 using ParentType = FVLocalAssemblerBase<TypeTag, Assembler,Implementation, isImplicit>;
48
49 using Problem = GetPropType<TypeTag, Properties::Problem>;
50 using SolutionVector = typename Assembler::SolutionVector;
51
52 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
53 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
54 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
55 using Scalar = typename GridVariables::Scalar;
56
57 using ElementFaceVariables = typename GetPropType<TypeTag, Properties::GridFaceVariables>::LocalView;
58 using CellCenterResidualValue = typename ParentType::LocalResidual::CellCenterResidualValue;
59 using FaceResidualValue = typename ParentType::LocalResidual::FaceResidualValue;
60
61 using GridGeometry = typename GridVariables::GridGeometry;
62 using FVElementGeometry = typename GridGeometry::LocalView;
63 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
64 using GridView = typename GridGeometry::GridView;
65 using Element = typename GridView::template Codim<0>::Entity;
66
67 using CouplingManager = typename Assembler::CouplingManager;
68
69 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
70
71 public:
72 static constexpr auto domainId = typename Dune::index_constant<id>();
73 static constexpr auto cellCenterId = GridGeometry::cellCenterIdx();
74 static constexpr auto faceId = GridGeometry::faceIdx();
75
76 static constexpr auto numEqCellCenter = CellCenterResidualValue::dimension;
77 static constexpr auto faceOffset = numEqCellCenter;
78
79 using ParentType::ParentType;
80
81 5442288 explicit SubDomainStaggeredLocalAssemblerBase(const Assembler& assembler,
82 const Element& element,
83 const SolutionVector& curSol,
84 CouplingManager& couplingManager)
85 : ParentType(assembler,
86 element,
87 curSol,
88 localView(assembler.gridGeometry(domainId)),
89
1/2
✓ Branch 1 taken 2721144 times.
✗ Branch 2 not taken.
5442288 localView(assembler.gridVariables(domainId).curGridVolVars()),
90
1/2
✓ Branch 1 taken 2721144 times.
✗ Branch 2 not taken.
5442288 localView(assembler.gridVariables(domainId).prevGridVolVars()),
91
1/2
✓ Branch 1 taken 2721144 times.
✗ Branch 2 not taken.
5442288 localView(assembler.gridVariables(domainId).gridFluxVarsCache()),
92
1/2
✓ Branch 1 taken 2721144 times.
✗ Branch 2 not taken.
5442288 assembler.localResidual(domainId),
93 5442288 (element.partitionType() == Dune::GhostEntity))
94 5442288 , curElemFaceVars_(localView(assembler.gridVariables(domainId).curGridFaceVars()))
95 5442288 , prevElemFaceVars_(localView(assembler.gridVariables(domainId).prevGridFaceVars()))
96
1/2
✓ Branch 2 taken 2721144 times.
✗ Branch 3 not taken.
16326864 , couplingManager_(couplingManager)
97 5442288 {}
98
99 /*!
100 * \brief Computes the derivatives with respect to the given element and adds them
101 * to the global matrix. The element residual is written into the right hand side.
102 */
103 template<class JacobianMatrixRow, class SubResidual, class GridVariablesTuple>
104 2721144 void assembleJacobianAndResidual(JacobianMatrixRow& jacRow, SubResidual& res, GridVariablesTuple& gridVariables)
105 {
106
2/4
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1360572 times.
✗ Branch 5 not taken.
2721144 this->asImp_().bindLocalViews();
107
2/4
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1360572 times.
✗ Branch 5 not taken.
2721144 this->elemBcTypes().update(problem(), this->element(), this->fvGeometry());
108
109
2/4
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1360572 times.
✗ Branch 5 not taken.
2721144 assembleJacobianAndResidualImpl_(domainId, jacRow, res, gridVariables);
110 2721144 }
111
112 /*!
113 * \brief Assemble the residual only
114 */
115 template<class SubResidual>
116 void assembleResidual(SubResidual& res)
117 {
118 this->asImp_().bindLocalViews();
119 this->elemBcTypes().update(problem(), this->element(), this->fvGeometry());
120
121 if constexpr (domainId == cellCenterId)
122 {
123 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
124 res[cellCenterGlobalI] = this->asImp_().assembleCellCenterResidualImpl();
125 }
126 else
127 {
128 for (auto&& scvf : scvfs(this->fvGeometry()))
129 res[scvf.dofIndex()] += this->asImp_().assembleFaceResidualImpl(scvf);
130 }
131 }
132
133 /*!
134 * \brief Convenience function to evaluate the complete local residual for the current element. Automatically chooses the the appropriate
135 * element volume variables.
136 */
137 41655204 CellCenterResidualValue evalLocalResidualForCellCenter() const
138 {
139 if (!isImplicit)
140 if (this->assembler().isStationaryProblem())
141 DUNE_THROW(Dune::InvalidStateException, "Using explicit jacobian assembler with stationary local residual");
142
143
3/4
✓ Branch 0 taken 3620 times.
✓ Branch 1 taken 37902636 times.
✓ Branch 2 taken 5200 times.
✗ Branch 3 not taken.
38985684 if (this->elementIsGhost())
144 {
145 return CellCenterResidualValue(0.0);
146 }
147
148 40126080 return isImplicit ? evalLocalResidualForCellCenter(this->curElemVolVars(), this->curElemFaceVars())
149 41300216 : evalLocalResidualForCellCenter(this->prevElemVolVars(), this->prevElemFaceVars());
150 }
151
152 /*!
153 * \brief Evaluates the complete local residual for the current cell center.
154 * \param elemVolVars The element volume variables
155 * \param elemFaceVars The element face variables
156 */
157 41655204 CellCenterResidualValue evalLocalResidualForCellCenter(const ElementVolumeVariables& elemVolVars,
158 const ElementFaceVariables& elemFaceVars) const
159 {
160 41655204 auto residual = evalLocalFluxAndSourceResidualForCellCenter(elemVolVars, elemFaceVars);
161
162
2/2
✓ Branch 0 taken 38681184 times.
✓ Branch 1 taken 2974020 times.
41655204 if (!this->assembler().isStationaryProblem())
163
2/2
✓ Branch 0 taken 124922520 times.
✓ Branch 1 taken 34154700 times.
167351640 residual += evalLocalStorageResidualForCellCenter();
164
165 // handle cells with a fixed Dirichlet value
166 41655204 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
167 41655204 const auto& scvI = this->fvGeometry().scv(cellCenterGlobalI);
168
2/2
✓ Branch 0 taken 92426480 times.
✓ Branch 1 taken 25243500 times.
134081684 for (int pvIdx = 0; pvIdx < numEqCellCenter; ++pvIdx)
169 {
170 static constexpr auto offset = numEq - numEqCellCenter;
171
3/3
✓ Branch 1 taken 58402008 times.
✓ Branch 2 taken 32608752 times.
✓ Branch 0 taken 1415720 times.
92426480 if (this->problem().isDirichletCell(this->element(), this->fvGeometry(), scvI, pvIdx + offset))
172 6605048 residual[pvIdx] = this->curSol()[cellCenterId][cellCenterGlobalI][pvIdx] - this->problem().dirichlet(this->element(), scvI)[pvIdx + offset];
173 }
174
175 41655204 return residual;
176 }
177
178 /*!
179 * \brief Convenience function to evaluate the flux and source terms (i.e, the terms without a time derivative)
180 * of the local residual for the current element. Automatically chooses the the appropriate
181 * element volume and face variables.
182 */
183 CellCenterResidualValue evalLocalFluxAndSourceResidualForCellCenter() const
184 {
185 return isImplicit ? evalLocalFluxAndSourceResidualForCellCenter(this->curElemVolVars(), this->curElemFaceVars())
186 : evalLocalFluxAndSourceResidualForCellCenter(this->prevElemVolVars(), this->prevElemFaceVars());
187 }
188
189 /*!
190 * \brief Evaluates the flux and source terms (i.e, the terms without a time derivative)
191 * of the local residual for the current element.
192 *
193 * \param elemVolVars The element volume variables
194 * \param elemFaceVars The element face variables
195 */
196 41655204 CellCenterResidualValue evalLocalFluxAndSourceResidualForCellCenter(const ElementVolumeVariables& elemVolVars, const ElementFaceVariables& elemFaceVars) const
197 {
198 41655204 return this->localResidual().evalFluxAndSourceForCellCenter(this->element(), this->fvGeometry(), elemVolVars, elemFaceVars, this->elemBcTypes(), this->elemFluxVarsCache());
199 }
200
201 /*!
202 * \brief Convenience function to evaluate storage term (i.e, the term with a time derivative)
203 * of the local residual for the current element. Automatically chooses the the appropriate
204 * element volume and face variables.
205 */
206 38681184 CellCenterResidualValue evalLocalStorageResidualForCellCenter() const
207 {
208 38681184 return this->localResidual().evalStorageForCellCenter(this->element(), this->fvGeometry(), this->prevElemVolVars(), this->curElemVolVars());
209 }
210
211 /*!
212 * \brief Convenience function to evaluate the local residual for the current face. Automatically chooses the the appropriate
213 * element volume and face variables.
214 * \param scvf The sub control volume face
215 */
216 151443068 FaceResidualValue evalLocalResidualForFace(const SubControlVolumeFace& scvf) const
217 {
218 if (!isImplicit)
219 if (this->assembler().isStationaryProblem())
220 DUNE_THROW(Dune::InvalidStateException, "Using explicit jacobian assembler with stationary local residual");
221
222
2/4
✓ Branch 0 taken 11340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22912 times.
✗ Branch 3 not taken.
129791388 if (this->elementIsGhost())
223 {
224 return FaceResidualValue(0.0);
225 }
226
227 81212752 return isImplicit ? evalLocalResidualForFace(scvf, this->curElemVolVars(), this->curElemFaceVars())
228 151443068 : evalLocalResidualForFace(scvf, this->prevElemVolVars(), this->prevElemFaceVars());
229 }
230
231 /*!
232 * \brief Evaluates the complete local residual for the current face.
233 * \param scvf The sub control volume face
234 * \param elemVolVars The element volume variables
235 * \param elemFaceVars The element face variables
236 */
237 151443068 FaceResidualValue evalLocalResidualForFace(const SubControlVolumeFace& scvf,
238 const ElementVolumeVariables& elemVolVars,
239 const ElementFaceVariables& elemFaceVars) const
240 {
241 151443068 auto residual = evalLocalFluxAndSourceResidualForFace(scvf, elemVolVars, elemFaceVars);
242
243
2/2
✓ Branch 0 taken 136711748 times.
✓ Branch 1 taken 14731320 times.
151443068 if (!this->assembler().isStationaryProblem())
244 136711748 residual += evalLocalStorageResidualForFace(scvf);
245
246 151443068 this->localResidual().evalDirichletBoundariesForFace(residual, this->problem(), this->element(),
247 151443068 this->fvGeometry(), scvf, elemVolVars, elemFaceVars,
248 151443068 this->elemBcTypes(), this->elemFluxVarsCache());
249
250 151443068 return residual;
251 }
252
253 /*!
254 * \brief Convenience function to evaluate the flux and source terms (i.e, the terms without a time derivative)
255 * of the local residual for the current element. Automatically chooses the the appropriate
256 * element volume and face variables.
257 * \param scvf The sub control volume face
258 */
259 FaceResidualValue evalLocalFluxAndSourceResidualForFace(const SubControlVolumeFace& scvf) const
260 {
261 return isImplicit ? evalLocalFluxAndSourceResidualForFace(scvf, this->curElemVolVars(), this->curElemFaceVars())
262 : evalLocalFluxAndSourceResidualForFace(scvf, this->prevElemVolVars(), this->prevElemFaceVars());
263 }
264
265 /*!
266 * \brief Evaluates the flux and source terms (i.e, the terms without a time derivative)
267 * of the local residual for the current face.
268 * \param scvf The sub control volume face
269 * \param elemVolVars The element volume variables
270 * \param elemFaceVars The element face variables
271 */
272 151443068 FaceResidualValue evalLocalFluxAndSourceResidualForFace(const SubControlVolumeFace& scvf,
273 const ElementVolumeVariables& elemVolVars,
274 const ElementFaceVariables& elemFaceVars) const
275 {
276 151443068 return this->localResidual().evalFluxAndSourceForFace(this->element(), this->fvGeometry(), elemVolVars, elemFaceVars, this->elemBcTypes(), this->elemFluxVarsCache(), scvf);
277 }
278
279 /*!
280 * \brief Convenience function to evaluate storage term (i.e, the term with a time derivative)
281 * of the local residual for the current face. Automatically chooses the the appropriate
282 * element volume and face variables.
283 * \param scvf The sub control volume face
284 */
285 136711748 FaceResidualValue evalLocalStorageResidualForFace(const SubControlVolumeFace& scvf) const
286 {
287 136711748 return this->localResidual().evalStorageForFace(this->element(), this->fvGeometry(), this->prevElemVolVars(), this->curElemVolVars(), this->prevElemFaceVars(), this->curElemFaceVars(), scvf);
288 }
289
290 296250350 const Problem& problem() const
291
7/10
✓ Branch 1 taken 1415720 times.
✓ Branch 2 taken 52769600 times.
✓ Branch 5 taken 1665872 times.
✓ Branch 6 taken 1195080 times.
✓ Branch 10 taken 621836 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 621836 times.
✗ Branch 14 not taken.
✓ Branch 8 taken 738736 times.
✗ Branch 9 not taken.
297361092 { return this->assembler().problem(domainId); }
292
293 //! The current element volume variables
294 ElementFaceVariables& curElemFaceVars()
295 50987424 { return curElemFaceVars_; }
296
297 //! The element volume variables of the provious time step
298 ElementFaceVariables& prevElemFaceVars()
299 { return prevElemFaceVars_; }
300
301 //! The current element volume variables
302 329810020 const ElementFaceVariables& curElemFaceVars() const
303
8/13
✓ Branch 1 taken 68787264 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 540936 times.
✓ Branch 7 taken 578560 times.
✓ Branch 9 taken 346352 times.
✓ Branch 10 taken 1327520 times.
✓ Branch 5 taken 3443776 times.
✓ Branch 3 taken 6983200 times.
✗ Branch 4 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✓ Branch 13 taken 1073600 times.
✗ Branch 14 not taken.
193098272 { return curElemFaceVars_; }
304
305 //! The element volume variables of the provious time step
306 136711748 const ElementFaceVariables& prevElemFaceVars() const
307 136711748 { return prevElemFaceVars_; }
308
309 296452238 CouplingManager& couplingManager()
310 298415840 { return couplingManager_; }
311
312 private:
313
314 //! Assembles the residuals and derivatives for the cell center dofs.
315 template<class JacobianMatrixRow, class SubResidual, class GridVariablesTuple>
316 1360572 auto assembleJacobianAndResidualImpl_(Dune::index_constant<cellCenterId>, JacobianMatrixRow& jacRow, SubResidual& res, GridVariablesTuple& gridVariables)
317 {
318 1360572 auto& gridVariablesI = *std::get<domainId>(gridVariables);
319 1360572 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
320 1360572 const auto residual = this->asImp_().assembleCellCenterJacobianAndResidualImpl(jacRow[domainId], gridVariablesI);
321 1360572 res[cellCenterGlobalI] = residual;
322
323
324 // for the coupling blocks
325 using namespace Dune::Hybrid;
326 static constexpr auto otherDomainIds = makeIncompleteIntegerSequence<JacobianMatrixRow::size(), domainId>{};
327 1360572 forEach(otherDomainIds, [&](auto&& domainJ)
328 {
329 1360572 this->asImp_().assembleJacobianCellCenterCoupling(domainJ, jacRow[domainJ], residual, gridVariablesI);
330 });
331
332 // handle cells with a fixed Dirichlet value
333 1360572 incorporateDirichletCells_(jacRow);
334 1360572 }
335
336 //! Assembles the residuals and derivatives for the face dofs.
337 template<class JacobianMatrixRow, class SubResidual, class GridVariablesTuple>
338 1360572 void assembleJacobianAndResidualImpl_(Dune::index_constant<faceId>, JacobianMatrixRow& jacRow, SubResidual& res, GridVariablesTuple& gridVariables)
339 {
340 1360572 auto& gridVariablesI = *std::get<domainId>(gridVariables);
341 1360572 const auto residual = this->asImp_().assembleFaceJacobianAndResidualImpl(jacRow[domainId], gridVariablesI);
342
343
2/2
✓ Branch 0 taken 5442288 times.
✓ Branch 1 taken 1360572 times.
6802860 for(auto&& scvf : scvfs(this->fvGeometry()))
344 5442288 res[scvf.dofIndex()] += residual[scvf.localFaceIdx()];
345
346 // for the coupling blocks
347 using namespace Dune::Hybrid;
348 static constexpr auto otherDomainIds = makeIncompleteIntegerSequence<JacobianMatrixRow::size(), domainId>{};
349
2/6
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1360572 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2721144 forEach(otherDomainIds, [&](auto&& domainJ)
350 {
351
1/2
✓ Branch 1 taken 947532 times.
✗ Branch 2 not taken.
1360572 this->asImp_().assembleJacobianFaceCoupling(domainJ, jacRow[domainJ], residual, gridVariablesI);
352 });
353 1360572 }
354
355 //! If specified in the problem, a fixed Dirichlet value can be assigned to cell centered unknowns such as pressure
356 template<class JacobianMatrixRow>
357 1360572 void incorporateDirichletCells_(JacobianMatrixRow& jacRow)
358 {
359 1360572 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
360
361 // overwrite the partial derivative with zero in case a fixed Dirichlet BC is used
362 static constexpr auto offset = numEq - numEqCellCenter;
363
2/2
✓ Branch 0 taken 2122216 times.
✓ Branch 1 taken 621836 times.
3482788 for (int eqIdx = 0; eqIdx < numEqCellCenter; ++eqIdx)
364 {
365
4/5
✓ Branch 1 taken 2094260 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 128178 times.
✓ Branch 4 taken 771002 times.
✓ Branch 0 taken 27956 times.
2122216 if (problem().isDirichletCell(this->element(), this->fvGeometry(), this->fvGeometry().scv(cellCenterGlobalI), eqIdx + offset))
366 {
367 using namespace Dune::Hybrid;
368
1/2
✓ Branch 1 taken 156134 times.
✗ Branch 2 not taken.
1561340 forEach(integralRange(Dune::Hybrid::size(jacRow)), [&, domainId = domainId](auto&& i)
369 {
370 312268 auto& ccRowI = jacRow[i][cellCenterGlobalI];
371
6/8
✗ Branch 0 not taken.
✓ Branch 1 taken 839581 times.
✓ Branch 2 taken 683447 times.
✓ Branch 3 taken 156134 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 780670 times.
✓ Branch 6 taken 624536 times.
✓ Branch 7 taken 156134 times.
1620251 for (auto col = ccRowI.begin(); col != ccRowI.end(); ++col)
372 {
373
2/2
✓ Branch 1 taken 1000 times.
✓ Branch 2 taken 2960 times.
1307983 ccRowI[col.index()][eqIdx] = 0.0;
374 // set the diagonal entry to 1.0
375
2/2
✓ Branch 0 taken 156134 times.
✓ Branch 1 taken 527313 times.
1307983 if ((i == domainId) && (col.index() == cellCenterGlobalI))
376 156134 ccRowI[col.index()][eqIdx][eqIdx] = 1.0;
377 }
378 });
379 }
380 }
381 621836 }
382
383 ElementFaceVariables curElemFaceVars_;
384 ElementFaceVariables prevElemFaceVars_;
385 CouplingManager& couplingManager_; //!< the coupling manager
386 };
387
388 /*!
389 * \ingroup Assembly
390 * \ingroup StaggeredDiscretization
391 * \ingroup MultiDomain
392 * \brief A base class for all implicit multidomain local assemblers (staggered)
393 * \tparam id the id of the sub domain
394 * \tparam TypeTag the TypeTag
395 * \tparam Assembler the assembler type
396 * \tparam Implementation the actual assembler implementation
397 */
398 template<std::size_t id, class TypeTag, class Assembler, class Implementation>
399 5442288 class SubDomainStaggeredLocalAssemblerImplicitBase : public SubDomainStaggeredLocalAssemblerBase<id, TypeTag, Assembler, Implementation>
400 {
401 using ParentType = SubDomainStaggeredLocalAssemblerBase<id, TypeTag, Assembler, Implementation>;
402 static constexpr auto domainId = Dune::index_constant<id>();
403 public:
404 2721144 using ParentType::ParentType;
405
406 5442288 void bindLocalViews()
407 {
408 // get some references for convenience
409 5442288 auto& couplingManager = this->couplingManager();
410 5442288 const auto& element = this->element();
411 5442288 const auto& curSol = this->curSol();
412 5442288 auto&& fvGeometry = this->fvGeometry();
413 5442288 auto&& curElemVolVars = this->curElemVolVars();
414 5442288 auto&& curElemFaceVars = this->curElemFaceVars();
415 5442288 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
416
417 // bind the caches
418 5442288 couplingManager.bindCouplingContext(domainId, element, this->assembler());
419 5442288 fvGeometry.bind(element);
420 5442288 curElemVolVars.bind(element, fvGeometry, curSol);
421 curElemFaceVars.bind(element, fvGeometry, curSol);
422 elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars);
423 5442288 if (!this->assembler().isStationaryProblem())
424 {
425 this->prevElemVolVars().bindElement(element, fvGeometry, this->assembler().prevSol());
426 this->prevElemFaceVars().bindElement(element, fvGeometry, this->assembler().prevSol());
427 }
428 5442288 }
429 };
430
431 /*!
432 * \ingroup Assembly
433 * \ingroup StaggeredDiscretization
434 * \ingroup MultiDomain
435 * \brief The staggered multidomain local assembler
436 * \tparam id the id of the sub domain
437 * \tparam TypeTag the TypeTag
438 * \tparam Assembler the assembler type
439 * \tparam DM the numeric differentiation method
440 * \tparam implicit whether the assembler is explicit or implicit in time
441 */
442 template<std::size_t id, class TypeTag, class Assembler, DiffMethod DM = DiffMethod::numeric, bool implicit = true>
443 class SubDomainStaggeredLocalAssembler;
444
445 /*!
446 * \ingroup Assembly
447 * \ingroup StaggeredDiscretization
448 * \ingroup MultiDomain
449 * \brief Staggered scheme local assembler using numeric differentiation and implicit time discretization
450 *
451 * The assembly of the cellCenterResidual is done element-wise, the assembly of the face residual is done half-element-wise.
452 *
453 * A sketch of what this means can be found in the following image:
454 *
455 * \image html staggered_halfelementwise.png
456 *
457 * Half-element wise assembly means, that integrals are
458 split into contributions from the left and right part of the staggered control volume. For an example term \f$\int_{\Omega}\varrho u\text{d}\Omega\f$ this reads
459 \f$\int_{\Omega}\varrho u\text{d}\Omega = \frac{1}{2}\Omega_\text{left}\varrho_\text{left}u+\frac{1}{2}\Omega_\text{right}\varrho_\text{right}u\f$.
460
461 During assembly, \f$\frac{1}{2}\Omega_\text{left}\varrho_\text{left}u\f$ is added to the residual of the
462 staggered control volume \f$\Omega\f$, when the loops reach the scvf within element \f$\Omega_\text{left}\f$. \f$\frac{1}{2}\Omega_\text{right}\varrho_\text{right}u\f$ is added to the residual of \f$\Omega\f$, when the loops reach the scvf within in element \f$\Omega_\text{right}\f$.
463 Other terms are split analogously.
464 */
465 template<std::size_t id, class TypeTag, class Assembler>
466 2721144 class SubDomainStaggeredLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>
467 : public SubDomainStaggeredLocalAssemblerImplicitBase<id, TypeTag, Assembler,
468 SubDomainStaggeredLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, true> >
469 {
470 using ThisType = SubDomainStaggeredLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>;
471 using ParentType = SubDomainStaggeredLocalAssemblerImplicitBase<id, TypeTag, Assembler, ThisType>;
472 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
473 using CellCenterResidualValue = typename ParentType::LocalResidual::CellCenterResidualValue;
474 using FaceResidualValue = typename ParentType::LocalResidual::FaceResidualValue;
475 using Element = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
476 using GridFaceVariables = GetPropType<TypeTag, Properties::GridFaceVariables>;
477 using ElementFaceVariables = typename GetPropType<TypeTag, Properties::GridFaceVariables>::LocalView;
478 using FaceVariables = typename ElementFaceVariables::FaceVariables;
479 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
480 using FVElementGeometry = typename GridGeometry::LocalView;
481 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
482 using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>;
483 using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>;
484 using FacePrimaryVariables = GetPropType<TypeTag, Properties::FacePrimaryVariables>;
485 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
486
487 static constexpr bool enableGridFluxVarsCache = GetPropType<TypeTag, Properties::GridVariables>::GridFluxVariablesCache::cachingEnabled;
488 static constexpr int maxNeighbors = 4*(2*ModelTraits::dim());
489 static constexpr auto domainI = Dune::index_constant<id>();
490 static constexpr auto cellCenterId = GridGeometry::cellCenterIdx();
491 static constexpr auto faceId = GridGeometry::faceIdx();
492
493 static constexpr auto numEq = ModelTraits::numEq();
494 static constexpr auto numEqCellCenter = CellCenterPrimaryVariables::dimension;
495 static constexpr auto numEqFace = FacePrimaryVariables::dimension;
496
497 public:
498
2/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 10 taken 1360572 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 1360572 times.
✗ Branch 15 not taken.
2721144 using ParentType::ParentType;
499
500 CellCenterResidualValue assembleCellCenterResidualImpl()
501 {
502 return this->evalLocalResidualForCellCenter();
503 }
504
505 FaceResidualValue assembleFaceResidualImpl(const SubControlVolumeFace& scvf)
506 {
507 return this->evalLocalResidualForFace(scvf);
508 }
509
510 /*!
511 * \brief Computes the derivatives with respect to the given element and adds them
512 * to the global matrix.
513 *
514 * \return The element residual at the current solution.
515 */
516 template<class JacobianMatrixDiagBlock, class GridVariables>
517 1360572 CellCenterResidualValue assembleCellCenterJacobianAndResidualImpl(JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
518 {
519 assert(domainI == cellCenterId);
520
521 // get some aliases for convenience
522 1360572 const auto& element = this->element();
523 1360572 const auto& fvGeometry = this->fvGeometry();
524 1360572 auto&& curElemVolVars = this->curElemVolVars();
525 1360572 const auto& gridGeometry = this->problem().gridGeometry();
526 1360572 const auto& curSol = this->curSol()[domainI];
527
528 1360572 const auto cellCenterGlobalI = gridGeometry.elementMapper().index(element);
529
1/2
✓ Branch 0 taken 354988 times.
✗ Branch 1 not taken.
1360572 const auto origResidual = this->evalLocalResidualForCellCenter();
530
531 /////////////////////////////////////////////////////////////////////////////////////////////////////////
532 // Calculate derivatives of all cell center residuals in the element w.r.t. to other cell center dofs. //
533 /////////////////////////////////////////////////////////////////////////////////////////////////////////
534
535 // lambda to evaluate the derivatives for cell center dofs with respect to neighbor cells
536 7863054 auto evaluateCellCenterDerivatives = [&](const std::size_t globalJ)
537 {
538 // get the volVars of the element with respect to which we are going to build the derivative
539 6502482 auto&& scvJ = fvGeometry.scv(globalJ);
540 6502482 const auto elementJ = fvGeometry.gridGeometry().element(globalJ);
541 6502482 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scvJ);
542 6502482 const auto origVolVars(curVolVars);
543
544
2/2
✓ Branch 0 taken 17234986 times.
✓ Branch 1 taken 6502482 times.
23737468 for (int pvIdx = 0; pvIdx < numEqCellCenter; ++pvIdx)
545 {
546
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1749274 times.
17234986 CellCenterPrimaryVariables cellCenterPriVars = curSol[globalJ];
547 using PrimaryVariables = typename VolumeVariables::PrimaryVariables;
548 17234986 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(cellCenterPriVars);
549
550 17234986 constexpr auto offset = numEq - numEqCellCenter;
551
552 48508950 auto evalResidual = [&](Scalar priVar)
553 {
554 // update the volume variables
555 31273964 priVars[pvIdx + offset] = priVar;
556 31273964 auto elemSol = elementSolution<FVElementGeometry>(std::move(priVars));
557
1/2
✓ Branch 1 taken 31273964 times.
✗ Branch 2 not taken.
31273964 curVolVars.update(elemSol, this->problem(), elementJ, scvJ);
558
559 // update the coupling context
560
2/2
✓ Branch 0 taken 1565888 times.
✓ Branch 1 taken 27839620 times.
31273964 cellCenterPriVars[pvIdx] = priVar;
561
2/2
✓ Branch 0 taken 2893408 times.
✓ Branch 1 taken 28380556 times.
31273964 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, cellCenterPriVars, pvIdx);
562
563 // compute element residual
564
3/4
✓ Branch 0 taken 1868456 times.
✓ Branch 1 taken 29405508 times.
✓ Branch 2 taken 1868456 times.
✗ Branch 3 not taken.
33142420 return this->evalLocalResidualForCellCenter();
565 31273964 };
566
567 // create the vector storing the partial derivatives
568 17234986 CellCenterResidualValue partialDeriv(0.0);
569
570 // derive the residuals numerically
571
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 17234935 times.
17234986 const auto& paramGroup = this->problem().paramGroup();
572
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 17234935 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
17234986 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
573
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 17234935 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
17234986 static const auto eps = this->couplingManager().numericEpsilon(domainI, paramGroup);
574 17234986 NumericDifferentiation::partialDerivative(evalResidual, priVars[pvIdx + offset], partialDeriv, origResidual,
575 17234986 eps(priVars[pvIdx + offset], pvIdx), numDiffMethod);
576
577 // update the global jacobian matrix with the current partial derivatives
578 17234986 updateGlobalJacobian_(A, cellCenterGlobalI, globalJ, pvIdx, partialDeriv);
579
580 // restore the original volVars
581 17234986 curVolVars = origVolVars;
582
583 // restore the undeflected state of the coupling context
584
2/2
✓ Branch 0 taken 2893408 times.
✓ Branch 1 taken 14341578 times.
20128394 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, curSol[globalJ], pvIdx);
585 }
586 };
587
588 // get the list of cell center dofs that have an influence on the cell center resdiual of the current element
589 1360572 const auto& connectivityMap = gridGeometry.connectivityMap();
590
591 // evaluate derivatives w.r.t. own dof
592 1360572 evaluateCellCenterDerivatives(cellCenterGlobalI);
593
594 // evaluate derivatives w.r.t. all other related cell center dofs
595
2/2
✓ Branch 0 taken 5141910 times.
✓ Branch 1 taken 1360572 times.
6502482 for (const auto& globalJ : connectivityMap(cellCenterId, cellCenterId, cellCenterGlobalI))
596 5141910 evaluateCellCenterDerivatives(globalJ);
597
598 1360572 return origResidual;
599 }
600
601 /*!
602 * \brief Computes the derivatives with respect to the given element and adds them
603 * to the global matrix.
604 *
605 * \return The element residual at the current solution.
606 */
607 template<class JacobianMatrixDiagBlock, class GridVariables>
608 1360572 auto assembleFaceJacobianAndResidualImpl(JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
609 {
610 assert(domainI == faceId);
611
612 // get some aliases for convenience
613
1/2
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
1360572 const auto& problem = this->problem();
614
1/2
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
1360572 const auto& element = this->element();
615
1/2
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
1360572 const auto& fvGeometry = this->fvGeometry();
616
1/2
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
1360572 const auto& gridGeometry = this->problem().gridGeometry();
617
1/2
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
1360572 const auto& curSol = this->curSol()[domainI];
618
619 using FaceSolutionVector = GetPropType<TypeTag, Properties::FaceSolutionVector>; // TODO: use reserved vector
620 1360572 FaceSolutionVector origResiduals;
621
1/2
✓ Branch 1 taken 1360572 times.
✗ Branch 2 not taken.
1360572 origResiduals.resize(fvGeometry.numScvf());
622 1360572 origResiduals = 0.0;
623
624 // treat the local residua of the face dofs:
625
2/2
✓ Branch 0 taken 5442288 times.
✓ Branch 1 taken 1360572 times.
6802860 for (auto&& scvf : scvfs(fvGeometry))
626
1/2
✓ Branch 0 taken 5442288 times.
✗ Branch 1 not taken.
10884576 origResiduals[scvf.localFaceIdx()] = this->evalLocalResidualForFace(scvf);
627
628 ///////////////////////////////////////////////////////////////////////////////////////////////////
629 // Calculate derivatives of all face residuals in the element w.r.t. to other face dofs. //
630 // Note that we do an element-wise assembly, therefore this is only the contribution of the //
631 // current element while the contribution of the element on the opposite side of the scvf will //
632 // be added separately. //
633 ///////////////////////////////////////////////////////////////////////////////////////////////////
634
635
3/4
✓ Branch 1 taken 5442288 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5442288 times.
✓ Branch 5 taken 1360572 times.
6802860 for (auto&& scvf : scvfs(fvGeometry))
636 {
637 // set the actual dof index
638 5442288 const auto faceGlobalI = scvf.dofIndex();
639
640 using FaceSolution = GetPropType<TypeTag, Properties::StaggeredFaceSolution>;
641
1/2
✓ Branch 1 taken 5442288 times.
✗ Branch 2 not taken.
5442288 const auto origFaceSolution = FaceSolution(scvf, curSol, gridGeometry);
642
643 // Lambda to evaluate the derivatives for faces
644
1/2
✓ Branch 1 taken 5442288 times.
✗ Branch 2 not taken.
48266280 auto evaluateFaceDerivatives = [&](const std::size_t globalJ)
645 {
646 // get the faceVars of the face with respect to which we are going to build the derivative
647 42823992 auto& faceVars = getFaceVarAccess_(gridVariables.curGridFaceVars(), this->curElemFaceVars(), scvf);
648 42823992 const auto origFaceVars = faceVars;
649
650
2/2
✓ Branch 0 taken 42823992 times.
✓ Branch 1 taken 42823992 times.
85647984 for (int pvIdx = 0; pvIdx < numEqFace; ++pvIdx)
651 {
652
1/2
✓ Branch 1 taken 42823992 times.
✗ Branch 2 not taken.
42823992 auto faceSolution = origFaceSolution;
653
654 113020056 auto evalResidual = [&](Scalar priVar)
655 {
656 // update the volume variables
657 70196064 faceSolution[globalJ][pvIdx] = priVar;
658 70196064 faceVars.update(faceSolution, problem, element, fvGeometry, scvf);
659
660 // update the coupling context
661
2/2
✓ Branch 1 taken 13016320 times.
✓ Branch 2 taken 57179744 times.
70196064 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, faceSolution[globalJ], pvIdx);
662
663 // compute face residual
664
1/2
✓ Branch 0 taken 70196064 times.
✗ Branch 1 not taken.
70196064 return this->evalLocalResidualForFace(scvf);
665 };
666
667 // derive the residuals numerically
668 42823992 FaceResidualValue partialDeriv(0.0);
669
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 42823941 times.
42823992 const auto& paramGroup = problem.paramGroup();
670
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 42823941 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
42823992 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
671
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 42823941 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
42823992 static const auto eps = this->couplingManager().numericEpsilon(domainI, paramGroup);
672
1/2
✓ Branch 1 taken 42823992 times.
✗ Branch 2 not taken.
42823992 NumericDifferentiation::partialDerivative(evalResidual, faceSolution[globalJ][pvIdx], partialDeriv, origResiduals[scvf.localFaceIdx()],
673 42823992 eps(faceSolution[globalJ][pvIdx], pvIdx), numDiffMethod);
674
675 // update the global jacobian matrix with the current partial derivatives
676
1/2
✓ Branch 1 taken 42823992 times.
✗ Branch 2 not taken.
42823992 updateGlobalJacobian_(A, faceGlobalI, globalJ, pvIdx, partialDeriv);
677
678 // restore the original faceVars
679 42823992 faceVars = origFaceVars;
680
681 // restore the undeflected state of the coupling context
682
2/2
✓ Branch 1 taken 13016320 times.
✓ Branch 2 taken 29807672 times.
55840312 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, origFaceSolution[globalJ], pvIdx);
683 }
684 };
685
686 // evaluate derivatives w.r.t. own dof
687
1/2
✓ Branch 1 taken 5442288 times.
✗ Branch 2 not taken.
5442288 evaluateFaceDerivatives(scvf.dofIndex());
688
689 // get the list of face dofs that have an influence on the resdiual of the current face
690 5442288 const auto& connectivityMap = gridGeometry.connectivityMap();
691
692 // evaluate derivatives w.r.t. all other related face dofs
693
2/2
✓ Branch 0 taken 37381704 times.
✓ Branch 1 taken 5442288 times.
42823992 for (const auto& globalJ : connectivityMap(faceId, faceId, scvf.index()))
694
1/2
✓ Branch 1 taken 37381704 times.
✗ Branch 2 not taken.
37381704 evaluateFaceDerivatives(globalJ);
695 }
696
697 1360572 return origResiduals;
698 }
699
700 /*!
701 * \brief Computes the derivatives with respect to the given element and adds them
702 * to the global matrix.
703 */
704 template<class JacobianBlock, class GridVariables>
705 1360572 void assembleJacobianCellCenterCoupling(Dune::index_constant<faceId> domainJ, JacobianBlock& A,
706 const CellCenterResidualValue& origResidual, GridVariables& gridVariables)
707 {
708 /////////////////////////////////////////////////////////////////////////////////////////////////////////
709 // Calculate derivatives of all cell center residuals in the element w.r.t. to all coupled faces dofs //
710 /////////////////////////////////////////////////////////////////////////////////////////////////////////
711
712 // get some aliases for convenience
713 1360572 const auto& element = this->element();
714 1360572 const auto& fvGeometry = this->fvGeometry();
715 1360572 const auto& gridGeometry = this->problem().gridGeometry();
716 1360572 const auto& curSol = this->curSol()[domainJ];
717 // build derivatives with for cell center dofs w.r.t. cell center dofs
718 1360572 const auto cellCenterGlobalI = gridGeometry.elementMapper().index(element);
719
720
2/2
✓ Branch 0 taken 5442288 times.
✓ Branch 1 taken 1360572 times.
6802860 for (const auto& scvfJ : scvfs(fvGeometry))
721 {
722 5442288 const auto globalJ = scvfJ.dofIndex();
723
724 // get the faceVars of the face with respect to which we are going to build the derivative
725 5442288 auto& faceVars = getFaceVarAccess_(gridVariables.curGridFaceVars(), this->curElemFaceVars(), scvfJ);
726 5442288 const auto origFaceVars(faceVars);
727
728
2/2
✓ Branch 0 taken 5442288 times.
✓ Branch 1 taken 5442288 times.
10884576 for (int pvIdx = 0; pvIdx < numEqFace; ++pvIdx)
729 {
730
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 5442237 times.
5442288 auto facePriVars = curSol[globalJ];
731
732 14428704 auto evalResidual = [&](Scalar priVar)
733 {
734 // update the face variables
735 8986416 facePriVars[pvIdx] = priVar;
736
2/2
✓ Branch 0 taken 1652160 times.
✓ Branch 1 taken 7334256 times.
8986416 faceVars.updateOwnFaceOnly(facePriVars);
737
738 // update the coupling context
739
2/2
✓ Branch 0 taken 1652160 times.
✓ Branch 1 taken 7334256 times.
8986416 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, facePriVars, pvIdx);
740
741 // compute element residual
742
1/2
✓ Branch 0 taken 1520304 times.
✗ Branch 1 not taken.
8986416 return this->evalLocalResidualForCellCenter();
743 };
744
745 // create the vector storing the partial derivatives
746 5442288 CellCenterResidualValue partialDeriv(0.0);
747
748 // derive the residuals numerically
749
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 5442237 times.
5442288 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
750
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 5442237 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
5442288 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
751
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 5442237 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
5442288 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
752
1/2
✓ Branch 1 taken 5442288 times.
✗ Branch 2 not taken.
5442288 NumericDifferentiation::partialDerivative(evalResidual, facePriVars[pvIdx], partialDeriv, origResidual,
753 5442288 epsCoupl(facePriVars[pvIdx], pvIdx), numDiffMethod);
754
755 // update the global jacobian matrix with the current partial derivatives
756
1/2
✓ Branch 1 taken 5442288 times.
✗ Branch 2 not taken.
5442288 updateGlobalJacobian_(A, cellCenterGlobalI, globalJ, pvIdx, partialDeriv);
757
758 // restore the original faceVars
759 5442288 faceVars = origFaceVars;
760
761 // restore the undeflected state of the coupling context
762
2/2
✓ Branch 0 taken 1652160 times.
✓ Branch 1 taken 3790128 times.
7094448 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, curSol[globalJ], pvIdx);
763 }
764 }
765 1360572 }
766
767 template<std::size_t otherId, class JacobianBlock, class GridVariables>
768 413040 void assembleJacobianCellCenterCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
769 const CellCenterResidualValue& res, GridVariables& gridVariables)
770 {
771 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
772 // Calculate derivatives of all cell center residuals in the element w.r.t. all dofs in the coupling stencil. //
773 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
774
775 // get some aliases for convenience
776 413040 const auto& element = this->element();
777
778 // get stencil information
779
2/2
✓ Branch 1 taken 11340 times.
✓ Branch 2 taken 401700 times.
413040 const auto& stencil = this->couplingManager().couplingStencil(domainI, element, domainJ);
780
781
2/2
✓ Branch 0 taken 11340 times.
✓ Branch 1 taken 401700 times.
413040 if (stencil.empty())
782 return;
783
784
2/2
✓ Branch 0 taken 11340 times.
✓ Branch 1 taken 11340 times.
22680 for (const auto globalJ : stencil)
785 {
786
1/2
✓ Branch 0 taken 3620 times.
✗ Branch 1 not taken.
11340 const auto origResidual = this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
787 11340 const auto& curSol = this->curSol()[domainJ];
788 11340 const auto origPriVarsJ = curSol[globalJ];
789
790
2/2
✓ Branch 0 taken 22912 times.
✓ Branch 1 taken 11340 times.
34252 for (int pvIdx = 0; pvIdx < JacobianBlock::block_type::cols; ++pvIdx)
791 {
792 45824 auto evalCouplingResidual = [&](Scalar priVar)
793 {
794 20872 auto deflectedPriVarsJ = origPriVarsJ;
795 22912 deflectedPriVarsJ[pvIdx] = priVar;
796 22912 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, deflectedPriVarsJ, pvIdx);
797
1/2
✓ Branch 0 taken 5200 times.
✗ Branch 1 not taken.
22912 return this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
798 };
799
800 // create the vector storing the partial derivatives
801 22912 CellCenterResidualValue partialDeriv(0.0);
802
803 // derive the residuals numerically
804
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22895 times.
22912 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
805
4/6
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22895 times.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
22912 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
806
4/6
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22895 times.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
22921 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
807 22912 NumericDifferentiation::partialDerivative(evalCouplingResidual, origPriVarsJ[pvIdx], partialDeriv, origResidual,
808 22912 epsCoupl(origPriVarsJ[pvIdx], pvIdx), numDiffMethod);
809
810 // update the global stiffness matrix with the current partial derivatives
811 22912 const auto cellCenterGlobalI = this->problem().gridGeometry().elementMapper().index(element);
812 22912 updateGlobalJacobian_(A, cellCenterGlobalI, globalJ, pvIdx, partialDeriv);
813
814 // restore the undeflected state of the coupling context
815 22912 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, origPriVarsJ, pvIdx);
816 }
817 }
818 }
819
820 /*!
821 * \brief Computes the derivatives with respect to the given element and adds them
822 * to the global matrix.
823 */
824 template<class JacobianBlock, class ElementResidualVector, class GridVariables>
825 1360572 void assembleJacobianFaceCoupling(Dune::index_constant<cellCenterId> domainJ, JacobianBlock& A,
826 const ElementResidualVector& origResiduals, GridVariables& gridVariables)
827 {
828 /////////////////////////////////////////////////////////////////////////////////////////////////////
829 // Calculate derivatives of all face residuals in the element w.r.t. all coupled cell center dofs //
830 /////////////////////////////////////////////////////////////////////////////////////////////////////
831
832 // get some aliases for convenience
833 1360572 const auto& problem = this->problem();
834 1360572 const auto& fvGeometry = this->fvGeometry();
835 1360572 const auto& gridGeometry = this->problem().gridGeometry();
836 1360572 const auto& connectivityMap = gridGeometry.connectivityMap();
837 1360572 const auto& curSol = this->curSol()[domainJ];
838
839 // build derivatives with for cell center dofs w.r.t. cell center dofs
840
2/2
✓ Branch 0 taken 5442288 times.
✓ Branch 1 taken 1360572 times.
6802860 for (auto&& scvf : scvfs(fvGeometry))
841 {
842 // set the actual dof index
843 5442288 const auto faceGlobalI = scvf.dofIndex();
844
845 // build derivatives with for face dofs w.r.t. cell center dofs
846
2/2
✓ Branch 0 taken 15726108 times.
✓ Branch 1 taken 5442288 times.
21168396 for (const auto& globalJ : connectivityMap(faceId, cellCenterId, scvf.index()))
847 {
848 // get the volVars of the element with respect to which we are going to build the derivative
849
1/2
✓ Branch 1 taken 15726108 times.
✗ Branch 2 not taken.
15726108 auto&& scvJ = fvGeometry.scv(globalJ);
850
1/2
✓ Branch 1 taken 15726108 times.
✗ Branch 2 not taken.
15726108 const auto elementJ = fvGeometry.gridGeometry().element(globalJ);
851 15726108 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), this->curElemVolVars(), scvJ);
852 15726108 const auto origVolVars(curVolVars);
853 15726108 const auto origCellCenterPriVars = curSol[globalJ];
854
855
2/2
✓ Branch 0 taken 41740932 times.
✓ Branch 1 taken 15726108 times.
57467040 for (int pvIdx = 0; pvIdx < numEqCellCenter; ++pvIdx)
856 {
857 using PrimaryVariables = typename VolumeVariables::PrimaryVariables;
858 41740932 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(origCellCenterPriVars);
859
860 41740932 constexpr auto offset = PrimaryVariables::dimension - CellCenterPrimaryVariables::dimension;
861
862 117511396 auto evalResidual = [&](Scalar priVar)
863 {
864 // update the volume variables
865 75770464 priVars[pvIdx + offset] = priVar;
866 75770464 auto elemSol = elementSolution<FVElementGeometry>(std::move(priVars));
867
1/2
✓ Branch 1 taken 75770464 times.
✗ Branch 2 not taken.
75770464 curVolVars.update(elemSol, problem, elementJ, scvJ);
868
869 // update the coupling context
870 75770464 auto deflectedCellCenterPriVars = origCellCenterPriVars;
871
2/2
✓ Branch 0 taken 3791360 times.
✓ Branch 1 taken 67482040 times.
75770464 deflectedCellCenterPriVars[pvIdx] = priVar;
872
2/2
✓ Branch 0 taken 6983200 times.
✓ Branch 1 taken 68787264 times.
75770464 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, deflectedCellCenterPriVars, pvIdx);
873
874 // compute face residual
875
2/4
✓ Branch 0 taken 75770464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75770464 times.
✗ Branch 3 not taken.
151540928 return this->evalLocalResidualForFace(scvf);
876 75770464 };
877
878 // derive the residuals numerically
879 41740932 FaceResidualValue partialDeriv(0.0);
880
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 41740881 times.
41740932 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
881
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 41740881 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
41740932 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
882
4/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 41740881 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
41740932 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
883
1/2
✓ Branch 1 taken 41740932 times.
✗ Branch 2 not taken.
41740932 NumericDifferentiation::partialDerivative(evalResidual, priVars[pvIdx + offset], partialDeriv, origResiduals[scvf.localFaceIdx()],
884 41740932 epsCoupl(priVars[pvIdx + offset], pvIdx), numDiffMethod);
885
886 // update the global jacobian matrix with the current partial derivatives
887
1/2
✓ Branch 1 taken 41740932 times.
✗ Branch 2 not taken.
41740932 updateGlobalJacobian_(A, faceGlobalI, globalJ, pvIdx, partialDeriv);
888
889 // restore the original volVars
890 41740932 curVolVars = origVolVars;
891
892 // restore the undeflected state of the coupling context
893
2/2
✓ Branch 0 taken 6983200 times.
✓ Branch 1 taken 34757732 times.
48724132 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, origCellCenterPriVars, pvIdx);
894 }
895 }
896 }
897 1360572 }
898
899 template<std::size_t otherId, class JacobianBlock, class ElementResidualVector, class GridVariables>
900 413040 void assembleJacobianFaceCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
901 const ElementResidualVector& res, GridVariables& gridVariables)
902 {
903 //////////////////////////////////////////////////////////////////////////////////////////////////////////
904 // Calculate derivatives of all face residuals in the element w.r.t. all dofs in the coupling stencil. //
905 //////////////////////////////////////////////////////////////////////////////////////////////////////////
906
907 // get some aliases for convenience
908 413040 const auto& fvGeometry = this->fvGeometry();
909 413040 const auto& curSol = this->curSol()[domainJ];
910
911 // build derivatives with for cell center dofs w.r.t. cell center dofs
912
2/2
✓ Branch 1 taken 1652160 times.
✓ Branch 2 taken 413040 times.
2065200 for (auto&& scvf : scvfs(fvGeometry))
913 {
914 // set the actual dof index
915 1652160 const auto faceGlobalI = scvf.dofIndex();
916
917 // get stencil information
918
2/2
✓ Branch 1 taken 1640820 times.
✓ Branch 2 taken 11340 times.
1652160 const auto& stencil = this->couplingManager().couplingStencil(domainI, scvf, domainJ);
919
920
2/2
✓ Branch 0 taken 1640820 times.
✓ Branch 1 taken 11340 times.
1652160 if (stencil.empty())
921 1640820 continue;
922
923 // build derivatives with for face dofs w.r.t. cell center dofs
924
2/2
✓ Branch 0 taken 11340 times.
✓ Branch 1 taken 11340 times.
22680 for (const auto& globalJ : stencil)
925 {
926
1/2
✓ Branch 0 taken 11340 times.
✗ Branch 1 not taken.
11340 const auto origPriVarsJ = curSol[globalJ];
927
1/2
✓ Branch 0 taken 11340 times.
✗ Branch 1 not taken.
11340 const auto origResidual = this->couplingManager().evalCouplingResidual(domainI, scvf, *this, domainJ, globalJ);
928
929
2/2
✓ Branch 0 taken 22912 times.
✓ Branch 1 taken 11340 times.
34252 for (int pvIdx = 0; pvIdx < JacobianBlock::block_type::cols; ++pvIdx)
930 {
931 45824 auto evalCouplingResidual = [&](Scalar priVar)
932 {
933 20872 auto deflectedPriVars = origPriVarsJ;
934 22912 deflectedPriVars[pvIdx] = priVar;
935 22912 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, deflectedPriVars, pvIdx);
936
1/2
✓ Branch 0 taken 22912 times.
✗ Branch 1 not taken.
22912 return this->couplingManager().evalCouplingResidual(domainI, scvf, *this, domainJ, globalJ);
937 };
938
939 // derive the residuals numerically
940 22912 FaceResidualValue partialDeriv(0.0);
941
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22895 times.
22912 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
942
4/6
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22895 times.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
22912 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
943
4/6
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22895 times.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
22921 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
944 22912 NumericDifferentiation::partialDerivative(evalCouplingResidual, origPriVarsJ[pvIdx], partialDeriv, origResidual,
945 22912 epsCoupl(origPriVarsJ[pvIdx], pvIdx), numDiffMethod);
946
947 // update the global stiffness matrix with the current partial derivatives
948 22912 updateGlobalJacobian_(A, faceGlobalI, globalJ, pvIdx, partialDeriv);
949
950 // restore the undeflected state of the coupling context
951 22912 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, origPriVarsJ, pvIdx);
952 }
953 }
954 }
955 413040 }
956
957 template<class JacobianMatrixDiagBlock, class GridVariables>
958 void evalAdditionalDerivatives(const std::vector<std::size_t>& additionalDofDependencies,
959 JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
960 { }
961
962 /*!
963 * \brief Updates the current global Jacobian matrix with the
964 * partial derivatives of all equations in regard to the
965 * primary variable 'pvIdx' at dof 'col'. Specialization for cc methods.
966 */
967 template<class SubMatrix, class CCOrFacePrimaryVariables>
968 214576044 static void updateGlobalJacobian_(SubMatrix& matrix,
969 const int globalI,
970 const int globalJ,
971 const int pvIdx,
972 const CCOrFacePrimaryVariables& partialDeriv)
973 {
974
2/2
✓ Branch 0 taken 154855474 times.
✓ Branch 1 taken 107288022 times.
524286992 for (int eqIdx = 0; eqIdx < partialDeriv.size(); eqIdx++)
975 {
976 // A[i][col][eqIdx][pvIdx] is the rate of change of
977 // the residual of equation 'eqIdx' at dof 'i'
978 // depending on the primary variable 'pvIdx' at dof
979 // 'col'.
980
981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 154855474 times.
309710948 assert(pvIdx >= 0);
982 309710948 assert(eqIdx < matrix[globalI][globalJ].size());
983
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 154855474 times.
309710948 assert(pvIdx < matrix[globalI][globalJ][eqIdx].size());
984 309710948 matrix[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
985 }
986 214576044 }
987
988 private:
989
990 48266280 FaceVariables& getFaceVarAccess_(GridFaceVariables& gridFaceVariables, ElementFaceVariables& elemFaceVars, const SubControlVolumeFace& scvf)
991 {
992 if constexpr (GetPropType<TypeTag, Properties::GridVariables>::GridFaceVariables::cachingEnabled)
993 48266280 return gridFaceVariables.faceVars(scvf.index());
994 else
995 return elemFaceVars[scvf];
996 }
997 };
998
999 } // end namespace Dumux
1000
1001 #endif
1002