ChemFoam

From OpenFOAMWiki
Revision as of 11:22, 1 February 2020 by MAlletto (Talk | contribs)

chemFoam

   Solver for chemistry problems, designed for use on single cell cases to
   provide comparison against other chemistry solvers, that uses a single cell
   mesh, and fields created from the initial conditions.

1 Solution Strategy

This solver provides an excellent starting point for those who want to have a first impression on the influence of the chemical reactions in the equations describing the evolution of the species concentration and also the evolution of temperature (i.e. the energy equation). Since the computational domain consists only of one cell, the only mechanism influencing the evolution of the spices concentration and of the temperature are the chemical reactions. The system of equations which is solved is the following:



    \frac{  \partial \rho Y_i}{\partial t}   =  \dot \omega_i (Y_i,T)
(1)

     h = u_0 + \frac{p}{\rho} + \int_0^t \frac{\dot q}{\rho} d\tau
(2)

     p = \frac{ \rho R T}{M_{avg}}
(3)

 Y_i, \omega_i, T, p, \rho, \dot q, R, M_{avg}, u_0, are the species mass mass fraction, the reaction rate, the temperature, the pressure, the density, the heat generated by the combustion, the gas constant, the average molar weight and the initial internal energy, respectively. Note that for a given enthalpy, pressure and density the temperature can be calculated.

Like most of the solvers present in OpenFOAM also this solver follows a segregated solution strategy. That means that for each quantity of interest one linear equation is solved and the coupling between the equations is achieved by explicit source terms. Briefly summarized the solution is achieved as follows:

1) Solve the chemistry: The purpose is to get the reaction rates for each species involved and the heat realized by the chemical reaction

2) Solve the species equation: The purpose it to get the species concentration at the new time step

3) Solve the energy equation: Here we get the enthalpy (over the thermodynamics also the temperature) at the new time step

4) Solve the pressure equation: Required to calculate the enthalpy


The source code can be found in chemFoam.C


 
 
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
    \\  /    A nd           | Copyright (C) 2010-2011 OpenCFD Ltd.
     \\/     M anipulation  |
-------------------------------------------------------------------------------
                            | Copyright (C) 2011-2017 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
    This file is part of OpenFOAM.
 
    OpenFOAM 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 3 of the License, or
    (at your option) any later version.
 
    OpenFOAM 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 OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
Application
    chemFoam
 
Group
    grpCombustionSolvers
 
Description
    Solver for chemistry problems, designed for use on single cell cases to
    provide comparison against other chemistry solvers, that uses a single cell
    mesh, and fields created from the initial conditions.
 
\*---------------------------------------------------------------------------*/
 
#include "fvCFD.H"
#include "psiReactionThermo.H"
#include "BasicChemistryModel.H"
#include "reactingMixture.H"
#include "chemistrySolver.H"
#include "OFstream.H"
#include "thermoPhysicsTypes.H"
#include "basicSpecieMixture.H"
#include "hexCellFvMesh.H"
 
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
int main(int argc, char *argv[])
{
    argList::addNote
    (
        "Solver for chemistry problems, designed for use on single cell cases"
        " to provide comparison against other chemistry solvers"
    );
 
    argList::noParallel();
 
    #define CREATE_MESH createSingleCellMesh.H
    #define NO_CONTROL
    #include "postProcess.H"
 
    #include "setRootCaseLists.H"
    #include "createTime.H"
    #include "createSingleCellMesh.H"
    #include "createFields.H"
    #include "createFieldRefs.H"
    #include "readInitialConditions.H"
    #include "createControls.H"
 
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
    Info<< "\nStarting time loop\n" << endl;
 
    while (runTime.run())
    {
        #include "readControls.H"
 
        #include "setDeltaT.H"
 
        ++runTime;
        Info<< "Time = " << runTime.timeName() << nl << endl;
 
        #include "solveChemistry.H"
        #include "YEqn.H"
        #include "hEqn.H"
        #include "pEqn.H"
 
        #include "output.H"
 
        runTime.printExecutionTime(Info);
    }
 
    Info << "Number of steps = " << runTime.timeIndex() << endl;
    Info << "End" << nl << endl;
 
    return 0;
}
 
 
// ************************************************************************* //
 
 

2 Chemical reactions

