From charlesreid1

As a TA for CHEN 6153, I gave a lecture on the installation and use of Cantera.

Cantera Overview

Cantera is a code written in C++ that can be used to perform chemical kinetic and thermodynamic calculations.

The way it does this is by providing the user with a set of building blocks, and allowing the user to piece these building blocks together to form complex kinetic/thermodynamic systems or networks

Users can interface with Cantera through C++, or through the other interfaces:

  • Matlab toolbox
  • Python
  • Fortran

Visit the Cantera (software) page for a Cantera installation guide for either Mac, Linux, or Windows.


Cantera Objects

Reservoir - fixed state

  • the state of the reservoir never changes
  • used to impose fixed upstream/inlet conditions
  • chemistry is frozen - so no reactions will take place

Reactor - canonical chemical reactor

  • contains some mixture of species
  • has a set of characteristics
  • e.g. T, V, P, composition, enthalpy, density, MW, etc...

Fluids - gases or liquids

Chemical Mechanisms - external files "fed" to Cantera

  • chemical mechanisms specify two things:
    • species
    • reactions
  • all thermodynamic data for species is specified (e.g. heat capacity as a polynomial function - "NASA coefficients")
  • all thermodynamic data for chemical reactions (pre-exponential factors, activation energies, etc.)

Walls - separate reactors

  • can have heat transfer via the usual mechanisms - convection, conduction, radiation
  • can have a set heating rate (a constant, or a function of time)
  • can move - due to a pressure difference, a displacement rate expression, etc.)

Flow controllers - control flow... 3 types

Mass flow controller - maintains a fixed mass flowrate
Valves - the mass flowrate is a function of \Delta P
Pressure flow controller - maintains a fixed P in the reactor (think of this as a pressure relief valve)

Matlab Examples

Batch Reactor Example

How might we combine the above Cantera objects to make a batch reactor?

e.g. where would the reactor go? Where would the flow controllers go?

Any reservoirs needed? No

Any flow controllers needed? No

What will we need? A reactor

What are we going to fill the reactor with? We also need a fluid phase, and a mechanism to go along with it (if we want reactions), or thermodynamic data to go along with it (if we want thermodynamic state changes)

Batch.jpg

We want to know what happens when the reactor is changing from state 1 to state 2

For a constant volume reactor:

What is going into our reactor?

% Import a phase to fill the reactor with
% (The H2 combustion mechanism is contained in the file h2o2.cti, which comes with Cantera)
gas = importPhase('h2o2.cti');

What is the thermodynamic state of the material going into the reactor?

% Set the gas temperature at 1500 K
% Set the pressure at 1 atm
% Set the composition to be 2 parts hydrogen, 1 part oxygen, and 20 parts dilute, inert Argon
set(gas, 'T',1500, 'P',oneatm, 'X','H2:2, O2:1, AR:20')

How to create a batch reactor? Create a Cantera Reactor object

% We have already set the thermodynamic state of the "gas" object
% But if we wanted to, we could set it when we create the Reactor
batch = Reactor(gas);

We didn't specify the volume of the Reactor object - so how do we find it?

How do we get information about the Reactor object?

What information can we get about the Reactor object?

% We can use the volume() function to find the reactor's volume
volume(batch)

% We can find the Matlab object type like this:
class(batch)
% This returns "Reactor" type

% Show the functions available for Reactor objects
methods Reactor

The method "setInitialVolume()" looks good, so we can use it to set the initial volume of the reactor:

setInitialVolume( batch, 10.0 );

Another interesting method is "massFractions()":

% Display the mass fractions in the reactor
massFractions(batch)

This returns a 9-element vector, but it isn't clear what mass fractions are for which species.

How can we figure out what species are in the reactor?

Is this a reactor property?

Or is it a gas/fluid property?

So use the same methodology:

% Find the class type of the gas phase object
class(gas)
% This returns type "Solution"

% This shows the methods available to Solution types
methods Solution 

% This list looks a little short - but we can show inherited methods like this:
methods Solution -full

The "speciesNames()" function looks like what we want:

speciesNames(gas)

This returns a 9-element vector of strings - names of species in the mechanism file 'h2o2.cti'.

Constant Pressure Reactor Example

Now for a more interesting (relevant) combustion problem:

How might we use reactors, walls, reservoirs, etc. to create a constant-pressure batch reactor?

We can create a piston-cylinder system - this would be a constant-pressure system, with combustion occurring inside the piston

Piston.jpg

The constant-pressure, constant-temperature, constant-property atmosphere is a reservoir

