3.4
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
porousmediumflow/nonequilibrium/thermal/localresidual.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2/*****************************************************************************
3 * See the file COPYING for full copying permissions. *
4 * *
5 * This program is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 *****************************************************************************/
25#ifndef DUMUX_ENERGY_NONEQUILIBRIUM_LOCAL_RESIDUAL_HH
26#define DUMUX_ENERGY_NONEQUILIBRIUM_LOCAL_RESIDUAL_HH
27
28#include <cmath>
34
35namespace Dumux {
36
42// forward declaration
43template <class TypeTag, int numEnergyEqFluid>
45
46template<class TypeTag>
47class EnergyLocalResidualNonEquilibrium<TypeTag, 1/*numEnergyEqFluid*/>
48{
52 using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
53 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
57 using Element = typename GridView::template Codim<0>::Entity;
58 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
59 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
60
62 using Indices = typename ModelTraits::Indices;
63
64 static constexpr auto numEnergyEqFluid = ModelTraits::numEnergyEqFluid();
65 static constexpr auto numEnergyEqSolid = ModelTraits::numEnergyEqSolid();
66 static constexpr auto energyEq0Idx = Indices::energyEq0Idx;
67 static constexpr auto energyEqSolidIdx = Indices::energyEqSolidIdx;
68
69 static constexpr auto numPhases = ModelTraits::numFluidPhases();
70 static constexpr auto numComponents = ModelTraits::numFluidComponents();
71
72public:
74 static void fluidPhaseStorage(NumEqVector& storage,
75 const SubControlVolume& scv,
76 const VolumeVariables& volVars,
77 int phaseIdx)
78 {
79 //in case we have one energy equation for more than one fluid phase, add up parts on the one energy equation
80 storage[energyEq0Idx] += volVars.porosity()
81 * volVars.density(phaseIdx)
82 * volVars.internalEnergy(phaseIdx)
83 * volVars.saturation(phaseIdx);
84
85 }
86
87
89 static void solidPhaseStorage(NumEqVector& storage,
90 const SubControlVolume& scv,
91 const VolumeVariables& volVars)
92 {
93 // heat conduction for the fluid phases
94 for(int sPhaseIdx = 0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx)
95 {
96 storage[energyEqSolidIdx+sPhaseIdx] += volVars.temperatureSolid()
97 * volVars.solidHeatCapacity()
98 * volVars.solidDensity()
99 * (1.0 - volVars.porosity());
100 }
101 }
102
103
105 static void heatConvectionFlux(NumEqVector& flux,
106 FluxVariables& fluxVars,
107 int phaseIdx)
108 {
109 auto upwindTerm = [phaseIdx](const auto& volVars)
110 { return volVars.density(phaseIdx)*volVars.mobility(phaseIdx)*volVars.enthalpy(phaseIdx); };
111
112 //in case we have one energy equation for more than one fluid phase, add up advective parts on the one energy equation
113 flux[energyEq0Idx] += fluxVars.advectiveFlux(phaseIdx, upwindTerm);
114
115 //now add the diffusive part
116 const auto diffusiveFluxes = fluxVars.molecularDiffusionFlux(phaseIdx);
117 const auto& elemVolVars = fluxVars.elemVolVars();
118 const auto& scvf = fluxVars.scvFace();
119 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
120 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
121
122 for (int compIdx = 0; compIdx < numComponents; ++compIdx)
123 {
124 //no diffusion of the main component, this is a hack to use normal fick's law which computes both diffusions (main and component). We only add the part from the component here
125 if (phaseIdx == compIdx)
126 continue;
127 //we need the upwind enthalpy. Even better would be the componentEnthalpy
128 auto enthalpy = 0.0;
129 if (diffusiveFluxes[compIdx] > 0)
130 enthalpy += insideVolVars.enthalpy(phaseIdx);
131 else
132 enthalpy += outsideVolVars.enthalpy(phaseIdx);
133
134 //check for the reference system and adapt units of the diffusive flux accordingly.
135 if (FluxVariables::MolecularDiffusionType::referenceSystemFormulation() == ReferenceSystemFormulation::massAveraged)
136 flux[energyEq0Idx] += diffusiveFluxes[compIdx]*enthalpy;
137 else
138 flux[energyEq0Idx] += diffusiveFluxes[compIdx]*FluidSystem::molarMass(compIdx)*enthalpy;
139 }
140 }
141
143 static void heatConductionFlux(NumEqVector& flux,
144 FluxVariables& fluxVars)
145 {
146 //in case we have one energy equation for more than one fluid phase we use an effective law in the nonequilibrium fourierslaw
147 flux[energyEq0Idx] += fluxVars.heatConductionFlux(0);
148 //heat conduction for the solid phases
149 for(int sPhaseIdx = 0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx)
150 flux[energyEqSolidIdx+sPhaseIdx] += fluxVars.heatConductionFlux(numPhases + sPhaseIdx);
151 }
152
162 static void computeSourceEnergy(NumEqVector& source,
163 const Element& element,
164 const FVElementGeometry& fvGeometry,
165 const ElementVolumeVariables& elemVolVars,
166 const SubControlVolume &scv)
167 {
168 // specialization for 2 fluid phases
169 const auto& volVars = elemVolVars[scv];
170 const Scalar characteristicLength = volVars.characteristicLength() ;
171
172 // interfacial area
173 // Shi & Wang, Transport in porous media (2011)
174 const Scalar as = volVars.fluidSolidInterfacialArea();
175
176 // temperature fluid is the same for both fluids
177 const Scalar TFluid = volVars.temperatureFluid(0);
178 const Scalar TSolid = volVars.temperatureSolid();
179
180 Scalar solidToFluidEnergyExchange ;
181
182 const Scalar fluidConductivity = volVars.fluidThermalConductivity(0) ;
183
184 const Scalar factorEnergyTransfer = volVars.factorEnergyTransfer() ;
185
186 solidToFluidEnergyExchange = factorEnergyTransfer * (TSolid - TFluid) / characteristicLength * as * fluidConductivity;
187
188 solidToFluidEnergyExchange *= volVars.nusseltNumber(0);
189
190 for(int energyEqIdx = 0; energyEqIdx < numEnergyEqFluid+numEnergyEqSolid; ++energyEqIdx)
191 {
192 switch (energyEqIdx)
193 {
194 case 0 :
195 source[energyEq0Idx + energyEqIdx] += solidToFluidEnergyExchange;
196 break;
197 case 1 :
198 source[energyEq0Idx + energyEqIdx] -= solidToFluidEnergyExchange;
199 break;
200 default:
201 DUNE_THROW(Dune::NotImplemented,
202 "wrong index");
203 } // end switch
204 } // end energyEqIdx
205 } // end source
206};
207
208template<class TypeTag>
209class EnergyLocalResidualNonEquilibrium<TypeTag, 2/*numEnergyEqFluid*/>
210: public EnergyLocalResidualNonEquilibrium<TypeTag, 1/*numEnergyEqFluid*/>
211{
215 using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
216 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
221 using Element = typename GridView::template Codim<0>::Entity;
222 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
223 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
224
226 using Indices = typename ModelTraits::Indices;
227
228 enum { numPhases = ModelTraits::numFluidPhases() };
229 enum { numEnergyEqFluid = ModelTraits::numEnergyEqFluid() };
230 enum { numEnergyEqSolid = ModelTraits::numEnergyEqSolid() };
231 enum { energyEq0Idx = Indices::energyEq0Idx };
232 enum { energyEqSolidIdx = Indices::energyEqSolidIdx};
233 enum { conti0EqIdx = Indices::conti0EqIdx };
234
235 enum { numComponents = ModelTraits::numFluidComponents() };
236 enum { phase0Idx = FluidSystem::phase0Idx};
237 enum { phase1Idx = FluidSystem::phase1Idx};
238 enum { sPhaseIdx = numPhases};
239
240 static constexpr bool enableChemicalNonEquilibrium = ModelTraits::enableChemicalNonEquilibrium();
241
242public:
243
245 static void fluidPhaseStorage(NumEqVector& storage,
246 const SubControlVolume& scv,
247 const VolumeVariables& volVars,
248 int phaseIdx)
249 {
250 storage[energyEq0Idx+phaseIdx] += volVars.porosity()
251 * volVars.density(phaseIdx)
252 * volVars.internalEnergy(phaseIdx)
253 * volVars.saturation(phaseIdx);
254 }
255
257 static void heatConvectionFlux(NumEqVector& flux,
258 FluxVariables& fluxVars,
259 int phaseIdx)
260 {
261 auto upwindTerm = [phaseIdx](const auto& volVars)
262 { return volVars.density(phaseIdx)*volVars.mobility(phaseIdx)*volVars.enthalpy(phaseIdx); };
263
264 // in case we have one energy equation for more than one fluid phase, add up advective parts on the one energy equation
265 flux[energyEq0Idx+phaseIdx] += fluxVars.advectiveFlux(phaseIdx, upwindTerm);
266
267 // add the diffusiv part
268 const auto diffusiveFluxes = fluxVars.molecularDiffusionFlux(phaseIdx);
269 const auto& elemVolVars = fluxVars.elemVolVars();
270 const auto& scvf = fluxVars.scvFace();
271 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
272 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
273
274 for (int compIdx = 0; compIdx < numComponents; ++compIdx)
275 {
276 // no diffusion of the main component, this is a hack to use normal fick's law which computes both diffusions (main and component). We only add the part from the component here
277 if (phaseIdx == compIdx)
278 continue;
279 // we need the upwind enthalpy. Even better would be the componentEnthalpy
280 auto enthalpy = 0.0;
281 if (diffusiveFluxes[compIdx] > 0)
282 enthalpy += insideVolVars.enthalpy(phaseIdx);
283 else
284 enthalpy += outsideVolVars.enthalpy(phaseIdx);
285 flux[energyEq0Idx+phaseIdx] += diffusiveFluxes[compIdx]*FluidSystem::molarMass(compIdx)*enthalpy;
286 }
287 }
288
290 static void heatConductionFlux(NumEqVector& flux,
291 FluxVariables& fluxVars)
292 {
293 for(int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
294 {
295 flux[energyEq0Idx+phaseIdx] += fluxVars.heatConductionFlux(phaseIdx);
296 }
297 for(int sPhaseIdx=0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx)
298 {
299 flux[energyEqSolidIdx+sPhaseIdx] += fluxVars.heatConductionFlux(numPhases + sPhaseIdx);
300 }
301 }
311 static void computeSourceEnergy(NumEqVector& source,
312 const Element& element,
313 const FVElementGeometry& fvGeometry,
314 const ElementVolumeVariables& elemVolVars,
315 const SubControlVolume &scv)
316 {
317 // specialization for 2 fluid phases
318 const auto &volVars = elemVolVars[scv];
319
320 const Scalar awn = volVars.interfacialArea(phase0Idx, phase1Idx);
321 const Scalar aws = volVars.interfacialArea(phase0Idx, sPhaseIdx);
322 const Scalar ans = volVars.interfacialArea(phase1Idx, sPhaseIdx);
323
324 const Scalar Tw = volVars.temperatureFluid(phase0Idx);
325 const Scalar Tn = volVars.temperatureFluid(phase1Idx);
326 const Scalar Ts = volVars.temperatureSolid();
327
328 const Scalar lambdaWetting = volVars.fluidThermalConductivity(phase0Idx);
329 const Scalar lambdaNonwetting = volVars.fluidThermalConductivity(phase1Idx);
330 const Scalar lambdaSolid = volVars.solidThermalConductivity();
331
332 const Scalar lambdaWN = harmonicMean(lambdaWetting, lambdaNonwetting);
333 const Scalar lambdaWS = harmonicMean(lambdaWetting, lambdaSolid);
334 const Scalar lambdaNS = harmonicMean(lambdaNonwetting, lambdaSolid);
335
336 const Scalar characteristicLength = volVars.characteristicLength() ;
337 const Scalar factorEnergyTransfer = volVars.factorEnergyTransfer() ;
338
339 const Scalar nusseltWN = harmonicMean(volVars.nusseltNumber(phase0Idx), volVars.nusseltNumber(phase1Idx));
340 const Scalar nusseltWS = volVars.nusseltNumber(phase0Idx);
341 const Scalar nusseltNS = volVars.nusseltNumber(phase1Idx);
342
343 const Scalar wettingToNonwettingEnergyExchange = factorEnergyTransfer * (Tw - Tn) / characteristicLength * awn * lambdaWN * nusseltWN ;
344 const Scalar wettingToSolidEnergyExchange = factorEnergyTransfer * (Tw - Ts) / characteristicLength * aws * lambdaWS * nusseltWS ;
345 const Scalar nonwettingToSolidEnergyExchange = factorEnergyTransfer * (Tn - Ts) / characteristicLength * ans * lambdaNS * nusseltNS ;
346
347 for(int phaseIdx = 0; phaseIdx < numEnergyEqFluid+numEnergyEqSolid; ++phaseIdx)
348 {
349 switch (phaseIdx)
350 {
351 case phase0Idx:
352 source[energyEq0Idx + phaseIdx] += ( - wettingToNonwettingEnergyExchange - wettingToSolidEnergyExchange);
353 break;
354 case phase1Idx:
355 source[energyEq0Idx + phaseIdx] += (+ wettingToNonwettingEnergyExchange - nonwettingToSolidEnergyExchange);
356 break;
357 case sPhaseIdx:
358 source[energyEq0Idx + phaseIdx] += (+ wettingToSolidEnergyExchange + nonwettingToSolidEnergyExchange);
359 break;
360 default:
361 DUNE_THROW(Dune::NotImplemented,
362 "wrong index");
363 } // end switch
364
365
366 using std::isfinite;
367 if (!isfinite(source[energyEq0Idx + phaseIdx]))
368 DUNE_THROW(NumericalProblem, "Calculated non-finite source, " << "Tw="<< Tw << " Tn="<< Tn<< " Ts="<< Ts);
369 }// end phases
370
371 // we only need to do this for when there is more than 1 fluid phase
372 if (enableChemicalNonEquilibrium)
373 {
374 // Here comes the catch: We are not doing energy conservation for the whole
375 // system, but rather for each individual phase.
376 // -> Therefore the energy fluxes over each phase boundary need be
377 // individually accounted for.
378 // -> Each particle crossing a phase boundary does carry some mass and
379 // thus energy!
380 // -> Therefore, this contribution needs to be added.
381 // -> the particle always brings the energy of the originating phase.
382 // -> Energy advectivly transported into a phase = the moles of a component that go into a phase
383 // * molMass * enthalpy of the component in the *originating* phase
384
385 const auto& fluidState = volVars.fluidState();
386
387 for(int phaseIdx = 0; phaseIdx < numEnergyEqFluid+numEnergyEqSolid; ++phaseIdx)
388 {
389 switch (phaseIdx)
390 {
391 case phase0Idx:
392 //sum up the transfered energy by the components into the wetting phase
393 for(int compIdx = 0; compIdx < numComponents; ++compIdx)
394 {
395 const unsigned int eqIdx = conti0EqIdx + compIdx + phaseIdx*numComponents;
396 source[energyEq0Idx + phaseIdx] += (source[eqIdx]
397 * FluidSystem::molarMass(compIdx)
398 * FluidSystem::componentEnthalpy(fluidState, phase1Idx, compIdx) );
399 }
400 break;
401 case phase1Idx:
402 //sum up the transfered energy by the components into the nonwetting phase
403 for(int compIdx =0; compIdx<numComponents; ++compIdx)
404 {
405 const unsigned int eqIdx = conti0EqIdx + compIdx + phaseIdx*numComponents;
406 source[energyEq0Idx + phaseIdx] += (source[eqIdx]
407 * FluidSystem::molarMass(compIdx)
408 *FluidSystem::componentEnthalpy(fluidState, phase0Idx, compIdx));
409 }
410 break;
411 case sPhaseIdx:
412 break; // no sorption
413 default:
414 DUNE_THROW(Dune::NotImplemented,
415 "wrong index");
416 } // end switch
417 } // end phases
418 } // EnableChemicalNonEquilibrium
419 } // end source
420};
421} // end namespace Dumux
422
423#endif
Some exceptions thrown in DuMux
Provides 3rd order polynomial splines.
A helper to deduce a vector with the same size as numbers of equations.
The reference frameworks and formulations available for splitting total fluxes into a advective and d...
constexpr Scalar harmonicMean(Scalar x, Scalar y, Scalar wx=1.0, Scalar wy=1.0) noexcept
Calculate the (weighted) harmonic mean of two scalar values.
Definition: math.hh:69
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:46
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
Exception thrown if a fixable numerical problem occurs.
Definition: exceptions.hh:39
This file contains the parts of the local residual to calculate the heat conservation in the thermal ...
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:44
static void computeSourceEnergy(NumEqVector &source, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const SubControlVolume &scv)
heat transfer between the phases for nonequilibrium models
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:162
static void solidPhaseStorage(NumEqVector &storage, const SubControlVolume &scv, const VolumeVariables &volVars)
The energy storage in the solid matrix.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:89
static void fluidPhaseStorage(NumEqVector &storage, const SubControlVolume &scv, const VolumeVariables &volVars, int phaseIdx)
The energy storage in the fluid phase with index phaseIdx.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:74
static void heatConductionFlux(NumEqVector &flux, FluxVariables &fluxVars)
The diffusive energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:143
static void heatConvectionFlux(NumEqVector &flux, FluxVariables &fluxVars, int phaseIdx)
The advective phase energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:105
static void computeSourceEnergy(NumEqVector &source, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const SubControlVolume &scv)
Calculates the source term of the equation.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:311
static void heatConvectionFlux(NumEqVector &flux, FluxVariables &fluxVars, int phaseIdx)
The advective phase energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:257
static void heatConductionFlux(NumEqVector &flux, FluxVariables &fluxVars)
The diffusive energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:290
static void fluidPhaseStorage(NumEqVector &storage, const SubControlVolume &scv, const VolumeVariables &volVars, int phaseIdx)
The energy storage in the fluid phase with index phaseIdx.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:245
Declares all properties used in Dumux.