Elementary chemical reaction involving  K species in  I reactions can be expressed in the following form (see also https://www3.nd.edu/~powers/ame.60636/chemkin2000.pdf or the book of [1]):


  \sum_{k=1}^K  \nu_{ki}' \chi_k \rightleftharpoons \sum_{k=1}^K  \nu_{ki}'' \chi_k  \ \ \ i=1...I
(4)

  \nu_{ki}',  \nu_{ki}'' and   \chi_k are the forward, the backward stoichiometric coefficient and the chemical symbol of the specie   k , respectively.

In order to make the notation more clear to those who start learning about the usage of CFD to simulate combustion process, Zel'dovich mechanism for the oxidation of N0 (see https://en.wikipedia.org/wiki/Zeldovich_mechanism or also the book of [2]) is used as an example:


  N_2 + O \rightleftharpoons  NO + N

N + O_2 \rightleftharpoons NO + O

Based on the above example the forward   \nu_{ki}' , the backward stoichiometric coefficient    \nu_{ki}'' and the chemical symbol of the specie k   \chi_k can be written as follows:


 \nu_{ki}' = \begin{pmatrix}1 & 1 & 0 & 0 & 0 \\0 & 0 & 0 & 1 & 1  \\\end{pmatrix},   \nu_{ki}'' = \begin{pmatrix}0 & 0 & 1 & 1 & 0 \\0 & 1 & 1 & 0 & 0  \\\end{pmatrix} ,   \chi_k = \begin{pmatrix}N_2 \\ O \\ NO \\ N \\ O_2  \\\end{pmatrix}

The reactions are specified in the file constant/thermophysicalProperties where the chemistry reader, the file containing the reactions and the thermodynamic properties have to be specified:


 
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1912                                 |
|   \\  /    A nd           | Website:  www.openfoam.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    location    "constant";
    object      thermophysicalProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
thermoType
{
    type            hePsiThermo;
    mixture         reactingMixture;
    transport       sutherland;
    thermo          janaf;
    energy          sensibleEnthalpy;
    equationOfState perfectGas;
    specie          specie;
}
 
 
chemistryReader foamChemistryReader;
foamChemistryFile "<constant>/reactions";
foamChemistryThermoFile "<constant>/thermo";
 
//CHEMKINFile         "<case>/chemkin/chem.inp";
//CHEMKINThermoFile   "<case>/chemkin/therm.dat";
//CHEMKINTransportFile "<case>/chemkin/transportProperties";
 
// ************************************************************************* //

For the above example the reactions look as follows:


 
elements        2(O N);
 
species         5(O O2 N2 N NO);
 
reactions
{
    un-named-reaction-0
    {
        type            reversibleArrheniusReaction;
        reaction        "NO + N = N2 + O";
        A               2.1e+10;
        beta            0;
        Ta              0;
    }
    un-named-reaction-1
    {
        type            reversibleArrheniusReaction;
        reaction        "N + O2 = NO + O";
        A               5.83e+06;
        beta            1.01;
        Ta              3120;
    }
}

3 Evolution of species


 
{
    forAll(Y, specieI)
    {
        volScalarField& Yi = Y[specieI];
 
        solve
        (
            fvm::ddt(rho, Yi) - chemistry.RR(specieI),
            mesh.solver("Yi")
        );
    }
}

4 Evolution of energy

The energy equation is derived from the first law of thermodynamics (see also https://en.wikipedia.org/wiki/Enthalpy): For closed systems the change of internal energy is equal to the heat supplied to the system. For open systems the change of enthalpy is equal to the heat supplied to the system. For the first case we get:

_
u = u_0 + q = u_0 + \int \dot q dt
(x)

If we add on both sides the pressure divided by the density we get:


_
u + \frac{p}{\rho}  = u_0 + \frac{p}{\rho} + \int \dot q dt \ \ , \ \  h = u + \frac{p}{\rho}
(x)

 u, u_0 are the internal energy and the internal energy at the time 0.


 
{
    volScalarField& h = thermo.he();
 
    if (constProp == "volume")
    {
        h[0] = u0 + p[0]/rho[0] + integratedHeat;
    }
    else
    {
        h[0] = h0 + integratedHeat;
    }
 
    thermo.correct();
}

With the above equation the evolution of the enthalpy with time can be calculated. Knowing the functional dependency of the heat capacity at constant pressure  c_p a relation between the enthalpy and the temperature can be established. For an example of how it is down in OpenFOAM with a polynomial dependency of the heat capacity from the temperature can be found here https://caefn.com/openfoam/temperature-calculation.

5 Evolution of the pressure

In order to calculate the pressure Daltons model is used: It says that the thermodynamic pressure can be calculated as the sum of the partial pressures of the individual species (see e.g. https://en.wikipedia.org/wiki/Dalton%27s_law):


_
p = \sum p_i = \sum n_i \frac{R T}{V} = \sum \frac{m_i}{M_i} \frac{R T}{V}  = \sum \frac{y_i}{M_i} \underbrace{ \frac{m_{tot}}{V}}_{\rho_0} R T
(x)

 p_i, n_i, m_i, M_i, y_i, m_{tot}, \rho_0 are the partial pressure, the number of molecules, the mass, the molar mass, the mass faction of the species i, the total mass and the initial density, respectively.


 
{
    rho = thermo.rho();
    if (constProp == "volume")
    {
        scalar invW = 0.0;
        forAll(Y, i)
        {
            invW += Y[i][0]/specieData[i].W();
        }
 
        Rspecific[0] = 1000.0*constant::physicoChemical::R.value()*invW;
 
        p[0] = rho0*Rspecific[0]*thermo.T()[0];
        rho[0] = rho0;
    }
}

Note that the constant 1000 in the above code comes from the fact that in OpenFOAM the molar weight is specified in [kg/kmol]. See the file $FOAM_SRC/thermophysicalModels/specie/specie/specie.H.

6 References

  1. Powers, Joseph. Combustion thermodynamics and dynamics. Cambridge University Press, 2016.
  2. Powers, Joseph. Combustion thermodynamics and dynamics. Cambridge University Press, 2016.