def setUp(self): # reservoir to represent the environment self.gas0 = ct.importPhase('air.cti') self.gas0.set(T=300, P=ct.OneAtm) self.env = reactors.Reservoir(self.gas0) # reactor to represent the side filled with Argon self.gas1 = ct.importPhase('air.cti') self.gas1.set(T=1000.0, P=30 * ct.OneAtm, X='AR:1.0') self.r1 = reactors.Reactor(self.gas1) # reactor to represent the combustible mixture self.gas2 = ct.importPhase('h2o2.cti') self.gas2.set(T=500.0, P=1.5 * ct.OneAtm, X='H2:0.5, O2:1.0, AR:10.0') self.r2 = reactors.Reactor(self.gas2) # Wall between the two reactors self.w1 = reactors.Wall(self.r2, self.r1) self.w1.set(area=1.0, K=2e-4, U=400.0) # Wall to represent heat loss to the environment self.w2 = reactors.Wall(self.r2, self.env) self.w2.set(area=1.0, U=2000.0) # Create the reactor network self.sim = reactors.ReactorNet([self.r1, self.r2])
def setUp(self): # reservoir to represent the environment self.gas0 = ct.importPhase("air.cti") self.gas0.set(T=300, P=ct.OneAtm) self.env = reactors.Reservoir(self.gas0) # reactor to represent the side filled with Argon self.gas1 = ct.importPhase("air.cti") self.gas1.set(T=1000.0, P=30 * ct.OneAtm, X="AR:1.0") self.r1 = reactors.Reactor(self.gas1) # reactor to represent the combustible mixture self.gas2 = ct.importPhase("h2o2.cti") self.gas2.set(T=500.0, P=1.5 * ct.OneAtm, X="H2:0.5, O2:1.0, AR:10.0") self.r2 = reactors.Reactor(self.gas2) # Wall between the two reactors self.w1 = reactors.Wall(self.r2, self.r1) self.w1.set(area=1.0, K=2e-4, U=400.0) # Wall to represent heat loss to the environment self.w2 = reactors.Wall(self.r2, self.env) self.w2.set(area=1.0, U=2000.0) # Create the reactor network self.sim = reactors.ReactorNet([self.r1, self.r2])
def checkConversion(self, refFile, testFile): ref = ct.IdealGasMix(refFile) gas = ct.IdealGasMix(testFile) self.assertEqual(ref.elementNames(), gas.elementNames()) self.assertEqual(ref.speciesNames(), gas.speciesNames()) self.assertTrue( (ref.reactantStoichCoeffs() == gas.reactantStoichCoeffs()).all()) compositionA = [[ref.nAtoms(i, j) for j in range(ref.nElements())] for i in range(ref.nSpecies())] compositionB = [[gas.nAtoms(i, j) for j in range(gas.nElements())] for i in range(gas.nSpecies())] self.assertEqual(compositionA, compositionB) return ref, gas
def test_equil_complete_stoichiometric(self): """ Equilibrium should correspond to complete combustion """ gas = ct.importPhase('equilibrium.cti', 'complete') gas.set(X='CH4:1.0, O2:2.0', T=298, P=100000) gas.equilibrate('TP', self.solver) self.check(gas, CH4=0, O2=0, H2O=2, CO2=1)
def test_transport_normal(self): convertMech('../../data/inputs/h2o2.inp', transportFile='../../data/transport/gri30_tran.dat', outName='h2o2_transport_normal.cti', quiet=True) gas = ct.IdealGasMix('h2o2_transport_normal.cti') gas.set(X='H2:1.0, O2:1.0', T=300, P=101325) self.assertAlmostEqual(gas.thermalConductivity(), 0.07663, 4)
def test_equil_complete_lean(self): """ Equilibrium should correspond to complete combustion (with excess O2) CH4 + 3 O2 -> CO2 + 2 H2O + O2 """ gas = ct.importPhase('equilibrium.cti', 'complete') gas.set(X='CH4:1.0, O2:3.0', T=298, P=100000) gas.equilibrate('TP', self.solver) self.check(gas, CH4=0, O2=1, H2O=2, CO2=1)
def setUp(self): self.gas = ct.importPhase('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])
def test_transport_embedded(self): convertMech('../data/with-transport.inp', outName='with-transport.cti', quiet=True) gas = ct.IdealGasMix('with-transport.cti') gas.set(X=[0.2, 0.3, 0.5]) D = gas.mixDiffCoeffs() for d in D: self.assertTrue(d > 0.0)
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])
def test_duplicate_species(self): self.assertRaises( ck2cti.InputParseError, lambda: convertMech('../data/duplicate-species.inp', outName='duplicate-species.cti', quiet=True)) convertMech('../data/duplicate-species.inp', outName='duplicate-species.cti', quiet=True, permissive=True) gas = ct.IdealGasMix('duplicate-species.cti') self.assertEqual(gas.speciesNames(), ['foo', 'bar', 'baz'])
def test_unterminatedSections(self): self.assertRaises( ck2cti.InputParseError, lambda: convertMech('../data/unterminated-sections.inp', outName='unterminated-sections.cti', quiet=True)) convertMech('../data/unterminated-sections.inp', outName='unterminated-sections.cti', quiet=True, permissive=True) gas = ct.IdealGasMix('unterminated-sections.cti') self.assertEqual(gas.nSpecies(), 3) self.assertEqual(gas.nReactions(), 2)
def test_pathologicalSpeciesNames(self): convertMech('../data/species-names.inp', outName='species-names.cti', quiet=True) gas = ct.IdealGasMix('species-names.cti') self.assertEqual(gas.nSpecies(), 3) self.assertEqual(gas.speciesName(0), '(Parens)') self.assertEqual(gas.speciesName(1), '@#$%^-2') self.assertEqual(gas.speciesName(2), '[xy2]*{.}') self.assertEqual(gas.nReactions(), 2) nu = gas.productStoichCoeffs() - gas.reactantStoichCoeffs() self.assertEqual(list(nu[:, 0]), [-1, -1, 2]) self.assertEqual(list(nu[:, 1]), [-2, 3, -1])
def test_duplicate_thermo(self): self.assertRaises( ck2cti.InputParseError, lambda: convertMech('../data/duplicate-thermo.inp', outName='duplicate-thermo.cti', quiet=True)) convertMech('../data/duplicate-thermo.inp', outName='duplicate-thermo.cti', quiet=True, permissive=True) gas = ct.IdealGasMix('duplicate-thermo.cti') self.assertTrue(gas.nSpecies(), 3) self.assertTrue(gas.nReactions(), 2)
def initializeCanteraSimulation(filepath, T, P, tf): """ Initialize a Cantera simulation at temperature `T`, pressure `P`, and solution termination time `tf`. """ # we change into the scratch folder for this because it creates xml files absfilepath = os.path.abspath(filepath) oldwd = os.getcwd() try: os.chdir(rmg.constants.scratchDirectory) # load the mechanism into gas gas = Cantera.importPhase(absfilepath,'chem') # create the environment gasAir = Cantera.Air() finally: os.chdir(oldwd) # set the inital gas and environment conditions gas.set(T=T, P=P) gasAir.set(T=T, P=P) # create a reactor for the batch reactor # and a reservoir for the environment reactor = Cantera.Reactor.Reactor(gas, volume = 1.0) environment = Cantera.Reactor.Reservoir(gasAir) # Define a wall between the reactor and the environment, and # make it flexible, so that the pressure in the reactor is held # at the environment pressure, and conductive so the temperature likewise wall = Cantera.Reactor.Wall(reactor,environment) wall.set(K = 1.0e12) # set expansion parameter. dV/dt = KA(P_1 - P_2) wall.set(A = 1.0) wall.setHeatTransferCoeff(1.0e15) # W/m2/K # put the reactor into a reactor network sim = Cantera.Reactor.ReactorNet([reactor]) sim.setInitialTime(0.0) maxtime = tf return gas, gasAir, reactor, environment, wall, sim, maxtime
def setUpClass(cls): cls.gas = ct.importPhase('../data/air-no-reactions.xml', 'air')
def setUpClass(cls): cls.gas = ct.importPhase('../data/air-no-reactions.xml', 'air') cls.T0 = cls.gas.temperature() cls.P0 = cls.gas.pressure() cls.X0 = cls.gas.moleFractions()
def test_importPhase_xml(self): gas1 = ct.importPhase('../data/air-no-reactions.xml', 'air') self.check(gas1, 'air', 300, 101325, 8, 3) gas2 = ct.importPhase('../data/air-no-reactions.xml', 'notair') self.check(gas2, 'notair', 900, 5 * 101325, 7, 2)
def test_import_GRI30(self): gas = ct.GRI30() self.check(gas, 'gri30', 300, 101325, 53, 5)
def test_importPhase_cti2(self): # This should import the first phase, i.e. 'air' gas = ct.importPhase('../data/air-no-reactions.cti') self.check(gas, 'air', 300, 101325, 8, 3)
def test_importPhase_xml(self): gas1 = ct.importPhase('../data/air-no-reactions.xml', 'air') self.check(gas1, 'air', 300, 101325, 8, 3) gas2 = ct.importPhase('../data/air-no-reactions.xml', 'notair') self.check(gas2, 'notair', 900, 5*101325, 7, 2)
def test_equil_gri_lean(self): gas = ct.importPhase('gri30.xml') gas.set(X='CH4:1.0, O2:3.0', T=301, P=100000) gas.equilibrate('TP', self.solver) self.check(gas, CH4=0, O2=1, H2O=2, CO2=1)
def runCantera(self, model): """ Execute a simulation of the reaction system in Cantera. The procedure: (1) write a CTML (Cantera) file, (2) read it into Cantera, (3) create the reactor in Cantera, and (4) return the simulation results. """ # Create a folder in the scratch directory for Cantera files if needed cantera_folder = os.path.join(settings.scratchDirectory,'cantera') os.path.exists(cantera_folder) or os.mkdir(cantera_folder) # Write the CTML file to scratch/cantera/ folder cti_file = os.path.join(cantera_folder, 'cantera_input_%03d' % len(model.core.species)) logging.debug("Writing CTML file %s" % cti_file) ctml_writer.dataset(cti_file) # change name ctml_writer.write() import Cantera import Cantera.Reactor # Load the CTML file into Cantera logging.info("Preparing Cantera simulation %d" % len(model.core.species)) Cantera.reset() gas = Cantera.importPhase('%s.xml' % cti_file, 'chem', loglevel=1) # Set initial concentrations moleFractions = numpy.zeros(len(model.core.species)) for spec, conc in self.initialMoleFraction.iteritems(): moleFractions[gas.speciesIndex(str(spec))] = conc gas.setMoleFractions(moleFractions) # it normalises it to 1 # Set initial temperature and pressure gas.set(T=self.initialTemperature, P=self.initialPressure) # create a batch reactor if self.heatTransferCoeff == 1.0e100: reactor = Cantera.Reactor.Reactor(gas, volume=self.volume, energy='off') else: reactor = Cantera.Reactor.Reactor(gas, volume=self.volume) # set the inital environment conditions gasAir = Cantera.Air() gasAir.set(T=self.reservoirTemperature, P=self.reservoirPressure) # create a reservoir for the environment environment = Cantera.Reactor.Reservoir(gasAir) # Define a wall between the reactor and the environment, and # make it flexible, so that the pressure in the reactor is held # at the environment pressure, and conductive so the temperature likewise wall = Cantera.Reactor.Wall(reactor, environment) wall.set(K=self.expansionCoeff) wall.set(A=self.area) wall.setHeatTransferCoeff(self.heatTransferCoeff) # W/m2/K # put reactor in a reactor network so it can be integrated sim = Cantera.Reactor.ReactorNet([reactor]) sim.setTolerances(atol=model.absoluteTolerance, rtol=model.relativeTolerance) #import pdb; pdb.set_trace() return sim, gas
def test_equil_overconstrained2(self): gas = ct.importPhase('equilibrium.cti', 'overconstrained-2') gas.set(X='CH4:1.0, O2:1.0', T=301, P=100000) gas.equilibrate('TP', self.solver) self.check(gas, CH4=1, O2=1)
def test_equil_incomplete_lean(self): gas = ct.importPhase('equilibrium.cti', 'incomplete') gas.set(X='CH4:1.0, O2:3.0', T=301, P=100000) gas.equilibrate('TP', self.solver) self.check(gas, CH4=0, O2=1, H2O=2, CO2=1)
def test_checkReactionBalance(self): self.assertRaises(Exception, lambda: ct.IdealGasMix('../data/h2o2_unbalancedReaction.xml'))
""" Unit tests for the Cantera Python module. This script gathers all the tests defined in all of the test<foo>.py files, runs them, and prints a report. """ import sys import os import unittest import Cantera Cantera.addDirectory(os.path.join(os.path.split(os.getcwd())[0], 'data')) if __name__ == '__main__': print '\n* INFO: using Cantera module found at this location:' print '* ', repr(Cantera.__file__), '\n' sys.stdout.flush() loader = unittest.TestLoader() runner = unittest.TextTestRunner(verbosity=2) suite = loader.loadTestsFromName('testSolution') suite = loader.loadTestsFromName('testKinetics') suite.addTests(loader.loadTestsFromName('testPureFluid')) suite.addTests(loader.loadTestsFromName('testEquilibrium')) suite.addTests(loader.loadTestsFromName('testReactors')) suite.addTests(loader.loadTestsFromName('testConvert')) results = runner.run(suite) sys.exit(len(results.errors) + len(results.failures))
def setUp(self): self.gas = ct.IdealGasMix('../data/explicit-forward-order.xml') self.gas.set(T=800, P=101325, X=[0.01, 0.90, 0.02, 0.03, 0.04])