View Issue Details

IDProjectCategoryView StatusLast Update
0003411OpenFOAMContributionpublic2020-01-13 09:58
ReporterblttkglAssigned To 
PrioritylowSeverityfeatureReproducibilityN/A
Status newResolutionopen 
PlatformUnixOSOtherOS Version(please specify)
Product Versiondev 
Fixed in Version 
Summary0003411: MIxture fraction functionObject
DescriptionMixture fraction (Z) is a normalized quantity for measuring the fuel/oxidizer ratio in a mixture, where Z=0 corresponds to pure oxidizer, and Z=1 corresponds to pure fuel. It is widely used by the researchers in combustion field.

I attach a patch which includes a functionObject to create the mixture fraction Z field for multi-species solvers, for example reactingFoam, based on Armin Wehrfritz's original implementation. To be able to define what "oxidizer" and "fuel" are, user should define their chemical composition in a mixtureFractionProperties dictionary. That's why, I have also modified the counterFlowFlame2D_GRI tutorial to use this new mixtureFraction functionObject.

The implementation is templated on the XiReactionRate functionObject, so I would say it follows OpenFOAM coding guidelines pretty well. Please let me know if you want something changed.

Best,

Bulut
TagsNo tags attached.

Activities

blttkgl

2019-12-12 23:01

reporter  

mixtureFraction.patch (18,563 bytes)
diff --git a/src/functionObjects/field/Make/files b/src/functionObjects/field/Make/files
index 2b950187e..ad1c7705f 100644
--- a/src/functionObjects/field/Make/files
+++ b/src/functionObjects/field/Make/files
@@ -59,6 +59,7 @@ writeCellCentres/writeCellCentres.C
 writeCellVolumes/writeCellVolumes.C
 
 XiReactionRate/XiReactionRate.C
+mixtureFraction/mixtureFraction.C
 streamFunction/streamFunction.C
 
 fieldsExpression/fieldsExpression.C
diff --git a/src/functionObjects/field/Make/options b/src/functionObjects/field/Make/options
index 5613d538a..d9a0004a8 100644
--- a/src/functionObjects/field/Make/options
+++ b/src/functionObjects/field/Make/options
@@ -11,7 +11,10 @@ EXE_INC = \
     -I$(LIB_SRC)/transportModels/compressible/lnInclude \
     -I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
     -I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
-    -I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude
+    -I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude \
+    -I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
+    -I$(LIB_SRC)/thermophysicalModels/reactionThermo/lnInclude \
+    -I$(LIB_SRC)/thermophysicalModels/chemistryModel/lnInclude
 
 LIB_LIBS = \
     -lfiniteVolume \
@@ -27,4 +30,5 @@ LIB_LIBS = \
     -llagrangian \
     -lfileFormats \
     -lsampling \
