def solve(gas, t): # Set the temperature and pressure for gas # t is different from t0 gas.TPX = t, pressure, composition surf.TP = t, pressure TDY = gas.TDY cov = surf.coverages # create a new reactor gas.TDY = TDY r = ct.IdealGasReactor(gas, energy='on') r.volume = rvol upstream = ct.Reservoir(gas, name='upstream') downstream = ct.Reservoir(gas, name='downstream') rsurf = ct.ReactorSurface(surf, r, A=cat_area) m = ct.MassFlowController(upstream, r, mdot=mass_flow_rate) v = ct.PressureController(r, downstream, master=m, K=1e-5) sim = ct.ReactorNet([r]) sim.max_err_test_fails = 20 sim.rtol = 1.0e-9 sim.atol = 1.0e-21 # define time, space, and other information vectors z2 = (np.arange(NReactors)) * rlen * 1e3 t_r2 = np.zeros_like(z2) # residence time in each reactor t2 = np.zeros_like(z2) states2 = ct.SolutionArray(gas) for n in range(NReactors): # Set the state of the reservoir to match that of the previous reactor gas.TDY = r.thermo.TDY upstream.syncState() sim.reinitialize() sim.advance_to_steady_state() dist = n * rlen * 1.0e3 # distance in mm t_r2[n] = r.mass / mass_flow_rate # residence time in this reactor t2[n] = np.sum(t_r2) states2.append(gas.state) print('Temperature of Gas :', t, ' residence time :', t2[-1]) MolFrac_CH4 = states2('CH4').X MolFrac_CO2 = states2('CO2').X MolFrac_CO = states2('CO').X MolFrac_H2 = states2('H2').X MolFrac_H2O = states2('H2O').X MolFrac_O2 = states2('O2').X kq = np.zeros(6) kq[0] = MolFrac_CH4[-1] * 100 kq[1] = MolFrac_CO2[-1] * 100 kq[2] = MolFrac_CO[-1] * 100 kq[3] = MolFrac_H2[-1] * 100 kq[4] = MolFrac_H2O[-1] * 100 kq[5] = MolFrac_O2[-1] * 100 return kq
def setup(self, T0, P0, mdot_fuel, mdot_ox): self.gas = ct.Solution('gri30.xml') # fuel inlet self.gas.TPX = T0, P0, "CH4:1.0" self.fuel_in = ct.Reservoir(self.gas) # oxidizer inlet self.gas.TPX = T0, P0, "N2:3.76, O2:1.0" self.oxidizer_in = ct.Reservoir(self.gas) # reactor, initially filled with N2 self.gas.TPX = T0, P0, "N2:1.0" self.combustor = ct.IdealGasReactor(self.gas) self.combustor.volume = 1.0 # outlet self.exhaust = ct.Reservoir(self.gas) # connect the reactor to the reservoirs self.fuel_mfc = ct.MassFlowController(self.fuel_in, self.combustor) self.fuel_mfc.set_mass_flow_rate(mdot_fuel) self.oxidizer_mfc = ct.MassFlowController(self.oxidizer_in, self.combustor) self.oxidizer_mfc.set_mass_flow_rate(mdot_ox) self.valve = ct.Valve(self.combustor, self.exhaust) self.valve.set_valve_coeff(1.0) self.net = ct.ReactorNet() self.net.add_reactor(self.combustor) self.net.max_err_test_fails = 10
def run_single(self): gas=self.processor.solution reactorPressure=gas.P self.reactorPressure=self.processor.solution.P pressureValveCoefficient=self.pvalveCoefficient maxPressureRiseAllowed=self.maxPrise print(maxPressureRiseAllowed,self.reactorPressure,pressureValveCoefficient) #Build the system components for JSR fuelAirMixtureTank=ct.Reservoir(self.processor.solution) exhaust=ct.Reservoir(self.processor.solution) stirredReactor=ct.IdealGasReactor(self.processor.solution,energy=self.energycon,volume=self.reactor_volume) massFlowController=ct.MassFlowController(upstream=fuelAirMixtureTank, downstream=stirredReactor,mdot=stirredReactor.mass/self.residence_time) pressureRegulator=ct.Valve(upstream=stirredReactor,downstream=exhaust,K=pressureValveCoefficient) reactorNetwork=ct.ReactorNet([stirredReactor]) if bool(self.observables) and self.kineticSens==1: for i in range(gas.n_reactions): stirredReactor.add_sensitivity_reaction(i) if self.kineticSens and bool(self.observables)==False: #except: print('Please supply a non-empty list of observables for sensitivity analysis or set kinetic_sens=0') if self.physicalSens==1 and bool(self.observables)==False:
def runSinglePSR(T, P, moleFraction, factor, reactionIndex, targetSpc): start = time.time() # create the gas mixture gas = ct.Solution('HXD15_Battin_mech.xml') gas.TPX = T, P, moleFraction # create an upstream reservoir that will supply the reactor. The temperature, # pressure, and composition of the upstream reservoir are set to those of the # 'gas' object at the time the reservoir is created. upstream = ct.Reservoir(gas) # Now create the reactor object with the same initial state cstr = ct.IdealGasReactor(gas) # Set its volume to 80 cm^3. In this problem, the reactor volume is fixed, so # the initial volume is the volume at all later times. cstr.volume = 80.0*1.0e-6 # Connect the upstream reservoir to the reactor with a mass flow controller # (constant mdot). Set the mass flow rate. vdot = 40* 1.0e-6 # m^3/s mdot = gas.density * vdot # kg/s mfc = ct.MassFlowController(upstream, cstr, mdot=mdot) # now create a downstream reservoir to exhaust into. downstream = ct.Reservoir(gas) # connect the reactor to the downstream reservoir with a valve, and set the # coefficient sufficiently large to keep the reactor pressure close to the # downstream pressure. v = ct.Valve(cstr, downstream, K=1.0e-9) # create the network network = ct.ReactorNet([cstr]) # modify the A factor of the given reaction gas.set_multiplier(factor,reactionIndex-1) # now integrate in time t = 0.0 dt = 0.1 print "\n\n\n**************************\n***** Solving case %d *****\n"%(reactionIndex) while t < 30.0: print t t += dt network.advance(t) results = [] for spc in targetSpc: results.append(cstr.thermo[spc].X[0]*1.0e6) end = time.time() print 'Execution time is:' print end - start return [gas.reaction_equation(reactionIndex-1)] + results
def setUp(self): self.gas = ct.Solution('h2o2.xml') # create a reservoir for the fuel inlet, and set to pure methane. self.gas.TPX = 300.0, ct.one_atm, 'H2:1.0' fuel_in = ct.Reservoir(self.gas) fuel_mw = self.gas.mean_molecular_weight # Oxidizer inlet self.gas.TPX = 300.0, ct.one_atm, 'O2:1.0, AR:3.0' oxidizer_in = ct.Reservoir(self.gas) oxidizer_mw = self.gas.mean_molecular_weight # 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.TPX = 300.0, ct.one_atm, 'H:1.0' self.igniter = ct.Reservoir(self.gas) # create the combustor, and fill it in initially with a diluent self.gas.TPX = 300.0, ct.one_atm, 'AR:1.0' self.combustor = ct.IdealGasReactor(self.gas) # create a reservoir for the exhaust self.exhaust = ct.Reservoir(self.gas) # compute fuel and air mass flow rates factor = 0.1 oxidizer_mdot = 4 * factor * oxidizer_mw fuel_mdot = factor * fuel_mw # The igniter will use a time-dependent igniter mass flow rate. def igniter_mdot(t, t0=0.1, fwhm=0.05, amplitude=0.1): return amplitude * math.exp( -(t - t0)**2 * 4 * math.log(2) / fwhm**2) # 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 = ct.MassFlowController(fuel_in, self.combustor, mdot=fuel_mdot) m2 = ct.MassFlowController(oxidizer_in, self.combustor, mdot=oxidizer_mdot) m3 = ct.MassFlowController(self.igniter, self.combustor, mdot=igniter_mdot) # put a valve on the exhaust line to regulate the pressure self.v = ct.Valve(self.combustor, self.exhaust, K=1.0) # the simulation only contains one reactor self.sim = ct.ReactorNet([self.combustor])
def cstr0(self, F, P, V, T=None, dt=2.0, t=None, disp=0): # mix streams if there is more than one self, F = mixer(self, F) # set initial conditions self.TP = T, P # create a new reactor if T == None or T == 0: r = ct.IdealGasReactor(self, energy='on') else: r = ct.IdealGasReactor(self, energy='off') r.volume = V # create up and downstream reservoirs upstream = ct.Reservoir(self) downstream = ct.Reservoir(self) # set mass flow into reactor m = ct.MassFlowController(upstream, r, mdot=F) # set valve to hold pressure constant ct.PressureController(r, downstream, master=m, K=1e-5) # create reactor network s = ct.ReactorNet([r]) s.rtol, s.atol, s.max_err_test_fails = rel_tol, abs_tol, test_fails # set parameters time = 0 residual = 1 all_done = False # forces reinitialization s.set_initial_time(0) while not all_done: Yo = r.thermo.Y To = r.thermo.T try: time += dt s.advance(time) except: dt *= 0.1 time += dt s.advance(time) if t != None and time >= t: all_done = False if time > 10 * dt: all_done = True residual = slope(Yo, r.thermo.Y, dt) if T == None: residual = np.max(np.append(residual,slope(To,r.thermo.T,dt))) if residual > rel_tol: all_done = False break if disp == True: print 'Residual: %1.3e' %(residual) return self, time, residual
def test_mass_flow_controller(self): self.makeReactors(nReactors=1) gas2 = ct.Solution('h2o2.xml') gas2.TPX = 300, 10*101325, 'H2:1.0' reservoir = ct.Reservoir(gas2) mfc = ct.MassFlowController(reservoir, self.r1) mfc.setMassFlowRate(lambda t: 0.1 if 0.2 <= t < 1.2 else 0.0) self.assertEqual(len(reservoir.inlets), 0) self.assertEqual(len(reservoir.outlets), 1) self.assertEqual(reservoir.outlets[0], mfc) self.assertEqual(len(self.r1.outlets), 0) self.assertEqual(len(self.r1.inlets), 1) self.assertEqual(self.r1.inlets[0], mfc) ma = self.r1.volume * self.r1.density Ya = self.r1.Y self.net.advance(2.5) mb = self.r1.volume * self.r1.density Yb = self.r1.Y self.assertNear(ma + 0.1, mb) self.assertArrayNear(ma * Ya + 0.1 * gas2.Y, mb * Yb)
def test_Reactor(self): phase = ct.PureFluid('liquidvapor.xml', 'oxygen') air = ct.Solution('air.xml') phase.TP = 93, 4e5 r1 = ct.Reactor(phase) r1.volume = 0.1 air.TP = 300, 4e5 r2 = ct.Reactor(air) r2.volume = 10.0 air.TP = 500, 4e5 env = ct.Reservoir(air) w1 = ct.Wall(r1,r2) w1.expansion_rate_coeff = 1e-3 w2 = ct.Wall(env,r1, Q=500000, A=1) net = ct.ReactorNet([r1,r2]) net.atol = 1e-10 net.rtol = 1e-6 states = ct.SolutionArray(phase, extra='t') for t in np.arange(0.0, 60.0, 1): net.advance(t) states.append(TD=r1.thermo.TD, t=net.time) self.assertEqual(states.X[0], 0) self.assertEqual(states.X[-1], 1) self.assertNear(states.X[30], 0.54806, 1e-4)
def def_reactors(z, zone, temp0, p0, mechanism, mixture): """ Defines reactors Returns ------- r : List of Cantera Reactor objects env: Cantera Reservoir object contents: List of Cantera solution objects corresponding to content of each reactor """ gas = ct.Solution(mechanism) gas.TPX = temp0, p0, mixture gas.transport_model = 'Multi' env = ct.Reservoir(ct.Solution(mechanism)) contents = [0] for x in range(1, z + 1): contents.append(gas) r = [ct.IdealGasReactor(gas)] for x in range(1, z + 1): r.append(ct.IdealGasReactor(contents[x], volume=zone[x].volume)) return r, env, contents
def setup_reactor(self): self.gas = ct.Solution(self.rxnmech) self.xinit = {"O2": 0.21, "N2": 0.79} self.gas.TPX = self.T0, self.p0, self.xinit self.injection_gas, _ = setup_injection_gas(self.rxnmech, self.fuel, pure_fuel=True) self.injection_gas.TP = self.T0, self.p0 fuel_res = ct.Reservoir(self.injection_gas) # Create the reactor object self.reactor = ct.Reactor(self.gas) self.rempty = ct.Reactor(self.gas) # Set the initial states of the reactor self.reactor.chemistry_enabled = True self.reactor.volume = self.history["V"][0] # Add in a fuel injector self.injector = ct.MassFlowController(fuel_res, self.reactor) # Add in a wall that moves according to piston velocity self.piston = ct.Wall( left=self.reactor, right=self.rempty, A=np.pi / 4.0 * self.bore**2, U=0.0, velocity=self.history["piston_velocity"][0], ) # Create the network object self.sim = ct.ReactorNet([self.reactor])
def setUp(self): self.referenceFile = pjoin(os.path.dirname(__file__), 'data', 'WallTest-integrateWithAdvance.csv') # reservoir to represent the environment self.gas0 = ct.Solution('air.xml') self.gas0.TP = 300, ct.one_atm self.env = ct.Reservoir(self.gas0) # reactor to represent the side filled with Argon self.gas1 = ct.Solution('air.xml') self.gas1.TPX = 1000.0, 30*ct.one_atm, 'AR:1.0' self.r1 = ct.Reactor(self.gas1) # reactor to represent the combustible mixture self.gas2 = ct.Solution('h2o2.xml') self.gas2.TPX = 500.0, 1.5*ct.one_atm, 'H2:0.5, O2:1.0, AR:10.0' self.r2 = ct.Reactor(self.gas2) # Wall between the two reactors self.w1 = ct.Wall(self.r2, self.r1, A=1.0, K=2e-4, U=400.0) # Wall to represent heat loss to the environment self.w2 = ct.Wall(self.r2, self.env, A=1.0, U=2000.0) # Create the reactor network self.sim = ct.ReactorNet([self.r1, self.r2])
def psr_ss(soln_in, soln_out, p, T0, T, X0, X, tau): #sys.stdout.flush() """ find the steady state of a PSR :param mech: mechanism :param p: pressure (Pa) :param T0: temperature (K) of the inlet flow :param T: initial temperature (K) of the reactor :param tau: residence time (s) of the reactor :return reactor: """ vol = 1.0 # unit: m3 K = 1.0 t_end = tau * 100.0 #print 't_end = '+str(t_end) soln_out.TPX = T, p, X soln_in.TPX = T0, p, X0 inlet = ct.Reservoir(soln_in) reactor = ct.IdealGasReactor(soln_out) reactor.volume = vol vdot = vol/tau mdot = soln_out.density * vdot mfc = ct.MassFlowController(inlet, reactor, mdot=mdot) exhaust = ct.Reservoir(soln_out) valve = ct.Valve(reactor, exhaust, K=K) network = ct.ReactorNet([reactor]) try: network.advance(t_end) except RuntimeError as e: print '@'*10+'\nct.exceptions = \n'+str(e) #sys.exit() return None return soln_out
def create_reactors(self, add_Q=False, add_mdot=False, add_surf=False): self.gas = ct.Solution('gri30.xml') self.gas.TPX = 900, 25*ct.one_atm, 'CO:0.5, H2O:0.2' self.gas1 = ct.Solution('gri30.xml') self.gas1.ID = 'gas' self.gas2 = ct.Solution('gri30.xml') self.gas2.ID = 'gas' resGas = ct.Solution('gri30.xml') solid = ct.Solution('diamond.xml', 'diamond') T0 = 1200 P0 = 25*ct.one_atm X0 = 'CH4:0.5, H2O:0.2, CO:0.3' self.gas1.TPX = T0, P0, X0 self.gas2.TPX = T0, P0, X0 self.r1 = ct.IdealGasReactor(self.gas1) self.r2 = self.reactorClass(self.gas2) self.r1.volume = 0.2 self.r2.volume = 0.2 resGas.TP = T0 - 300, P0 env = ct.Reservoir(resGas) U = 300 if add_Q else 0 self.w1 = ct.Wall(self.r1, env, K=1e3, A=0.1, U=U) self.w2 = ct.Wall(self.r2, env, A=0.1, U=U) if add_mdot: mfc1 = ct.MassFlowController(env, self.r1, mdot=0.05) mfc2 = ct.MassFlowController(env, self.r2, mdot=0.05) if add_surf: self.interface1 = ct.Interface('diamond.xml', 'diamond_100', (self.gas1, solid)) self.interface2 = ct.Interface('diamond.xml', 'diamond_100', (self.gas2, solid)) C = np.zeros(self.interface1.n_species) C[0] = 0.3 C[4] = 0.7 self.surf1 = ct.ReactorSurface(self.interface1, A=0.2) self.surf2 = ct.ReactorSurface(self.interface2, A=0.2) self.surf1.coverages = C self.surf2.coverages = C self.surf1.install(self.r1) self.surf2.install(self.r2) self.net1 = ct.ReactorNet([self.r1]) self.net2 = ct.ReactorNet([self.r2]) self.net1.set_max_time_step(0.05) self.net2.set_max_time_step(0.05) self.net2.max_err_test_fails = 10
def test_valve_errors(self): self.make_reactors() res = ct.Reservoir() with self.assertRaises(ct.CanteraError): # Must assign contents of both reactors before creating Valve v = ct.Valve(self.r1, res) v = ct.Valve(self.r1, self.r2) with self.assertRaises(ct.CanteraError): # inlet and outlet cannot be reassigned v._install(self.r2, self.r1)
def createReactors(self): """Use this function to create exhaust stream network""" #Creating fuel reservoir self.fuel.equilibrate('HP') self.fuelReservoir = ct.Reservoir(contents=self.fuel, name='fuel') #Creating combustor self.reactors = ct.ConstPressureReactor(contents=self.fuel, name='combustor', energy='on'), #Creating exhaust reactors exCycle = it.cycle(self.exhausts) self.reactors += tuple([ ct.ConstPressureReactor(contents=next(exCycle), name='exhaust{}'.format(i), energy='on') for i in range(self.nex) ]) #Creating atomspheric reactor self.atmosReservoir = ct.Reservoir(contents=self.atmosphere, name='atmosphere') self.exhaustReservoir = ct.Reservoir(contents=self.atmosphere, name='exhaust')
def test_pressure_controller(self): self.makeReactors(nReactors=1) g = ct.Solution('h2o2.xml') g.TPX = 500, 2*101325, 'H2:1.0' inletReservoir = ct.Reservoir(g) g.TP = 300, 101325 outletReservoir = ct.Reservoir(g) mfc = ct.MassFlowController(inletReservoir, self.r1) mdot = lambda t: np.exp(-100*(t-0.5)**2) mfc.setMassFlowRate(mdot) pc = ct.PressureController(self.r1, outletReservoir) pc.setMaster(mfc) pc.setPressureCoeff(1e-5) t = 0 while t < 1.0: t = self.net.step(1.0) self.assertNear(mdot(t), mfc.mdot(t)) dP = self.r1.thermo.P - outletReservoir.thermo.P self.assertNear(mdot(t) + 1e-5 * dP, pc.mdot(t))
def __init__(self, initial_temperature, initial_pressure, volume, is_reactive, end_temp=2500., end_time=0.2, chem_file='species.cti', cti_source=None): if volume is None: volume = np.genfromtxt('volume.csv', delimiter=',') inp_time = volume[:, 0] inp_vol = volume[:, 1] self.time = [] self.temperature = [] self.pressure = [] self.input_volume = volume self.simulated_volume = [] self.end_temp = end_temp self.end_time = end_time self.is_reactive = is_reactive self.chem_file = chem_file self.initial_temperature = initial_temperature self.initial_pressure = initial_pressure if cti_source is None: gas = ct.Solution(chem_file) else: gas = ct.Solution(source=cti_source) gas.TP = self.initial_temperature, self.initial_pressure if not self.is_reactive: gas.set_multiplier(0) reac = ct.IdealGasReactor(gas) env = ct.Reservoir(ct.Solution('air.xml')) ct.Wall(reac, env, A=1.0, velocity=VolumeProfile(inp_time, inp_vol)) netw = ct.ReactorNet([reac]) netw.set_max_time_step(inp_time[1]) self.time.append(netw.time) self.temperature.append(reac.T) self.pressure.append(gas.P/1E5) self.simulated_volume.append(reac.volume) while reac.T < self.end_temp and netw.time < self.end_time: netw.step() self.time.append(netw.time) self.temperature.append(reac.T) self.pressure.append(gas.P/1E5) self.simulated_volume.append(reac.volume) self.time = np.array(self.time) self.pressure = np.array(self.pressure) self.temperature = np.array(self.temperature) self.simulated_volume = np.array(self.simulated_volume) self.derivative = self.calculate_derivative(self.pressure, self.time)
def run(self,): gas=processor.solution.P reactorPressure=gas pressureValveCoefficient=pvalveCoefficient maxPressureRiseAllowed=maxPrise #Build the system components for JSR fuelAirMixtureTank=ct.Reservoir(gas) exhaust=ct.Reservoir(gas) stirredReactor=ct.IdealGasReactor(gas,energy=energycon,volume=volume) massFlowController=ct.MassFlowController(upstream=fuelAirMixtureTank, downstream=stirredReactor,mdot=stirredReactor.mass/restime) pressureRegulator=ct.Valve(upstream=stirredReactor,downstream=exhaust,K=pressureValveCoefficient) reactorNetwork=ct.ReactorNet([stirredReactor]) if bool(self.moleFractionObservables) and self.kineticSens==1: for i in range(gas.n_reactions): stirredReactor.add_sensitivity_reaction(i) if self.kineticSens and bool(self.moleFractionObservables)==False: except:
def test_pressure_controller_errors(self): self.make_reactors() res = ct.Reservoir(self.gas1) mfc = ct.MassFlowController(res, self.r1, mdot=0.6) p = ct.PressureController(self.r1, self.r2, master=mfc, K=0.5) with self.assertRaises(ct.CanteraError): p = ct.PressureController(self.r1, self.r2, K=0.5) p.mdot(0.0) with self.assertRaises(ct.CanteraError): p = ct.PressureController(self.r1, self.r2, master=mfc) p.mdot(0.0) with self.assertRaises(ct.CanteraError): p = ct.PressureController(self.r1, self.r2) p.mdot(0.0)
def __init__(self, idx, properties, model, path=''): """Initialize simulation case. :param idx: identifier number for this case :type idx: int :param properties: set of properties for this case :type properties: dict :param str model_file: Filename for Cantera-format model :param str path: Path for data file """ self.idx = idx self.properties = properties self.gas = model self.time_end = 10 #This is just a filler idk how end time should actually be determined yet self.gas.TP = (self.properties['temperature'], self.properties['pressure'] * float(ct.one_atm)) self.gas.set_equivalence_ratio(self.properties['equivalence_ratio'], self.properties['fuel'], self.properties['oxidizer']) # Create non-interacting ``Reservoir`` on other side of ``Wall`` env = ct.Reservoir(ct.Solution('air.xml')) # All reactors are ``IdealGasReactor`` objects self.reac = ct.IdealGasReactor(self.gas) self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) # Create ``ReactorNet`` newtork self.reac_net = ct.ReactorNet([self.reac]) # Set file for later data file file_path = os.path.join(path, str(self.idx) + '.h5') self.save_file = file_path self.sample_points = [] self.ignition_delay = 0.0
def test_ConstPressureReactor(self): phase = ct.Nitrogen() air = ct.Solution('air.xml') phase.TP = 75, 4e5 r1 = ct.ConstPressureReactor(phase) r1.volume = 0.1 air.TP = 500, 4e5 env = ct.Reservoir(air) w2 = ct.Wall(env,r1, Q=250000, A=1) net = ct.ReactorNet([r1]) states = ct.SolutionArray(phase, extra='t') for t in np.arange(0.0, 100.0, 10): net.advance(t) states.append(TD=r1.thermo.TD, t=t) self.assertEqual(states.X[1], 0) self.assertEqual(states.X[-2], 1) for i in range(3,7): self.assertNear(states.T[i], states.T[2])
def setUp(self): # reservoir to represent the environment self.gas0 = ct.Solution('air.xml') self.gas0.TP = 300, ct.one_atm self.env = ct.Reservoir(self.gas0) # reactor to represent the side filled with Argon self.gas1 = ct.Solution('air.xml') self.gas1.TPX = 1000.0, 30 * ct.one_atm, 'AR:1.0' self.r1 = ct.Reactor(self.gas1) # reactor to represent the combustible mixture self.gas2 = ct.Solution('h2o2.xml') self.gas2.TPX = 500.0, 1.5 * ct.one_atm, 'H2:0.5, O2:1.0, AR:10.0' self.r2 = ct.Reactor(self.gas2) # Wall between the two reactors self.w1 = ct.Wall(self.r2, self.r1, A=1.0, K=2e-4, U=400.0) # Wall to represent heat loss to the environment self.w2 = ct.Wall(self.r2, self.env, A=1.0, U=2000.0) # Create the reactor network self.sim = ct.ReactorNet([self.r1, self.r2])
""" import numpy as np import matplotlib.pyplot as plt import cantera as ct # Use reaction mechanism GRI-Mech 3.0. For 0-D simulations, # no transport model is necessary. gas = ct.Solution('gri30.yaml') # Create a Reservoir for the inlet, set to a methane/air mixture at a specified # equivalence ratio equiv_ratio = 0.5 # lean combustion gas.TP = 300.0, ct.one_atm gas.set_equivalence_ratio(equiv_ratio, 'CH4:1.0', 'O2:1.0, N2:3.76') inlet = ct.Reservoir(gas) # Create the combustor, and fill it initially with a mixture consisting of the # equilibrium products of the inlet mixture. This state corresponds to the state # the reactor would reach with infinite residence time, and thus provides a good # initial condition from which to reach a steady-state solution on the reacting # branch. gas.equilibrate('HP') combustor = ct.IdealGasReactor(gas) combustor.volume = 1.0 # Create a reservoir for the exhaust exhaust = ct.Reservoir(gas) # Use a variable mass flow rate to keep the residence time in the reactor # constant (residence_time = mass / mass_flow_rate). The mass flow rate function
import cantera as ct #----------------------------------------------------------------------- # First create each gas needed, and a reactor or reservoir for each one. #----------------------------------------------------------------------- # create an argon gas object and set its state ar = ct.Solution('argon.xml') ar.TP = 1000.0, 20.0 * ct.one_atm # create a reactor to represent the side of the cylinder filled with argon r1 = ct.IdealGasReactor(ar) # create a reservoir for the environment, and fill it with air. env = ct.Reservoir(ct.Solution('air.xml')) # use GRI-Mech 3.0 for the methane/air mixture, and set its initial state gas = ct.Solution('gri30.xml') gas.TP = 500.0, 0.2 * ct.one_atm gas.set_equivalence_ratio(1.1, 'CH4:1.0', 'O2:2, N2:7.52') # create a reactor for the methane/air side r2 = ct.IdealGasReactor(gas) #----------------------------------------------------------------------------- # Now couple the reactors by defining common walls that may move (a piston) or # conduct heat #----------------------------------------------------------------------------- # add a flexible wall (a piston) between r2 and r1
def runSinglePFR(T_0, pressure, composition_0, length, v_0, d, tempProfile, factor, reactionIndex): start = time.time() # input file containing the reaction mechanism reaction_mechanism = 'HXD15_Battin_mech.xml' # import the gas model and set the initial conditions gas2 = ct.Solution(reaction_mechanism) gas2.TPX = T_0, pressure, composition_0 mass_flow_rate2 = v_0 * gas2.density * (1.01325e5 / pressure) * (T_0 / 298.15) # Resolution: The PFR will be simulated by 'n_steps' time steps or by a chain # of 'n_steps' stirred reactors. n_steps = 100 area = math.pi * d * d / 4 dz = length / n_steps r_vol = area * dz # create a new reactor r2 = ct.IdealGasReactor(gas2) r2.volume = r_vol # create a reservoir to represent the reactor immediately upstream. Note # that the gas object is set already to the state of the upstream reactor upstream = ct.Reservoir(gas2, name='upstream') # create a reservoir for the reactor to exhaust into. The composition of # this reservoir is irrelevant. downstream = ct.Reservoir(gas2, name='downstream') # The mass flow rate into the reactor will be fixed by using a # MassFlowController object. m = ct.MassFlowController(upstream, r2, mdot=mass_flow_rate2) # We need an outlet to the downstream reservoir. This will determine the # pressure in the reactor. The value of K will only affect the transient # pressure difference. v = ct.PressureController(r2, downstream, master=m, K=1.0e-9) sim2 = ct.ReactorNet([r2]) from scipy.interpolate import UnivariateSpline [zz, tem] = readTemperatureProfile(tempProfile) para = UnivariateSpline(zz, tem) # modify the A factor of the given reaction gas2.set_multiplier(factor, reactionIndex - 1) # iterate through the PFR cells # define time, space, and other information vectors # z2 = (np.arange(n_steps+1) + 1) * dz # t_r2 = np.zeros_like(z2) # residence time in each reactor # u2 = np.zeros_like(z2) # t2 = np.zeros_like(z2) for n in range(n_steps + 1): print n position = dz * float(n) # Set the state of the reservoir to match that of the previous reactor gas2.TDY = para(position), r2.thermo.density, r2.thermo.Y upstream.syncState() sim2.reinitialize() # integrate the reactor forward in time until steady state is reached sim2.advance_to_steady_state() # compute velocity and transform into time # u2[n] = mass_flow_rate2 / area / r2.thermo.density # t_r2[n] = r2.mass / mass_flow_rate2 # residence time in this reactor # t2[n] = np.sum(t_r2) # write output data # print position, r2.thermo.T, r2.thermo.P, u2[n], t2[n], r2.thermo['C3H6'].X[0] # moleFractionC3H6.append([dz*n, u2[n], t2[n], r2.thermo.T, r2.thermo['C3H6'].X[0]]) end = time.time() print 'Done! Execution time is:' print end - start return [ gas2.reaction_equation(reactionIndex - 1), r2.thermo['C3H6'].X[0] * 1.0e6 ]
a MassFlowController, and the use of the SolutionArray class to store results during reactor network integration and use these results to generate plots. Requires: cantera >= 2.5.0, matplotlib >= 2.0 """ import numpy as np import matplotlib.pyplot as plt import cantera as ct # Use a reduced n-dodecane mechanism with PAH formation pathways gas = ct.Solution('nDodecane_Reitz.yaml', 'nDodecane_IG') # Create a Reservoir for the fuel inlet, set to pure dodecane gas.TPX = 300, 20 * ct.one_atm, 'c12h26:1.0' inlet = ct.Reservoir(gas) # Create Reactor and set initial contents to be products of lean combustion gas.TP = 1000, 20 * ct.one_atm gas.set_equivalence_ratio(0.30, 'c12h26', 'n2:3.76, o2:1.0') gas.equilibrate('TP') r = ct.IdealGasReactor(gas) r.volume = 0.001 # 1 liter def fuel_mdot(t): """Create an inlet for the fuel, supplied as a Gaussian pulse""" total = 3.0e-3 # mass of fuel [kg] width = 0.5 # width of the pulse [s] t0 = 2.0 # time of fuel pulse peak [s] amplitude = total / (width * np.sqrt(2 * np.pi))
# import the gas model and set the initial conditions ignition_delay = [] for T_0 in (i): gas2 = ct.Solution(reaction_mechanism) gas2.TPX = T_0, pressure, composition_0 mass_flow_rate2 = u_0 * gas2.density * area dz = length / n_steps r_vol = area * dz # create a new reactor r2 = ct.IdealGasReactor(gas2) r2.volume = r_vol # create a reservoir to represent the reactor immediately upstream. Note # that the gas object is set already to the state of the upstream reactor upstream = ct.Reservoir(gas2, name='upstream') # create a reservoir for the reactor to exhaust into. The composition of # this reservoir is irrelevant. downstream = ct.Reservoir(gas2, name='downstream') # The mass flow rate into the reactor will be fixed by using a # MassFlowController object. m = ct.MassFlowController(upstream, r2, mdot=mass_flow_rate2) # We need an outlet to the downstream reservoir. This will determine the # pressure in the reactor. The value of K will only affect the transient # pressure difference. v = ct.PressureController(r2, downstream, master=m, K=1e-5) sim2 = ct.ReactorNet([r2])
the chemistry. A simple igniter is a pulsed flow of atomic hydrogen. After the igniter is turned off, the system approaches the steady burning solution. """ import math import csv import cantera as ct # use reaction mechanism GRI-Mech 3.0 gas = ct.Solution('gri30.xml') # create a reservoir for the fuel inlet, and set to pure methane. gas.TPX = 300.0, ct.one_atm, 'CH4:1.0' fuel_in = ct.Reservoir(gas) fuel_mw = gas.mean_molecular_weight # use predefined function Air() for the air inlet air = ct.Solution('air.xml') air_in = ct.Reservoir(air) air_mw = air.mean_molecular_weight # 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. gas.TPX = 300.0, ct.one_atm, 'H:1.0' igniter = ct.Reservoir(gas) # create the combustor, and fill it in initially with N2 gas.TPX = 300.0, ct.one_atm, 'N2:1.0'
# In[2]: # create the gas mixture gas = ct.Solution('h2o2.cti') # pressure = 60 Torr, T = 770 K p = 60.0 * 133.3 t = 770.0 gas.TPX = t, p, 'H2:2, O2:1' # create an upstream reservoir that will supply the reactor. The temperature, # pressure, and composition of the upstream reservoir are set to those of the # 'gas' object at the time the reservoir is created. upstream = ct.Reservoir(gas) # Now create the reactor object with the same initial state cstr = ct.IdealGasReactor(gas) # Set its volume to 10 cm^3. In this problem, the reactor volume is fixed, so # the initial volume is the volume at all later times. cstr.volume = 10.0 * 1.0e-6 # We need to have heat loss to see the oscillations. Create a reservoir to # represent the environment, and initialize its temperature to the reactor # temperature. env = ct.Reservoir(gas) # Create a heat-conducting wall between the reactor and the environment. Set its # area, and its overall heat transfer coefficient. Larger U causes the reactor
def setup_case(self): """ Sets up the case to be run. Initializes the ``ThermoPhase``, ``Reactor``, and ``ReactorNet`` according to the values from the input file. """ self.gas = ct.Solution(self.mech_filename) initial_temp = self.keywords['temperature'] # The initial pressure in Cantera is expected in Pa; in SENKIN # it is expected in atm, so convert initial_pres = self.keywords['pressure'] * ct.one_atm # If the equivalence ratio has been specified, send the # keywords for conversion. if 'eqRatio' in self.keywords: reactants = utils.equivalence_ratio( self.gas, self.keywords['eqRatio'], self.keywords['fuel'], self.keywords['oxidizer'], self.keywords['completeProducts'], self.keywords['additionalSpecies'], ) else: # The reactants are stored in the ``keywords`` dictionary # as a list of strings, so they need to be joined. reactants = ','.join(self.keywords['reactants']) self.gas.TPX = initial_temp, initial_pres, reactants # Create a non-interacting ``Reservoir`` to be on the other # side of the ``Wall``. env = ct.Reservoir(ct.Solution('air.xml')) # Set the ``temp_func`` to ``None`` as default; it will be set # later if needed. self.temp_func = None # All of the reactors are ``IdealGas`` Reactors. Set a ``Wall`` # for every case so that later code can be more generic. If the # velocity is set to zero, the ``Wall`` won't affect anything. # We have to set the ``n_vars`` here because until the first # time step, ``ReactorNet.n_vars`` is zero, but we need the # ``n_vars`` before the first time step. if self.keywords['problemType'] == 1: self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 2: self.reac = ct.IdealGasConstPressureReactor(self.gas) # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 3: self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=VolumeProfile(self.keywords)) elif self.keywords['problemType'] == 4: self.reac = ct.IdealGasConstPressureReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 5: self.reac = ct.IdealGasReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) elif self.keywords['problemType'] == 6: from user_routines import VolumeFunctionTime self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=VolumeFunctionTime()) elif self.keywords['problemType'] == 7: from user_routines import TemperatureFunctionTime self.reac = ct.IdealGasConstPressureReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) self.temp_func = ct.Func1(TemperatureFunctionTime()) elif self.keywords['problemType'] == 8: self.reac = ct.IdealGasConstPressureReactor(self.gas, energy='off') # Number of solution variables is number of species + mass, # temperature self.n_vars = self.reac.kinetics.n_species + 2 self.wall = ct.Wall(self.reac, env, A=1.0, velocity=0) self.temp_func = ct.Func1(TemperatureProfile(self.keywords)) elif self.keywords['problemType'] == 9: self.reac = ct.IdealGasReactor(self.gas) # Number of solution variables is number of species + mass, # volume, temperature self.n_vars = self.reac.kinetics.n_species + 3 self.wall = ct.Wall(env, self.reac, A=1.0, velocity=ICEngineProfile(self.keywords)) if 'reactorVolume' in self.keywords: self.reac.volume = self.keywords['reactorVolume'] # Create the Reactor Network. self.netw = ct.ReactorNet([self.reac]) if 'sensitivity' in self.keywords: self.sensitivity = True # There is no automatic way to calculate the sensitivity of # all of the reactions, so do it manually. for i in range(self.reac.kinetics.n_reactions): self.reac.add_sensitivity_reaction(i) # If no tolerances for the sensitivity are specified, set # to the SENKIN defaults. if 'sensAbsTol' in self.keywords: self.netw.atol_sensitivity = self.keywords['sensAbsTol'] else: self.netw.atol_sensitivity = 1.0E-06 if 'sensRelTol' in self.keywords: self.netw.rtol_sensitivity = self.keywords['sensRelTol'] else: self.netw.rtol_sensitivity = 1.0E-04 else: self.sensitivity = False # If no solution tolerances are specified, set to the default # SENKIN values. if 'abstol' in self.keywords: self.netw.atol = self.keywords['abstol'] else: self.netw.atol = 1.0E-20 if 'reltol' in self.keywords: self.netw.rtol = self.keywords['reltol'] else: self.netw.rtol = 1.0E-08 if 'tempLimit' in self.keywords: self.temp_limit = self.keywords['tempLimit'] else: # tempThresh is set in the parser even if it is not present # in the input file self.temp_limit = (self.keywords['tempThresh'] + self.keywords['temperature']) self.tend = self.keywords['endTime'] # Set the maximum time step the solver can take. If a value is # not specified in the input file, default to 0.001*self.tend. # Set the time steps for saving to the binary file and writing # to the screen. If the time step for printing to the screen is # not set, default to printing 100 times. print_time_int = self.keywords.get('prntTimeInt') save_time_int = self.keywords.get('saveTimeInt') max_time_int = self.keywords.get('maxTimeStep') time_ints = [ value for value in [print_time_int, save_time_int, max_time_int] if value is not None ] if time_ints: self.netw.set_max_time_step(min(time_ints)) else: self.netw.set_max_time_step(self.tend / 100) if print_time_int is not None: self.print_time_step = print_time_int else: self.print_time_step = self.tend / 100 self.print_time = self.print_time_step self.save_time_step = save_time_int if self.save_time_step is not None: self.save_time = self.save_time_step # Store the species names in a slightly shorter variable name self.species_names = self.reac.thermo.species_names # Initialize the ignition time, in case the end time is reached # before ignition occurs self.ignition_time = None