From 3556eac76c87ba20c23d412ab99319bb3ff47aff Mon Sep 17 00:00:00 2001 From: Katharina Heck <katharina.heck@iws.uni-stuttgart.de> Date: Mon, 19 Nov 2018 09:16:51 +0100 Subject: [PATCH] [mpnc][test] use extra combustionlocalresidual for combustion test as this is has some unique qboil functions. Cleanup normal nonequilibrium thermal localresidual, does now only normal energy exchange between phases --- .../nonequilibrium/thermal/localresidual.hh | 120 +--------- .../thermalnonequilibrium/CMakeLists.txt | 1 + .../combustionlocalresidual.hh | 225 ++++++++++++++++++ .../implicit/thermalnonequilibrium/problem.hh | 5 + 4 files changed, 238 insertions(+), 113 deletions(-) create mode 100644 test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/combustionlocalresidual.hh diff --git a/dumux/porousmediumflow/nonequilibrium/thermal/localresidual.hh b/dumux/porousmediumflow/nonequilibrium/thermal/localresidual.hh index f714851509..4047df849d 100644 --- a/dumux/porousmediumflow/nonequilibrium/thermal/localresidual.hh +++ b/dumux/porousmediumflow/nonequilibrium/thermal/localresidual.hh @@ -66,8 +66,6 @@ class EnergyLocalResidualNonEquilibrium<TypeTag, 1/*numEnergyEqFluid*/> enum { numPhases = ModelTraits::numPhases() }; enum { numComponents = ModelTraits::numComponents() }; - enum { phase0Idx = FluidSystem::phase0Idx}; - enum { phase1Idx = FluidSystem::phase1Idx}; public: //! The energy storage in the fluid phase with index phaseIdx @@ -147,12 +145,12 @@ public: FluxVariables& fluxVars) { //in case we have one energy equation for more than one fluid phase we use an effective law in the nonequilibrium fourierslaw - flux[energyEq0Idx] += fluxVars.heatConductionFlux(0); + flux[energyEq0Idx] += fluxVars.heatConductionFlux(0); //heat conduction for the solid phases - for(int sPhaseIdx=0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx) - { - flux[energyEqSolidIdx+sPhaseIdx] += fluxVars.heatConductionFlux(numPhases + sPhaseIdx); - } + for(int sPhaseIdx=0; sPhaseIdx<numEnergyEqSolid; ++sPhaseIdx) + { + flux[energyEqSolidIdx+sPhaseIdx] += fluxVars.heatConductionFlux(numPhases + sPhaseIdx); + } } /*! @@ -168,7 +166,6 @@ public: { //specialization for 2 fluid phases const auto& volVars = elemVolVars[scv]; - const auto& fs = volVars.fluidState() ; const Scalar characteristicLength = volVars.characteristicLength() ; //interfacial area @@ -179,71 +176,15 @@ public: const Scalar TFluid = volVars.temperatureFluid(0); const Scalar TSolid = volVars.temperatureSolid(); - const Scalar satW = fs.saturation(phase0Idx) ; - const Scalar satN = fs.saturation(phase1Idx) ; - - const Scalar eps = 1e-6 ; Scalar solidToFluidEnergyExchange ; - Scalar fluidConductivity ; - if (satW < 1.0 - eps) - fluidConductivity = volVars.fluidThermalConductivity(phase1Idx) ; - else if (satW >= 1.0 - eps) - fluidConductivity = volVars.fluidThermalConductivity(phase0Idx) ; - else - DUNE_THROW(Dune::NotImplemented, - "wrong range"); + const Scalar fluidConductivity = volVars.fluidThermalConductivity(0) ; const Scalar factorEnergyTransfer = volVars.factorEnergyTransfer() ; solidToFluidEnergyExchange = factorEnergyTransfer * (TSolid - TFluid) / characteristicLength * as * fluidConductivity ; - const Scalar epsRegul = 1e-3 ; - - if (satW < (0 + eps) ) - { - solidToFluidEnergyExchange *= volVars.nusseltNumber(phase1Idx) ; - } - else if ( (satW >= 0 + eps) and (satW < 1.0-eps) ) - { - solidToFluidEnergyExchange *= (volVars.nusseltNumber(phase1Idx) * satN ); - Scalar qBoil ; - if (satW<=epsRegul) - {// regularize - typedef Dumux::Spline<Scalar> Spline; - Spline sp(0.0, epsRegul, // x1, x2 - QBoilFunc(volVars, 0.0), QBoilFunc(volVars, epsRegul), // y1, y2 - 0.0,dQBoil_dSw(volVars, epsRegul)); // m1, m2 - - qBoil = sp.eval(satW) ; - } - - else if (satW>= (1.0-epsRegul) ) - {// regularize - typedef Dumux::Spline<Scalar> Spline; - Spline sp(1.0-epsRegul, 1.0, // x1, x2 - QBoilFunc(volVars, 1.0-epsRegul), 0.0, // y1, y2 - dQBoil_dSw(volVars, 1.0-epsRegul), 0.0 ); // m1, m2 - - qBoil = sp.eval(satW) ; - } - else - { - qBoil = QBoilFunc(volVars, satW) ; - } - - solidToFluidEnergyExchange += qBoil; - } - else if (satW >= 1.0-eps) - { - solidToFluidEnergyExchange *= volVars.nusseltNumber(phase0Idx) ; - } - else - DUNE_THROW(Dune::NotImplemented, - "wrong range"); - using std::isfinite; - if (!isfinite(solidToFluidEnergyExchange)) - DUNE_THROW(NumericalProblem, "Calculated non-finite source, " << "TFluid="<< TFluid << " TSolid="<< TSolid); + solidToFluidEnergyExchange *= volVars.nusseltNumber(0) ; for(int energyEqIdx =0; energyEqIdx<numEnergyEqFluid+numEnergyEqSolid; ++energyEqIdx) { @@ -261,53 +202,6 @@ public: } // end switch }// end energyEqIdx }// end source - - - /*! \brief Calculate the energy transfer during boiling, i.e. latent heat - * - * \param volVars The volume variables - * \param satW The wetting phase saturation. Not taken from volVars, because we regularize. - */ - static Scalar QBoilFunc(const VolumeVariables & volVars, - const Scalar satW) - { - // using saturation as input (instead of from volVars) - // in order to make regularization (evaluation at different points) easyer - const auto& fs = volVars.fluidState() ; - const Scalar g( 9.81 ) ; - const Scalar gamma(0.0589) ; - const Scalar TSolid = volVars.temperatureSolid(); - const Scalar characteristicLength = volVars.characteristicLength() ; - using std::pow; - const Scalar as = 6.0 * (1.0-volVars.porosity()) / characteristicLength ; - const Scalar mul = fs.viscosity(phase0Idx) ; - const Scalar deltahv = fs.enthalpy(phase1Idx) - fs.enthalpy(phase0Idx); - const Scalar deltaRho = fs.density(phase0Idx) - fs.density(phase1Idx) ; - const Scalar firstBracket = pow(g * deltaRho / gamma, 0.5); - const Scalar cp = FluidSystem::heatCapacity(fs, phase0Idx) ; - // This use of Tsat is only justified if the fluid is always boiling (tsat equals boiling conditions) - // If a different state is to be simulated, please use the actual fluid temperature instead. - const Scalar Tsat = FluidSystem::vaporTemperature(fs, phase1Idx ) ; - const Scalar deltaT = TSolid - Tsat ; - const Scalar secondBracket = pow( (cp *deltaT / (0.006 * deltahv) ) , 3.0 ) ; - const Scalar Prl = volVars.prandtlNumber(phase0Idx) ; - const Scalar thirdBracket = pow( 1/Prl , (1.7/0.33) ); - const Scalar QBoil = satW * as * mul * deltahv * firstBracket * secondBracket * thirdBracket ; - return QBoil; - } - - /*! \brief Calculate the derivative of the energy transfer function during boiling. Needed for regularization. - * - * \param volVars The volume variables - * \param satW The wetting phase saturation. Not taken from volVars, because we regularize. - */ - static Scalar dQBoil_dSw(const VolumeVariables & volVars, - const Scalar satW) - { - // on the fly derive w.r.t. Sw. - // Only linearly depending on it (directly) - return (QBoilFunc(volVars, satW) / satW ) ; - } }; template<class TypeTag> diff --git a/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/CMakeLists.txt b/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/CMakeLists.txt index 9fff88d75d..65f3ad9ac3 100644 --- a/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/CMakeLists.txt +++ b/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/CMakeLists.txt @@ -15,6 +15,7 @@ dune_add_test(COMPILE_ONLY # since it currently fails miserably with very differ #install sources install(FILES combustionfluidsystem.hh +combustionlocalresidual.hh problem.hh spatialparams.hh main.cc diff --git a/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/combustionlocalresidual.hh b/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/combustionlocalresidual.hh new file mode 100644 index 0000000000..4e2d8ff702 --- /dev/null +++ b/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/combustionlocalresidual.hh @@ -0,0 +1,225 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \ingroup PorousmediumThermalNonEquilibriumModel + * \brief This file contains the parts of the local residual to + * calculate the heat conservation in the thermal non-equilibrium model. + */ +#ifndef DUMUX_ENERGY_COMBUSTION_LOCAL_RESIDUAL_HH +#define DUMUX_ENERGY_COMBUSTION_LOCAL_RESIDUAL_HH + +#include <cmath> +#include <dumux/common/spline.hh> +#include <dumux/common/exceptions.hh> +#include <dumux/common/properties.hh> + +#include <dumux/porousmediumflow/nonequilibrium/thermal/localresidual.hh> + +namespace Dumux { + +/*! + * \ingroup PorousmediumThermalNonEquilibriumModel + * \brief This file contains the parts of the local residual to + * calculate the heat conservation in the thermal non-equilibrium model. + */ +template<class TypeTag> +class CombustionEnergyLocalResidual +: public EnergyLocalResidualNonEquilibrium<TypeTag, 1/*numEnergyEqFluid*/> +{ + using Scalar = GetPropType<TypeTag, Properties::Scalar>; + using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>; + using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>; + using FVElementGeometry = typename GetPropType<TypeTag, Properties::FVGridGeometry>::LocalView; + using SubControlVolume = typename FVElementGeometry::SubControlVolume; + using FluxVariables = GetPropType<TypeTag, Properties::FluxVariables>; + using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>; + using SolidSystem = GetPropType<TypeTag, Properties::SolidSystem>; + using GridView = GetPropType<TypeTag, Properties::GridView>; + using Element = typename GridView::template Codim<0>::Entity; + using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView; + using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; + + using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>; + using Indices = typename ModelTraits::Indices; + + enum { numEnergyEqFluid = ModelTraits::numEnergyEqFluid() }; + enum { numEnergyEqSolid = ModelTraits::numEnergyEqSolid() }; + enum { energyEq0Idx = Indices::energyEq0Idx }; + enum { energyEqSolidIdx = Indices::energyEqSolidIdx}; + + enum { numComponents = ModelTraits::numComponents() }; + +public: + /*! + * \brief Calculate the source term of the equation + * + * \param scv The sub-control volume over which we integrate the source term + */ + static void computeSourceEnergy(NumEqVector& source, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolume &scv) + { + //specialization for 2 fluid phases + const auto& volVars = elemVolVars[scv]; + const auto& fs = volVars.fluidState() ; + const Scalar characteristicLength = volVars.characteristicLength() ; + + //interfacial area + // Shi & Wang, Transport in porous media (2011) + const Scalar as = 6.0 * (1.0-volVars.porosity()) / characteristicLength ; + + //temperature fluid is the same for both fluids + const Scalar TFluid = volVars.temperatureFluid(0); + const Scalar TSolid = volVars.temperatureSolid(); + + const Scalar satW = fs.saturation(0) ; + const Scalar satN = fs.saturation(1) ; + + const Scalar eps = 1e-6 ; + Scalar solidToFluidEnergyExchange ; + + Scalar fluidConductivity ; + if (satW < 1.0 - eps) + fluidConductivity = volVars.fluidThermalConductivity(1) ; + else if (satW >= 1.0 - eps) + fluidConductivity = volVars.fluidThermalConductivity(0) ; + else + DUNE_THROW(Dune::NotImplemented, + "wrong range"); + + const Scalar factorEnergyTransfer = volVars.factorEnergyTransfer() ; + + solidToFluidEnergyExchange = factorEnergyTransfer * (TSolid - TFluid) / characteristicLength * as * fluidConductivity ; + const Scalar epsRegul = 1e-3 ; + + if (satW < (0 + eps) ) + { + solidToFluidEnergyExchange *= volVars.nusseltNumber(1) ; + } + else if ( (satW >= 0 + eps) and (satW < 1.0-eps) ) + { + solidToFluidEnergyExchange *= (volVars.nusseltNumber(1) * satN ); + Scalar qBoil ; + if (satW<=epsRegul) + {// regularize + typedef Dumux::Spline<Scalar> Spline; + Spline sp(0.0, epsRegul, // x1, x2 + QBoilFunc(volVars, 0.0), QBoilFunc(volVars, epsRegul), // y1, y2 + 0.0,dQBoil_dSw(volVars, epsRegul)); // m1, m2 + + qBoil = sp.eval(satW) ; + } + + else if (satW>= (1.0-epsRegul) ) + {// regularize + typedef Dumux::Spline<Scalar> Spline; + Spline sp(1.0-epsRegul, 1.0, // x1, x2 + QBoilFunc(volVars, 1.0-epsRegul), 0.0, // y1, y2 + dQBoil_dSw(volVars, 1.0-epsRegul), 0.0 ); // m1, m2 + + qBoil = sp.eval(satW) ; + } + else + { + qBoil = QBoilFunc(volVars, satW) ; + } + + solidToFluidEnergyExchange += qBoil; + } + else if (satW >= 1.0-eps) + { + solidToFluidEnergyExchange *= volVars.nusseltNumber(0) ; + } + else + DUNE_THROW(Dune::NotImplemented, + "wrong range"); + + using std::isfinite; + if (!isfinite(solidToFluidEnergyExchange)) + DUNE_THROW(NumericalProblem, "Calculated non-finite source, " << "TFluid="<< TFluid << " TSolid="<< TSolid); + + for(int energyEqIdx =0; energyEqIdx<numEnergyEqFluid+numEnergyEqSolid; ++energyEqIdx) + { + switch (energyEqIdx) + { + case 0 : + source[energyEq0Idx + energyEqIdx] += solidToFluidEnergyExchange; + break; + case 1 : + source[energyEq0Idx + energyEqIdx] -= solidToFluidEnergyExchange; + break; + default: + DUNE_THROW(Dune::NotImplemented, + "wrong index"); + } // end switch + }// end energyEqIdx + }// end source + + + /*! \brief Calculate the energy transfer during boiling, i.e. latent heat + * + * \param volVars The volume variables + * \param satW The wetting phase saturation. Not taken from volVars, because we regularize. + */ + static Scalar QBoilFunc(const VolumeVariables & volVars, + const Scalar satW) + { + // using saturation as input (instead of from volVars) + // in order to make regularization (evaluation at different points) easyer + const auto& fs = volVars.fluidState() ; + const Scalar g( 9.81 ) ; + const Scalar gamma(0.0589) ; + const Scalar TSolid = volVars.temperatureSolid(); + const Scalar characteristicLength = volVars.characteristicLength() ; + using std::pow; + const Scalar as = 6.0 * (1.0-volVars.porosity()) / characteristicLength ; + const Scalar mul = fs.viscosity(0) ; + const Scalar deltahv = fs.enthalpy(1) - fs.enthalpy(0); + const Scalar deltaRho = fs.density(0) - fs.density(1) ; + const Scalar firstBracket = pow(g * deltaRho / gamma, 0.5); + const Scalar cp = FluidSystem::heatCapacity(fs, 0) ; + // This use of Tsat is only justified if the fluid is always boiling (tsat equals boiling conditions) + // If a different state is to be simulated, please use the actual fluid temperature instead. + const Scalar Tsat = FluidSystem::vaporTemperature(fs, 1 ) ; + const Scalar deltaT = TSolid - Tsat ; + const Scalar secondBracket = pow( (cp *deltaT / (0.006 * deltahv) ) , 3.0 ) ; + const Scalar Prl = volVars.prandtlNumber(0) ; + const Scalar thirdBracket = pow( 1/Prl , (1.7/0.33) ); + const Scalar QBoil = satW * as * mul * deltahv * firstBracket * secondBracket * thirdBracket ; + return QBoil; + } + + /*! \brief Calculate the derivative of the energy transfer function during boiling. Needed for regularization. + * + * \param volVars The volume variables + * \param satW The wetting phase saturation. Not taken from volVars, because we regularize. + */ + static Scalar dQBoil_dSw(const VolumeVariables & volVars, + const Scalar satW) + { + // on the fly derive w.r.t. Sw. + // Only linearly depending on it (directly) + return (QBoilFunc(volVars, satW) / satW ) ; + } +}; +} // end namespace Dumux + +#endif // diff --git a/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/problem.hh b/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/problem.hh index 596bd1b626..2ef8a197bd 100644 --- a/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/problem.hh +++ b/test/porousmediumflow/mpnc/implicit/thermalnonequilibrium/problem.hh @@ -44,6 +44,7 @@ #include "spatialparams.hh" #include "combustionfluidsystem.hh" +#include "combustionlocalresidual.hh" namespace Dumux { @@ -154,6 +155,10 @@ private: public: using type = CompositionalSolidState<Scalar, SolidSystem>; }; + +template<class TypeTag> +struct EnergyLocalResidual<TypeTag, TTag::CombustionOneComponent> +{ using type = CombustionEnergyLocalResidual<TypeTag>; }; } /*! * \ingroup MPNCTests -- GitLab