-    -lsurfMesh
+    -lsurfMesh \
+    -lchemistryModel
diff --git a/src/functionObjects/field/mixtureFraction/mixtureFraction.C b/src/functionObjects/field/mixtureFraction/mixtureFraction.C
new file mode 100644
index 000000000..11a84947e
--- /dev/null
+++ b/src/functionObjects/field/mixtureFraction/mixtureFraction.C
@@ -0,0 +1,337 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     | Website:  https://openfoam.org
+    \\  /    A nd           | Copyright (C) 2016-2018 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "mixtureFraction.H"
+#include "volFields.H"
+#include "fvcGrad.H"
+#include "addToRunTimeSelectionTable.H"
+#include "atomicWeights.H"
+#include "psiReactionThermo.H"
+#include "BasicChemistryModel.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+    defineTypeNameAndDebug(mixtureFraction, 0);
+    addToRunTimeSelectionTable(functionObject, mixtureFraction, dictionary);
+}
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::functionObjects::mixtureFraction::mixtureFraction
+(
+    const word& name,
+    const Time& runTime,
+    const dictionary& dict
+)
+:
+    fvMeshFunctionObject(name, runTime, dict),
+    alpha(init_alpha()),
+    beta_of(init_beta())
+{
+    read(dict);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::functionObjects::mixtureFraction::~mixtureFraction()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+Foam::List<Foam::scalar> Foam::functionObjects::mixtureFraction::init_alpha() const{
+
+  const IOdictionary mixFracDict
+    (
+        IOobject
+        (
+            "mixtureFractionProperties",
+            mesh_.time().constant(),
+            mesh_,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        )
+    );
+
+    const psiReactionThermo& thermo = mesh_.lookupObject<psiReactionThermo>("thermophysicalProperties");
+
+    const wordList& species_ = thermo.composition().species();
+    List<scalar> alpha(species_.size(), 0.0);
+
+    forAll(alpha, i)
+    {
+        const dictionary& dict = mixFracDict.subDict(species_[i]).subDict("elements");
+        scalar a0
+        (
+            2.0
+        *dict.lookupOrDefault<label>("C",0)
+        /thermo.composition().Wi(i)
+        );
+        scalar a1
+        (
+            0.5
+        *dict.lookupOrDefault<label>("H",0)
+        /thermo.composition().Wi(i)
+        );
+        scalar a2
+        (
+        -1.0
+        *dict.lookupOrDefault<label>("O",0)
+        /thermo.composition().Wi(i)
+        );
+        alpha[i] = a0 + a1 + a2;
+    }
+
+    return alpha;
+
+}
+
+Foam::List<Foam::scalar> Foam::functionObjects::mixtureFraction::init_beta() const{
+
+   const IOdictionary mixFracDict
+    (
+        IOobject
+        (
+            "mixtureFractionProperties",
+            mesh_.time().constant(),
+            mesh_,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        )
+    );
+
+    const psiReactionThermo& thermo = mesh_.lookupObject<psiReactionThermo>("thermophysicalProperties");
+
+    const wordList& species_ = thermo.composition().species();
+    List<scalar> alpha(species_.size(), 0.0);
+
+    forAll(alpha, i)
+    {
+        const dictionary& dict = mixFracDict.subDict(species_[i]).subDict("elements");
+        scalar a0
+        (
+            2.0
+        *dict.lookupOrDefault<label>("C",0)
+        /thermo.composition().Wi(i)
+        );
+        scalar a1
+        (
+            0.5
+        *dict.lookupOrDefault<label>("H",0)
+        /thermo.composition().Wi(i)
+        );
+        scalar a2
+        (
+        -1.0
+        *dict.lookupOrDefault<label>("O",0)
+        /thermo.composition().Wi(i)
+        );
+        alpha[i] = a0 + a1 + a2;
+    }
+
+
+    //Constant oxidizer and fuel stream variables 
+    List<List<scalar> > Yconst( 2, List<scalar>(species_.size(),0.0) );
+    forAll(species_, i)
+    {
+        Yconst[0][i] =
+            mixFracDict.subDict
+            (
+                "oxidizerMassFractions"
+            ).lookupOrDefault<scalar>(species_[i], 0.0);
+        Yconst[1][i] =
+            mixFracDict.subDict
+            (
+                "fuelMassFractions"
+            ).lookupOrDefault<scalar>(species_[i], 0.0);
+    }
+
+    scalar YoxTot = 0.0;
+    scalar YfuTot = 0.0;
+    forAll(species_, i)
+    {
+        YoxTot += Yconst[0][i];
+        YfuTot += Yconst[1][i];
+    }
+
+    if (mag(1.0 - YoxTot) > SMALL || mag(1.0 - YfuTot) > SMALL)
+    {
+        FatalErrorIn
+        (
+            "createMixtureFraction.H :"
+        )
+        << "oxidizerMassFractions or fuelMassFractions do not sum up to 1.0"
+        << abort(FatalError);
+    }
+
+    // constructing the beta function at the oxidizer and fuel streams
+    List<scalar> beta_of(2, 0.0);
+    forAll(species_, i)
+    {
+        beta_of[0] += alpha[i]*Yconst[0][i]; // oxidizer
+        beta_of[1] += alpha[i]*Yconst[1][i]; // fuel
+    }
+
+    // Compute element mass fraction coefficients (only for printing information)
+    List<List<scalar> > a(species_.size(), List<scalar>(3,0.0));
+    forAll(species_, i)
+    {
+        const dictionary& dict = mixFracDict.subDict(species_[i]).subDict("elements");
+        a[i][0] =
+            dict.lookupOrDefault<label>("C",0)
+        *atomicWeights["C"]
+        /thermo.composition().Wi(i) ;
+        a[i][1] =
+            dict.lookupOrDefault<label>("H",0)
+        *atomicWeights["H"]
+        /thermo.composition().Wi(i) ;
+        a[i][2] =
+            dict.lookupOrDefault<label>("O",0)
+        *atomicWeights["O"]
+        /thermo.composition().Wi(i) ;
+    }
+
+    // Compute element mass fractions (only for printing)
+    List<scalar> Zox(species_.size(),0.0);
+    List<scalar> Zfu(species_.size(),0.0);
+    forAll(Zox, j)
+    {
+        forAll(species_, i)
+        {
+            Zox[j] += a[i][j]*Yconst[0][i];
+        }
+    }
+    forAll(Zfu, j)
+    {
+        forAll(species_, i)
+        {
+            Zfu[j] += a[i][j]*Yconst[1][i];
+        }
+    }
+
+
+    // Stoichiometric mixture fraction
+    scalar Z_st =  (0.0 - beta_of[0])/(beta_of[1] - beta_of[0]);
+
+
+
+
+    // Print out some information
+    Info<< "    Oxidizer:" << nl
+        << "    speciesMassFractions:" << nl;
+    forAll(species_, i)
+    {
+        if (Yconst[0][i] != 0.0)
+        {
+            Info<< "        Y("<<species_[i]<<") = " << Yconst[0][i] << nl;
+        }
+    }
+    Info<< "    elementMassFractions:" << nl
+        << "        Z(C) = " << Zox[0] << nl
+        << "        Z(H) = " << Zox[1] << nl
+        << "        Z(O) = " << Zox[2] << nl
+        << endl;
+
+    Info<< "    Fuel:" << nl
+        << "    speciesMassFractions:" << nl;
+    forAll(species_, i)
+    {
+        if (Yconst[1][i] != 0.0)
+        {
+            Info<< "        Y("<<species_[i]<<") = " << Yconst[1][i] << nl;
+        }
+    }
+    Info<< "    elementMassFractions:" << nl
+        << "        Z(C) = " << Zfu[0] << nl
+        << "        Z(H) = " << Zfu[1] << nl
+        << "        Z(O) = " << Zfu[2] << nl
+        << endl;
+
+    // Stoichiometric mixture fraction
+    Info<<"    Stoichiomentric mixture fraction Zst = " << Z_st << endl;
+
+    return beta_of;
+
+}
+
+
+
+bool Foam::functionObjects::mixtureFraction::execute()
+{
+    return true;
+}
+
+
+bool Foam::functionObjects::mixtureFraction::write()
+{
+
+    const psiReactionThermo& thermo = mesh_.lookupObject<psiReactionThermo>("thermophysicalProperties");
+    const PtrList<volScalarField>& Y = thermo.composition().Y();
+
+    const volScalarField& p = mesh_.lookupObject<volScalarField>("p");
+    volScalarField Z
+    (
+        IOobject
+        (
+            "Z",
+            time_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::AUTO_WRITE,
+            true
+        ),
+        mesh_,
+        dimensionedScalar("Z", dimless, 0.0)
+    );
+
+
+
+    forAll(p, celli)
+    {
+        scalar beta = 0.0;
+        forAll(Y, iField)
+        {
+            scalarField Yi = Y[iField];        
+            beta += alpha[iField]*Yi[celli];
+        }
+        Z[celli] = (beta - beta_of[0])/(beta_of[1] - beta_of[0]);
+    }
+    Z.correctBoundaryConditions();
+    Z.write();
+
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/functionObjects/field/mixtureFraction/mixtureFraction.H b/src/functionObjects/field/mixtureFraction/mixtureFraction.H
new file mode 100644
index 000000000..a43ad106c
--- /dev/null
+++ b/src/functionObjects/field/mixtureFraction/mixtureFraction.H
@@ -0,0 +1,199 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     | Website:  https://openfoam.org
+    \\  /    A nd           | Copyright (C) 2016-2018 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+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/>.
+
+Class
+    Foam::functionObjects::mixtureFraction
+
+Description
+    Computes the mixture fraction (Z) definition by Bilger et al. (1990),
+    based on element conservation for multi-species solvers. Based on original
+    implementation by Armin Wehrfritz.
+
+
+    \f[
+        Z = (beta - beta_0)/(beta_1 - beta_0)
+    \f]
+
+    with
+    \f[
+        beta = 2 \frac{Z_C}{W_C} + 0.5 \frac{Z_H}{W_H} - 1 \frac{Z_O}{W_O}
+    \f]
+
+    and
+    \f[
+        Z_k = \sum\limits_{i=1}^N(\frac{a_{k,i} W_k}{W_i} Y_i)
+    \f]
+
+    where
+    \vartable
+        Z       | Mixture fraction
+        beta    | Conserved scalar
+        beta_0  | Conserved scalar in the oxidiser stream
+        beta_1  | Conserved scalar in the fuel stream
+        Z_k     | Element mass fractions (k = [C, H, O])
+        W_k     | Atomic weights (k = [C, H, O])
+        a_{k,i} | Number of atoms of element 'k' in specie 'i'
+        N       | Number of species
+        Y_i     | Species mass fractions
+    \endvartable
+
+
+Usage:
+
+    A mixtureFractionProperties object file must be created in the constant
+    folder defining the oxidizer and fuel port mass fraction values.
+
+    Example:
+
+	oxidizerMassFractions
+	{
+	    N2       0.77;
+	    O2	     0.23;
+
+	}
+
+	fuelMassFractions
+	{
+	    CH4       1.0;
+	}
+
+
+	#include "$FOAM_CASE/constant/thermo.compressibleGasGRI"
+
+
+    
+    \table
+        Property  | Description                  | Required  | Default value
+        type      | type name: mixtureFraction   | yes       |
+    \endtable
+
+
+References:
+
+    \verbatim
+        Bilger, R.; Stårner, S. & Kee, R.
+        On reduced mechanisms for methane-air combustion in nonpremixed flames
+        Combustion and Flame, 1990, 80, 135 - 149
+
+        J. C. Sutherland, P. J. Smith, And J. H. Chen
+        Quantification of differential diffusion in nonpremixed systems
+        Combustion Theory and Modelling, Vol. 9, No. 2, May 2005, 365–383
+
+        "Large Eddy Simulation of Fuel Spray Combustion"
+        Armin Wehrfritz,
+        PhD thesis, Aalto University, Finland, 2016
+    \endverbatim
+
+
+See also
+    Foam::functionObjects::fvMeshFunctionObject
+
+SourceFiles
+    mixtureFraction.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef functionObjects_mixtureFraction_H
+#define functionObjects_mixtureFraction_H
+
+#include "fvMeshFunctionObject.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class mixtureFraction Declaration
+\*---------------------------------------------------------------------------*/
+
+class mixtureFraction
+:
+    public fvMeshFunctionObject
+{
+    // Private member functions
+
+        //- Disallow default bitwise copy construct
+        mixtureFraction(const mixtureFraction&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const mixtureFraction&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("mixtureFraction");
+
+
+    // Constructors
+
+        //- Construct from Time and dictionary
+        mixtureFraction
+        (
+            const word& name,
+            const Time& runTime,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~mixtureFraction();
+
+
+    // Member Functions
+
+        //- Do nothing
+        virtual bool execute();
+
+
+        //- Write the cell-centre fields
+
+
+        virtual bool write();
+
+private:
+
+        List<scalar> alpha;
+        List<scalar> beta_of;
+
+        Foam::List<Foam::scalar> init_alpha() const;
+        Foam::List<Foam::scalar> init_beta() const;
+
+
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace functionObjects
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI/constant/mixtureFractionProperties b/tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI/constant/mixtureFractionProperties
new file mode 100644
index 000000000..4a58fdbe9
--- /dev/null
+++ b/tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI/constant/mixtureFractionProperties
@@ -0,0 +1,34 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  2.4.0                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    location    "constant";
+    object      mixtureFractionProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+oxidizerMassFractions
+{
+    N2       0.77;
+    O2	     0.23;
+
+}
+
+fuelMassFractions
+{
+    CH4       1.0;
+}
+
+
+#include "$FOAM_CASE/constant/thermo.compressibleGasGRI"
+
+
+// ************************************************************************* //
diff --git a/tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI/system/controlDict b/tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI/system/controlDict
index c50188f3a..9d984be50 100644
--- a/tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI/system/controlDict
+++ b/tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI/system/controlDict
@@ -52,6 +52,14 @@ maxCo           0.4;
 functions
 {
     #includeFunc Qdot
+
+    mixtureFraction
+    {
+        type        mixtureFraction;
+        libs        ("libfieldFunctionObjects.so");
+        writeControl    outputTime;
+    }
+
 }
 
 
mixtureFraction.patch (18,563 bytes)

blttkgl

2020-01-13 09:58

reporter   ~0011052

I don't know if you had the chance to look at this but a small update.

I realized after testing that the implementation I made, which calculates the mixture fraction inside the write() function fails for instance if the user wants to get cutplanes more often than field writing frequency. With this in mind I think the calculation of the mixture fraction should be in execute() function, while write() function should only have the command to write the field. In this case the user can decide how often should mixture fraction is calculated (executeControl) and how often it is written as a field (writeControl).

I can push an update on this if you are interested.

Best,

Bulut

Issue History

Date Modified Username Field Change
2019-12-12 23:01 blttkgl New Issue
2019-12-12 23:01 blttkgl File Added: mixtureFraction.patch
2020-01-13 09:58 blttkgl Note Added: 0011052