version 3.10-dev
multidomain/dualnetwork/couplingmanager.hh
Go to the documentation of this file.
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//
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
26#include <dumux/common/math.hh>
34
35#include "couplingmapper.hh"
36
37namespace Dumux::PoreNetwork {
38
45template<class MDTraits>
47: public CouplingManager<MDTraits>
48{
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
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>;
82
83
84public:
85 static constexpr auto solidDomainIdx = typename MDTraits::template SubDomain<0>::Index();
86 static constexpr auto voidDomainIdx = typename MDTraits::template SubDomain<1>::Index();
87
88private:
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 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 { return data_; }
116
117 template<std::size_t i>
118 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 const auto eIdx = couplingManager.gridGeometry(domainI).elementMapper().index(element);
124 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 if (couplingManager.couplingStencil(domainI, element, domainJ).empty())
131 return;
132
133 data_.clear();
134
135 // each element has two pores for which we need to bind some connection coupling context
136 for (int localVertexIdx = 0; localVertexIdx < 2; ++localVertexIdx)
137 {
138 const auto vIdx = couplingManager.gridGeometry(domainI).vertexMapper().subIndex(element, localVertexIdx, 1);
139 if (!couplingManager.isCoupledPore(domainI, vIdx))
140 continue;
141
142 initialized_ = true;
143 domaindId_ = i;
144 boundElementIndex_ = eIdx;
145
146 const auto& connections = [&]
147 {
148 if constexpr(domainI == solidDomainIdx)
149 return couplingManager.couplingMapper().solidToVoidConnections(vIdx);
150 else
151 return couplingManager.couplingMapper().voidToSolidConnections(vIdx);
152 }();
153 const auto numConnections = std::distance(connections.begin(), connections.end());
154 assert(numConnections == (domainI == solidDomainIdx ? couplingManager.couplingMapper().solidToVoidConnectionIds().at(vIdx).size() : couplingManager.couplingMapper().voidToSolidConnectionIds().at(vIdx).size()));
155
156 data_.push_back(CouplingContextForOnePore{});
157
158 // iterate over all solid/void connections for the given pore
159 data_.back().first = vIdx;
160 data_.back().second.reserve(numConnections);
161 for (const auto& connection : connections)
162 {
163 CouplingContextForOneConnection context;
164 context.connectionGlobalId = connection.id;
165
166 const auto& solidElement = couplingManager.solidGridGeometry_->element(connection.someSolidElementIdx);
167 auto solidFVGeometry = localView(*couplingManager.solidGridGeometry_);
168 solidFVGeometry.bindElement(solidElement);
169 context.solidFVGeometry.push_back(solidFVGeometry);
170
171 for (const auto& solidScv : scvs(solidFVGeometry))
172 {
173 if (solidScv.dofIndex() == connection.solidVertexIdx)
174 context.solidVolVars = couplingManager.volVars(solidDomainIdx, solidElement, solidScv);
175 }
176
177 auto voidFVGeometry = localView(couplingManager.gridGeometry(voidDomainIdx));
178 auto voidElemVolVars = localView(couplingManager.gridVariables(voidDomainIdx).curGridVolVars());
179 auto voidElemFluxVarsCache = localView(couplingManager.gridVariables(voidDomainIdx).gridFluxVarsCache());
180
181 const auto numConvectionVoidElems = connection.convectionVoidElementIdx.size();
182 context.voidFVGeometry.reserve(numConvectionVoidElems);
183 context.voidElemVolVars.reserve(numConvectionVoidElems);
184 context.voidElemFluxVarsCache.reserve(numConvectionVoidElems);
185 for (const auto voidElemIdx : connection.convectionVoidElementIdx)
186 {
187 const auto voidElem = couplingManager.gridGeometry(voidDomainIdx).element(voidElemIdx);
188 voidFVGeometry.bindElement(voidElem);
189 voidElemVolVars.bindElement(voidElem, voidFVGeometry, couplingManager.curSol(voidDomainIdx));
190 voidElemFluxVarsCache.bindElement(voidElem, voidFVGeometry, voidElemVolVars);
191
192 context.voidFVGeometry.push_back(voidFVGeometry);
193 context.voidElemVolVars.push_back(voidElemVolVars);
194 context.voidElemFluxVarsCache.push_back(voidElemFluxVarsCache);
195 }
196 data_.back().second.push_back(std::move(context));
197 }
198 }
199 }
200
201 const auto& operator[](const std::size_t dofIdx) const
202 {
203 for (const auto& d : data_)
204 {
205 if (d.first == dofIdx)
206 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
219public:
220
222 using MultiDomainTraits = MDTraits;
224 using CouplingStencils = std::unordered_map<std::size_t, CouplingStencil>;
225
229 // \{
230
231 template<class HostGridView, class HostGridData, class VoidGridView, class SolidGridView>
232 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 voidGridGeometry_ = &voidProblem->gridGeometry();
241 solidGridGeometry_ = &solidProblem->gridGeometry();
242 couplingMapper_ = std::make_unique<CouplingMapper>(hostGridView, hostGridData, voidProblem->gridGeometry(), solidProblem->gridGeometry());
243 this->setSubProblems(std::make_tuple(solidProblem, voidProblem));
244 this->updateSolution(curSol);
245
246 const auto& someVoidElement = voidGridGeometry_->element(0);
247 const auto& someSolidElement = solidGridGeometry_->element(0);
251 }
252
253 // \}
254
258 // \{
259
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 {
278 };
279
280 const auto& stencils = getStencils();
281
282 return (stencils.count(eIdx)) ? stencils.at(eIdx) : emptyStencil_;
283 }
284
288 template<std::size_t i>
289 bool isCoupledPore(Dune::index_constant<i> domainI, const std::size_t dofIdx) const
290 {
291 const auto& isCoupledDof = [&]
292 {
293 if constexpr(domainI == solidDomainIdx)
295 else //voidDomainIdx
297 }();
298 return isCoupledDof[dofIdx];
299 }
300
304 template<std::size_t i>
305 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 const auto& solidSol = this->curSol(solidDomainIdx);
312 const auto& voidSol = this->curSol(voidDomainIdx);
313
314 Scalar source = 0.0;
315 const auto& connections = [&]
316 {
317 if constexpr(domainI == solidDomainIdx)
318 return couplingMapper().solidToVoidConnections(scv.dofIndex());
319 else //voidDomainIdx
320 return couplingMapper().voidToSolidConnections(scv.dofIndex());
321 }();
322
323 // iterate over all connection throats
324 for (const auto& connection : connections)
325 {
326 const Scalar t = getConnectionTransmissiblity(domainI, connection, elemVolVars, scv);
327 const Scalar deltaT = [&]
328 {
329 if constexpr(domainI == solidDomainIdx)
330 return solidSol[scv.dofIndex()][Indices<solidDomainIdx>::temperatureIdx] - voidSol[connection.voidVertexIdx][Indices<voidDomainIdx>::temperatureIdx];
331 else //voidDomainIdx
332 return voidSol[scv.dofIndex()][Indices<voidDomainIdx>::temperatureIdx] - solidSol[connection.solidVertexIdx][Indices<solidDomainIdx>::temperatureIdx];
333 }();
334
335 source -= t * deltaT;
336 }
337
338 source /= (scv.volume() * fvGeometry.gridGeometry().coordinationNumber()[scv.dofIndex()]);
339 return source;
340 }
341
342 template<class Connection, class Context>
343 Scalar convectiveHeatFluxForOneConnection(const Connection& connection, const Context& context) const
344 {
345 const auto& solidSol = this->curSol(solidDomainIdx);
346 const auto& voidSol = this->curSol(voidDomainIdx);
347 const Scalar tSolid = solidSol[connection.solidVertexIdx];
348 Scalar resultConvection = 0.0;
349
350 // iterate over all convection void elements
351 for (const auto& [localConvectionVoidElementIdx, convectionVoidElementIdx] : enumerate(connection.convectionVoidElementIdx))
352 {
353 const auto& voidElement = voidGridGeometry_->element(convectionVoidElementIdx);
354 const auto& voidFVGeometry = context.voidFVGeometry[localConvectionVoidElementIdx];
355 const auto& voidElemVolVars = context.voidElemVolVars[localConvectionVoidElementIdx];
356 const auto& voidElemFluxVarsCache = context.voidElemFluxVarsCache[localConvectionVoidElementIdx];
357
358 const Scalar distance = [&, convectionVoidElementIdx = convectionVoidElementIdx, solidVertexIdx = connection.solidVertexIdx]
359 {
360 const auto& throatCenter = this->problem(voidDomainIdx).spatialParams().throatCenter(convectionVoidElementIdx);
361 for (const auto& solidScv : scvs(context.solidFVGeometry[0]))
362 {
363 if (solidScv.dofIndex() == solidVertexIdx)
364 return (solidScv.dofPosition() - throatCenter).two_norm();
365 }
366 DUNE_THROW(Dune::InvalidStateException, "No solid scv found");
367 }();
368
369 using VoidFluxVariables = GetPropType<SubDomainTypeTag<voidDomainIdx>, Properties::FluxVariables>;
370 VoidFluxVariables fluxVars;
371 const auto& scvf = voidFVGeometry.scvf(0/*localScvfIdx*/); //only one scvf per element -> localScvfIdx = 0
372 fluxVars.init(this->problem(voidDomainIdx), voidElement, voidFVGeometry, voidElemVolVars, scvf, voidElemFluxVarsCache);
373
374 static constexpr auto phaseIdx = 0;
375 const Scalar flux = fluxVars.advectiveFlux(phaseIdx, [phaseIdx = phaseIdx](const auto& volVars){ return volVars.mobility(phaseIdx);});
376 const Scalar velocity = flux / voidElemFluxVarsCache[scvf].throatCrossSectionalArea(phaseIdx);
377
378 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 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 static const auto fluidTemperatureMode = [&]
396 {
397 static const auto mode = getParam<std::string>("DualNetwork.FluidTemperatureMode", "mean");
398 std::cout << "Using FluidTemperatureMode " << mode << std::endl;
399 if (mode == "mean")
400 return FluidTemperatureMode::mean;
401 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 }();
408
409 const Scalar tFluid = [&, voidVertexIdx = connection.voidVertexIdx]
410 {
411 if (fluidTemperatureMode == FluidTemperatureMode::mean)
412 return tFluidMean();
413 else if (fluidTemperatureMode == FluidTemperatureMode::self)
414 return voidSol[voidVertexIdx][Indices<voidDomainIdx>::temperatureIdx];
415 else
416 return tFluidUpstream();
417 }();
418
419 const Scalar meanKinematicViscosity = 0.5*(voidElemVolVars[0].viscosity(phaseIdx)/voidElemVolVars[0].density(phaseIdx)
420 + voidElemVolVars[1].viscosity(phaseIdx)/voidElemVolVars[1].density(phaseIdx));
421 const Scalar characteristicLength = 2.0*voidElemFluxVarsCache[scvf].throatInscribedRadius();
422 using std::abs;
423 const Scalar Re = DimLessNum::reynoldsNumber(abs(velocity), characteristicLength, meanKinematicViscosity);
424
425 static const Scalar fixedLambda = getParam<Scalar>("DualNetwork.FixedConvectionLambda", -1.0);
426 static const Scalar lambaFactor = getParam<Scalar>("DualNetwork.ConvectionLambaFactor", 0.9);
427 static const Scalar lambaExponent = getParam<Scalar>("DualNetwork.ConvectionLambaExponent", 0.4);
428 using std::pow;
429 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 const Scalar selfA = connection.connectionArea / connection.convectionVoidElementIdx.size();
431
432 const auto neighborA = [&]
433 {
434 // get the area associated to the other void dof
435 for (const auto& voidScv : scvs(voidFVGeometry))
436 {
437 if (voidScv.dofIndex() != connection.voidVertexIdx)
438 {
439 const auto& otherConnections = couplingMapper().voidToSolidConnections(voidScv.dofIndex());
440 for (const auto& otherConn : otherConnections)
441 {
442 if (otherConn.solidVertexIdx == connection.solidVertexIdx)
443 {
444 if (otherConn.voidVertexIdx != voidScv.dofIndex())
445 DUNE_THROW(Dune::InvalidStateException, "Void dofs don't match");
446
447 return otherConn.connectionArea/otherConn.convectionVoidElementIdx.size();
448 }
449 }
450 }
451 }
452 DUNE_THROW(Dune::InvalidStateException, "No neighbor area found");
453 };
454
455 static const bool useAvgA = getParam<bool>("DualNetwork.UseAverageConvectionArea", false);
456 const Scalar A = useAvgA ? 0.5*(selfA + neighborA()) : selfA;
457
458 const Scalar deltaT = (elementCouplingContext_.boundDomainId() == voidDomainIdx) ? (tSolid - tFluid) : (tFluid - tSolid);
459
460 static const int verbose = getParam<int>("DualNetwork.SourceVerboseForDof", -1);
461 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 resultConvection += lambda*A/distance * deltaT;
472 }
473
474 return resultConvection;
475 }
476
481 template<std::size_t i>
482 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 bindCouplingContext(domainI, element);
489
490 static const int verbose = getParam<int>("DualNetwork.SourceVerboseForDof", -1);
491 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 const auto& connections = [&]
496 {
497 if constexpr (domainI == solidDomainIdx)
498 return couplingMapper().solidToVoidConnections(scv.dofIndex());
499 else
500 return couplingMapper().voidToSolidConnections(scv.dofIndex());
501 }();
502
503 Scalar source = 0.0;
504 const auto& contextForPore = elementCouplingContext_[scv.dofIndex()];
505
506 for (const auto& [localConnectionIdx, connection] : enumerate(connections))
507 source += convectiveHeatFluxForOneConnection(connection, contextForPore[localConnectionIdx]);
508
509 if (scv.dofIndex() == verbose)
510 std::cout << std::scientific << std::setprecision(15) << "total conv source " << source << "\n\n ********************" << std::endl;
511
512 source /= (scv.volume() * fvGeometry.gridGeometry().coordinationNumber()[scv.dofIndex()]);
513
514 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 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 const auto poreRadiusVoid = [&]
559 {
560 static const bool useExactPoreRadiusVoid = getParam<bool>("DualNetwork.UseExactPoreRadiusVoid", false);
561 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 return gridGeometry(voidDomainIdx).poreInscribedRadius(connection.voidVertexIdx);
572 }();
573
574 const auto poreRadiusSolid = [&]
575 {
576 static const bool useExactPoreRadiusSolid = getParam<bool>("DualNetwork.UseExactPoreRadiusSolid", false);
577 if (useExactPoreRadiusSolid)
578 {
579 static const Scalar R = getParam<Scalar>("DualNetwork.SphereRadius", 50e-6);
580 return R;
581 }
582 else
583 return this->problem(solidDomainIdx).spatialParams().poreExtendedRadius(connection.solidVertexIdx);
584 }();
585
586 const Scalar fluidThermalConductivity = [&]
587 {
588 if constexpr (isVoid)
589 return elemVolVars[scv].effectiveThermalConductivity();
590 else
591 {
592 const auto& voidElement = voidGridGeometry_->element(connection.someVoidElementIdx);
593 auto voidFVGeometry = localView(*voidGridGeometry_);
594 voidFVGeometry.bindElement(voidElement);
595
596 for (const auto& voidScv : scvs(voidFVGeometry))
597 {
598 if (voidScv.dofIndex() == connection.voidVertexIdx)
599 return volVars(voidDomainIdx, voidElement, voidScv).effectiveThermalConductivity();
600 }
601
602 DUNE_THROW(Dune::InvalidStateException, "No scv found");
603 }
604 }();
605
606 const Scalar solidThermalConductivity = [&]
607 {
608 if constexpr (!isVoid) //solid
609 return elemVolVars[scv].effectiveThermalConductivity();
610 else
611 {
612 const auto& solidElement = solidGridGeometry_->element(connection.someSolidElementIdx);
613 auto solidFVGeometry = localView(*solidGridGeometry_);
614 solidFVGeometry.bindElement(solidElement);
615
616 for (const auto& solidScv : scvs(solidFVGeometry))
617 {
618 if (solidScv.dofIndex() == connection.solidVertexIdx)
619 return volVars(solidDomainIdx, solidElement, solidScv).effectiveThermalConductivity();
620 }
621
622 DUNE_THROW(Dune::InvalidStateException, "No scv found");
623 }
624 }();
625
626 const Scalar kappa = fluidThermalConductivity / solidThermalConductivity;
627 static const Scalar Nu = getParam<Scalar>("DualNetwork.Nu", 1.0);
628 static const Scalar Bi = getParam<Scalar>("DualNetwork.Bi", 1.0);
629
630 static const bool useExactConnectionLength = getParam<bool>("DualNetwork.UseExactConnectionLength", false);
631 const Scalar length = useExactConnectionLength ? poreRadiusSolid + poreRadiusVoid : connection.connectionLength;
632
633 static const bool useExactConnectionAreaSphere = getParam<bool>("DualNetwork.UseExactConnectionAreaSphere", false);
634 static const Scalar connectionAreaShapeFactor = getParam<Scalar>("DualNetwork.ConnectionAreaShapeFactor", 0.9);
635 const Scalar area = [&]()
636 {
637 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 return connection.connectionArea*connectionAreaShapeFactor;
649 }();
650 //distance weighted harmonic mean of thermal conductivities
651 const Scalar meanThermalConductivity = (fluidThermalConductivity*Bi*(poreRadiusSolid + poreRadiusVoid))/(poreRadiusSolid*kappa + poreRadiusVoid*Bi/Nu);
652 return area / length * meanThermalConductivity;
653 }
654
655 // \}
656
660 template<std::size_t i>
661 VolumeVariables<i> volVars(Dune::index_constant<i> domainI,
662 const Element<i>& element,
663 const SubControlVolume<i>& scv) const
664 {
665 VolumeVariables<i> volVars;
666 const auto elemSol = elementSolution(element, this->curSol(domainI), gridGeometry(domainI));
667 volVars.update(elemSol, this->problem(domainI), element, scv);
668 return volVars;
669 }
670
671 template<std::size_t i, std::size_t j, class LocalAssemblerI>
672 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 typename LocalAssemblerI::LocalResidual::ElementResidualVector residual;
680
681 const auto& element = localAssemblerI.element();
682 const auto& fvGeometry = localAssemblerI.fvGeometry();
683 const auto& curElemVolVars = localAssemblerI.curElemVolVars();
684
685 residual.resize(fvGeometry.numScv());
686 for (const auto& scv : scvs(fvGeometry))
687 {
688 auto couplingSource = this->problem(domainI).source(element, fvGeometry, curElemVolVars, scv);
689 couplingSource *= -scv.volume()*curElemVolVars[scv].extrusionFactor();
690 residual[scv.indexInElement()] = couplingSource;
691 }
692
693 return residual;
694 }
695
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 { elementCouplingContext_.bind(domainI, element, *this); }
700
704 template<std::size_t i, class LocalAssemblerI, std::size_t j, class PriVars>
705 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 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 for (auto& context : elementCouplingContext_.data())
716 {
717 for (auto& connInfo : context.second)
718 {
719 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 const auto& solidElement = gridGeometry(domainJ).element(staticConnectionInfo.someSolidElementIdx);
725 for (const auto& scv : scvs(connInfo.solidFVGeometry.front()))
726 {
727 solidElementSolution_[scv.localDofIndex()] = this->curSol(domainJ)[scv.dofIndex()];
728 if (scv.dofIndex() == dofIdxGlobalJ)
729 connInfo.solidVolVars.update(solidElementSolution_, this->problem(domainJ), solidElement, scv);
730 }
731 }
732 else // deflection of void dofs
733 {
734 assert(staticConnectionInfo.convectionVoidElementIdx.size() == connInfo.voidFVGeometry.size());
735 for (int voidElemLocalIdx = 0; voidElemLocalIdx < staticConnectionInfo.convectionVoidElementIdx.size(); ++voidElemLocalIdx)
736 {
737 const auto eIdx = staticConnectionInfo.convectionVoidElementIdx[voidElemLocalIdx];
738 const auto& element = gridGeometry(voidDomainIdx).element(eIdx);
739 const auto& fvGeometry = connInfo.voidFVGeometry[voidElemLocalIdx];
740 auto& elemVolVars = connInfo.voidElemVolVars[voidElemLocalIdx];
741
742 for (const auto& scv : scvs(fvGeometry))
743 {
744 if (scv.dofIndex() == dofIdxGlobalJ)
745 {
746 voidElementSolution_[scv.localDofIndex()] = this->curSol(voidDomainIdx)[scv.dofIndex()];
747 getVolVarAccess_(domainJ, gridVars_(voidDomainIdx).curGridVolVars(), elemVolVars, scv).update(voidElementSolution_, this->problem(voidDomainIdx), element, scv);
748 }
749 }
750
751 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 connInfo.voidElemFluxVarsCache[voidElemLocalIdx][scvf].update(this->problem(voidDomainIdx), element, fvGeometry, elemVolVars, scvf);
757 }
758 }
759 }
760 }
761 }
762 }
763
764 const auto& couplingContext() const
765 { 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
778 { return *couplingMapper_; }
779
784 void setGridVariables(GridVariablesTuple&& gridVariables)
786
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
800 template<std::size_t i>
801 const GridVariables<i>& gridVariables(Dune::index_constant<i> domainIdx) const
802 {
803 if (std::get<i>(gridVariables_))
804 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
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
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 extendedSourceStencil_.evalAdditionalDomainDerivatives(*this, domainI, localAssemblerI, this->curSol(domainI), A, gridVariables); //TODO: call without curSol, but currently protected .../dumux/dumux/multidomain/couplingmanager.hh
837 }
838
840 std::vector<std::size_t>& emptyStencil()
841 { return emptyStencil_; }
842
843
845 template<std::size_t i>
846 const std::vector<std::size_t>& emptyStencil(Dune::index_constant<i> domainI) const
847 { return emptyStencil_; }
848
849 template<std::size_t i>
850 const auto& gridView(Dune::index_constant<i> domainI) const
851 {
852 return gridGeometry(domainI).gridView();
853 }
854
855
857 {
859
860 for (const auto& element : elements(gridView(voidDomainIdx)))
861 {
862 const auto eIdx = gridGeometry(voidDomainIdx).elementMapper().index(element);
863 const auto vIdx0 = gridGeometry(voidDomainIdx).vertexMapper().subIndex(element, 0, 1);
864 const auto vIdx1 = gridGeometry(voidDomainIdx).vertexMapper().subIndex(element, 1, 1);
865
866 for (const auto& is : intersections(gridView(voidDomainIdx), element))
867 {
868 if (is.neighbor())
869 {
870 const auto& outsideElement = is.outside();
871 for (int i = 0; i < 2; ++i)
872 {
873 const auto outsideVertexIdx = gridGeometry(voidDomainIdx).vertexMapper().subIndex(outsideElement, i, 1);
874 if (outsideVertexIdx != vIdx0 && outsideVertexIdx != vIdx1)
875 extendedSourceStencil_.stencil()[eIdx].push_back(outsideVertexIdx);
876 }
877 }
878 }
879
881 }
882 }
883
884
885protected:
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 return elemVolVars[scv];
894 }
895
900 template<std::size_t i>
901 GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
902 {
903 if (std::get<i>(gridVariables_))
904 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
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
918
919 std::vector<std::size_t> emptyStencil_;
920 std::unique_ptr<const CouplingMapper> couplingMapper_;
923
924 VoidElementSolution voidElementSolution_;
925 SolidElementSolution solidElementSolution_;
926 mutable ElementCouplingContext elementCouplingContext_;
927
931 GridVariablesTuple gridVariables_;
932
935};
936
937}; // end namespace Dumux::PoreNetwork
938
939#endif
The interface of the coupling manager for multi domain problems.
Definition: multidomain/couplingmanager.hh:37
void setSubProblems(const std::tuple< std::shared_ptr< SubProblems >... > &problems)
set the pointers to the sub problems
Definition: multidomain/couplingmanager.hh:276
const Problem< i > & problem(Dune::index_constant< i > domainIdx) const
Return a reference to the sub problem.
Definition: multidomain/couplingmanager.hh:298
SubSolutionVector< i > & curSol(Dune::index_constant< i > domainIdx)
the solution vector of the subproblem
Definition: multidomain/couplingmanager.hh:327
void updateSolution(const SolutionVector &curSol)
Updates the entire solution vector, e.g. before assembly or after grid adaption Overload might want t...
Definition: multidomain/couplingmanager.hh:208
Collection of functions which calculate dimensionless numbers. Each number has it's own function....
Definition: dimensionlessnumbers.hh:53
static Scalar reynoldsNumber(const Scalar darcyMagVelocity, const Scalar charcteristicLength, const Scalar kinematicViscosity)
Calculate the Reynolds Number [-] (Re).
Definition: dimensionlessnumbers.hh:76
Coupling mapper for Stokes and Darcy domains with equal dimension.
Definition: dualnetwork/couplingmapper.hh:40
auto voidToSolidConnections(const std::size_t dofIdx) const
Returns an iterator allowing for (const auto& conn : voidToSolidConnections(dofIdx)) {....
Definition: dualnetwork/couplingmapper.hh:255
const auto & voidToSolidStencils() const
Definition: dualnetwork/couplingmapper.hh:242
const std::vector< bool > & isCoupledVoidDof() const
Definition: dualnetwork/couplingmapper.hh:248
const std::vector< bool > & isCoupledSolidDof() const
Definition: dualnetwork/couplingmapper.hh:251
const auto & connectionInfo() const
Definition: dualnetwork/couplingmapper.hh:277
auto solidToVoidConnections(const std::size_t dofIdx) const
Definition: dualnetwork/couplingmapper.hh:263
const auto & solidToVoidStencils() const
Definition: dualnetwork/couplingmapper.hh:245
A class managing an extended source stencil.
Definition: dualnetwork/extendedsourcestencil.hh:36
Coupling manager for dual network approach for pore network models.
Definition: multidomain/dualnetwork/couplingmanager.hh:48
static constexpr auto solidDomainIdx
Definition: multidomain/dualnetwork/couplingmanager.hh:85
void setGridVariables(GridVariablesTuple &&gridVariables)
set the pointers to the grid variables
Definition: multidomain/dualnetwork/couplingmanager.hh:784
void evalAdditionalDomainDerivatives(Dune::index_constant< i > domainI, const LocalAssemblerI &localAssemblerI, const typename LocalAssemblerI::LocalResidual::ElementResidualVector &, JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
evaluate additional derivatives of the element residual of a domain with respect to dofs in the same ...
Definition: multidomain/dualnetwork/couplingmanager.hh:829
const auto & gridView(Dune::index_constant< i > domainI) const
Definition: multidomain/dualnetwork/couplingmanager.hh:850
bool convectiveHeatTransfer_
Definition: multidomain/dualnetwork/couplingmanager.hh:917
const CouplingStencil & couplingStencil(Dune::index_constant< i > domainI, const Element< i > &element, Dune::index_constant< j > domainJ) const
Methods to be accessed by the assembly.
Definition: multidomain/dualnetwork/couplingmanager.hh:269
std::vector< std::size_t > & emptyStencil()
Return a reference to an empty stencil.
Definition: multidomain/dualnetwork/couplingmanager.hh:840
VolumeVariables< i > volVars(Dune::index_constant< i > domainI, const Element< i > &element, const SubControlVolume< i > &scv) const
Return the volume variables of domain i for a given element and scv.
Definition: multidomain/dualnetwork/couplingmanager.hh:661
std::unique_ptr< const CouplingMapper > couplingMapper_
Definition: multidomain/dualnetwork/couplingmanager.hh:920
void setGridVariables(std::shared_ptr< GridVariables > gridVariables, Dune::index_constant< i > domainIdx)
set a pointer to one of the grid variables
Definition: multidomain/dualnetwork/couplingmanager.hh:793
const auto & couplingContext() const
Definition: multidomain/dualnetwork/couplingmanager.hh:764
void init(std::shared_ptr< Problem< solidDomainIdx > > solidProblem, std::shared_ptr< Problem< voidDomainIdx > > voidProblem, const HostGridView &hostGridView, const HostGridData &hostGridData, const VoidGridView &voidGridView, const SolidGridView &solidGridView, const SolutionVector &curSol)
Methods to be accessed by main.
Definition: multidomain/dualnetwork/couplingmanager.hh:232
const auto & gridGeometry(Dune::index_constant< i > domainI) const
Definition: multidomain/dualnetwork/couplingmanager.hh:769
Scalar convectiveHeatFluxForOneConnection(const Connection &connection, const Context &context) const
Definition: multidomain/dualnetwork/couplingmanager.hh:343
const GridGeometry< voidDomainIdx > * voidGridGeometry_
Definition: multidomain/dualnetwork/couplingmanager.hh:921
SolidElementSolution solidElementSolution_
Definition: multidomain/dualnetwork/couplingmanager.hh:925
const std::vector< std::size_t > & emptyStencil(Dune::index_constant< i > domainI) const
Return a reference to an empty stencil.
Definition: multidomain/dualnetwork/couplingmanager.hh:846
VoidElementSolution voidElementSolution_
Definition: multidomain/dualnetwork/couplingmanager.hh:924
void setupExtendedStencil()
Definition: multidomain/dualnetwork/couplingmanager.hh:856
PoreNetwork::PNMHeatExtendedSourceStencil< ThisType > extendedSourceStencil_
the extended source stencil object
Definition: multidomain/dualnetwork/couplingmanager.hh:934
const CouplingMapper & couplingMapper() const
Definition: multidomain/dualnetwork/couplingmanager.hh:777
bool isCoupledPore(Dune::index_constant< i > domainI, const std::size_t dofIdx) const
Returns whether a given solid grain/void pore body is coupled to the other domain.
Definition: multidomain/dualnetwork/couplingmanager.hh:289
Scalar conductionSource(Dune::index_constant< i > domainI, const Element< i > &element, const FVElementGeometry< i > &fvGeometry, const ElementVolumeVariables< i > &elemVolVars, const SubControlVolume< i > &scv) const
Returns summed conductive flux between void and solid for one void pore body or one solid grain.
Definition: multidomain/dualnetwork/couplingmanager.hh:305
std::vector< std::size_t > emptyStencil_
Definition: multidomain/dualnetwork/couplingmanager.hh:919
void removeDuplicates_(std::vector< std::size_t > &stencil)
Removes duplicate entries from the coupling stencils.
Definition: multidomain/dualnetwork/couplingmanager.hh:910
GridVariablesTuple gridVariables_
A tuple of std::shared_ptrs to the grid variables of the sub problems.
Definition: multidomain/dualnetwork/couplingmanager.hh:931
ElementCouplingContext elementCouplingContext_
Definition: multidomain/dualnetwork/couplingmanager.hh:926
Scalar convectionSource(Dune::index_constant< i > domainI, const Element< i > &element, const FVElementGeometry< i > &fvGeometry, const ElementVolumeVariables< i > &elemVolVars, const SubControlVolume< i > &scv) const
Returns summed conductive heat fluxes for one void pore body coupled to solid grains (or the other wa...
Definition: multidomain/dualnetwork/couplingmanager.hh:482
GridVariables< i > & gridVars_(Dune::index_constant< i > domainIdx)
Return a reference to the grid variables of a sub problem.
Definition: multidomain/dualnetwork/couplingmanager.hh:901
void extendJacobianPattern(Dune::index_constant< id > domainI, JacobianPattern &pattern) const
extend the jacobian pattern of the diagonal block of domain i by those entries that are not already i...
Definition: multidomain/dualnetwork/couplingmanager.hh:816
void bindCouplingContext(Dune::index_constant< i > domainI, const Element< i > &element, const Assembler &assembler=0) const
Bind the coupling context for a low dim element TODO remove Assembler.
Definition: multidomain/dualnetwork/couplingmanager.hh:698
decltype(auto) evalCouplingResidual(Dune::index_constant< i > domainI, const LocalAssemblerI &localAssemblerI, Dune::index_constant< j > domainJ, std::size_t dofIdxGlobalJ)
Definition: multidomain/dualnetwork/couplingmanager.hh:672
static constexpr auto voidDomainIdx
Definition: multidomain/dualnetwork/couplingmanager.hh:86
const GridVariables< i > & gridVariables(Dune::index_constant< i > domainIdx) const
Return a reference to the grid variables of a sub problem.
Definition: multidomain/dualnetwork/couplingmanager.hh:801
std::unordered_map< std::size_t, CouplingStencil > CouplingStencils
export stencil types
Definition: multidomain/dualnetwork/couplingmanager.hh:224
VolumeVariables< i > & getVolVarAccess_(Dune::index_constant< i > domainIdx, GridVolumeVariables< i > &gridVolVars, ElementVolumeVariables< i > &elemVolVars, const SubControlVolume< i > &scv)
Definition: multidomain/dualnetwork/couplingmanager.hh:888
const GridGeometry< solidDomainIdx > * solidGridGeometry_
Definition: multidomain/dualnetwork/couplingmanager.hh:922
MDTraits MultiDomainTraits
export traits
Definition: multidomain/dualnetwork/couplingmanager.hh:222
void updateCouplingContext(Dune::index_constant< i > domainI, const LocalAssemblerI &localAssemblerI, Dune::index_constant< j > domainJ, const std::size_t dofIdxGlobalJ, const PriVars &priVars, int pvIdxJ)
Update the coupling context.
Definition: multidomain/dualnetwork/couplingmanager.hh:705
Scalar getConnectionTransmissiblity(Dune::index_constant< i > domainI, const Connection &connection, const ElementVolumeVariables< i > &elemVolVars, const SubControlVolume< i > &scv) const
Definition: multidomain/dualnetwork/couplingmanager.hh:551
Scalar sourceWithFixedTransmissibility(Dune::index_constant< i > domainI, const Element< i > &element, const FVElementGeometry< i > &fvGeometry, const ElementVolumeVariables< i > &elemVolVars, const SubControlVolume< i > &scv, Dune::index_constant< j > domainJ) const
Definition: multidomain/dualnetwork/couplingmanager.hh:519
Defines all properties used in Dumux.
Collection of functions, calculating dimensionless numbers.
Element solution classes and factory functions.
Extended source stencil helper class for coupling managers.
A Python-like enumerate function.
typename NumEqVectorTraits< PrimaryVariables >::type NumEqVector
A vector with the same size as numbers of equations This is the default implementation and has to be ...
Definition: numeqvector.hh:34
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::cctpfa||GridGeometry::discMethod==DiscretizationMethods::ccmpfa, CCElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for cell-centered schemes.
Definition: cellcentered/elementsolution.hh:101
static ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: distance.hh:282
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296
Define some often used mathematical functions.
The available discretization methods in Dumux.
The interface of the coupling manager for multi domain problems.
Definition: discretization/porenetwork/fvelementgeometry.hh:24
constexpr auto enumerate(Range &&iterable)
A Python-like enumerate function.
Definition: enumerate.hh:30
A helper to deduce a vector with the same size as numbers of equations.