3.6-git
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// vi: set et ts=4 sw=4 sts=4:
3/*****************************************************************************
4 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
26#ifndef DUMUX_ENERGY_NONEQUILIBRIUM_LOCAL_RESIDUAL_HH
27#define DUMUX_ENERGY_NONEQUILIBRIUM_LOCAL_RESIDUAL_HH
28
29#include <cmath>
35
36namespace Dumux {
37
43// forward declaration
44template <class TypeTag, int numEnergyEqFluid>
46
47template<class TypeTag>
48class EnergyLocalResidualNonEquilibrium<TypeTag, 1/*numEnergyEqFluid*/>
49{
53 using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
54 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
58 using Element = typename GridView::template Codim<0>::Entity;
59 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
60 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
61
63 using Indices = typename ModelTraits::Indices;
64
65 static constexpr auto numEnergyEqFluid = ModelTraits::numEnergyEqFluid();
66 static constexpr auto numEnergyEqSolid = ModelTraits::numEnergyEqSolid();
67 static constexpr auto energyEq0Idx = Indices::energyEq0Idx;
68 static constexpr auto energyEqSolidIdx = Indices::energyEqSolidIdx;
69
70 static constexpr auto numPhases = ModelTraits::numFluidPhases();
71 static constexpr auto numComponents = ModelTraits::numFluidComponents();
72
73public:
75 static void fluidPhaseStorage(NumEqVector& storage,
76 const SubControlVolume& scv,
77 const VolumeVariables& volVars,
78 int phaseIdx)
79 {
80 //in case we have one energy equation for more than one fluid phase, add up parts on the one energy equation
81 storage[energyEq0Idx] += volVars.porosity()
82 * volVars.density(phaseIdx)
83 * volVars.internalEnergy(phaseIdx)
84 * volVars.saturation(phaseIdx);
85
86 }
87
88
90 static void solidPhaseStorage(NumEqVector& storage,
91 const SubControlVolume& scv,
92 const VolumeVariables& volVars)
93 {
94 // heat conduction for the fluid phases
95 for(int sPhaseIdx = 0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx)
96 {
97 storage[energyEqSolidIdx+sPhaseIdx] += volVars.temperatureSolid()
98 * volVars.solidHeatCapacity()
99 * volVars.solidDensity()
100 * (1.0 - volVars.porosity());
101 }
102 }
103
110 static void heatDispersionFlux(NumEqVector& flux,
111 FluxVariables& fluxVars)
112 {}
113
115 static void heatConvectionFlux(NumEqVector& flux,
116 FluxVariables& fluxVars,
117 int phaseIdx)
118 {
119 auto upwindTerm = [phaseIdx](const auto& volVars)
120 { return volVars.density(phaseIdx)*volVars.mobility(phaseIdx)*volVars.enthalpy(phaseIdx); };
121
122 //in case we have one energy equation for more than one fluid phase, add up advective parts on the one energy equation
123 flux[energyEq0Idx] += fluxVars.advectiveFlux(phaseIdx, upwindTerm);
124
125 //now add the diffusive part
126 const auto diffusiveFluxes = fluxVars.molecularDiffusionFlux(phaseIdx);
127 const auto& elemVolVars = fluxVars.elemVolVars();
128 const auto& scvf = fluxVars.scvFace();
129 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
130 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
131
132 for (int compIdx = 0; compIdx < numComponents; ++compIdx)
133 {
134 //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
135 if (phaseIdx == compIdx)
136 continue;
137 //we need the upwind enthalpy. Even better would be the componentEnthalpy
138 auto enthalpy = 0.0;
139 if (diffusiveFluxes[compIdx] > 0)
140 enthalpy += insideVolVars.enthalpy(phaseIdx);
141 else
142 enthalpy += outsideVolVars.enthalpy(phaseIdx);
143
144 //check for the reference system and adapt units of the diffusive flux accordingly.
145 if (FluxVariables::MolecularDiffusionType::referenceSystemFormulation() == ReferenceSystemFormulation::massAveraged)
146 flux[energyEq0Idx] += diffusiveFluxes[compIdx]*enthalpy;
147 else
148 flux[energyEq0Idx] += diffusiveFluxes[compIdx]*FluidSystem::molarMass(compIdx)*enthalpy;
149 }
150 }
151
153 static void heatConductionFlux(NumEqVector& flux,
154 FluxVariables& fluxVars)
155 {
156 //in case we have one energy equation for more than one fluid phase we use an effective law in the nonequilibrium fourierslaw
157 flux[energyEq0Idx] += fluxVars.heatConductionFlux(0);
158 //heat conduction for the solid phases
159 for(int sPhaseIdx = 0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx)
160 flux[energyEqSolidIdx+sPhaseIdx] += fluxVars.heatConductionFlux(numPhases + sPhaseIdx);
161 }
162
172 static void computeSourceEnergy(NumEqVector& source,
173 const Element& element,
174 const FVElementGeometry& fvGeometry,
175 const ElementVolumeVariables& elemVolVars,
176 const SubControlVolume &scv)
177 {
178 // specialization for 2 fluid phases
179 const auto& volVars = elemVolVars[scv];
180 const Scalar characteristicLength = volVars.characteristicLength() ;
181
182 // interfacial area
183 // Shi & Wang, Transport in porous media (2011)
184 const Scalar as = volVars.fluidSolidInterfacialArea();
185
186 // temperature fluid is the same for both fluids
187 const Scalar TFluid = volVars.temperatureFluid(0);
188 const Scalar TSolid = volVars.temperatureSolid();
189
190 Scalar solidToFluidEnergyExchange ;
191
192 const Scalar fluidConductivity = volVars.fluidThermalConductivity(0) ;
193
194 const Scalar factorEnergyTransfer = volVars.factorEnergyTransfer() ;
195
196 solidToFluidEnergyExchange = factorEnergyTransfer * (TSolid - TFluid) / characteristicLength * as * fluidConductivity;
197
198 solidToFluidEnergyExchange *= volVars.nusseltNumber(0);
199
200 for(int energyEqIdx = 0; energyEqIdx < numEnergyEqFluid+numEnergyEqSolid; ++energyEqIdx)
201 {
202 switch (energyEqIdx)
203 {
204 case 0 :
205 source[energyEq0Idx + energyEqIdx] += solidToFluidEnergyExchange;
206 break;
207 case 1 :
208 source[energyEq0Idx + energyEqIdx] -= solidToFluidEnergyExchange;
209 break;
210 default:
211 DUNE_THROW(Dune::NotImplemented,
212 "wrong index");
213 } // end switch
214 } // end energyEqIdx
215 } // end source
216};
217
218template<class TypeTag>
219class EnergyLocalResidualNonEquilibrium<TypeTag, 2/*numEnergyEqFluid*/>
220: public EnergyLocalResidualNonEquilibrium<TypeTag, 1/*numEnergyEqFluid*/>
221{
225 using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
226 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
231 using Element = typename GridView::template Codim<0>::Entity;
232 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
233 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
234
236 using Indices = typename ModelTraits::Indices;
237
238 enum { numPhases = ModelTraits::numFluidPhases() };
239 enum { numEnergyEqFluid = ModelTraits::numEnergyEqFluid() };
240 enum { numEnergyEqSolid = ModelTraits::numEnergyEqSolid() };
241 enum { energyEq0Idx = Indices::energyEq0Idx };
242 enum { energyEqSolidIdx = Indices::energyEqSolidIdx};
243 enum { conti0EqIdx = Indices::conti0EqIdx };
244
245 enum { numComponents = ModelTraits::numFluidComponents() };
246 enum { phase0Idx = FluidSystem::phase0Idx};
247 enum { phase1Idx = FluidSystem::phase1Idx};
248 enum { sPhaseIdx = numPhases};
249
250 static constexpr bool enableChemicalNonEquilibrium = ModelTraits::enableChemicalNonEquilibrium();
251
252public:
253
255 static void fluidPhaseStorage(NumEqVector& storage,
256 const SubControlVolume& scv,
257 const VolumeVariables& volVars,
258 int phaseIdx)
259 {
260 storage[energyEq0Idx+phaseIdx] += volVars.porosity()
261 * volVars.density(phaseIdx)
262 * volVars.internalEnergy(phaseIdx)
263 * volVars.saturation(phaseIdx);
264 }
265
267 static void heatConvectionFlux(NumEqVector& flux,
268 FluxVariables& fluxVars,
269 int phaseIdx)
270 {
271 auto upwindTerm = [phaseIdx](const auto& volVars)
272 { return volVars.density(phaseIdx)*volVars.mobility(phaseIdx)*volVars.enthalpy(phaseIdx); };
273
274 // in case we have one energy equation for more than one fluid phase, add up advective parts on the one energy equation
275 flux[energyEq0Idx+phaseIdx] += fluxVars.advectiveFlux(phaseIdx, upwindTerm);
276
277 // add the diffusiv part
278 const auto diffusiveFluxes = fluxVars.molecularDiffusionFlux(phaseIdx);
279 const auto& elemVolVars = fluxVars.elemVolVars();
280 const auto& scvf = fluxVars.scvFace();
281 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
282 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
283
284 for (int compIdx = 0; compIdx < numComponents; ++compIdx)
285 {
286 // 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
287 if (phaseIdx == compIdx)
288 continue;
289 // we need the upwind enthalpy. Even better would be the componentEnthalpy
290 auto enthalpy = 0.0;
291 if (diffusiveFluxes[compIdx] > 0)
292 enthalpy += insideVolVars.enthalpy(phaseIdx);
293 else
294 enthalpy += outsideVolVars.enthalpy(phaseIdx);
295 flux[energyEq0Idx+phaseIdx] += diffusiveFluxes[compIdx]*FluidSystem::molarMass(compIdx)*enthalpy;
296 }
297 }
298
300 static void heatConductionFlux(NumEqVector& flux,
301 FluxVariables& fluxVars)
302 {
303 for(int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
304 {
305 flux[energyEq0Idx+phaseIdx] += fluxVars.heatConductionFlux(phaseIdx);
306 }
307 for(int sPhaseIdx=0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx)
308 {
309 flux[energyEqSolidIdx+sPhaseIdx] += fluxVars.heatConductionFlux(numPhases + sPhaseIdx);
310 }
311 }
312
319 static void heatDispersionFlux(NumEqVector& flux,
320 FluxVariables& fluxVars)
321 {}
322
332 static void computeSourceEnergy(NumEqVector& source,
333 const Element& element,
334 const FVElementGeometry& fvGeometry,
335 const ElementVolumeVariables& elemVolVars,
336 const SubControlVolume &scv)
337 {
338 // specialization for 2 fluid phases
339 const auto &volVars = elemVolVars[scv];
340
341 const Scalar areaWN = volVars.interfacialArea(phase0Idx, phase1Idx);
342 const Scalar areaWS = volVars.interfacialArea(phase0Idx, sPhaseIdx);
343 const Scalar areaNS = volVars.interfacialArea(phase1Idx, sPhaseIdx);
344
345 const Scalar Tw = volVars.temperatureFluid(phase0Idx);
346 const Scalar Tn = volVars.temperatureFluid(phase1Idx);
347 const Scalar Ts = volVars.temperatureSolid();
348
349 const Scalar lambdaWetting = volVars.fluidThermalConductivity(phase0Idx);
350 const Scalar lambdaNonwetting = volVars.fluidThermalConductivity(phase1Idx);
351 const Scalar lambdaSolid = volVars.solidThermalConductivity();
352
353 const Scalar lambdaWN = harmonicMean(lambdaWetting, lambdaNonwetting);
354 const Scalar lambdaWS = harmonicMean(lambdaWetting, lambdaSolid);
355 const Scalar lambdaNS = harmonicMean(lambdaNonwetting, lambdaSolid);
356
357 const Scalar characteristicLength = volVars.characteristicLength() ;
358 const Scalar factorEnergyTransfer = volVars.factorEnergyTransfer() ;
359
360 const Scalar nusseltWN = harmonicMean(volVars.nusseltNumber(phase0Idx), volVars.nusseltNumber(phase1Idx));
361 const Scalar nusseltWS = volVars.nusseltNumber(phase0Idx);
362 const Scalar nusseltNS = volVars.nusseltNumber(phase1Idx);
363
364 const Scalar wettingToNonwettingEnergyExchange = factorEnergyTransfer * (Tw - Tn) / characteristicLength * areaWN * lambdaWN * nusseltWN ;
365 const Scalar wettingToSolidEnergyExchange = factorEnergyTransfer * (Tw - Ts) / characteristicLength * areaWS * lambdaWS * nusseltWS ;
366 const Scalar nonwettingToSolidEnergyExchange = factorEnergyTransfer * (Tn - Ts) / characteristicLength * areaNS * lambdaNS * nusseltNS ;
367
368 for(int phaseIdx = 0; phaseIdx < numEnergyEqFluid+numEnergyEqSolid; ++phaseIdx)
369 {
370 switch (phaseIdx)
371 {
372 case phase0Idx:
373 source[energyEq0Idx + phaseIdx] += ( - wettingToNonwettingEnergyExchange - wettingToSolidEnergyExchange);
374 break;
375 case phase1Idx:
376 source[energyEq0Idx + phaseIdx] += (+ wettingToNonwettingEnergyExchange - nonwettingToSolidEnergyExchange);
377 break;
378 case sPhaseIdx:
379 source[energyEq0Idx + phaseIdx] += (+ wettingToSolidEnergyExchange + nonwettingToSolidEnergyExchange);
380 break;
381 default:
382 DUNE_THROW(Dune::NotImplemented,
383 "wrong index");
384 } // end switch
385
386
387 using std::isfinite;
388 if (!isfinite(source[energyEq0Idx + phaseIdx]))
389 DUNE_THROW(NumericalProblem, "Calculated non-finite source, " << "Tw="<< Tw << " Tn="<< Tn<< " Ts="<< Ts);
390 }// end phases
391
392 // we only need to do this for when there is more than 1 fluid phase
393 if (enableChemicalNonEquilibrium)
394 {
395 // Here comes the catch: We are not doing energy conservation for the whole
396 // system, but rather for each individual phase.
397 // -> Therefore the energy fluxes over each phase boundary need be
398 // individually accounted for.
399 // -> Each particle crossing a phase boundary does carry some mass and
400 // thus energy!
401 // -> Therefore, this contribution needs to be added.
402 // -> the particle always brings the energy of the originating phase.
403 // -> Energy advectivly transported into a phase = the moles of a component that go into a phase
404 // * molMass * enthalpy of the component in the *originating* phase
405
406 const auto& fluidState = volVars.fluidState();
407
408 for(int phaseIdx = 0; phaseIdx < numEnergyEqFluid+numEnergyEqSolid; ++phaseIdx)
409 {
410 switch (phaseIdx)
411 {
412 case phase0Idx:
413 // sum up the transferred energy by the components into the wetting phase
414 for(int compIdx = 0; compIdx < numComponents; ++compIdx)
415 {
416 const unsigned int eqIdx = conti0EqIdx + compIdx + phaseIdx*numComponents;
417 source[energyEq0Idx + phaseIdx] += (source[eqIdx]
418 * FluidSystem::molarMass(compIdx)
419 * FluidSystem::componentEnthalpy(fluidState, phase1Idx, compIdx) );
420 }
421 break;
422 case phase1Idx:
423 // sum up the transferred energy by the components into the nonwetting phase
424 for(int compIdx =0; compIdx<numComponents; ++compIdx)
425 {
426 const unsigned int eqIdx = conti0EqIdx + compIdx + phaseIdx*numComponents;
427 source[energyEq0Idx + phaseIdx] += (source[eqIdx]
428 * FluidSystem::molarMass(compIdx)
429 *FluidSystem::componentEnthalpy(fluidState, phase0Idx, compIdx));
430 }
431 break;
432 case sPhaseIdx:
433 break; // no sorption
434 default:
435 DUNE_THROW(Dune::NotImplemented,
436 "wrong index");
437 } // end switch
438 } // end phases
439 } // EnableChemicalNonEquilibrium
440 } // end source
441};
442} // end namespace Dumux
443
444#endif
Some exceptions thrown in DuMux
A helper to deduce a vector with the same size as numbers of equations.
Provides 3rd order polynomial splines.
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
Adaption of the non-isothermal two-phase two-component flow model to problems with CO2.
Definition: adapt.hh:29
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:180
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:45
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:172
static void solidPhaseStorage(NumEqVector &storage, const SubControlVolume &scv, const VolumeVariables &volVars)
The energy storage in the solid matrix.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:90
static void heatDispersionFlux(NumEqVector &flux, FluxVariables &fluxVars)
The dispersive energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:110
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:75
static void heatConductionFlux(NumEqVector &flux, FluxVariables &fluxVars)
The diffusive energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:153
static void heatConvectionFlux(NumEqVector &flux, FluxVariables &fluxVars, int phaseIdx)
The advective phase energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:115
static void heatDispersionFlux(NumEqVector &flux, FluxVariables &fluxVars)
The dispersive energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:319
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:332
static void heatConvectionFlux(NumEqVector &flux, FluxVariables &fluxVars, int phaseIdx)
The advective phase energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:267
static void heatConductionFlux(NumEqVector &flux, FluxVariables &fluxVars)
The diffusive energy fluxes.
Definition: porousmediumflow/nonequilibrium/thermal/localresidual.hh:300
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:255
Declares all properties used in Dumux.