The piston lid is a wall

The reactants and products inside the piston are gases

So first, we'll create a gas phase to fill the piston with

% Create the H2-O2 gas phase
gas = importPhase('h2o2.cti');

% Set the thermodynamic state of the gas
set(gas, 'T', 1500, 'P', oneatm, 'X', 'H2:2,O2:1,AR:20');

Next, create the reservoir that represents the atmosphere, and fill it with air:

% Create an ideal gas mix of air
a = IdealGasMix('air.cti');
atmosphere = reservoir(a);

A batch reactor must be created to represent the piston reactor:

batch = Reactor(gas);

The next step is to create a wall representing the piston between the reservoir and the gas. Walls in Cantera can be thought of as pistons with a certain amount of friction, or weight.

The wall expansion parameter is defined as:


\frac{dV}{dt} = K_{\mbox{expansion}} A_{\mbox{wall}} ( P_1 - P_2 )

What happens when K=0?

What happens when K=\infty?

The larger the K value, the faster the response of the wall (piston).

% Create a wall between the reactor and the atmosphere
w = Wall;
install(w, batch, atmosphere);
setArea(w,1.0);

% Set the expansion coefficient K
setExpansionRateCoeff(w, 1.0e10);

Remember, we can also have walls with heat transfer, so we could have heat flowing in, or flowing out, through the wall

By default, the wall is adiabatic

Next, a reactor network can be created, in order to advance the reactor in time.

network = ReactorNet( {batch} );

CSTR Combustor

This example is for a continuously-fired combustor.

The reactor is a combustor with a fuel and oxidizer reservoir, as well as a reservoir of igniter to initiate combustion.

There is also a reservoir for the exhaust.

Cstr.jpg

So we will need some reservoirs, a reactor...

What else? Flow controllers

We want to run the CSTR with various fuel/oxidizer ratios, and see how it affects the concentrations, temperatures, etc.

We might want to vary residence time, too - see the extent of combustion as a function of residence time

Create a reservoir of fuel, a reservoir of air, and a reservoir of hydrogen radicals (radicals are sure to initiate combustion reactions).

% Create a fuel from the GRI combustion mechanism
fuel = GRI30;
set(fuel, 'T', 300, 'P', oneatm, 'X', 'C3H8:1.0');
fuel_mw = meanMolecularWeight(fuel);

% Create the fuel reservoir
fuel_in = Reservoir(fuel);

% Create the oxidizer
oxidizer = Air();
set(oxidizer, 'T', 300, 'P', oneatm);
oxidizer_mw = meanMolecularWeight(oxidizer);

% Create the oxidizer reservoir
oxidizer_in = Reservoir(oxidizer);

% Create the igniter reservoir
igniter = GRI30;
set(igniter, 'T', 300, 'P', oneatm, 'X', 'H:1.0');
igniter_in = Reservoir(igniter);

The combustor must be initially filled with something - an inert gas is a good idea

inert = GRI30;
set(inert, 'T', 300, 'P', oneatm, 'X', 'N2:1.0');
combustor = Reactor(inert);

The next step is to set the equivalence ratio, and set the mass flowrates accordingly.

ER = 0.7;

% Fuel mass flowrate
fuel_mdot = fuel_mw*ER;

% Oxidizer mass flowrate
oxidizer_mdot = (1/ER)*(1/.21)*oxidizer_mw;

% Igniter mass flowrate
igniter_mdot = 0.05;

The mass flowrates could also be a Gaussian function in time, or a polynomial, e.g.

igniter_mdot = Func('gaussian', 0, [1.0, 0.0, 0.1] );
igniter_mdot = Func('polynomial', 2.0, [0.0, 0.0, 0.1] );

You can type "help Func" for more information.

(However, this does not seem to be working...)

The next step is to create the mass flow controllers entering the reactor, and the pressure exhaust valve, and finally to set up the reactor network.

% Create the mass flowrate controllers feeding into the combustor
m1 = MassFlowController(oxidizer_in, combustor);
setMassFlowRate(m1, oxidizer_mdot);

m2 = MassFlowController(fuel_in, combustor);
setMassFlowRate(m2, fuel_mdot);

m3 = MassFlowController(igniter_in, combustor);
setMassFlowrate(m3, igniter_mdot);

% And create an exhaust valve regulating the pressure in the combustor
exhaust_valve = Valve(combustor,exhaust);
setValveCoeff(exhaust_valve,1.0);

% Now the reactor network can be created
network = ReactorNet( {combustor} );