1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "chemkinReader.H"
29 #include "atomicWeights.H"
30 #include "IrreversibleReaction.H"
31 #include "ReversibleReaction.H"
32 #include "NonEquilibriumReversibleReaction.H"
33 #include "ArrheniusReactionRate.H"
34 #include "thirdBodyArrheniusReactionRate.H"
35 #include "FallOffReactionRate.H"
36 #include "ChemicallyActivatedReactionRate.H"
37 #include "LindemannFallOffFunction.H"
38 #include "TroeFallOffFunction.H"
39 #include "SRIFallOffFunction.H"
40 #include "LandauTellerReactionRate.H"
41 #include "JanevReactionRate.H"
42 #include "powerSeriesReactionRate.H"
43 #include "addToRunTimeSelectionTable.H"
45 /* * * * * * * * * * * * * * * * * Static data * * * * * * * * * * * * * * * */
49 addChemistryReaderType(chemkinReader, gasThermoPhysics);
52 /* * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * */
54 const char* Foam::chemkinReader::reactionTypeNames[4] =
58 "nonEquilibriumReversible",
62 const char* Foam::chemkinReader::reactionRateTypeNames[8] =
66 "unimolecularFallOff",
67 "chemicallyActivatedBimolecular",
71 "unknownReactionRateType"
74 const char* Foam::chemkinReader::fallOffFunctionNames[4] =
79 "unknownFallOffFunctionType"
82 void Foam::chemkinReader::initReactionKeywordTable()
84 reactionKeywordTable_.insert("M", thirdBodyReactionType);
85 reactionKeywordTable_.insert("LOW", unimolecularFallOffReactionType);
86 reactionKeywordTable_.insert("HIGH", chemicallyActivatedBimolecularReactionType);
87 reactionKeywordTable_.insert("TROE", TroeReactionType);
88 reactionKeywordTable_.insert("SRI", SRIReactionType);
89 reactionKeywordTable_.insert("LT", LandauTellerReactionType);
90 reactionKeywordTable_.insert("RLT", reverseLandauTellerReactionType);
91 reactionKeywordTable_.insert("JAN", JanevReactionType);
92 reactionKeywordTable_.insert("FIT1", powerSeriesReactionRateType);
93 reactionKeywordTable_.insert("HV", radiationActivatedReactionType);
94 reactionKeywordTable_.insert("TDEP", speciesTempReactionType);
95 reactionKeywordTable_.insert("EXCI", energyLossReactionType);
96 reactionKeywordTable_.insert("MOME", plasmaMomentumTransfer);
97 reactionKeywordTable_.insert("XSMI", collisionCrossSection);
98 reactionKeywordTable_.insert("REV", nonEquilibriumReversibleReactionType);
99 reactionKeywordTable_.insert("DUPLICATE", duplicateReactionType);
100 reactionKeywordTable_.insert("DUP", duplicateReactionType);
101 reactionKeywordTable_.insert("FORD", speciesOrderForward);
102 reactionKeywordTable_.insert("RORD", speciesOrderReverse);
103 reactionKeywordTable_.insert("UNITS", UnitsOfReaction);
104 reactionKeywordTable_.insert("END", end);
108 Foam::scalar Foam::chemkinReader::molecularWeight
110 const List<specieElement>& specieComposition
115 forAll (specieComposition, i)
117 label nAtoms = specieComposition[i].nAtoms;
118 const word& elementName = specieComposition[i].elementName;
120 if (isotopeAtomicWts_.found(elementName))
122 molWt += nAtoms*isotopeAtomicWts_[elementName];
124 else if (atomicWeights.found(elementName))
126 molWt += nAtoms*atomicWeights[elementName];
130 FatalErrorIn("chemkinReader::lex()")
131 << "Unknown element " << elementName
132 << " on line " << lineNo_-1 << nl
133 << " specieComposition: " << specieComposition
142 void Foam::chemkinReader::checkCoeffs
144 const scalarList& reactionCoeffs,
145 const char* reactionRateName,
149 if (reactionCoeffs.size() != nCoeffs)
151 FatalErrorIn("chemkinReader::checkCoeffs")
152 << "Wrong number of coefficients for the " << reactionRateName
153 << " rate expression on line "
154 << lineNo_-1 << ", should be "
155 << nCoeffs << " but " << reactionCoeffs.size() << " supplied." << nl
156 << "Coefficients are "
157 << reactionCoeffs << nl
162 template<class ReactionRateType>
163 void Foam::chemkinReader::addReactionType
165 const reactionType rType,
166 DynamicList<gasReaction::specieCoeffs>& lhs,
167 DynamicList<gasReaction::specieCoeffs>& rhs,
168 const ReactionRateType& rr
177 new IrreversibleReaction<gasThermoPhysics, ReactionRateType>
179 Reaction<gasThermoPhysics>
196 new ReversibleReaction<gasThermoPhysics, ReactionRateType>
198 Reaction<gasThermoPhysics>
215 FatalErrorIn("chemkinReader::addReactionType")
216 << "Reaction type " << reactionTypeNames[rType]
217 << " on line " << lineNo_-1
218 << " not handled by this function"
223 FatalErrorIn("chemkinReader::addReactionType")
224 << "Unknown reaction type " << rType
225 << " on line " << lineNo_-1
231 template<template<class, class> class PressureDependencyType>
232 void Foam::chemkinReader::addPressureDependentReaction
234 const reactionType rType,
235 const fallOffFunctionType fofType,
236 DynamicList<gasReaction::specieCoeffs>& lhs,
237 DynamicList<gasReaction::specieCoeffs>& rhs,
238 const scalarList& efficiencies,
239 const scalarList& k0Coeffs,
240 const scalarList& kInfCoeffs,
241 const HashTable<scalarList>& reactionCoeffsTable,
242 const scalar Afactor0,
243 const scalar AfactorInf,
247 checkCoeffs(k0Coeffs, "k0", 3);
248 checkCoeffs(kInfCoeffs, "kInf", 3);
258 PressureDependencyType
259 <ArrheniusReactionRate, LindemannFallOffFunction>
261 ArrheniusReactionRate
263 Afactor0*k0Coeffs[0],
267 ArrheniusReactionRate
269 AfactorInf*kInfCoeffs[0],
273 LindemannFallOffFunction(),
274 thirdBodyEfficiencies(speciesTable_, efficiencies)
282 scalarList TroeCoeffs
284 reactionCoeffsTable[fallOffFunctionNames[fofType]]
287 if (TroeCoeffs.size() != 4 && TroeCoeffs.size() != 3)
289 FatalErrorIn("chemkinReader::addPressureDependentReaction")
290 << "Wrong number of coefficients for Troe rate expression"
291 " on line " << lineNo_-1 << ", should be 3 or 4 but "
292 << TroeCoeffs.size() << " supplied." << nl
293 << "Coefficients are "
298 if (TroeCoeffs.size() == 3)
300 TroeCoeffs.setSize(4);
301 TroeCoeffs[3] = GREAT;
308 PressureDependencyType
309 <ArrheniusReactionRate, TroeFallOffFunction>
311 ArrheniusReactionRate
313 Afactor0*k0Coeffs[0],
317 ArrheniusReactionRate
319 AfactorInf*kInfCoeffs[0],
330 thirdBodyEfficiencies(speciesTable_, efficiencies)
340 reactionCoeffsTable[fallOffFunctionNames[fofType]]
343 if (SRICoeffs.size() != 5 && SRICoeffs.size() != 3)
345 FatalErrorIn("chemkinReader::addPressureDependentReaction")
346 << "Wrong number of coefficients for SRI rate expression"
347 " on line " << lineNo_-1 << ", should be 3 or 5 but "
348 << SRICoeffs.size() << " supplied." << nl
349 << "Coefficients are "
354 if (SRICoeffs.size() == 3)
356 SRICoeffs.setSize(5);
365 PressureDependencyType
366 <ArrheniusReactionRate, SRIFallOffFunction>
368 ArrheniusReactionRate
370 Afactor0*k0Coeffs[0],
374 ArrheniusReactionRate
376 AfactorInf*kInfCoeffs[0],
388 thirdBodyEfficiencies(speciesTable_, efficiencies)
398 FatalErrorIn("chemkinReader::addPressureDependentReaction")
399 << "Fall-off function type "
400 << fallOffFunctionNames[fofType]
401 << " on line " << lineNo_-1
402 << " not implemented"
407 FatalErrorIn("chemkinReader::addPressureDependentReaction")
408 << "Unknown fall-off function type " << fofType
409 << " on line " << lineNo_-1
417 void Foam::chemkinReader::addReaction
419 DynamicList<gasReaction::specieCoeffs>& lhs,
420 DynamicList<gasReaction::specieCoeffs>& rhs,
421 const scalarList& efficiencies,
422 const reactionType rType,
423 const reactionRateType rrType,
424 const fallOffFunctionType fofType,
425 const scalarList& ArrheniusCoeffs,
426 HashTable<scalarList>& reactionCoeffsTable,
430 checkCoeffs(ArrheniusCoeffs, "Arrhenius", 3);
432 scalarList nAtoms(elementNames_.size(), 0.0);
436 const List<specieElement>& specieComposition =
437 specieComposition_[speciesTable_[lhs[i].index]];
439 forAll (specieComposition, j)
441 label elementi = elementIndices_[specieComposition[j].elementName];
442 nAtoms[elementi] += lhs[i].stoichCoeff*specieComposition[j].nAtoms;
448 const List<specieElement>& specieComposition =
449 specieComposition_[speciesTable_[rhs[i].index]];
451 forAll (specieComposition, j)
453 label elementi = elementIndices_[specieComposition[j].elementName];
454 nAtoms[elementi] -= rhs[i].stoichCoeff*specieComposition[j].nAtoms;
459 // Calculate the unit conversion factor for the A coefficient
460 // for the change from mol/cm^3 to kmol/m^3 concentraction units
461 const scalar concFactor = 0.001;
465 sumExp += lhs[i].exponent;
467 scalar Afactor = pow(concFactor, sumExp - 1.0);
469 scalar AfactorRev = Afactor;
471 if (rType == nonEquilibriumReversible)
476 sumExp += rhs[i].exponent;
478 AfactorRev = pow(concFactor, sumExp - 1.0);
485 if (rType == nonEquilibriumReversible)
487 const scalarList& reverseArrheniusCoeffs =
488 reactionCoeffsTable[reactionTypeNames[rType]];
490 checkCoeffs(reverseArrheniusCoeffs, "reverse Arrhenius", 3);
494 new NonEquilibriumReversibleReaction
495 <gasThermoPhysics, ArrheniusReactionRate>
497 Reaction<gasThermoPhysics>
504 ArrheniusReactionRate
506 Afactor*ArrheniusCoeffs[0],
508 ArrheniusCoeffs[2]/RR
510 ArrheniusReactionRate
512 AfactorRev*reverseArrheniusCoeffs[0],
513 reverseArrheniusCoeffs[1],
514 reverseArrheniusCoeffs[2]/RR
525 ArrheniusReactionRate
527 Afactor*ArrheniusCoeffs[0],
529 ArrheniusCoeffs[2]/RR
536 case thirdBodyArrhenius:
538 if (rType == nonEquilibriumReversible)
540 const scalarList& reverseArrheniusCoeffs =
541 reactionCoeffsTable[reactionTypeNames[rType]];
543 checkCoeffs(reverseArrheniusCoeffs, "reverse Arrhenius", 3);
547 new NonEquilibriumReversibleReaction
548 <gasThermoPhysics, thirdBodyArrheniusReactionRate>
550 Reaction<gasThermoPhysics>
557 thirdBodyArrheniusReactionRate
559 Afactor*concFactor*ArrheniusCoeffs[0],
561 ArrheniusCoeffs[2]/RR,
562 thirdBodyEfficiencies(speciesTable_, efficiencies)
564 thirdBodyArrheniusReactionRate
566 AfactorRev*concFactor*reverseArrheniusCoeffs[0],
567 reverseArrheniusCoeffs[1],
568 reverseArrheniusCoeffs[2]/RR,
569 thirdBodyEfficiencies(speciesTable_, efficiencies)
580 thirdBodyArrheniusReactionRate
582 Afactor*concFactor*ArrheniusCoeffs[0],
584 ArrheniusCoeffs[2]/RR,
585 thirdBodyEfficiencies(speciesTable_, efficiencies)
592 case unimolecularFallOff:
594 addPressureDependentReaction<FallOffReactionRate>
601 reactionCoeffsTable[reactionRateTypeNames[rrType]],
611 case chemicallyActivatedBimolecular:
613 addPressureDependentReaction<ChemicallyActivatedReactionRate>
621 reactionCoeffsTable[reactionRateTypeNames[rrType]],
632 const scalarList& LandauTellerCoeffs =
633 reactionCoeffsTable[reactionRateTypeNames[rrType]];
634 checkCoeffs(LandauTellerCoeffs, "Landau-Teller", 2);
636 if (rType == nonEquilibriumReversible)
638 const scalarList& reverseArrheniusCoeffs =
639 reactionCoeffsTable[reactionTypeNames[rType]];
640 checkCoeffs(reverseArrheniusCoeffs, "reverse Arrhenius", 3);
642 const scalarList& reverseLandauTellerCoeffs =
645 word(reactionTypeNames[rType])
646 + reactionRateTypeNames[rrType]
648 checkCoeffs(LandauTellerCoeffs, "reverse Landau-Teller", 2);
652 new NonEquilibriumReversibleReaction
653 <gasThermoPhysics, LandauTellerReactionRate>
655 Reaction<gasThermoPhysics>
662 LandauTellerReactionRate
664 Afactor*ArrheniusCoeffs[0],
666 ArrheniusCoeffs[2]/RR,
667 LandauTellerCoeffs[0],
668 LandauTellerCoeffs[1]
670 LandauTellerReactionRate
672 AfactorRev*reverseArrheniusCoeffs[0],
673 reverseArrheniusCoeffs[1],
674 reverseArrheniusCoeffs[2]/RR,
675 reverseLandauTellerCoeffs[0],
676 reverseLandauTellerCoeffs[1]
687 LandauTellerReactionRate
689 Afactor*ArrheniusCoeffs[0],
691 ArrheniusCoeffs[2]/RR,
692 LandauTellerCoeffs[0],
693 LandauTellerCoeffs[1]
702 const scalarList& JanevCoeffs =
703 reactionCoeffsTable[reactionRateTypeNames[rrType]];
705 checkCoeffs(JanevCoeffs, "Janev", 9);
713 Afactor*ArrheniusCoeffs[0],
715 ArrheniusCoeffs[2]/RR,
724 const scalarList& powerSeriesCoeffs =
725 reactionCoeffsTable[reactionRateTypeNames[rrType]];
727 checkCoeffs(powerSeriesCoeffs, "power-series", 4);
733 powerSeriesReactionRate
735 Afactor*ArrheniusCoeffs[0],
737 ArrheniusCoeffs[2]/RR,
738 powerSeriesCoeffs.begin()
744 case unknownReactionRateType:
746 FatalErrorIn("chemkinReader::addReaction")
747 << "Internal error on line " << lineNo_-1
748 << ": reaction rate type has not been set"
757 FatalErrorIn("chemkinReader::addReaction")
758 << "Reaction rate type " << reactionRateTypeNames[rrType]
759 << " on line " << lineNo_-1
760 << " not implemented"
765 FatalErrorIn("chemkinReader::addReaction")
766 << "Unknown reaction rate type " << rrType
767 << " on line " << lineNo_-1
776 if (mag(nAtoms[i]) > SMALL)
778 FatalErrorIn("chemkinReader::addReaction")
779 << "Elemental imbalance in " << elementNames_[i]
780 << " in reaction" << nl
781 << reactions_.last() << nl
782 << " on line " << lineNo_-1
789 reactionCoeffsTable.clear();
793 void Foam::chemkinReader::read
795 const fileName& CHEMKINFileName,
796 const fileName& thermoFileName
799 if (thermoFileName != fileName::null)
801 std::ifstream thermoStream(thermoFileName.c_str());
807 "chemkin::chemkin(const fileName& CHEMKINFileName, "
808 "const fileName& thermoFileName)"
809 ) << "file " << thermoFileName << " not found"
813 yy_buffer_state* bufferPtr(yy_create_buffer(&thermoStream, yyBufSize));
814 yy_switch_to_buffer(bufferPtr);
819 yy_delete_buffer(bufferPtr);
824 std::ifstream CHEMKINStream(CHEMKINFileName.c_str());
830 "chemkin::chemkin(const fileName& CHEMKINFileName, "
831 "const fileName& thermoFileName)"
832 ) << "file " << CHEMKINFileName << " not found"
836 yy_buffer_state* bufferPtr(yy_create_buffer(&CHEMKINStream, yyBufSize));
837 yy_switch_to_buffer(bufferPtr);
839 initReactionKeywordTable();
844 yy_delete_buffer(bufferPtr);
848 // * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * * //
850 // Construct from components
851 Foam::chemkinReader::chemkinReader
853 const fileName& CHEMKINFileName,
854 const fileName& thermoFileName
859 speciesTable_(static_cast<const wordList&>(wordList()))
861 read(CHEMKINFileName, thermoFileName);
865 // Construct from components
866 Foam::chemkinReader::chemkinReader(const dictionary& thermoDict)
870 speciesTable_(static_cast<const wordList&>(wordList()))
874 fileName(thermoDict.lookup("CHEMKINFile")).expand()
877 fileName thermoFile = fileName::null;
879 if (thermoDict.found("CHEMKINThermoFile"))
881 thermoFile = fileName(thermoDict.lookup("CHEMKINThermoFile")).expand();
884 // allow relative file names
885 fileName relPath = thermoDict.name().path();
888 if (chemkinFile.size() && chemkinFile[0] != '/')
890 chemkinFile = relPath/chemkinFile;
893 if (thermoFile.size() && thermoFile[0] != '/')
895 thermoFile = relPath/thermoFile;
899 read(chemkinFile, thermoFile);
902 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //