1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2004-2010 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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "chemkinReader.H"
28 #include "atomicWeights.H"
29 #include "IrreversibleReaction.H"
30 #include "ReversibleReaction.H"
31 #include "NonEquilibriumReversibleReaction.H"
32 #include "ArrheniusReactionRate.H"
33 #include "thirdBodyArrheniusReactionRate.H"
34 #include "FallOffReactionRate.H"
35 #include "ChemicallyActivatedReactionRate.H"
36 #include "LindemannFallOffFunction.H"
37 #include "TroeFallOffFunction.H"
38 #include "SRIFallOffFunction.H"
39 #include "LandauTellerReactionRate.H"
40 #include "JanevReactionRate.H"
41 #include "powerSeriesReactionRate.H"
42 #include "addToRunTimeSelectionTable.H"
44 /* * * * * * * * * * * * * * * * * Static data * * * * * * * * * * * * * * * */
48 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
89 chemicallyActivatedBimolecularReactionType
91 reactionKeywordTable_.insert("TROE", TroeReactionType);
92 reactionKeywordTable_.insert("SRI", SRIReactionType);
93 reactionKeywordTable_.insert("LT", LandauTellerReactionType);
94 reactionKeywordTable_.insert("RLT", reverseLandauTellerReactionType);
95 reactionKeywordTable_.insert("JAN", JanevReactionType);
96 reactionKeywordTable_.insert("FIT1", powerSeriesReactionRateType);
97 reactionKeywordTable_.insert("HV", radiationActivatedReactionType);
98 reactionKeywordTable_.insert("TDEP", speciesTempReactionType);
99 reactionKeywordTable_.insert("EXCI", energyLossReactionType);
100 reactionKeywordTable_.insert("MOME", plasmaMomentumTransfer);
101 reactionKeywordTable_.insert("XSMI", collisionCrossSection);
102 reactionKeywordTable_.insert("REV", nonEquilibriumReversibleReactionType);
103 reactionKeywordTable_.insert("DUPLICATE", duplicateReactionType);
104 reactionKeywordTable_.insert("DUP", duplicateReactionType);
105 reactionKeywordTable_.insert("FORD", speciesOrderForward);
106 reactionKeywordTable_.insert("RORD", speciesOrderReverse);
107 reactionKeywordTable_.insert("UNITS", UnitsOfReaction);
108 reactionKeywordTable_.insert("END", end);
112 Foam::scalar Foam::chemkinReader::molecularWeight
114 const List<specieElement>& specieComposition
119 forAll(specieComposition, i)
121 label nAtoms = specieComposition[i].nAtoms;
122 const word& elementName = specieComposition[i].elementName;
124 if (isotopeAtomicWts_.found(elementName))
126 molWt += nAtoms*isotopeAtomicWts_[elementName];
128 else if (atomicWeights.found(elementName))
130 molWt += nAtoms*atomicWeights[elementName];
134 FatalErrorIn("chemkinReader::lex()")
135 << "Unknown element " << elementName
136 << " on line " << lineNo_-1 << nl
137 << " specieComposition: " << specieComposition
146 void Foam::chemkinReader::checkCoeffs
148 const scalarList& reactionCoeffs,
149 const char* reactionRateName,
153 if (reactionCoeffs.size() != nCoeffs)
155 FatalErrorIn("chemkinReader::checkCoeffs")
156 << "Wrong number of coefficients for the " << reactionRateName
157 << " rate expression on line "
158 << lineNo_-1 << ", should be "
159 << nCoeffs << " but " << reactionCoeffs.size() << " supplied." << nl
160 << "Coefficients are "
161 << reactionCoeffs << nl
166 template<class ReactionRateType>
167 void Foam::chemkinReader::addReactionType
169 const reactionType rType,
170 DynamicList<gasReaction::specieCoeffs>& lhs,
171 DynamicList<gasReaction::specieCoeffs>& rhs,
172 const ReactionRateType& rr
181 new IrreversibleReaction<gasThermoPhysics, ReactionRateType>
183 Reaction<gasThermoPhysics>
200 new ReversibleReaction<gasThermoPhysics, ReactionRateType>
202 Reaction<gasThermoPhysics>
219 FatalErrorIn("chemkinReader::addReactionType")
220 << "Reaction type " << reactionTypeNames[rType]
221 << " on line " << lineNo_-1
222 << " not handled by this function"
227 FatalErrorIn("chemkinReader::addReactionType")
228 << "Unknown reaction type " << rType
229 << " on line " << lineNo_-1
235 template<template<class, class> class PressureDependencyType>
236 void Foam::chemkinReader::addPressureDependentReaction
238 const reactionType rType,
239 const fallOffFunctionType fofType,
240 DynamicList<gasReaction::specieCoeffs>& lhs,
241 DynamicList<gasReaction::specieCoeffs>& rhs,
242 const scalarList& efficiencies,
243 const scalarList& k0Coeffs,
244 const scalarList& kInfCoeffs,
245 const HashTable<scalarList>& reactionCoeffsTable,
246 const scalar Afactor0,
247 const scalar AfactorInf,
251 checkCoeffs(k0Coeffs, "k0", 3);
252 checkCoeffs(kInfCoeffs, "kInf", 3);
262 PressureDependencyType
263 <ArrheniusReactionRate, LindemannFallOffFunction>
265 ArrheniusReactionRate
267 Afactor0*k0Coeffs[0],
271 ArrheniusReactionRate
273 AfactorInf*kInfCoeffs[0],
277 LindemannFallOffFunction(),
278 thirdBodyEfficiencies(speciesTable_, efficiencies)
286 scalarList TroeCoeffs
288 reactionCoeffsTable[fallOffFunctionNames[fofType]]
291 if (TroeCoeffs.size() != 4 && TroeCoeffs.size() != 3)
293 FatalErrorIn("chemkinReader::addPressureDependentReaction")
294 << "Wrong number of coefficients for Troe rate expression"
295 " on line " << lineNo_-1 << ", should be 3 or 4 but "
296 << TroeCoeffs.size() << " supplied." << nl
297 << "Coefficients are "
302 if (TroeCoeffs.size() == 3)
304 TroeCoeffs.setSize(4);
305 TroeCoeffs[3] = GREAT;
312 PressureDependencyType
313 <ArrheniusReactionRate, TroeFallOffFunction>
315 ArrheniusReactionRate
317 Afactor0*k0Coeffs[0],
321 ArrheniusReactionRate
323 AfactorInf*kInfCoeffs[0],
334 thirdBodyEfficiencies(speciesTable_, efficiencies)
344 reactionCoeffsTable[fallOffFunctionNames[fofType]]
347 if (SRICoeffs.size() != 5 && SRICoeffs.size() != 3)
349 FatalErrorIn("chemkinReader::addPressureDependentReaction")
350 << "Wrong number of coefficients for SRI rate expression"
351 " on line " << lineNo_-1 << ", should be 3 or 5 but "
352 << SRICoeffs.size() << " supplied." << nl
353 << "Coefficients are "
358 if (SRICoeffs.size() == 3)
360 SRICoeffs.setSize(5);
369 PressureDependencyType
370 <ArrheniusReactionRate, SRIFallOffFunction>
372 ArrheniusReactionRate
374 Afactor0*k0Coeffs[0],
378 ArrheniusReactionRate
380 AfactorInf*kInfCoeffs[0],
392 thirdBodyEfficiencies(speciesTable_, efficiencies)
402 FatalErrorIn("chemkinReader::addPressureDependentReaction")
403 << "Fall-off function type "
404 << fallOffFunctionNames[fofType]
405 << " on line " << lineNo_-1
406 << " not implemented"
411 FatalErrorIn("chemkinReader::addPressureDependentReaction")
412 << "Unknown fall-off function type " << fofType
413 << " on line " << lineNo_-1
421 void Foam::chemkinReader::addReaction
423 DynamicList<gasReaction::specieCoeffs>& lhs,
424 DynamicList<gasReaction::specieCoeffs>& rhs,
425 const scalarList& efficiencies,
426 const reactionType rType,
427 const reactionRateType rrType,
428 const fallOffFunctionType fofType,
429 const scalarList& ArrheniusCoeffs,
430 HashTable<scalarList>& reactionCoeffsTable,
434 checkCoeffs(ArrheniusCoeffs, "Arrhenius", 3);
436 scalarList nAtoms(elementNames_.size(), 0.0);
440 const List<specieElement>& specieComposition =
441 specieComposition_[speciesTable_[lhs[i].index]];
443 forAll(specieComposition, j)
445 label elementi = elementIndices_[specieComposition[j].elementName];
446 nAtoms[elementi] += lhs[i].stoichCoeff*specieComposition[j].nAtoms;
452 const List<specieElement>& specieComposition =
453 specieComposition_[speciesTable_[rhs[i].index]];
455 forAll(specieComposition, j)
457 label elementi = elementIndices_[specieComposition[j].elementName];
458 nAtoms[elementi] -= rhs[i].stoichCoeff*specieComposition[j].nAtoms;
463 // Calculate the unit conversion factor for the A coefficient
464 // for the change from mol/cm^3 to kmol/m^3 concentraction units
465 const scalar concFactor = 0.001;
469 sumExp += lhs[i].exponent;
471 scalar Afactor = pow(concFactor, sumExp - 1.0);
473 scalar AfactorRev = Afactor;
475 if (rType == nonEquilibriumReversible)
480 sumExp += rhs[i].exponent;
482 AfactorRev = pow(concFactor, sumExp - 1.0);
489 if (rType == nonEquilibriumReversible)
491 const scalarList& reverseArrheniusCoeffs =
492 reactionCoeffsTable[reactionTypeNames[rType]];
494 checkCoeffs(reverseArrheniusCoeffs, "reverse Arrhenius", 3);
498 new NonEquilibriumReversibleReaction
499 <gasThermoPhysics, ArrheniusReactionRate>
501 Reaction<gasThermoPhysics>
508 ArrheniusReactionRate
510 Afactor*ArrheniusCoeffs[0],
512 ArrheniusCoeffs[2]/RR
514 ArrheniusReactionRate
516 AfactorRev*reverseArrheniusCoeffs[0],
517 reverseArrheniusCoeffs[1],
518 reverseArrheniusCoeffs[2]/RR
529 ArrheniusReactionRate
531 Afactor*ArrheniusCoeffs[0],
533 ArrheniusCoeffs[2]/RR
540 case thirdBodyArrhenius:
542 if (rType == nonEquilibriumReversible)
544 const scalarList& reverseArrheniusCoeffs =
545 reactionCoeffsTable[reactionTypeNames[rType]];
547 checkCoeffs(reverseArrheniusCoeffs, "reverse Arrhenius", 3);
551 new NonEquilibriumReversibleReaction
552 <gasThermoPhysics, thirdBodyArrheniusReactionRate>
554 Reaction<gasThermoPhysics>
561 thirdBodyArrheniusReactionRate
563 Afactor*concFactor*ArrheniusCoeffs[0],
565 ArrheniusCoeffs[2]/RR,
566 thirdBodyEfficiencies(speciesTable_, efficiencies)
568 thirdBodyArrheniusReactionRate
570 AfactorRev*concFactor*reverseArrheniusCoeffs[0],
571 reverseArrheniusCoeffs[1],
572 reverseArrheniusCoeffs[2]/RR,
573 thirdBodyEfficiencies(speciesTable_, efficiencies)
584 thirdBodyArrheniusReactionRate
586 Afactor*concFactor*ArrheniusCoeffs[0],
588 ArrheniusCoeffs[2]/RR,
589 thirdBodyEfficiencies(speciesTable_, efficiencies)
596 case unimolecularFallOff:
598 addPressureDependentReaction<FallOffReactionRate>
605 reactionCoeffsTable[reactionRateTypeNames[rrType]],
615 case chemicallyActivatedBimolecular:
617 addPressureDependentReaction<ChemicallyActivatedReactionRate>
625 reactionCoeffsTable[reactionRateTypeNames[rrType]],
636 const scalarList& LandauTellerCoeffs =
637 reactionCoeffsTable[reactionRateTypeNames[rrType]];
638 checkCoeffs(LandauTellerCoeffs, "Landau-Teller", 2);
640 if (rType == nonEquilibriumReversible)
642 const scalarList& reverseArrheniusCoeffs =
643 reactionCoeffsTable[reactionTypeNames[rType]];
644 checkCoeffs(reverseArrheniusCoeffs, "reverse Arrhenius", 3);
646 const scalarList& reverseLandauTellerCoeffs =
649 word(reactionTypeNames[rType])
650 + reactionRateTypeNames[rrType]
652 checkCoeffs(LandauTellerCoeffs, "reverse Landau-Teller", 2);
656 new NonEquilibriumReversibleReaction
657 <gasThermoPhysics, LandauTellerReactionRate>
659 Reaction<gasThermoPhysics>
666 LandauTellerReactionRate
668 Afactor*ArrheniusCoeffs[0],
670 ArrheniusCoeffs[2]/RR,
671 LandauTellerCoeffs[0],
672 LandauTellerCoeffs[1]
674 LandauTellerReactionRate
676 AfactorRev*reverseArrheniusCoeffs[0],
677 reverseArrheniusCoeffs[1],
678 reverseArrheniusCoeffs[2]/RR,
679 reverseLandauTellerCoeffs[0],
680 reverseLandauTellerCoeffs[1]
691 LandauTellerReactionRate
693 Afactor*ArrheniusCoeffs[0],
695 ArrheniusCoeffs[2]/RR,
696 LandauTellerCoeffs[0],
697 LandauTellerCoeffs[1]
706 const scalarList& JanevCoeffs =
707 reactionCoeffsTable[reactionRateTypeNames[rrType]];
709 checkCoeffs(JanevCoeffs, "Janev", 9);
717 Afactor*ArrheniusCoeffs[0],
719 ArrheniusCoeffs[2]/RR,
720 FixedList<scalar, 9>(JanevCoeffs)
728 const scalarList& powerSeriesCoeffs =
729 reactionCoeffsTable[reactionRateTypeNames[rrType]];
731 checkCoeffs(powerSeriesCoeffs, "power-series", 4);
737 powerSeriesReactionRate
739 Afactor*ArrheniusCoeffs[0],
741 ArrheniusCoeffs[2]/RR,
742 FixedList<scalar, 4>(powerSeriesCoeffs)
748 case unknownReactionRateType:
750 FatalErrorIn("chemkinReader::addReaction")
751 << "Internal error on line " << lineNo_-1
752 << ": reaction rate type has not been set"
761 FatalErrorIn("chemkinReader::addReaction")
762 << "Reaction rate type " << reactionRateTypeNames[rrType]
763 << " on line " << lineNo_-1
764 << " not implemented"
769 FatalErrorIn("chemkinReader::addReaction")
770 << "Unknown reaction rate type " << rrType
771 << " on line " << lineNo_-1
780 if (mag(nAtoms[i]) > SMALL)
782 FatalErrorIn("chemkinReader::addReaction")
783 << "Elemental imbalance in " << elementNames_[i]
784 << " in reaction" << nl
785 << reactions_.last() << nl
786 << " on line " << lineNo_-1
793 reactionCoeffsTable.clear();
797 void Foam::chemkinReader::read
799 const fileName& CHEMKINFileName,
800 const fileName& thermoFileName
803 if (thermoFileName != fileName::null)
805 std::ifstream thermoStream(thermoFileName.c_str());
811 "chemkin::chemkin(const fileName& CHEMKINFileName, "
812 "const fileName& thermoFileName)"
813 ) << "file " << thermoFileName << " not found"
817 yy_buffer_state* bufferPtr(yy_create_buffer(&thermoStream, yyBufSize));
818 yy_switch_to_buffer(bufferPtr);
823 yy_delete_buffer(bufferPtr);
828 std::ifstream CHEMKINStream(CHEMKINFileName.c_str());
834 "chemkin::chemkin(const fileName& CHEMKINFileName, "
835 "const fileName& thermoFileName)"
836 ) << "file " << CHEMKINFileName << " not found"
840 yy_buffer_state* bufferPtr(yy_create_buffer(&CHEMKINStream, yyBufSize));
841 yy_switch_to_buffer(bufferPtr);
843 initReactionKeywordTable();
848 yy_delete_buffer(bufferPtr);
852 // * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * * //
854 Foam::chemkinReader::chemkinReader
856 const fileName& CHEMKINFileName,
857 const fileName& thermoFileName
863 reactions_(speciesTable_, speciesThermo_)
865 read(CHEMKINFileName, thermoFileName);
869 Foam::chemkinReader::chemkinReader(const dictionary& thermoDict)
874 reactions_(speciesTable_, speciesThermo_)
878 fileName(thermoDict.lookup("CHEMKINFile")).expand()
881 fileName thermoFile = fileName::null;
883 if (thermoDict.found("CHEMKINThermoFile"))
885 thermoFile = fileName(thermoDict.lookup("CHEMKINThermoFile")).expand();
888 // allow relative file names
889 fileName relPath = thermoDict.name().path();
892 if (chemkinFile.size() && chemkinFile[0] != '/')
894 chemkinFile = relPath/chemkinFile;
897 if (thermoFile.size() && thermoFile[0] != '/')
899 thermoFile = relPath/thermoFile;
903 read(chemkinFile, thermoFile);
907 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //