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 CCMpfaFlux | ||
10 | * \brief Fick's law for cell-centered finite volume schemes with multi-point flux approximation | ||
11 | */ | ||
12 | #ifndef DUMUX_DISCRETIZATION_CC_MPFA_FICKS_LAW_HH | ||
13 | #define DUMUX_DISCRETIZATION_CC_MPFA_FICKS_LAW_HH | ||
14 | |||
15 | #include <dune/common/fvector.hh> | ||
16 | #include <dumux/common/properties.hh> | ||
17 | #include <dumux/discretization/method.hh> | ||
18 | |||
19 | #include <dumux/flux/fickiandiffusioncoefficients.hh> | ||
20 | #include <dumux/flux/referencesystemformulation.hh> | ||
21 | |||
22 | namespace Dumux { | ||
23 | |||
24 | //! forward declaration of the method-specific implementation | ||
25 | template<class TypeTag, class DiscretizationMethod, ReferenceSystemFormulation referenceSystem> | ||
26 | class FicksLawImplementation; | ||
27 | |||
28 | /*! | ||
29 | * \ingroup CCMpfaFlux | ||
30 | * \brief Fick's law for cell-centered finite volume schemes with multi-point flux approximation | ||
31 | */ | ||
32 | template <class TypeTag, ReferenceSystemFormulation referenceSystem> | ||
33 | class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa, referenceSystem> | ||
34 | { | ||
35 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
36 | using Problem = GetPropType<TypeTag, Properties::Problem>; | ||
37 | using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView; | ||
38 | using Element = typename GridView::template Codim<0>::Entity; | ||
39 | |||
40 | static constexpr int dim = GridView::dimension; | ||
41 | static constexpr int dimWorld = GridView::dimensionworld; | ||
42 | |||
43 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
44 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
45 | using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>; | ||
46 | using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; | ||
47 | using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView; | ||
48 | using GridFluxVariablesCache = GetPropType<TypeTag, Properties::GridFluxVariablesCache>; | ||
49 | using ElementFluxVariablesCache = typename GridFluxVariablesCache::LocalView; | ||
50 | using FluxVariablesCache = typename GridFluxVariablesCache::FluxVariablesCache; | ||
51 | using BalanceEqOpts = GetPropType<TypeTag, Properties::BalanceEqOpts>; | ||
52 | |||
53 | static constexpr int numComponents = GetPropType<TypeTag, Properties::ModelTraits>::numFluidComponents(); | ||
54 | static constexpr int numPhases = GetPropType<TypeTag, Properties::ModelTraits>::numFluidPhases(); | ||
55 | using ComponentFluxVector = Dune::FieldVector<Scalar, numComponents>; | ||
56 | |||
57 | //! Class that fills the cache corresponding to mpfa Fick's Law | ||
58 | class MpfaFicksLawCacheFiller | ||
59 | { | ||
60 | public: | ||
61 | //! Function to fill an MpfaFicksLawCache of a given scvf | ||
62 | //! This interface has to be met by any diffusion-related cache filler class | ||
63 | template<class FluxVariablesCacheFiller> | ||
64 | ✗ | static void fill(FluxVariablesCache& scvfFluxVarsCache, | |
65 | unsigned int phaseIdx, unsigned int compIdx, | ||
66 | const Problem& problem, | ||
67 | const Element& element, | ||
68 | const FVElementGeometry& fvGeometry, | ||
69 | const ElementVolumeVariables& elemVolVars, | ||
70 | const SubControlVolumeFace& scvf, | ||
71 | const FluxVariablesCacheFiller& fluxVarsCacheFiller) | ||
72 | { | ||
73 | // get interaction volume related data from the filler class & update the cache | ||
74 |
0/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
302288248 | if (fvGeometry.gridGeometry().vertexUsesSecondaryInteractionVolume(scvf.vertexIndex())) |
75 | ✗ | scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.secondaryInteractionVolume(), | |
76 | fluxVarsCacheFiller.secondaryIvLocalFaceData(), | ||
77 | fluxVarsCacheFiller.secondaryIvDataHandle(), | ||
78 | phaseIdx, compIdx); | ||
79 | else | ||
80 | 302288248 | scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.primaryInteractionVolume(), | |
81 | fluxVarsCacheFiller.primaryIvLocalFaceData(), | ||
82 | fluxVarsCacheFiller.primaryIvDataHandle(), | ||
83 | phaseIdx, compIdx); | ||
84 | ✗ | } | |
85 | }; | ||
86 | |||
87 | //! The cache used in conjunction with the mpfa Fick's Law | ||
88 | class MpfaFicksLawCache | ||
89 | { | ||
90 | using DualGridNodalIndexSet = GetPropType<TypeTag, Properties::DualGridNodalIndexSet>; | ||
91 | using Stencil = typename DualGridNodalIndexSet::NodalGridStencilType; | ||
92 | |||
93 | static constexpr int numPhases = GetPropType<TypeTag, Properties::ModelTraits>::numFluidPhases(); | ||
94 | static constexpr bool considerSecondaryIVs = GridGeometry::MpfaHelper::considerSecondaryIVs(); | ||
95 | using PrimaryDataHandle = typename ElementFluxVariablesCache::PrimaryIvDataHandle::DiffusionHandle; | ||
96 | using SecondaryDataHandle = typename ElementFluxVariablesCache::SecondaryIvDataHandle::DiffusionHandle; | ||
97 | |||
98 | //! sets the pointer to the data handle (overload for secondary data handles) | ||
99 | template< bool doSecondary = considerSecondaryIVs, std::enable_if_t<doSecondary, int> = 0 > | ||
100 | ✗ | void setHandlePointer_(const SecondaryDataHandle& dataHandle) | |
101 | ✗ | { secondaryHandlePtr_ = &dataHandle; } | |
102 | |||
103 | //! sets the pointer to the data handle (overload for primary data handles) | ||
104 | ✗ | void setHandlePointer_(const PrimaryDataHandle& dataHandle) | |
105 | 302288248 | { primaryHandlePtr_ = &dataHandle; } | |
106 | |||
107 | public: | ||
108 | // export filler type | ||
109 | using Filler = MpfaFicksLawCacheFiller; | ||
110 | |||
111 | /*! | ||
112 | * \brief Update cached objects (transmissibilities). | ||
113 | * This is used for updates with primary interaction volumes. | ||
114 | * | ||
115 | * \param iv The interaction volume this scvf is embedded in | ||
116 | * \param localFaceData iv-local info on this scvf | ||
117 | * \param dataHandle Transmissibility matrix & gravity data of this iv | ||
118 | */ | ||
119 | template<class IV, class LocalFaceData, class DataHandle> | ||
120 | void updateDiffusion(const IV& iv, | ||
121 | const LocalFaceData& localFaceData, | ||
122 | const DataHandle& dataHandle, | ||
123 | unsigned int phaseIdx, unsigned int compIdx) | ||
124 | { | ||
125 | 604576496 | stencil_[phaseIdx][compIdx] = &iv.stencil(); | |
126 | 604576496 | switchFluxSign_[phaseIdx][compIdx] = localFaceData.isOutsideFace(); | |
127 | 604576496 | setHandlePointer_(dataHandle.diffusionHandle()); | |
128 | } | ||
129 | |||
130 | //! The stencils corresponding to the transmissibilities | ||
131 | const Stencil& diffusionStencil(unsigned int phaseIdx, unsigned int compIdx) const | ||
132 | { return *stencil_[phaseIdx][compIdx]; } | ||
133 | |||
134 | //! The corresponding data handles | ||
135 | ✗ | const PrimaryDataHandle& diffusionPrimaryDataHandle() const { return *primaryHandlePtr_; } | |
136 | ✗ | const SecondaryDataHandle& diffusionSecondaryDataHandle() const { return *secondaryHandlePtr_; } | |
137 | |||
138 | //! Returns whether or not this scvf is an "outside" face in the scope of the iv. | ||
139 | bool diffusionSwitchFluxSign(unsigned int phaseIdx, unsigned int compIdx) const | ||
140 |
2/2✓ Branch 0 taken 4112126 times.
✓ Branch 1 taken 3757222 times.
|
317882352 | { return switchFluxSign_[phaseIdx][compIdx]; } |
141 | |||
142 | |||
143 | private: | ||
144 | //! phase-/component- specific data | ||
145 | std::array< std::array<bool, numComponents>, numPhases > switchFluxSign_; | ||
146 | std::array< std::array<const Stencil*, numComponents>, numPhases > stencil_; | ||
147 | |||
148 | //! pointers to the corresponding iv-data handles | ||
149 | const PrimaryDataHandle* primaryHandlePtr_; | ||
150 | const SecondaryDataHandle* secondaryHandlePtr_; | ||
151 | }; | ||
152 | |||
153 | public: | ||
154 | using DiscretizationMethod = DiscretizationMethods::CCMpfa; | ||
155 | // state the discretization method this implementation belongs to | ||
156 | static constexpr DiscretizationMethod discMethod{}; | ||
157 | |||
158 | //return the reference system | ||
159 | static constexpr ReferenceSystemFormulation referenceSystemFormulation() | ||
160 | { return referenceSystem; } | ||
161 | |||
162 | // state the type for the corresponding cache and its filler | ||
163 | using Cache = MpfaFicksLawCache; | ||
164 | |||
165 | // export the diffusion container | ||
166 | using DiffusionCoefficientsContainer = FickianDiffusionCoefficients<Scalar, numPhases, numComponents>; | ||
167 | |||
168 | /*! | ||
169 | * \brief Returns the diffusive fluxes of all components within | ||
170 | * a fluid phase across the given sub-control volume face. | ||
171 | * The computed fluxes are given in mole/s or kg/s, depending | ||
172 | * on the template parameter ReferenceSystemFormulation. | ||
173 | */ | ||
174 | 278602352 | static ComponentFluxVector flux(const Problem& problem, | |
175 | const Element& element, | ||
176 | const FVElementGeometry& fvGeometry, | ||
177 | const ElementVolumeVariables& elemVolVars, | ||
178 | const SubControlVolumeFace& scvf, | ||
179 | const int phaseIdx, | ||
180 | const ElementFluxVariablesCache& elemFluxVarsCache) | ||
181 | { | ||
182 | // obtain this scvf's cache | ||
183 | 278602352 | const auto& fluxVarsCache = elemFluxVarsCache[scvf]; | |
184 | |||
185 | 278602352 | ComponentFluxVector componentFlux(0.0); | |
186 |
2/2✓ Branch 0 taken 557204704 times.
✓ Branch 1 taken 278602352 times.
|
835807056 | for (int compIdx = 0; compIdx < numComponents; compIdx++) |
187 | { | ||
188 | if constexpr (!FluidSystem::isTracerFluidSystem()) | ||
189 |
2/2✓ Branch 0 taken 239322352 times.
✓ Branch 1 taken 239322352 times.
|
478644704 | if (compIdx == FluidSystem::getMainComponent(phaseIdx)) |
190 | continue; | ||
191 | |||
192 | // calculate the density at the interface | ||
193 | 317882352 | const auto rho = interpolateDensity(elemVolVars, scvf, phaseIdx); | |
194 | |||
195 | // compute the flux | ||
196 |
2/2✓ Branch 0 taken 120080 times.
✓ Branch 1 taken 3532800 times.
|
317882352 | if (fluxVarsCache.usesSecondaryIv()) |
197 | 120080 | componentFlux[compIdx] = rho*computeVolumeFlux(problem, | |
198 | fluxVarsCache, | ||
199 | fluxVarsCache.diffusionSecondaryDataHandle(), | ||
200 | phaseIdx, compIdx); | ||
201 | else | ||
202 | 317762272 | componentFlux[compIdx] = rho*computeVolumeFlux(problem, | |
203 | fluxVarsCache, | ||
204 | fluxVarsCache.diffusionPrimaryDataHandle(), | ||
205 | phaseIdx, compIdx); | ||
206 | } | ||
207 | |||
208 | // accumulate the phase component flux | ||
209 |
2/2✓ Branch 0 taken 478644704 times.
✓ Branch 1 taken 239322352 times.
|
757247056 | for (int compIdx = 0; compIdx < numComponents; compIdx++) |
210 | if constexpr (!FluidSystem::isTracerFluidSystem()) | ||
211 |
2/2✓ Branch 0 taken 239322352 times.
✓ Branch 1 taken 239322352 times.
|
478644704 | if (compIdx != FluidSystem::getMainComponent(phaseIdx) && BalanceEqOpts::mainComponentIsBalanced(phaseIdx)) |
212 | 717967056 | componentFlux[FluidSystem::getMainComponent(phaseIdx)] -= componentFlux[compIdx]; | |
213 | |||
214 | 278602352 | return componentFlux; | |
215 | } | ||
216 | |||
217 | private: | ||
218 | template< class Problem, class FluxVarsCache, class DataHandle > | ||
219 | 321535232 | static Scalar computeVolumeFlux(const Problem& problem, | |
220 | const FluxVarsCache& cache, | ||
221 | const DataHandle& dataHandle, | ||
222 | int phaseIdx, int compIdx) | ||
223 | { | ||
224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 317882352 times.
|
321535232 | dataHandle.setPhaseIndex(phaseIdx); |
225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 317882352 times.
|
321535232 | dataHandle.setComponentIndex(compIdx); |
226 | |||
227 |
2/2✓ Branch 0 taken 4112126 times.
✓ Branch 1 taken 3757222 times.
|
321535232 | const bool switchSign = cache.diffusionSwitchFluxSign(phaseIdx, compIdx); |
228 | |||
229 | 321535232 | const auto localFaceIdx = cache.ivLocalFaceIndex(); | |
230 | 321535232 | const auto idxInOutside = cache.indexInOutsideFaces(); | |
231 |
2/2✓ Branch 0 taken 4112126 times.
✓ Branch 1 taken 3757222 times.
|
321535232 | const auto& xj = dataHandle.uj(); |
232 |
2/2✓ Branch 0 taken 4112126 times.
✓ Branch 1 taken 3757222 times.
|
635201116 | const auto& tij = dim == dimWorld ? dataHandle.T()[localFaceIdx] |
233 | 12336378 | : (!switchSign ? dataHandle.T()[localFaceIdx] | |
234 | 15028888 | : dataHandle.tijOutside()[localFaceIdx][idxInOutside]); | |
235 | 321535232 | Scalar scvfFlux = tij*xj; | |
236 | |||
237 | // switch the sign if necessary | ||
238 |
2/2✓ Branch 0 taken 158333330 times.
✓ Branch 1 taken 159549022 times.
|
321535232 | if (switchSign) |
239 | 160149586 | scvfFlux *= -1.0; | |
240 | |||
241 | 321535232 | return scvfFlux; | |
242 | } | ||
243 | |||
244 | //! compute the density at branching facets for network grids as arithmetic mean | ||
245 | 317882352 | static Scalar interpolateDensity(const ElementVolumeVariables& elemVolVars, | |
246 | const SubControlVolumeFace& scvf, | ||
247 | const unsigned int phaseIdx) | ||
248 | { | ||
249 | // use arithmetic mean of the densities around the scvf | ||
250 |
2/2✓ Branch 0 taken 317214928 times.
✓ Branch 1 taken 667424 times.
|
317882352 | if (!scvf.boundary()) |
251 | { | ||
252 | 317214928 | const Scalar rhoInside = massOrMolarDensity(elemVolVars[scvf.insideScvIdx()], referenceSystem, phaseIdx); | |
253 | |||
254 | 317214928 | Scalar rho = rhoInside; | |
255 |
4/4✓ Branch 0 taken 317214928 times.
✓ Branch 1 taken 317214928 times.
✓ Branch 2 taken 7793888 times.
✓ Branch 3 taken 7793888 times.
|
1593868528 | for (const auto outsideIdx : scvf.outsideScvIndices()) |
256 | { | ||
257 | 317214928 | const Scalar rhoOutside = massOrMolarDensity(elemVolVars[outsideIdx], referenceSystem, phaseIdx); | |
258 | 317214928 | rho += rhoOutside; | |
259 | } | ||
260 | 642223744 | return rho/(scvf.outsideScvIndices().size()+1); | |
261 | } | ||
262 | else | ||
263 | 1334848 | return massOrMolarDensity(elemVolVars[scvf.outsideScvIdx()], referenceSystem, phaseIdx); | |
264 | } | ||
265 | }; | ||
266 | |||
267 | } // end namespace | ||
268 | |||
269 | #endif | ||
270 |