GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/multidomain/dualnetwork/couplingmanager.hh
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 270 335 80.6%
Functions: 27 49 55.1%
Branches: 275 560 49.1%

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 DualNetworkCoupling
10 * \ingroup DarcyDarcyCoupling
11 * \brief Coupling manager for equal-dimension boundary coupling
12 */
13
14 #ifndef DUMUX_MULTIDOMAIN_DUAL_NETWORK_COUPLINGMANAGER_HH
15 #define DUMUX_MULTIDOMAIN_DUAL_NETWORK_COUPLINGMANAGER_HH
16
17 #include <iostream>
18 #include <vector>
19 #include <tuple>
20
21 #include <dune/common/indices.hh>
22 #include <dune/common/exceptions.hh>
23 #include <dune/common/reservedvector.hh>
24
25 #include <dumux/common/properties.hh>
26 #include <dumux/common/math.hh>
27 #include <dumux/common/enumerate.hh>
28 #include <dumux/common/numeqvector.hh>
29 #include <dumux/common/dimensionlessnumbers.hh>
30 #include <dumux/discretization/elementsolution.hh>
31 #include <dumux/discretization/method.hh>
32 #include <dumux/multidomain/couplingmanager.hh>
33 #include "extendedsourcestencil.hh"
34
35 #include "couplingmapper.hh"
36
37 namespace Dumux::PoreNetwork {
38
39 /*!
40 * \ingroup DualNetworkCoupling
41 * \ingroup DarcyDarcyCoupling
42 * \brief Coupling manager for dual network approach for pore network models
43 * \note Concept and algorithms described in Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5
44 */
45 template<class MDTraits>
46 class PNMHeatTransferCouplingManager
47 : public CouplingManager<MDTraits>
48 {
49 using ParentType = CouplingManager<MDTraits>;
50 using ThisType = PNMHeatTransferCouplingManager<MDTraits>;
51
52 using Scalar = typename MDTraits::Scalar;
53 using SolutionVector = typename MDTraits::SolutionVector;
54
55 template<std::size_t i> using SubDomainTypeTag = typename MDTraits::template SubDomain<i>::TypeTag;
56 template<std::size_t i> using Problem = GetPropType<SubDomainTypeTag<i>, Properties::Problem>;
57 template<std::size_t i> using PrimaryVariables = GetPropType<SubDomainTypeTag<i>, Properties::PrimaryVariables>;
58 template<std::size_t i> using NumEqVector = Dumux::NumEqVector<PrimaryVariables<i>>;
59 template<std::size_t i> using GridVolumeVariables = GetPropType<SubDomainTypeTag<i>, Properties::GridVolumeVariables>;
60 template<std::size_t i> using ElementVolumeVariables = typename GridVolumeVariables<i>::LocalView;
61 template<std::size_t i> using ElementFluxVariablesCache = typename GetPropType<SubDomainTypeTag<i>, Properties::GridFluxVariablesCache>::LocalView;
62 template<std::size_t i> using VolumeVariables = typename GridVolumeVariables<i>::VolumeVariables;
63 template<std::size_t i> using GridGeometry = typename MDTraits::template SubDomain<i>::GridGeometry;
64 template<std::size_t i> using FVElementGeometry = typename GridGeometry<i>::LocalView;
65 template<std::size_t i> using SubControlVolumeFace = typename GridGeometry<i>::SubControlVolumeFace;
66 template<std::size_t i> using SubControlVolume = typename GridGeometry<i>::SubControlVolume;
67 template<std::size_t i> using GridView = typename GridGeometry<i>::GridView;
68 template<std::size_t i> using Element = typename GridView<i>::template Codim<0>::Entity;
69 template<std::size_t i> using Indices = typename GetPropType<SubDomainTypeTag<i>, Properties::ModelTraits>::Indices;
70
71 template<std::size_t id> using GridVariables = typename MDTraits::template SubDomain<id>::GridVariables;
72 using GridVariablesTuple = typename MDTraits::template TupleOfSharedPtr<GridVariables>;
73
74 using CouplingMapper = DualNetworkCouplingMapper<Scalar>;
75
76 template<std::size_t i>
77 static constexpr auto domainIdx()
78 { return typename MDTraits::template SubDomain<i>::Index{}; }
79
80 using CouplingStencil = std::vector<std::size_t>;
81 using DimLessNum = DimensionlessNumbers<Scalar>;
82
83
84 public:
85 static constexpr auto solidDomainIdx = typename MDTraits::template SubDomain<0>::Index();
86 static constexpr auto voidDomainIdx = typename MDTraits::template SubDomain<1>::Index();
87
88 private:
89
90 using VoidElementSolution = std::decay_t<decltype(elementSolution(std::declval<Element<voidDomainIdx>>(), std::declval<SolutionVector>()[voidDomainIdx], std::declval<GridGeometry<voidDomainIdx>>()))>;
91 using SolidElementSolution = std::decay_t<decltype(elementSolution(std::declval<Element<solidDomainIdx>>(), std::declval<SolutionVector>()[solidDomainIdx], std::declval<GridGeometry<solidDomainIdx>>()))>;
92
93 2086288 struct CouplingContextForOneConnection
94 {
95 std::size_t connectionGlobalId;
96 std::vector<FVElementGeometry<solidDomainIdx>> solidFVGeometry; // only one needed, but FVElementGeometry can't be default constructed
97 VolumeVariables<solidDomainIdx> solidVolVars;
98 std::vector<FVElementGeometry<voidDomainIdx>> voidFVGeometry;
99 std::vector<ElementVolumeVariables<voidDomainIdx>> voidElemVolVars;
100 std::vector<ElementFluxVariablesCache<voidDomainIdx>> voidElemFluxVarsCache;
101 };
102
103 using CouplingContextForOnePore = std::pair<std::size_t, std::vector<CouplingContextForOneConnection>>;
104 using CouplingContextForOneElement = Dune::ReservedVector<CouplingContextForOnePore, 2>;
105
106 struct ElementCouplingContext
107 {
108 std::size_t boundElementIndex() const
109 { return boundElementIndex_; }
110
111 std::size_t boundDomainId() const
112 { return domaindId_; }
113
114 auto& data()
115 818168 { return data_; }
116
117 template<std::size_t i>
118 2534262 void bind(Dune::index_constant<i> domainI,
119 const Element<i>& element,
120 const ThisType& couplingManager)
121 {
122 // do nothing if context is already bound correctly
123 5068524 const auto eIdx = couplingManager.gridGeometry(domainI).elementMapper().index(element);
124
5/6
✓ Branch 0 taken 1267118 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 1237405 times.
✓ Branch 3 taken 29713 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1237405 times.
2534262 if (domaindId_ == i && boundElementIndex_ == eIdx && initialized_)
125 return;
126
127 // do nothing if the element does not couple at all
128 // (this check is probably more expensive, so we do it after the above one)
129 constexpr auto domainJ = Dune::index_constant<1-i>{};
130
2/4
✓ Branch 1 taken 29726 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 29726 times.
✗ Branch 4 not taken.
59452 if (couplingManager.couplingStencil(domainI, element, domainJ).empty())
131 return;
132
133 59452 data_.clear();
134
135 // each element has two pores for which we need to bind some connection coupling context
136
2/2
✓ Branch 0 taken 59452 times.
✓ Branch 1 taken 29726 times.
178356 for (int localVertexIdx = 0; localVertexIdx < 2; ++localVertexIdx)
137 {
138 237808 const auto vIdx = couplingManager.gridGeometry(domainI).vertexMapper().subIndex(element, localVertexIdx, 1);
139
2/2
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 59398 times.
118904 if (!couplingManager.isCoupledPore(domainI, vIdx))
140 108 continue;
141
142 118796 initialized_ = true;
143 118796 domaindId_ = i;
144 118796 boundElementIndex_ = eIdx;
145
146 118796 const auto& connections = [&]
147 {
148 if constexpr(domainI == solidDomainIdx)
149 235548 return couplingManager.couplingMapper().solidToVoidConnections(vIdx);
150 else
151 120840 return couplingManager.couplingMapper().voidToSolidConnections(vIdx);
152 237592 }();
153 118796 const auto numConnections = std::distance(connections.begin(), connections.end());
154
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 59398 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 59398 times.
118796 assert(numConnections == (domainI == solidDomainIdx ? couplingManager.couplingMapper().solidToVoidConnectionIds().at(vIdx).size() : couplingManager.couplingMapper().voidToSolidConnectionIds().at(vIdx).size()));
155
156 237592 data_.push_back(CouplingContextForOnePore{});
157
158 // iterate over all solid/void connections for the given pore
159 118796 data_.back().first = vIdx;
160 237592 data_.back().second.reserve(numConnections);
161
4/4
✓ Branch 0 taken 521572 times.
✓ Branch 1 taken 59398 times.
✓ Branch 2 taken 521572 times.
✓ Branch 3 taken 59398 times.
1161940 for (const auto& connection : connections)
162 {
163 1043144 CouplingContextForOneConnection context;
164 1043144 context.connectionGlobalId = connection.id;
165
166 1043144 const auto& solidElement = couplingManager.solidGridGeometry_->element(connection.someSolidElementIdx);
167 1043144 auto solidFVGeometry = localView(*couplingManager.solidGridGeometry_);
168
1/2
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
1043144 solidFVGeometry.bindElement(solidElement);
169
1/2
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
1043144 context.solidFVGeometry.push_back(solidFVGeometry);
170
171
2/2
✓ Branch 0 taken 1043144 times.
✓ Branch 1 taken 521572 times.
3129432 for (const auto& solidScv : scvs(solidFVGeometry))
172 {
173
2/2
✓ Branch 0 taken 521572 times.
✓ Branch 1 taken 521572 times.
2086288 if (solidScv.dofIndex() == connection.solidVertexIdx)
174
1/2
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
1043144 context.solidVolVars = couplingManager.volVars(solidDomainIdx, solidElement, solidScv);
175 }
176
177 1043144 auto voidFVGeometry = localView(couplingManager.gridGeometry(voidDomainIdx));
178
3/8
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 521572 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 521572 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2086288 auto voidElemVolVars = localView(couplingManager.gridVariables(voidDomainIdx).curGridVolVars());
179
5/10
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 521572 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 521572 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 502484 times.
✓ Branch 10 taken 19088 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
2086288 auto voidElemFluxVarsCache = localView(couplingManager.gridVariables(voidDomainIdx).gridFluxVarsCache());
180
181
1/2
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
1043144 const auto numConvectionVoidElems = connection.convectionVoidElementIdx.size();
182
1/2
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
1043144 context.voidFVGeometry.reserve(numConvectionVoidElems);
183
1/2
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
1043144 context.voidElemVolVars.reserve(numConvectionVoidElems);
184
1/2
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
1043144 context.voidElemFluxVarsCache.reserve(numConvectionVoidElems);
185
4/4
✓ Branch 0 taken 1233344 times.
✓ Branch 1 taken 521572 times.
✓ Branch 2 taken 1233344 times.
✓ Branch 3 taken 521572 times.
5596120 for (const auto voidElemIdx : connection.convectionVoidElementIdx)
186 {
187
1/2
✓ Branch 1 taken 1233344 times.
✗ Branch 2 not taken.
2466688 const auto voidElem = couplingManager.gridGeometry(voidDomainIdx).element(voidElemIdx);
188
1/2
✓ Branch 1 taken 1233344 times.
✗ Branch 2 not taken.
2466688 voidFVGeometry.bindElement(voidElem);
189
2/4
✓ Branch 1 taken 1233344 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1233344 times.
✗ Branch 5 not taken.
4933376 voidElemVolVars.bindElement(voidElem, voidFVGeometry, couplingManager.curSol(voidDomainIdx));
190
1/2
✓ Branch 1 taken 1233344 times.
✗ Branch 2 not taken.
2466688 voidElemFluxVarsCache.bindElement(voidElem, voidFVGeometry, voidElemVolVars);
191
192
1/2
✓ Branch 1 taken 1233344 times.
✗ Branch 2 not taken.
2466688 context.voidFVGeometry.push_back(voidFVGeometry);
193
1/2
✓ Branch 1 taken 1233344 times.
✗ Branch 2 not taken.
2466688 context.voidElemVolVars.push_back(voidElemVolVars);
194
1/2
✓ Branch 1 taken 1233344 times.
✗ Branch 2 not taken.
2466688 context.voidElemFluxVarsCache.push_back(voidElemFluxVarsCache);
195 }
196
4/6
✓ Branch 1 taken 521572 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 521572 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 502484 times.
✓ Branch 7 taken 19088 times.
2086288 data_.back().second.push_back(std::move(context));
197 }
198 }
199 }
200
201 1253354 const auto& operator[](const std::size_t dofIdx) const
202 {
203
1/2
✓ Branch 0 taken 1879782 times.
✗ Branch 1 not taken.
4386490 for (const auto& d : data_)
204 {
205
2/2
✓ Branch 0 taken 1253354 times.
✓ Branch 1 taken 626428 times.
1879782 if (d.first == dofIdx)
206 1253354 return d.second;
207 }
208 DUNE_THROW(Dune::InvalidStateException, "No connection found");
209 }
210
211 private:
212
213 bool initialized_ = false;
214 std::size_t domaindId_;
215 std::size_t boundElementIndex_;
216 mutable Dune::ReservedVector<CouplingContextForOnePore, 2> data_;
217 };
218
219 public:
220
221 //! export traits
222 using MultiDomainTraits = MDTraits;
223 //! export stencil types
224 using CouplingStencils = std::unordered_map<std::size_t, CouplingStencil>;
225
226 /*!
227 * \brief Methods to be accessed by main
228 */
229 // \{
230
231 template<class HostGridView, class HostGridData, class VoidGridView, class SolidGridView>
232 1 void init(std::shared_ptr<Problem<solidDomainIdx>> solidProblem,
233 std::shared_ptr<Problem<voidDomainIdx>> voidProblem,
234 const HostGridView& hostGridView,
235 const HostGridData& hostGridData,
236 const VoidGridView& voidGridView,
237 const SolidGridView& solidGridView,
238 const SolutionVector& curSol)
239 {
240 2 voidGridGeometry_ = &voidProblem->gridGeometry();
241 2 solidGridGeometry_ = &solidProblem->gridGeometry();
242
2/4
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
5 couplingMapper_ = std::make_unique<CouplingMapper>(hostGridView, hostGridData, voidProblem->gridGeometry(), solidProblem->gridGeometry());
243 2 this->setSubProblems(std::make_tuple(solidProblem, voidProblem));
244 1 this->updateSolution(curSol);
245
246 1 const auto& someVoidElement = voidGridGeometry_->element(0);
247 1 const auto& someSolidElement = solidGridGeometry_->element(0);
248 2 voidElementSolution_.update(someVoidElement, curSol[voidDomainIdx], *voidGridGeometry_);
249 2 solidElementSolution_.update(someSolidElement, curSol[solidDomainIdx], *solidGridGeometry_);
250 1 setupExtendedStencil();
251 1 }
252
253 // \}
254
255 /*!
256 * \brief Methods to be accessed by the assembly
257 */
258 // \{
259
260 /*!
261 * \brief returns an iterable container of all indices of degrees of freedom of domain j
262 * that couple with / influence the element residual of the given element of domain i
263 *
264 * \param domainI the domain index of domain i
265 * \param element the coupled element of domain í
266 * \param domainJ the domain index of domain j
267 */
268 template<std::size_t i, std::size_t j>
269 const CouplingStencil& couplingStencil(Dune::index_constant<i> domainI,
270 const Element<i>& element,
271 Dune::index_constant<j> domainJ) const
272 {
273 const auto eIdx = gridGeometry(domainI).elementMapper().index(element);
274
275 auto getStencils = [this, domainI]() -> const auto&
276 {
277 return (domainI == solidDomainIdx) ? couplingMapper().solidToVoidStencils() : couplingMapper().voidToSolidStencils();
278 };
279
280 const auto& stencils = getStencils();
281
282 return (stencils.count(eIdx)) ? stencils.at(eIdx) : emptyStencil_;
283 }
284
285 /*!
286 * \brief Returns whether a given solid grain/void pore body is coupled to the other domain
287 */
288 template<std::size_t i>
289 2613832 bool isCoupledPore(Dune::index_constant<i> domainI, const std::size_t dofIdx) const
290 {
291 10455328 const auto& isCoupledDof = [&]
292 {
293 if constexpr(domainI == solidDomainIdx)
294 1711518 return couplingMapper().isCoupledSolidDof();
295 else //voidDomainIdx
296 902314 return couplingMapper().isCoupledVoidDof();
297 2613832 }();
298 5227664 return isCoupledDof[dofIdx];
299 }
300
301 /*!
302 * \brief Returns summed conductive flux between void and solid for one void pore body or one solid grain
303 */
304 template<std::size_t i>
305 25504 Scalar conductionSource(Dune::index_constant<i> domainI,
306 const Element<i>& element,
307 const FVElementGeometry<i>& fvGeometry,
308 const ElementVolumeVariables<i>& elemVolVars,
309 const SubControlVolume<i>& scv) const
310 {
311 25504 const auto& solidSol = this->curSol(solidDomainIdx);
312 25504 const auto& voidSol = this->curSol(voidDomainIdx);
313
314 25504 Scalar source = 0.0;
315 25504 const auto& connections = [&]
316 {
317 if constexpr(domainI == solidDomainIdx)
318 52344 return couplingMapper().solidToVoidConnections(scv.dofIndex());
319 else //voidDomainIdx
320 24168 return couplingMapper().voidToSolidConnections(scv.dofIndex());
321 51008 }();
322
323 // iterate over all connection throats
324
4/4
✓ Branch 0 taken 111842 times.
✓ Branch 1 taken 12752 times.
✓ Branch 2 taken 111842 times.
✓ Branch 3 taken 12752 times.
472872 for (const auto& connection : connections)
325 {
326 223684 const Scalar t = getConnectionTransmissiblity(domainI, connection, elemVolVars, scv);
327 const Scalar deltaT = [&]
328 {
329 if constexpr(domainI == solidDomainIdx)
330 301104 return solidSol[scv.dofIndex()][Indices<solidDomainIdx>::temperatureIdx] - voidSol[connection.voidVertexIdx][Indices<voidDomainIdx>::temperatureIdx];
331 else //voidDomainIdx
332 146264 return voidSol[scv.dofIndex()][Indices<voidDomainIdx>::temperatureIdx] - solidSol[connection.solidVertexIdx][Indices<solidDomainIdx>::temperatureIdx];
333 223684 }();
334
335 223684 source -= t * deltaT;
336 }
337
338 76512 source /= (scv.volume() * fvGeometry.gridGeometry().coordinationNumber()[scv.dofIndex()]);
339 25504 return source;
340 }
341
342 template<class Connection, class Context>
343 12939279 Scalar convectiveHeatFluxForOneConnection(const Connection& connection, const Context& context) const
344 {
345 12939279 const auto& solidSol = this->curSol(solidDomainIdx);
346 12939279 const auto& voidSol = this->curSol(voidDomainIdx);
347 12939279 const Scalar tSolid = solidSol[connection.solidVertexIdx];
348 12939279 Scalar resultConvection = 0.0;
349
350 // iterate over all convection void elements
351
4/4
✓ Branch 0 taken 31948674 times.
✓ Branch 1 taken 12939279 times.
✓ Branch 2 taken 31948674 times.
✓ Branch 3 taken 12939279 times.
115654464 for (const auto& [localConvectionVoidElementIdx, convectionVoidElementIdx] : enumerate(connection.convectionVoidElementIdx))
352 {
353 31948674 const auto& voidElement = voidGridGeometry_->element(convectionVoidElementIdx);
354 31948674 const auto& voidFVGeometry = context.voidFVGeometry[localConvectionVoidElementIdx];
355 31948674 const auto& voidElemVolVars = context.voidElemVolVars[localConvectionVoidElementIdx];
356 31948674 const auto& voidElemFluxVarsCache = context.voidElemFluxVarsCache[localConvectionVoidElementIdx];
357
358 63897348 const Scalar distance = [&, convectionVoidElementIdx = convectionVoidElementIdx, solidVertexIdx = connection.solidVertexIdx]
359 {
360 31948674 const auto& throatCenter = this->problem(voidDomainIdx).spatialParams().throatCenter(convectionVoidElementIdx);
361
1/2
✓ Branch 0 taken 61174665 times.
✗ Branch 1 not taken.
93123339 for (const auto& solidScv : scvs(context.solidFVGeometry[0]))
362 {
363 122349330 if (solidScv.dofIndex() == solidVertexIdx)
364 95846022 return (solidScv.dofPosition() - throatCenter).two_norm();
365 }
366 DUNE_THROW(Dune::InvalidStateException, "No solid scv found");
367
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 31948674 times.
✓ Branch 3 taken 31948674 times.
✓ Branch 4 taken 29225991 times.
125072013 }();
368
369 using VoidFluxVariables = GetPropType<SubDomainTypeTag<voidDomainIdx>, Properties::FluxVariables>;
370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31948674 times.
31948674 VoidFluxVariables fluxVars;
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31948674 times.
31948674 const auto& scvf = voidFVGeometry.scvf(0/*localScvfIdx*/); //only one scvf per element -> localScvfIdx = 0
372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31948674 times.
31948674 fluxVars.init(this->problem(voidDomainIdx), voidElement, voidFVGeometry, voidElemVolVars, scvf, voidElemFluxVarsCache);
373
374 static constexpr auto phaseIdx = 0;
375 159743370 const Scalar flux = fluxVars.advectiveFlux(phaseIdx, [phaseIdx = phaseIdx](const auto& volVars){ return volVars.mobility(phaseIdx);});
376
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
31948674 const Scalar velocity = flux / voidElemFluxVarsCache[scvf].throatCrossSectionalArea(phaseIdx);
377
378 31948674 const auto tFluidMean = [&]
379 {
380 Scalar result = 0.0;
381 const auto numScv = voidFVGeometry.numScv();
382 assert(numScv == 2);
383 for (const auto& voidScv : scvs(voidFVGeometry))
384 result += 1.0/numScv * voidSol[voidScv.dofIndex()][Indices<voidDomainIdx>::temperatureIdx];
385 return result;
386 };
387
388 31948674 const auto tFluidUpstream = [&]
389 {
390 const auto upstreamDofIdx = flux > 0.0 ? voidFVGeometry.scv(scvf.insideScvIdx()).dofIndex() : voidFVGeometry.scv(scvf.outsideScvIdx()).dofIndex();
391 return voidSol[upstreamDofIdx][Indices<voidDomainIdx>::temperatureIdx];
392 };
393
394 enum class FluidTemperatureMode {mean, self, upstream};
395
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
31948675 static const auto fluidTemperatureMode = [&]
396 {
397
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 static const auto mode = getParam<std::string>("DualNetwork.FluidTemperatureMode", "mean");
398 2 std::cout << "Using FluidTemperatureMode " << mode << std::endl;
399
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (mode == "mean")
400 return FluidTemperatureMode::mean;
401
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 else if (mode == "self")
402 return FluidTemperatureMode::self;
403 else if (mode == "upstream")
404 return FluidTemperatureMode::upstream;
405 else
406 DUNE_THROW(Dune::IOError, mode << " is not a valid FluidTemperatureMode");
407
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 }();
408
409 63897348 const Scalar tFluid = [&, voidVertexIdx = connection.voidVertexIdx]
410 {
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31948674 times.
31948674 if (fluidTemperatureMode == FluidTemperatureMode::mean)
412 return tFluidMean();
413
1/2
✓ Branch 0 taken 31948674 times.
✗ Branch 1 not taken.
31948674 else if (fluidTemperatureMode == FluidTemperatureMode::self)
414 63897348 return voidSol[voidVertexIdx][Indices<voidDomainIdx>::temperatureIdx];
415 else
416 return tFluidUpstream();
417 31948674 }();
418
419
8/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 31948673 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 31948673 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 31948673 times.
127794696 const Scalar meanKinematicViscosity = 0.5*(voidElemVolVars[0].viscosity(phaseIdx)/voidElemVolVars[0].density(phaseIdx)
420
8/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 31948673 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 31948673 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 31948673 times.
127794696 + voidElemVolVars[1].viscosity(phaseIdx)/voidElemVolVars[1].density(phaseIdx));
421
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
31948674 const Scalar characteristicLength = 2.0*voidElemFluxVarsCache[scvf].throatInscribedRadius();
422 using std::abs;
423
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 31948673 times.
63897348 const Scalar Re = DimLessNum::reynoldsNumber(abs(velocity), characteristicLength, meanKinematicViscosity);
424
425
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
31948674 static const Scalar fixedLambda = getParam<Scalar>("DualNetwork.FixedConvectionLambda", -1.0);
426
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
31948674 static const Scalar lambaFactor = getParam<Scalar>("DualNetwork.ConvectionLambaFactor", 0.9);
427
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
31948674 static const Scalar lambaExponent = getParam<Scalar>("DualNetwork.ConvectionLambaExponent", 0.4);
428 using std::pow;
429
1/2
✓ Branch 0 taken 31948674 times.
✗ Branch 1 not taken.
31948674 const Scalar lambda = fixedLambda > 0.0 ? fixedLambda : 1.0 + lambaFactor*pow(Re, lambaExponent); //approximation: see eq.30 in Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5
430
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
31948674 const Scalar selfA = connection.connectionArea / connection.convectionVoidElementIdx.size();
431
432 95846022 const auto neighborA = [&]
433 {
434 // get the area associated to the other void dof
435
1/2
✓ Branch 0 taken 47696623 times.
✗ Branch 1 not taken.
79645297 for (const auto& voidScv : scvs(voidFVGeometry))
436 {
437
2/2
✓ Branch 0 taken 31948674 times.
✓ Branch 1 taken 15747949 times.
47696623 if (voidScv.dofIndex() != connection.voidVertexIdx)
438 {
439 95846022 const auto& otherConnections = couplingMapper().voidToSolidConnections(voidScv.dofIndex());
440
2/4
✓ Branch 0 taken 177395633 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 177395633 times.
✗ Branch 3 not taken.
177395633 for (const auto& otherConn : otherConnections)
441 {
442
2/2
✓ Branch 0 taken 31948674 times.
✓ Branch 1 taken 145446959 times.
177395633 if (otherConn.solidVertexIdx == connection.solidVertexIdx)
443 {
444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31948674 times.
31948674 if (otherConn.voidVertexIdx != voidScv.dofIndex())
445 DUNE_THROW(Dune::InvalidStateException, "Void dofs don't match");
446
447 63897348 return otherConn.connectionArea/otherConn.convectionVoidElementIdx.size();
448 }
449 }
450 }
451 }
452 DUNE_THROW(Dune::InvalidStateException, "No neighbor area found");
453 };
454
455
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
31948674 static const bool useAvgA = getParam<bool>("DualNetwork.UseAverageConvectionArea", false);
456
1/2
✓ Branch 0 taken 31948674 times.
✗ Branch 1 not taken.
31948674 const Scalar A = useAvgA ? 0.5*(selfA + neighborA()) : selfA;
457
458
2/2
✓ Branch 0 taken 12458322 times.
✓ Branch 1 taken 19490352 times.
31948674 const Scalar deltaT = (elementCouplingContext_.boundDomainId() == voidDomainIdx) ? (tSolid - tFluid) : (tFluid - tSolid);
459
460
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31948673 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
31948674 static const int verbose = getParam<int>("DualNetwork.SourceVerboseForDof", -1);
461
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 31948674 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
31948674 if (verbose >= 0 && (connection.voidVertexIdx == verbose || connection.solidVertexIdx == verbose))
462 {
463 std::cout << "\n" << std::endl;
464 const auto domain = elementCouplingContext_.boundDomainId() == solidDomainIdx ? "solid" : "void";
465 std::cout << "At " << domain << ", dof " << verbose << ", flow elem " << convectionVoidElementIdx << ", globalId " << connection.id << std::endl;
466 std::cout << std::scientific << std::setprecision(15) << "velocity " << velocity << ", Re " << Re << ", delTaT " << deltaT << ", result " << lambda*A/distance*deltaT << std::endl;
467 std::cout << std::scientific << std::setprecision(15) << "A " << A << ", distance " << distance << std::endl;
468 std::cout << std::endl;
469 }
470
471 31948674 resultConvection += lambda*A/distance * deltaT;
472 }
473
474 12939279 return resultConvection;
475 }
476
477 /*!
478 * \brief Returns summed conductive heat fluxes for one void pore body coupled to solid grains (or the other way around)
479 * that occur due to convection in void throats
480 */
481 template<std::size_t i>
482 2493956 Scalar convectionSource(Dune::index_constant<i> domainI,
483 const Element<i>& element,
484 const FVElementGeometry<i>& fvGeometry,
485 const ElementVolumeVariables<i>& elemVolVars,
486 const SubControlVolume<i>& scv) const
487 {
488 4987912 bindCouplingContext(domainI, element);
489
490
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1246976 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2493956 static const int verbose = getParam<int>("DualNetwork.SourceVerboseForDof", -1);
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1246978 times.
2493956 if (scv.dofIndex() == verbose)
492 std::cout << "Start Source at elemn " << fvGeometry.gridGeometry().elementMapper().index(element) << " *******************************" << std::endl;
493
494 // iterate over all connection throats
495 2493956 const auto& connections = [&]
496 {
497 if constexpr (domainI == solidDomainIdx)
498 4895766 return couplingMapper().solidToVoidConnections(scv.dofIndex());
499 else
500 2586102 return couplingMapper().voidToSolidConnections(scv.dofIndex());
501 4987912 }();
502
503 2493956 Scalar source = 0.0;
504 2493956 const auto& contextForPore = elementCouplingContext_[scv.dofIndex()];
505
506
4/4
✓ Branch 0 taken 12932091 times.
✓ Branch 1 taken 1246978 times.
✓ Branch 2 taken 12932091 times.
✓ Branch 3 taken 1246978 times.
59210232 for (const auto& [localConnectionIdx, connection] : enumerate(connections))
507 51728364 source += convectiveHeatFluxForOneConnection(connection, contextForPore[localConnectionIdx]);
508
509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1246978 times.
2493956 if (scv.dofIndex() == verbose)
510 std::cout << std::scientific << std::setprecision(15) << "total conv source " << source << "\n\n ********************" << std::endl;
511
512 4987912 source /= (scv.volume() * fvGeometry.gridGeometry().coordinationNumber()[scv.dofIndex()]);
513
514 2493956 return source;
515 }
516
517 //TODO: this should not be in the general coupling manager
518 template<std::size_t i, std::size_t j>
519 Scalar sourceWithFixedTransmissibility(Dune::index_constant<i> domainI,
520 const Element<i>& element,
521 const FVElementGeometry<i>& fvGeometry,
522 const ElementVolumeVariables<i>& elemVolVars,
523 const SubControlVolume<i>& scv,
524 Dune::index_constant<j> domainJ) const
525 {
526 const auto& voidSol = this->curSol(voidDomainIdx);
527 const auto& solidSol = this->curSol(solidDomainIdx);
528
529 Scalar source = 0.0;
530
531 // iterate over all connection throats
532 for (const auto& connection : couplingMapper().voidToSolidConnections(scv.dofIndex()))
533 {
534 const Scalar t = this->problem(voidDomainIdx).getInternalReferenceHeatTransmissibilityCoupling();
535 const Scalar deltaT = [&]
536 {
537 if constexpr(domainI == solidDomainIdx)
538 return solidSol[scv.dofIndex()][Indices<solidDomainIdx>::temperatureIdx] - voidSol[connection.voidVertexIdx][Indices<voidDomainIdx>::temperatureIdx];
539 else //voidDomainIdx
540 return voidSol[scv.dofIndex()][Indices<voidDomainIdx>::temperatureIdx] - solidSol[connection.solidVertexIdx][Indices<solidDomainIdx>::temperatureIdx];
541 }();
542
543 source -= t * deltaT;
544 }
545
546 source /= (scv.volume() * fvGeometry.gridGeometry().coordinationNumber()[scv.dofIndex()]);
547 return source;
548 }
549
550 template<std::size_t i, class Connection>
551 223684 Scalar getConnectionTransmissiblity(Dune::index_constant<i> domainI,
552 const Connection& connection,
553 const ElementVolumeVariables<i>& elemVolVars,
554 const SubControlVolume<i>& scv) const
555 {
556 static constexpr bool isVoid = (domainI == voidDomainIdx);
557
558 111842 const auto poreRadiusVoid = [&]
559 {
560 111842 static const bool useExactPoreRadiusVoid = getParam<bool>("DualNetwork.UseExactPoreRadiusVoid", false);
561 111842 if (useExactPoreRadiusVoid)
562 {
563 using std::sqrt;
564 static const Scalar R = getParam<Scalar>("DualNetwork.SphereRadius", 50e-6);
565 static const Scalar overlapFactor = getParam<Scalar>("DualNetwork.OverlapFactor");
566 static const Scalar dx = overlapFactor*R;
567 static const Scalar r = sqrt(3.0) * dx - R;
568 return r;
569 }
570 else
571 111842 return gridGeometry(voidDomainIdx).poreInscribedRadius(connection.voidVertexIdx);
572 335526 }();
573
574 111842 const auto poreRadiusSolid = [&]
575 {
576 111842 static const bool useExactPoreRadiusSolid = getParam<bool>("DualNetwork.UseExactPoreRadiusSolid", false);
577 111842 if (useExactPoreRadiusSolid)
578 {
579 static const Scalar R = getParam<Scalar>("DualNetwork.SphereRadius", 50e-6);
580 return R;
581 }
582 else
583 335526 return this->problem(solidDomainIdx).spatialParams().poreExtendedRadius(connection.solidVertexIdx);
584 335526 }();
585
586 75276 const Scalar fluidThermalConductivity = [&]
587 {
588 if constexpr (isVoid)
589 73132 return elemVolVars[scv].effectiveThermalConductivity();
590 else
591 {
592 283100 const auto& voidElement = voidGridGeometry_->element(connection.someVoidElementIdx);
593 75276 auto voidFVGeometry = localView(*voidGridGeometry_);
594 75276 voidFVGeometry.bindElement(voidElement);
595
596 132548 for (const auto& voidScv : scvs(voidFVGeometry))
597 {
598 132548 if (voidScv.dofIndex() == connection.voidVertexIdx)
599 150552 return volVars(voidDomainIdx, voidElement, voidScv).effectiveThermalConductivity();
600 }
601
602 DUNE_THROW(Dune::InvalidStateException, "No scv found");
603 }
604 374236 }();
605
606 36566 const Scalar solidThermalConductivity = [&]
607 {
608 if constexpr (!isVoid) //solid
609
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 75275 times.
150552 return elemVolVars[scv].effectiveThermalConductivity();
610 else
611 {
612 141938 const auto& solidElement = solidGridGeometry_->element(connection.someSolidElementIdx);
613 36566 auto solidFVGeometry = localView(*solidGridGeometry_);
614 36566 solidFVGeometry.bindElement(solidElement);
615
616 68806 for (const auto& solidScv : scvs(solidFVGeometry))
617 {
618 68806 if (solidScv.dofIndex() == connection.solidVertexIdx)
619 73132 return volVars(solidDomainIdx, solidElement, solidScv).effectiveThermalConductivity();
620 }
621
622 DUNE_THROW(Dune::InvalidStateException, "No scv found");
623 }
624
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 75275 times.
296816 }();
625
626 223684 const Scalar kappa = fluidThermalConductivity / solidThermalConductivity;
627
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 111840 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
223684 static const Scalar Nu = getParam<Scalar>("DualNetwork.Nu", 1.0);
628
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 111840 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
223684 static const Scalar Bi = getParam<Scalar>("DualNetwork.Bi", 1.0);
629
630
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 111840 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
223684 static const bool useExactConnectionLength = getParam<bool>("DualNetwork.UseExactConnectionLength", false);
631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111842 times.
223684 const Scalar length = useExactConnectionLength ? poreRadiusSolid + poreRadiusVoid : connection.connectionLength;
632
633
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 111840 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
223684 static const bool useExactConnectionAreaSphere = getParam<bool>("DualNetwork.UseExactConnectionAreaSphere", false);
634
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 111840 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
223684 static const Scalar connectionAreaShapeFactor = getParam<Scalar>("DualNetwork.ConnectionAreaShapeFactor", 0.9);
635 111842 const Scalar area = [&]()
636 {
637 111842 if (useExactConnectionAreaSphere)
638 {
639 static const Scalar R = getParam<Scalar>("DualNetwork.SphereRadius", 50e-6);
640 static const Scalar overlapFactor = getParam<Scalar>("DualNetwork.OverlapFactor");
641 static const auto dx = overlapFactor*R;
642 static const auto h = R - dx;
643 static const auto interfacialArea = 4*M_PI*R*R - 6*(2*M_PI*R*h);
644 assert(std::abs(length - std::sqrt(3.0) * dx) < 1e-14); // TODO remove
645 return interfacialArea/8.0*connectionAreaShapeFactor;
646 }
647 else
648 111842 return connection.connectionArea*connectionAreaShapeFactor;
649 223684 }();
650 //distance weighted harmonic mean of thermal conductivities
651 223684 const Scalar meanThermalConductivity = (fluidThermalConductivity*Bi*(poreRadiusSolid + poreRadiusVoid))/(poreRadiusSolid*kappa + poreRadiusVoid*Bi/Nu);
652 223684 return area / length * meanThermalConductivity;
653 }
654
655 // \}
656
657 /*!
658 * \brief Return the volume variables of domain i for a given element and scv
659 */
660 template<std::size_t i>
661 150552 VolumeVariables<i> volVars(Dune::index_constant<i> domainI,
662 const Element<i>& element,
663 const SubControlVolume<i>& scv) const
664 {
665
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
150552 VolumeVariables<i> volVars;
666
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
301104 const auto elemSol = elementSolution(element, this->curSol(domainI), gridGeometry(domainI));
667
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 75276 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
150552 volVars.update(elemSol, this->problem(domainI), element, scv);
668 150552 return volVars;
669 }
670
671 template<std::size_t i, std::size_t j, class LocalAssemblerI>
672 973616 decltype(auto) evalCouplingResidual(Dune::index_constant<i> domainI,
673 const LocalAssemblerI& localAssemblerI,
674 Dune::index_constant<j> domainJ,
675 std::size_t dofIdxGlobalJ)
676 {
677 static_assert(i != j, "A domain cannot be coupled to itself!");
678
679 973616 typename LocalAssemblerI::LocalResidual::ElementResidualVector residual;
680
681 973616 const auto& element = localAssemblerI.element();
682 973616 const auto& fvGeometry = localAssemblerI.fvGeometry();
683 973616 const auto& curElemVolVars = localAssemblerI.curElemVolVars();
684
685 1947232 residual.resize(fvGeometry.numScv());
686
2/2
✓ Branch 0 taken 973616 times.
✓ Branch 1 taken 486808 times.
3894464 for (const auto& scv : scvs(fvGeometry))
687 {
688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 973616 times.
1947232 auto couplingSource = this->problem(domainI).source(element, fvGeometry, curElemVolVars, scv);
689 3894464 couplingSource *= -scv.volume()*curElemVolVars[scv].extrusionFactor();
690 3894464 residual[scv.indexInElement()] = couplingSource;
691 }
692
693 973616 return residual;
694 }
695
696 //! Bind the coupling context for a low dim element TODO remove Assembler
697 template<std::size_t i, class Assembler = int>
698 void bindCouplingContext(Dune::index_constant<i> domainI, const Element<i>& element, const Assembler& assembler = 0) const
699
5/14
✓ Branch 5 taken 1007 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2184 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 2184 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1007 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1007 times.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
1267131 { elementCouplingContext_.bind(domainI, element, *this); }
700
701 /*!
702 * \brief Update the coupling context
703 */
704 template<std::size_t i, class LocalAssemblerI, std::size_t j, class PriVars>
705 1636336 void updateCouplingContext(Dune::index_constant<i> domainI,
706 const LocalAssemblerI& localAssemblerI,
707 Dune::index_constant<j> domainJ,
708 const std::size_t dofIdxGlobalJ,
709 const PriVars& priVars,
710 int pvIdxJ)
711 {
712 5941728 this->curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVars[pvIdxJ];
713
714 // each element has two pores for which we need to bind some connection coupling context
715
2/2
✓ Branch 0 taken 1635728 times.
✓ Branch 1 taken 818168 times.
8180464 for (auto& context : elementCouplingContext_.data())
716 {
717
4/4
✓ Branch 0 taken 17045136 times.
✓ Branch 1 taken 1635728 times.
✓ Branch 2 taken 17045136 times.
✓ Branch 3 taken 1635728 times.
43904640 for (auto& connInfo : context.second)
718 {
719
1/2
✓ Branch 0 taken 13877856 times.
✗ Branch 1 not taken.
34090272 const auto& staticConnectionInfo = couplingMapper().connectionInfo()[connInfo.connectionGlobalId];
720
721 // when the solid dof is deflected, just updated the solid volVars
722 if constexpr (domainJ == solidDomainIdx)
723 {
724 6334560 const auto& solidElement = gridGeometry(domainJ).element(staticConnectionInfo.someSolidElementIdx);
725
2/2
✓ Branch 0 taken 6334560 times.
✓ Branch 1 taken 3167280 times.
31672800 for (const auto& scv : scvs(connInfo.solidFVGeometry.front()))
726 {
727
6/6
✓ Branch 0 taken 556664 times.
✓ Branch 1 taken 5777896 times.
✓ Branch 2 taken 556664 times.
✓ Branch 3 taken 5777896 times.
✓ Branch 4 taken 556664 times.
✓ Branch 5 taken 5777896 times.
38007360 solidElementSolution_[scv.localDofIndex()] = this->curSol(domainJ)[scv.dofIndex()];
728
2/2
✓ Branch 0 taken 556664 times.
✓ Branch 1 taken 5777896 times.
12669120 if (scv.dofIndex() == dofIdxGlobalJ)
729
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 556664 times.
1113328 connInfo.solidVolVars.update(solidElementSolution_, this->problem(domainJ), solidElement, scv);
730 }
731 }
732 else // deflection of void dofs
733 {
734
3/6
✓ Branch 0 taken 13877856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13877856 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13877856 times.
✗ Branch 5 not taken.
83267136 assert(staticConnectionInfo.convectionVoidElementIdx.size() == connInfo.voidFVGeometry.size());
735
4/4
✓ Branch 0 taken 34084704 times.
✓ Branch 1 taken 13877856 times.
✓ Branch 2 taken 34084704 times.
✓ Branch 3 taken 13877856 times.
123680832 for (int voidElemLocalIdx = 0; voidElemLocalIdx < staticConnectionInfo.convectionVoidElementIdx.size(); ++voidElemLocalIdx)
736 {
737 68169408 const auto eIdx = staticConnectionInfo.convectionVoidElementIdx[voidElemLocalIdx];
738 68169408 const auto& element = gridGeometry(voidDomainIdx).element(eIdx);
739 68169408 const auto& fvGeometry = connInfo.voidFVGeometry[voidElemLocalIdx];
740 68169408 auto& elemVolVars = connInfo.voidElemVolVars[voidElemLocalIdx];
741
742
2/2
✓ Branch 0 taken 68169408 times.
✓ Branch 1 taken 34084704 times.
272677632 for (const auto& scv : scvs(fvGeometry))
743 {
744
2/2
✓ Branch 0 taken 4219776 times.
✓ Branch 1 taken 63949632 times.
136338816 if (scv.dofIndex() == dofIdxGlobalJ)
745 {
746 25318656 voidElementSolution_[scv.localDofIndex()] = this->curSol(voidDomainIdx)[scv.dofIndex()];
747
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4219776 times.
8439552 getVolVarAccess_(domainJ, gridVars_(voidDomainIdx).curGridVolVars(), elemVolVars, scv).update(voidElementSolution_, this->problem(voidDomainIdx), element, scv);
748 }
749 }
750
751
2/2
✓ Branch 0 taken 34084704 times.
✓ Branch 1 taken 34084704 times.
204508224 for (const auto& scvf : scvfs(fvGeometry))
752 {
753 if constexpr (getPropValue<SubDomainTypeTag<j>, Properties::EnableGridFluxVariablesCache>())
754 gridVars_(voidDomainIdx).gridFluxVarsCache().cache(eIdx, scvf.index()).update(problem(voidDomainIdx), element, fvGeometry, elemVolVars, scvf);
755 else
756
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 34084704 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34084704 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 34084704 times.
204508224 connInfo.voidElemFluxVarsCache[voidElemLocalIdx][scvf].update(this->problem(voidDomainIdx), element, fvGeometry, elemVolVars, scvf);
757 }
758 }
759 }
760 }
761 }
762 1636336 }
763
764 const auto& couplingContext() const
765
2/4
✓ Branch 1 taken 4362 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2014 times.
✗ Branch 5 not taken.
6376 { return elementCouplingContext_; }
766
767
768 template<std::size_t i>
769 const auto& gridGeometry(Dune::index_constant<i> domainI) const
770 {
771 if constexpr (i == voidDomainIdx)
772 return *voidGridGeometry_;
773 else
774 return *solidGridGeometry_;
775 }
776
777 const CouplingMapper& couplingMapper() const
778
16/32
✓ Branch 0 taken 3695232 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3695232 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10182624 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10182624 times.
✗ Branch 7 not taken.
✓ Branch 51 taken 3594 times.
✗ Branch 52 not taken.
✓ Branch 54 taken 3594 times.
✗ Branch 55 not taken.
✓ Branch 57 taken 3594 times.
✗ Branch 58 not taken.
✓ Branch 60 taken 3594 times.
✗ Branch 61 not taken.
✓ Branch 63 taken 3594 times.
✗ Branch 64 not taken.
✓ Branch 66 taken 3594 times.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✓ Branch 69 taken 1 times.
✗ Branch 70 not taken.
✓ Branch 71 taken 1 times.
✓ Branch 73 taken 4362 times.
✗ Branch 74 not taken.
✓ Branch 76 taken 4362 times.
✗ Branch 77 not taken.
✓ Branch 79 taken 2014 times.
✗ Branch 80 not taken.
✓ Branch 82 taken 2014 times.
✗ Branch 83 not taken.
103392822 { return *couplingMapper_; }
779
780 /*!
781 * \brief set the pointers to the grid variables
782 * \param gridVariables A tuple of shared pointers to the grid variables
783 */
784 void setGridVariables(GridVariablesTuple&& gridVariables)
785 1 { gridVariables_ = gridVariables; }
786
787 /*!
788 * \brief set a pointer to one of the grid variables
789 * \param gridVariables a pointer to the grid variables
790 * \param domainIdx the domain index of the grid variables
791 */
792 template<class GridVariables, std::size_t i>
793 void setGridVariables(std::shared_ptr<GridVariables> gridVariables, Dune::index_constant<i> domainIdx)
794 { std::get<i>(gridVariables_) = gridVariables; }
795
796 /*!
797 * \brief Return a reference to the grid variables of a sub problem
798 * \param domainIdx The domain index
799 */
800 template<std::size_t i>
801 1043144 const GridVariables<i>& gridVariables(Dune::index_constant<i> domainIdx) const
802 {
803
2/4
✓ Branch 0 taken 1043144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1043144 times.
✗ Branch 3 not taken.
2086288 if (std::get<i>(gridVariables_))
804 3129432 return *std::get<i>(gridVariables_);
805 else
806 DUNE_THROW(Dune::InvalidStateException, "The gridVariables pointer was not set. Use setGridVariables() before calling this function");
807 }
808
809 /*!
810 * \brief extend the jacobian pattern of the diagonal block of domain i
811 * by those entries that are not already in the uncoupled pattern
812 * \note Such additional dependencies can arise from the coupling, e.g. if a coupling source
813 * term depends on a non-local average of a quantity of the same domain
814 */
815 template<std::size_t id, class JacobianPattern>
816 void extendJacobianPattern(Dune::index_constant<id> domainI, JacobianPattern& pattern) const
817 {
818 extendedSourceStencil_.extendJacobianPattern(*this, domainI, pattern);
819 }
820
821 /*!
822 * \brief evaluate additional derivatives of the element residual of a domain with respect
823 * to dofs in the same domain that are not in the regular stencil (per default this is not the case)
824 * \note Such additional dependencies can arise from the coupling, e.g. if a coupling source
825 * term depends on a non-local average of a quantity of the same domain
826 * \note This is the same for box and cc
827 */
828 template<std::size_t i, class LocalAssemblerI, class JacobianMatrixDiagBlock, class GridVariables>
829 void evalAdditionalDomainDerivatives(Dune::index_constant<i> domainI,
830 const LocalAssemblerI& localAssemblerI,
831 const typename LocalAssemblerI::LocalResidual::ElementResidualVector&,
832 JacobianMatrixDiagBlock& A,
833 GridVariables& gridVariables)
834 {
835 // std::cout << "calling evalAdditionalDomainDerivatives " << std::endl;
836 25528 extendedSourceStencil_.evalAdditionalDomainDerivatives(*this, domainI, localAssemblerI, this->curSol(domainI), A, gridVariables); //TODO: call without curSol, but currently protected .../dumux/dumux/multidomain/couplingmanager.hh
837 }
838
839 //! Return a reference to an empty stencil
840 std::vector<std::size_t>& emptyStencil()
841 { return emptyStencil_; }
842
843
844 //! Return a reference to an empty stencil
845 template<std::size_t i>
846 const std::vector<std::size_t>& emptyStencil(Dune::index_constant<i> domainI) const
847
1/2
✓ Branch 0 taken 8736 times.
✗ Branch 1 not taken.
10920 { return emptyStencil_; }
848
849 template<std::size_t i>
850 const auto& gridView(Dune::index_constant<i> domainI) const
851 {
852 4 return gridGeometry(domainI).gridView();
853 }
854
855
856 1 void setupExtendedStencil()
857 {
858 1 extendedSourceStencil_.clear();
859
860
4/4
✓ Branch 2 taken 1007 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1007 times.
✓ Branch 5 taken 1 times.
2016 for (const auto& element : elements(gridView(voidDomainIdx)))
861 {
862 2014 const auto eIdx = gridGeometry(voidDomainIdx).elementMapper().index(element);
863 2014 const auto vIdx0 = gridGeometry(voidDomainIdx).vertexMapper().subIndex(element, 0, 1);
864 2014 const auto vIdx1 = gridGeometry(voidDomainIdx).vertexMapper().subIndex(element, 1, 1);
865
866
9/12
✓ Branch 3 taken 1007 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1007 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 27915 times.
✓ Branch 9 taken 1007 times.
✓ Branch 10 taken 27915 times.
✓ Branch 11 taken 1007 times.
✓ Branch 12 taken 9632 times.
✓ Branch 13 taken 18283 times.
✓ Branch 15 taken 27915 times.
✗ Branch 16 not taken.
29929 for (const auto& is : intersections(gridView(voidDomainIdx), element))
867 {
868
4/4
✓ Branch 0 taken 9632 times.
✓ Branch 1 taken 18283 times.
✓ Branch 2 taken 9632 times.
✓ Branch 3 taken 18283 times.
55830 if (is.neighbor())
869 {
870
1/2
✓ Branch 1 taken 9632 times.
✗ Branch 2 not taken.
9632 const auto& outsideElement = is.outside();
871
2/2
✓ Branch 0 taken 19264 times.
✓ Branch 1 taken 9632 times.
28896 for (int i = 0; i < 2; ++i)
872 {
873
2/4
✓ Branch 1 taken 19264 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19264 times.
✗ Branch 5 not taken.
38528 const auto outsideVertexIdx = gridGeometry(voidDomainIdx).vertexMapper().subIndex(outsideElement, i, 1);
874
2/2
✓ Branch 0 taken 9632 times.
✓ Branch 1 taken 9632 times.
19264 if (outsideVertexIdx != vIdx0 && outsideVertexIdx != vIdx1)
875
3/6
✓ Branch 1 taken 9632 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9632 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9632 times.
✗ Branch 8 not taken.
19264 extendedSourceStencil_.stencil()[eIdx].push_back(outsideVertexIdx);
876 }
877 }
878 }
879
880 2014 removeDuplicates_(extendedSourceStencil_.stencil()[eIdx]);
881 }
882 1 }
883
884
885 protected:
886
887 template<std::size_t i>
888 VolumeVariables<i>& getVolVarAccess_(Dune::index_constant<i> domainIdx, GridVolumeVariables<i>& gridVolVars, ElementVolumeVariables<i>& elemVolVars, const SubControlVolume<i>& scv)
889 {
890 if constexpr (getPropValue<SubDomainTypeTag<i>, Properties::EnableGridVolumeVariablesCache>())
891 return gridVolVars.volVars(scv);
892 else
893
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1489024 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1489024 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2730752 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2730752 times.
8439552 return elemVolVars[scv];
894 }
895
896 /*!
897 * \brief Return a reference to the grid variables of a sub problem
898 * \param domainIdx The domain index
899 */
900 template<std::size_t i>
901 4219776 GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
902 {
903
2/4
✓ Branch 0 taken 4219776 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4219776 times.
✗ Branch 3 not taken.
8439552 if (std::get<i>(gridVariables_))
904 12659328 return *std::get<i>(gridVariables_);
905 else
906 DUNE_THROW(Dune::InvalidStateException, "The gridVariables pointer was not set. Use setGridVariables() before calling this function");
907 }
908
909 //! Removes duplicate entries from the coupling stencils
910 void removeDuplicates_(std::vector<std::size_t>& stencil)
911 {
912 std::sort(stencil.begin(), stencil.end());
913 stencil.erase(std::unique(stencil.begin(), stencil.end()), stencil.end());
914 }
915
916
917 bool convectiveHeatTransfer_;
918
919 std::vector<std::size_t> emptyStencil_;
920 std::unique_ptr<const CouplingMapper> couplingMapper_;
921 const GridGeometry<voidDomainIdx>* voidGridGeometry_;
922 const GridGeometry<solidDomainIdx>* solidGridGeometry_;
923
924 VoidElementSolution voidElementSolution_;
925 SolidElementSolution solidElementSolution_;
926 mutable ElementCouplingContext elementCouplingContext_;
927
928 /*!
929 * \brief A tuple of std::shared_ptrs to the grid variables of the sub problems
930 */
931 GridVariablesTuple gridVariables_;
932
933 //! the extended source stencil object
934 PoreNetwork::PNMHeatExtendedSourceStencil<ThisType> extendedSourceStencil_;
935 };
936
937 }; // end namespace Dumux::PoreNetwork
938
939 #endif
940