113 lines
4.3 KiB
Python
113 lines
4.3 KiB
Python
import unittest
|
|
import pprint
|
|
|
|
import numpy as np
|
|
|
|
import Cantera as ct
|
|
from Cantera import Reactor as reactors
|
|
from Cantera.Func import Gaussian
|
|
|
|
import utilities
|
|
|
|
class CombustorTestImplementation(object):
|
|
"""
|
|
These tests are based on the sample:
|
|
|
|
python/reactors/combustor_sim/combustor.py
|
|
|
|
with some simplifications so that they run faster and produce more
|
|
consistent output.
|
|
"""
|
|
|
|
referenceFile = '../data/CombustorTest-integrateWithAdvance.csv'
|
|
def setUp(self):
|
|
self.gas = ct.importPhase('../../data/inputs/h2o2.cti')
|
|
|
|
# create a reservoir for the fuel inlet, and set to pure methane.
|
|
self.gas.set(T=300.0, P=ct.OneAtm, X='H2:1.0')
|
|
fuel_in = reactors.Reservoir(self.gas)
|
|
fuel_mw = self.gas.meanMolarMass()
|
|
|
|
# Oxidizer inlet
|
|
self.gas.set(T=300.0, P=ct.OneAtm, X='O2:1.0, AR:3.0')
|
|
oxidizer_in = reactors.Reservoir(self.gas)
|
|
oxidizer_mw = self.gas.meanMolarMass()
|
|
|
|
# to ignite the fuel/air mixture, we'll introduce a pulse of radicals.
|
|
# The steady-state behavior is independent of how we do this, so we'll
|
|
# just use a stream of pure atomic hydrogen.
|
|
self.gas.set(T=300.0, P=ct.OneAtm, X='H:1.0')
|
|
self.igniter = reactors.Reservoir(self.gas)
|
|
|
|
# create the combustor, and fill it in initially with a diluent
|
|
self.gas.set(T=300.0, P=ct.OneAtm, X='AR:1.0')
|
|
self.combustor = reactors.Reactor(contents=self.gas, volume=1.0)
|
|
|
|
# create a reservoir for the exhaust
|
|
self.exhaust = reactors.Reservoir(self.gas)
|
|
|
|
# compute fuel and air mass flow rates
|
|
factor = 0.1
|
|
oxidizer_mdot = 4 * factor*oxidizer_mw
|
|
fuel_mdot = factor*fuel_mw
|
|
|
|
# create and install the mass flow controllers. Controllers
|
|
# m1 and m2 provide constant mass flow rates, and m3 provides
|
|
# a short Gaussian pulse only to ignite the mixture
|
|
m1 = reactors.MassFlowController(upstream=fuel_in,
|
|
downstream=self.combustor,
|
|
mdot=fuel_mdot)
|
|
|
|
m2 = reactors.MassFlowController(upstream=oxidizer_in,
|
|
downstream=self.combustor,
|
|
mdot=oxidizer_mdot)
|
|
|
|
# The igniter will use a Gaussian 'functor' object to specify the
|
|
# time-dependent igniter mass flow rate.
|
|
igniter_mdot = Gaussian(t0=0.1, FWHM=0.05, A=0.1)
|
|
m3 = reactors.MassFlowController(upstream=self.igniter,
|
|
downstream=self.combustor,
|
|
mdot=igniter_mdot)
|
|
|
|
# put a valve on the exhaust line to regulate the pressure
|
|
self.v = reactors.Valve(upstream=self.combustor,
|
|
downstream=self.exhaust, Kv=1.0)
|
|
|
|
# the simulation only contains one reactor
|
|
self.sim = reactors.ReactorNet([self.combustor])
|
|
#self.sim.setTolerances(1e-8, 1e-12)
|
|
|
|
def test_integrateWithStep(self):
|
|
tnow = 0.0
|
|
tfinal = 0.25
|
|
self.data = []
|
|
while tnow < tfinal:
|
|
tnow = self.sim.step(tfinal)
|
|
self.data.append([tnow, self.combustor.temperature()] +
|
|
list(self.combustor.moleFractions()))
|
|
|
|
self.assertTrue(tnow >= tfinal)
|
|
bad = utilities.compareTimeSeries(self.referenceFile, self.data,
|
|
rtol=1e-3, atol=1e-9)
|
|
self.assertFalse(bad, bad)
|
|
|
|
def test_integrateWithAdvance(self, saveReference=False):
|
|
times = np.linspace(0, 0.25, 101)
|
|
self.data = []
|
|
for t in times[1:]:
|
|
self.sim.advance(t)
|
|
self.data.append([t, self.combustor.temperature()] +
|
|
list(self.combustor.moleFractions()))
|
|
|
|
if saveReference:
|
|
np.savetxt(self.referenceFile, np.array(self.data), '%11.6e', ', ')
|
|
else:
|
|
bad = utilities.compareTimeSeries(self.referenceFile, self.data,
|
|
rtol=1e-6, atol=1e-12)
|
|
self.assertFalse(bad, bad)
|
|
|
|
# Keep the implementation separate from the unittest-derived class
|
|
# so that it can be run independently to generate the reference data file.
|
|
class CombustorTest(CombustorTestImplementation, unittest.TestCase):
|
|
pass
|
|
|