Release 2.2

Updated 5/2009

Table of Contents

i Foreward
  1.2Thermal Background
   1.2.1Mass versus Molar
   1.2.3Enthalpy and Cp
  1.3Promise of Transparency
  2.1Installing in Matlab
  2.2Installing in Octave
3Files and Directories
4Using HOT
  4.1Loading the Data
  4.2The Data Format
   4.2.1Tabular Data
   4.2.1Curve Fit Data
  4.3Low- and High-Level Operations
  4.5Source Data and Units
  5.1Reporting Bugs
  5.2Reverse Compatibility
6Contributing to HOT

i Foreward

In the spirit of collegial cooperation, we at the Virginia Active Combustion Control Group of the Department of Mechanical Engineering at Virginia Tech are pleased to share the first public release of the HOT thermal database package for Matlab and Octave. We do so hoping that engineers, scientists, and students alike will find the software as great an aid as we for the routine acurate calculation of thermodynamic data across a variety of species.

I started working on code that later evolved into HOT in 2004 when I began my graduate work at Virginia Tech. Since then it has involved a handfull of other programmers and been used by a small group of researchers with whom I have had close contact. I am personally eager to hear comments and suggestions from a broader group of users. Because our focus is on combustion, the selection of included species has been focused on those present in combustion systems; thus we are eager to include data submitted or suggested by other users.

Chris Martin
PhD Candidate
Virginia Active Combustion Control Group
Virginia Tech

ii License

This software package is distributed under the Academic Free License v3.0.

The license can be found here:

A summary and comparison with other licenses can be found here:

1 Overview

1.1 Applications

The HOT thermal database package is designed to store, recall, and perform computations on thermodynamic data in Matlab or Octave for a variety of species at a variety of temperatures and pressures. This is a system developed primarily for combustion modeling, but has already been used for a variety of applications in modeling thermodynamic cycles. Ultimately, every step of the software design placed transparency and flexibility at a premium. This is true to the point that the addition of new data (such as viscosity) will not disturb the operation of the old code. In fact, the existing tools can be instructed to look for new data fields in the hope that users will add their own data as it becomes necessary. At present, the package includes entropy, enthalpy, specific heat, molecular weight, and enthalpy of formation. Enthalpy and specific heat are referenced as functions of temperature only while entropy is referenced as a function of both pressure and temperature.

We can offer ABSOLUTELY NO WARANTY WHATSOEVER as to the reliability or acuracy of the code or data. Don't go using this code to control nuclear power plants or to design attack subs without checking your numbers. In the future, we intend to exhaustively validate the code against the original JANAF tables.

1.2 Thermal Background

Here's just a little primer on the sorts of calculations the code performs.

1.2.1 Mass vs Molar

There is an everlasting dialogue between the engineers and the chemists (the chemical engineers are just caught in the middle) as to whether extensive properties should be given in terms of mass or moles. Engineers, ever working in terms of mass flows frequently find thinking in terms of molecule counts counter intuitive. The chemists, thoughtful of the actual physical processes at work which are inherently linked to the vibration of individual molecules, want their units in moles. In the end, there is a potato/potato (a cliche that doesn't work well in ascii) debate.

Being engineers ourselves, we have come down on the side of mass rather than molar units. Should you or someone you love be sympathetic to the chemists on this one, a simple division by molecular weight is all you need to bridge the gap.

1.2.2 Properties

The HOT package currently supports the following properties with the following default units:

h enthalpy J/kg
hf enthalpy of formation at 298.15K J/kg
sref reference entropy at 298.15K J/kg/K
cp specific heat J/kg/K
s entropy J/kg/K
MW molecular weight kg/kmol, lbm/lbmol, etc...

At present, the HOT thermal database package assumes ideal, but not perfect gasses. For readers without a thermodynamic textbook in easy reach, the ideal gas assumption implies that the gas constant really is constant (Pv = RT) and a perfect gas has a constant specific heat (both cv and cp).

1.2.3 Enthalpy and Cp

Enthalpy is the total energy a fluid contains including both internal energy, u, and the fluid-mechanical potential energy, Pv. Thus enthalpy is defined as

(1)h(T,P) = u(T) + Pv

When the fluid in question is an ideal gas, the specific volume, v, can be written in terms of P and T and

(2)Pv = RT

Thus, h(T,P) = u(T) + RT and enthalpy is only a function of temperature.

Given that h = h(T), it can be shown that the amount of energy required to raise the fluid temperature a single degree when held at constant pressure is

cp(T) = ----

From the fundamental theorem of calculus,

h(T) - h(Tref) = &int  cp(x)dx

The constant-pressure specific heat can be related to the constant volume specific heat by differentiating (1) with the ideal gas substitution. In the end,

(5)cp(T)=cv(T) + R

Since cv can be quite easy to measure in a calorimeter, frequently that is the information tabulated, from which we use (4) to compute enthalpy. Not that Tref and h(Tref) need to be supplied. While the selection of Tref is arbitrary, h(Tref) is the enthalpy of formation and is determined through a separate experiment.

1.2.4 entropy

Gibbs relation states that Tds = du + Pdv or

(6)Tds = dh - vdP

Therefore, substituting the ideal gas law for v again...

ds = -------dT - -------dP

Thus, the entropy can be computed similarly to enthalpy

s(T) - s(Tref) = &int -------dx   -   R ln( P / Pref )

It is quite common to split the entropy into two parts

(9)s(T,P) = s0(T) - R ln( P / Pref )


s0(T) - s(Tref,Pref) = &int-------dx

where the later (s0) is tabulated and the pressure dependency is calculated explicitly.

The HOT system is currently designed to deal with both explicity tabulated values and specific heat curve fits. Future versions may support integration of tabulated specific heats via a spline.

1.2.5 Mixtures

HOT deals with mixtures of species. Given the above methods for computing the properties of the individual species, it remains to be seen how one computes the properties of a mixture of species. Since most of the properties supported by HOT are extensive in nature (per unit mass), finding the total mixture properties is usually as simple as a mass-weighted average.

In a mixture, the mass fraction, Yi, of specie, "i", is defined as the mass of specie "i" divided by the total mass in the mixture. The mass fraction also has relevance in a continuum, wherein the mass fraction can change in space. In this case, the mass fraction can be defined as the local mass density of specie i divided by the local density of the fluid. There are several important things to note about mass fractions.

For most extensive properties, the following is true (where "z" is an make-believe property)

z = &sum zi Yi

This is just the mass weighted average of the individual specie properties. It is true for the following properties currently supported in HOT:

(11)h = &sum hi Yi
(12)s = &sum si Yi
(13)h = &sum cpi Yi
(14)hf = &sum hfi Yi

It is NOT true, however, for molecular weight.

Molecular weight is defined as the mass per molecule of a specie. Typically MW is reported in g/mol, kg/kmol, lb/lbmol, or AMU. For a group of molecules of specie "i", the molecular weight can be defined as

MWi =

where M is the mass of the fluid and N is the number of molecules present. If the fluid is a mixture of species, then

MW =

where N = sum Ni. Substituting from (15), and with a little manipulation

MW =
&sum Yi / MWi

1.3 Promise of transparency

HOT is released as open-source software because we believe in the importance of shared information to research. It is our fervent hope that it be modified to meet the needs of various users. To that end, all data, all code, and all files ever having anything to do with this project are and will always be formatted either in plain text or in a format readable by free or open-source software.

2 Installation

2.1 Installing in Matlab

Copy the "HOT" and "utility" directories onto the desired hard drive. A typical place might be in "C:\programs\Matlab_RXX\work\", but you can place them anywhere you like. Open Matlab. Use the following commands to install the files:

%Navigate to the utility directory.
>> cd C:\programs\Matlab_R14\work\utility

%The install command located in the utility directory 
%adds the current directory to the Matlab path.
>> install

%With utility added to the Matlab path, the install
%utility is now accessible everywhere. Navigate to
%the HOT directory. Replace the path with your path
%to HOT.
>> cd C:\programs\Matlab_R14\work\HOT

%Now run the install command again.
>> install

If you change your mind, you can always remove the directories using the "uinstall" command.

2.2 Installing in Octave

Copy the "HOT" and "utility" directories into the file system. A typical place might be in "/usr/share/octave/3.0.1/m/", but you can place them anywhere you like. Start Octave. Use the following copmmands to install the files:

%Navigate to the utility directory. Replace the path 
%with your path to the utility directory.
1> cd /usr/share/octave/3.0.1/m/utility

%The install command located in the utility directory 
%adds the current directory to the Matlab path.
2> install

%With utility added to the Matlab path, the install
%utility is now accessible everywhere. Navigate to
%the HOT directory. Replace the path with your path
%to HOT.
3> cd /usr/share/octave/3.0.1/m/HOT

%Now run the install command again.
4> install

If you change your mind, you can always remove the directories using the "uinstall" command.

3 Files and Directories

This is a listing of each file in the HOT and utility directories.

3.1 HOT

3.1.1 enthalpy.m
ENTHALPY.M computes the enthalpy of mixtures. This is a high-level function that makes presumptions about the format of the data elements and relies on data loaded using janload.
3.1.2 entropy.m
ENTROPY.M computes the entropy of mixtures. This is a high-level function that makes presumptions about the format of the data elements and relies on data loaded using janload.
3.1.3 jancheck.m
JANCHECK.M tests data that has already been loaded for compatibility with the high-level functions mweight, spheat, mixture, entropy, and enthalpy.
3.1.4 janfit.m
JANFIT.M performs a number of operation on fit coefficients. It automatically resolves fits that are valid in segments. It also integrates and differentiates those fits as needed. This is a low-level function that makes only limited presumptions about the format of data elements and is as flexible as possible.
3.1.5 janload.m
JANLOAD.M uses the dread utility to open ascii data files. If set to verbose operation, it also runs jancheck to test the data.
3.1.6 janlookup.m
JANLOOKUP.M uses variable-order spline interpolation to interpret tabular data. It includes the ability to compute derivatives of the splines. This is useful, for example, when computing specific heat from enthalpy data.
3.1.7 mixture.m
MIXTURE.M creates a new specie that is a mixture of other, pre-existing species.
3.1.8 mweight.m
MWEIGHT.M computes the molecular weight of mixtures.
3.1.9 spheat.m
SPHEAT.M computes the specific heat of mixtures.

3.2 utility

The utility folder contains files used by HOT and by other VACCG packages.
3.2.1 clamp.m
CLAMP.M forces the values of a vector between a max and minimum value.
3.2.2 collapse.m
COLLAPSE.M reduces an array of structs to a struct of arrays.
3.2.4 dread.m
DREAD.M parses ascii files for struct array data.
3.2.5 dwrite.m
DWRITE.M writes data from struct arrays to ascii files.
3.2.6 install.m
INSTALL.M adds the current directory, and when configured to do so, all subdirectories to the search path.
3.2.7 iseven.m
ISEVEN.M tests a number for if it is an integer divisible by 2.
3.2.8 isodd.m
ISODD.M tests a number for if it is an odd integer.
3.2.9 mparsef.m
MPARSEF.M parses files for configurable data patterns.
3.2.10 mparses.m
MPARSES.M parses strings for configurable data patterns.
3.2.11 orderfields.m
ORDERFIELDS.M sorts the fields of a struct in alphabetical order.
3.2.12 shuffle.m
SHUFFLE.M collapses multiple vectors into a single vector.
3.2.13 uinstall.m
UINSTALL.M removes the current directory, and when configured to do so, all subdirectories from the search path.
3.2.14 unixtext.m
UNIXTEXT.M prunes all '\r' characters from files to ensure uniformity across platforms.
3.2.15 varargparam.m
VARARGPARAM.M parses parameter-value pairs and is configurable to automatically deal with error handling.

4 Using HOT

4.1 Loading Data

Using the HOT thermal database begins with being able to access the data. For ease of access, cross-platform universality, and to encourage users to modify the code to meet their needs, all of the thermal database files are stored in ascii. They are in easy-to-read formats that make it practical to manually open the text files as one might a text book. Though editing the files is generally discouraged, the utilities that access them are programed to be as flexible as possible to allow for manual edits and comments.

To load data from a file, "filename", use the command

>> data = janload('filename');

The variable, "data", will be a 1-D struct array with fields depending on the content of the data. At this point, one can either rely on the integrity of the data or one can check that it was loaded properly.

>> flags = jancheck(data);

By default, jancheck runs verbosely; printing out a summary of the data it finds and the tests it conducts as it does them. It identifies the fields in the struct array, checks whether they are consistent with fit or tabular data, and tests each specie to see that its data is properly formatted for use with the thermal database. If it is run non-verbosely (see jancheck's help for more details) then the user has only the content of the "flags" variable to indicate the results of the check (again - see jancheck's help for details).

To do all of this in one step, run

>> data = janload('filename','verbose',1);

When janload is run verbosely, it automatically runs jancheck so the user can see a summary of the data and a reassurance of its integrity. Lastly, janload can also be configured to automatically sort the data.

>> data = janload('filename','sort','species');

This command will automatically sort the elements of data by the contents of the field, "species".

4.2 The Data Format

Except for users interested in understanding the nuts and bolts of the code a little butter, the data format is not particularly important since users should never need to interact with it dirrectly. If you just want a straight-forward description for how to look up properties, it is safe to skip to subsection 4.4.

The format of the data is somewhat flexible. Fields can be added or subtracted from the data array on a whim so long as a core few remain unaltered. What those few are depends on the type of data being stored. For that reason, the functions that operate on the data can be grouped into two types; ones that look for specific fields and make assumptions about how the data is organized, and ones that need to be told explicitly how the data is organized and what to do with it. The idea is that there are certain low-level operations that are needed regardless of how the data might be re-arranged in the future, but it is hardly convenient to explicitly configure these functions every time one calls them. Therefore, there are also high-level functions that automatically configure the low-level ones based on the current configuration of the data. Usually, all of this is transparent to the user, but for the interested, the next subsection will spell out the details.

The data is a 1-D struct array. Each element of the array corresponds to a specie such as H20, CH4, CO2, etc... Regardless of format (tabular or curve fit), most high-level functions look for two fields; species and MW. Species is a string containing the species name and MW is a float containing the molecular weight of the species.

4.2.1 Tabular Data
If the data is in a tabular format, then jancheck (and all the high-level functions) looks for the "T", "h", and "s" fields, containing lookup table data for the temperature, enthalpy, and entropy respectively. For each specie in the array, these must be numerical vectors of the same length and T must be monotonically increasing. For a given temperature in "T", the corresponding element of "s" or "h" contain the entropy and enthalpy at that temperature respectively.
4.2.2 Curve Fit Data

If the data is in curve fit format, then jancheck looks for the "C", "F", and "T" fields, containing the specific heat coefficients, function specifiers, and temperature range specifiers respectively. Janfit uses the numerical function specifiers to evaluate the fit function. An element of "F", "fk", indicates a term in the fit function, T.^fk. If "fk" is "NaN" or "inf", then the function is ln(T) instead.

Frequently, curve fit data is only valid over a limited range of temperatures and multiple fit curves can be spliced together for a more acurate fit. The "T" vector indicates the temperatures above which one fit becomes invalid and the next fit should be used. Therefore, the "T" vector must be monotonically increasing.

Given that the "F" vector length indicates the number of functions, and that the "T" vector length indicates the number of curve fits, the "C" coefficient matrix dimensions are completely constrained. Each row corresponds to an element of "F" and each column to an element of "T". For example, if a mock data element were configured by

>> data(1).F = [0;1;NaN];
>> data(1).T = [500 1000];
>> data(1).C = [500 550; 30 15; 0 0.1];

then the specific heat at anywhere above 500K would be evaluated as

[cp @ T > 500] = 550 + 15 T + 0.1 ln(T)
[cp @ T < 500] = 500 + 30 T + 0.0 ln(T)

4.3 Low- and High-Level Operations

Low-level operations need lots of configuring in order to work properly, but are highly adaptable to changes in the data. On the other hand, high-level functions require very little information from the user and do most of the book keeping themselves, but they are extremely dependent on the structure and content of the data.

Most of the functions named jan*.m (such as JANLOAD) are low-level functions, while most of the functions with more memorable names (such as enthalpy and entropy), are high-level functions.

JANLOAD, already mentioned in Section 4.1, is a perfect example of a low-level function. It knows that it must load a struct array, but it has absolutely no knowledge of what the fields will be, how many elements it will have, or what type of data will be in the struct. All of this, it learns from the file it is loading (implicitly through DREAD).

ENTHALPY, ENTROPY, MWEIGHT, and SPHEAT are excellent examples of high-level functions. Discussed in more detail in Section 4.4, they look for very specific data in the files they open. They do this by automatically configuring low-level functions (such as JANFIT or JANLOOKUP) to do most of the work.

JANCHECK, on the other hand, doesn't fit well into the naming convention. Rather, it bridges the gap between high- and low-level functions. JANCHECK is responsible for testing data that is usable by the low-level functions to see if it is compatible with the high-level functions. If there are problems, it will make recommendations on how to fix them.

4.4 Calculations

4.4.1 Basic
The high-level functions are designed to be as convenient for common calculations as possible by taking full use of Matlab's vector-friendliness. Assuming that the "data" variable created in Section 4.1 is still in memory, very little else needs to be done to compute properties. For example, the commands
>> enthalpy(data, 'H2O', 1, 450)
>> entropy(data, 'H20', 1, 450)
>> mweight(data, 'H2O', 1)

will print the enthalpy, entropy, and molecular weight of water at 450K respectively.

In each of these statements, there is quite a bit going on that is not obvious. Each function checks the struct array to see if it contains fit or lookup data. It then calls JANFIND to locate 'H2O' the element in the data struct whose "species" field contains 'H2O'. Then it uses the appropriate low-level function (JANFIT or JANLOOKUP) to compute/interpolate the requested property.

4.4.2 Mixtures

That doesn't explain why the third argument in the above function calls was a "1". All of the high-level functions can deal with mixtures of multiple species. For example, the function call

>> enthalpy(data, {'N2' 'O2'},[102.76; 16], 450)

computes the enthalpy of a mixture of nitrogen and oxygen (52.64 kg N2 and 16 kg O2). This is the enthalpy of air at 450 K. When these sorts of mixtures are dealt with, the function automatically normalizes the masses to be mass fractions.

4.4.3 Libraries
It is quite possible that one might want to consider mixtures of species that were loaded from different files. If those data sets have different fields, it would be impossible to collapse them into a single struct array. For that reason, all of the high-level functions can deal with a library of struct arrays contained in a cell array. For example:
>> A = janload('');
>> B = janload('');
>> enthalpy({A B}, {'H2O' 'As'}, [0.99; 0.01], 450);

ENTHALPY is smart enough to look around in the library formed by the cell array, "{A B}", to find 'H2O' and 'As', even though they were loaded from different files. It also deals with the fact that the properties must be computed differently from each of them.

4.4.4 Vectors

The whole advantage to Matlab is that one can deal with gobs and gobs of data in relatively complicated structures quite easily. The high-level functions take full advantage of that fact. Consider the session:

>> data = janload('');
>> T = [300:100:2000];
>> mix = [1 0.5 0;0 0.5 1];
>> spec = {'CH4' 'O2};
>> h = enthalpy(data, spec, mix, T);

The variable, "h", will be an 18x3 matrix. Each row in "h" corresponds to one of the temperatures given. Each column corresponds to one of the three mixtures specified.

This is also useful if one simply wants the properties of a list of species.

>> spec = {'CH4', 'O2', 'N2', 'CO2', 'H2O'};
>> h = enthalpy(data, spec, eye(length(spec)), 400);

This session segment will be a row vector containing the enthalpy of the respective species at 400 K.

4.5 Data Files and Units

4.5.1 Files

In the present release, there are two files that contain thermodynamic data; "" and "". The file extensions denote the format of the data, but appart from good practices, there is no reason to preserve the extension convention. JANLOAD relies on the names and format of the fields to determine the data type and not the file extension. They are named for their origins. "" is a derivative from the data used by GRI-MECH. Similarly, "" is a derivative of one of the data files used by the old combustion favorite, Stanjan.

The original NASA data is available from the GRI-MECH homepage, here:

The university of Wisconsin has a site devoted to the Stanjan files here.

Colorado State University also hosts a web interface for Stanjan that's quite useful.

4.5.2 Units
ALL DATA USED BY HOT IS ASSUMED TO BE IN SI UNITS. That implies the following:
Energy  J
Mass    kg
Time    s
Force   N
Length  m
Press.  Pa
The high-level functions have a limited capacity for converting to other unit systems, but there is very little error checking and the interface is still a little difficult to use properly. IT IS STRONGLY RECOMMENDED THAT YOU HANDLE UNITS CONVERSION IN YOUR OWN CODE. Future releases of HOT will address this.

5 Support

5.1 Reporting Bugs

If you find a bug, please contact me:

Chris Martin

To be sure that I can deal with the problem in as timely a manner as possible, please include the following:
1) place "hot-tdb" somewhere in the subject line,
2) a copy of your commands or the mfile you were running at the time to help me reconstruct the problem,
3) a brief description of the bug you encountered in case it doesn't do the same for me.
I'll get back to you as soon as I can.

5.2 Reverse compatibility

Since some of us are sluggish about updating systems and others are yet more sluggish when told the must pay to do so, a number of folks are still using old versions of Octave and Matlab. On this matter, I must be very clear. I have only tested this code on Matlab 7.1 (R14) and Octave 3.0.1, but I have designed the code with as much attention to out-dated versions as possible. In fact, the sluggishness in loading the text files is entirely do to the fact that I wrote my own parsers to avoid compatability problems. That's something you can expect to see improve in later versions.

6 Contributing to HOT

We welcome suggestions. We are eager to find ways in which the project can be adapted to meet people's needs.

We also welcome the opportunity to work with international contributors to put together translated version. We are currently looking for French and German translations for the help headers and especially this README.

6.1 Contact

Via mail:
100 Randolph Hall
Virginia Active Combustion Control Group
Department of Mechanical Engineering
Virginia Tech
Blacksburg, VA 24061
(540) 231-9100

Chris Martin
Author, PhD Candidate

Steve Lepera
VACCG Lab Manager

Uri Vandsburger, Ph.D.
VACCG Lead Professor

Special thanks to:
Nikita Sharakov
Robert Wiedman