Free Flame Example

This example uses ctwrap for one-dimensional adiabatic premixed flame simulations defined by the simulation module freeflame (ctwrap.modules.freeflame).

Function/Class Definitions

[1]:
import cantera as ct
import ctwrap as cw
import json

Simulations

Create Simulation Object

Uses a module in the modules folder. Modules do not have to depend on ctwrap.

[2]:
sim = cw.Simulation.from_module(cw.modules.freeflame)
sim
[2]:
<ctwrap.wrapper.Freeflame at 0x7f2ebd57dbd0>

Create Simulation Handler

[3]:
fname = 'freeflame.yaml'
s = cw.SimulationHandler.from_yaml(fname, strategy='matrix', verbosity=1)
s
Simulations for entries ['upstream.phi', 'model.transport']
[3]:
<ctwrap.handler.SimulationHandler at 0x7f2ee0aef710>

Run Simulation Tasks in Parallel

[4]:
%%time
s.run_parallel(sim, verbosity=0)
    flamespeed = 0.201060 m/s (mix)
    flamespeed = 0.215236 m/s (multi)
    flamespeed = 0.205173 m/s (soret)
    flamespeed = 1.735115 m/s (mix)
    flamespeed = 1.720500 m/s (multi)
    flamespeed = 1.535611 m/s (soret)
    flamespeed = 2.716008 m/s (mix)
    flamespeed = 2.671855 m/s (multi)
    flamespeed = 2.473064 m/s (soret)
    flamespeed = 3.051440 m/s (mix)
    flamespeed = 2.997041 m/s (multi)
    flamespeed = 2.823779 m/s (soret)
    flamespeed = 2.973848 m/s (mix)
    flamespeed = 2.924944 m/s (multi)
    flamespeed = 2.787100 m/s (soret)
    flamespeed = 2.726691 m/s (mix)
    flamespeed = 2.691647 m/s (multi)
    flamespeed = 2.565048 m/s (soret)
CPU times: user 25.5 ms, sys: 22.7 ms, total: 48.2 ms
Wall time: 1min 10s
[4]:
True

Create Graphical Output

[5]:
import h5py
import matplotlib.pyplot as plt
import matplotlib as mpl
col = mpl.rcParams['axes.prop_cycle'].by_key()['color']
n_col = len(col)

Load Data

[6]:
data = h5py.File(s.output_name, 'r')
data.keys()
[6]:
<KeysViewHDF5 ['case_00', 'case_01', 'case_02', 'case_03', 'case_04', 'case_05', 'case_06', 'case_07', 'case_08', 'case_09', 'case_10', 'case_11', 'case_12', 'case_13', 'case_14', 'case_15', 'case_16', 'case_17']>
[7]:
data.attrs.keys()
[7]:
<KeysViewHDF5 ['cases', 'defaults', 'strategy']>
[8]:
var = json.loads(data.attrs['strategy'])
var
[8]:
{'matrix': {'upstream.phi': {'mode': 'linspace',
   'limits': [0.4, 2.4],
   'npoints': 6},
  'model.transport': ['mix', 'multi', 'soret']}}
[9]:
default = json.loads(data.attrs['defaults'])
default
[9]:
{'upstream': {'T': '300. kelvin',
  'P': '1. atmosphere',
  'phi': 0.55,
  'fuel': 'H2',
  'oxidizer': 'O2:1,AR:5'},
 'model': {'mechanism': 'h2o2.yaml', 'transport': 'mix'},
 'domain': {'width': '30 millimeter'}}
[10]:
up = default.get('upstream')
up
[10]:
{'T': '300. kelvin',
 'P': '1. atmosphere',
 'phi': 0.55,
 'fuel': 'H2',
 'oxidizer': 'O2:1,AR:5'}
[11]:
cases = json.loads(data.attrs['cases'])
cases
[11]:
{'case_00': {'upstream.phi': 0.4, 'model.transport': 'mix'},
 'case_01': {'upstream.phi': 0.4, 'model.transport': 'multi'},
 'case_02': {'upstream.phi': 0.4, 'model.transport': 'soret'},
 'case_03': {'upstream.phi': 0.8, 'model.transport': 'mix'},
 'case_04': {'upstream.phi': 0.8, 'model.transport': 'multi'},
 'case_05': {'upstream.phi': 0.8, 'model.transport': 'soret'},
 'case_06': {'upstream.phi': 1.2, 'model.transport': 'mix'},
 'case_07': {'upstream.phi': 1.2, 'model.transport': 'multi'},
 'case_08': {'upstream.phi': 1.2, 'model.transport': 'soret'},
 'case_09': {'upstream.phi': 1.6, 'model.transport': 'mix'},
 'case_10': {'upstream.phi': 1.6, 'model.transport': 'multi'},
 'case_11': {'upstream.phi': 1.6, 'model.transport': 'soret'},
 'case_12': {'upstream.phi': 2.0, 'model.transport': 'mix'},
 'case_13': {'upstream.phi': 2.0, 'model.transport': 'multi'},
 'case_14': {'upstream.phi': 2.0, 'model.transport': 'soret'},
 'case_15': {'upstream.phi': 2.4, 'model.transport': 'mix'},
 'case_16': {'upstream.phi': 2.4, 'model.transport': 'multi'},
 'case_17': {'upstream.phi': 2.4, 'model.transport': 'soret'}}
[12]:
phi = [t['upstream.phi'] for t in cases.values()
       if t['model.transport'] == 'mix']
phi
[12]:
[0.4, 0.8, 1.2, 1.6, 2.0, 2.4]
[13]:
mix = {k: dict(data[k]['flame']) for k, v in cases.items()
       if v['model.transport'] == 'mix'}
mlt = {k: dict(data[k]['flame']) for k, v in cases.items()
       if v['model.transport'] == 'multi'}
sor = {k: dict(data[k]['flame']) for k, v in cases.items()
       if v['model.transport'] == 'soret'}
[14]:
mix.keys()
[14]:
dict_keys(['case_00', 'case_03', 'case_06', 'case_09', 'case_12', 'case_15'])

Plot

Plot flame speeds and temperature profiles

[15]:
# create figure
fig, ax = plt.subplots(1)
fig.set_size_inches(8.,6.)

# plot results
u_mix = [ mix[t]['velocity'][0] for t in mix]
u_mlt = [ mlt[t]['velocity'][0] for t in mlt]
u_sor = [ sor[t]['velocity'][0] for t in sor]

ax.plot(phi, u_mix, marker='o',
            linestyle='none', label='mixture-averaged')
ax.plot(phi, u_mlt, marker='s',
            markerfacecolor='none',
            linestyle='none', label='multi-component')
ax.plot(phi, u_sor, marker='x',
            markerfacecolor='none',
            linestyle='none', label='soret enabled')

# add title/axis labels
ax.set_xlabel('Equivalence ratio (-)')
ax.set_ylabel('Flame speed (m/s)')

ax.set_title('Free premixed flame simulation for {} with {}'.format(up['fuel'],up['oxidizer']))

# add legend
leg = ax.legend(loc='lower right',#prop={'size':11},
                title='Transport Model') # % mech)
_ = leg.draw_frame(False)
../_images/examples_freeflame_example_23_0.svg
[ ]: