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 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 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 make_reactors(self, independent=True, n_reactors=2, T1=300, P1=101325, X1='O2:1.0', T2=300, P2=101325, X2='O2:1.0'): self.net = ct.ReactorNet() self.gas1 = ct.Solution('h2o2.xml') self.gas1.TPX = T1, P1, X1 self.r1 = ct.Reactor(self.gas1) self.net.add_reactor(self.r1) if independent: self.gas2 = ct.Solution('h2o2.xml') else: self.gas2 = self.gas1 if n_reactors >= 2: self.gas2.TPX = T2, P2, X2 self.r2 = ct.Reactor(self.gas2) self.net.add_reactor(self.r2)
def makeReactors(self): self.net = ct.ReactorNet() self.gas = ct.Solution('diamond.xml', 'gas') self.solid = ct.Solution('diamond.xml', 'diamond') self.interface = ct.Interface('diamond.xml', 'diamond_100', (self.gas, self.solid)) self.r1 = ct.Reactor(self.gas) self.net.addReactor(self.r1) self.r2 = ct.Reactor(self.gas) self.net.addReactor(self.r2) self.w = ct.Wall(self.r1, self.r2)
def setup(): net = ct.ReactorNet() gas.TPX = 900, 101325, 'H2:0.1, OH:1e-7, O2:0.1, AR:1e-5' r = ct.Reactor(gas) net.addReactor(r) return r, net
def eval_idt(args): mech, options, x = args gas = global_var.gases[mech] t_fin = options.t_fin time_vec = [] temp_vec = [] # DCN Conditions p = options.pres # Pa t = options.temp # K phi = options.phi # Add air to the mixture stoich_o2 = 0.0 for idx, species in enumerate(options.palette): stoich_o2 += x[idx] * (gas.n_atoms(species, 'C') + 0.25 * gas.n_atoms(species, 'H')) # Set gas composition with air x_mod = (options.phi / stoich_o2) * x comp_string = set_gas_using_palette(gas, options, t, p, x_mod) comp_string += ',O2:1,N2:3.76' gas.TPX = t, p, comp_string # Create reactor network r = ct.Reactor(gas) sim = ct.ReactorNet([r]) # Advance the reactor time = 0.0 time_vec.append(time) while time < t_fin: time = sim.step() time_vec.append(time) temp_vec.append(r.T) # Find maximum slope of temperature max_der = 0.0 der = 0.0 index = 0 for idx, val in enumerate(temp_vec): der = (temp_vec[idx] - temp_vec[idx-1]) / \ (time_vec[idx] - time_vec[idx-1]) if abs(der) > max_der: max_der = der index = idx if temp_vec[index] < t: return -1 else: print str(["{:0.3f}".format(y) for y in x]) + ", " + str("{:0.7e}".format(time_vec[index])) #print str(options.pres) + ", " + str(options.temp) + ", " + str(options.phi) + ", " + str("{:0.7e}".format(time_vec[index])) sys.stdout.flush() return time_vec[index]
def setup(reverse=False): net = ct.ReactorNet() gas1 = ct.Solution('h2o2.xml') gas1.TPX = 900, 101325, 'H2:0.1, OH:1e-7, O2:0.1, AR:1e-5' rA = ct.Reactor(gas1) gas2 = ct.Solution('h2o2.xml') gas2.TPX = 920, 101325, 'H2:0.1, OH:1e-7, O2:0.1, AR:0.5' rB = ct.Reactor(gas2) if reverse: net.addReactor(rB) net.addReactor(rA) else: net.addReactor(rA) net.addReactor(rB) return rA, rB, net
def test_cantera_reactornet(): """ Testing basic Cantera ReactorNet functionality """ g = get_gas() ctreactor = ct.Reactor(g) ctnet = ct.ReactorNet([ctreactor]) ctnet.advance(0.01)
def test_sensitivities2(self): net = ct.ReactorNet() gas1 = ct.Solution('diamond.xml', 'gas') solid = ct.Solution('diamond.xml', 'diamond') interface = ct.Interface('diamond.xml', 'diamond_100', (gas1, solid)) r1 = ct.Reactor(gas1) net.addReactor(r1) gas2 = ct.Solution('h2o2.xml') gas2.TPX = 900, 101325, 'H2:0.1, OH:1e-7, O2:0.1, AR:1e-5' r2 = ct.Reactor(gas2) net.addReactor(r2) w = ct.Wall(r1, r2) w.left.kinetics = interface C = np.zeros(interface.nSpecies) C[0] = 0.3 C[4] = 0.7 w.left.coverages = C w.left.addSensitivityReaction(2) r2.addSensitivityReaction(18) for T in (901, 905, 910, 950, 1500): while r2.T < T: net.step(1.0) S = net.sensitivities() K1 = gas1.nSpecies + interface.nSpecies # Constant internal energy and volume should generate zero # sensitivity coefficients self.assertArrayNear(S[0:2,:], np.zeros((2,2))) self.assertArrayNear(S[K1+2:K1+4,:], np.zeros((2,2))) S11 = np.linalg.norm(S[2:K1+2,0]) S21 = np.linalg.norm(S[2:K1+2,1]) S12 = np.linalg.norm(S[K1+4:,0]) S22 = np.linalg.norm(S[K1+4:,1]) self.assertTrue(S11 > 1e5 * S12) self.assertTrue(S22 > 1e5 * S21)
def getAI(self): gas = Global.gas ifuel = gas.species_index(self.fuel) io2 = gas.species_index('O2') in2 = gas.species_index('N2') self.putMultiplier(gas) x = np.zeros(gas.n_species) x[ifuel] = self.phi x[io2] = gas.n_atoms(self.fuel, 'C') + 0.25 * \ gas.n_atoms(self.fuel, 'H') x[in2] = x[io2] * self.n2_o2_ratio gas.TPX = self.Tin, self.P, x # Create reactor network r = ct.Reactor(gas) sim = ct.ReactorNet([r]) # Advance the reactor time = 0.0 time0 = 0.0 time1 = 0.0 curT0 = r.T curT1 = r.T iteration = 0 #sim.atol = 1e-7 #sim.rtol = 1e-4 try: while curT1 < self.Ttarget: time = sim.step() curT0 = curT1 curT1 = r.T time0 = time1 time1 = time iteration += 1 if (time > 4.e2): print('Current time too large, continuing') return 4.e2 if (iteration > 100000): print('Max Iteration reached, continuing') return 0. except: print('Failed! Continuing...') return 4.e2 weight = (self.Ttarget - curT0) / (curT1 - curT0) AItime = (1. - weight) * time0 + weight * time1 return AItime
def test_insert(self): R = ct.Reactor() f1 = lambda r: r.T f2 = lambda r: r.kinetics.netProductionRates self.assertRaises(Exception, f1, R) self.assertRaises(Exception, f2, R) g = ct.Solution('h2o2.xml') g.TP = 300, 101325 R.insert(g) self.assertNear(R.T, 300) self.assertEqual(len(R.kinetics.netProductionRates), g.nSpecies)
def setup(order): gas1.TPX = 1200, 1e3, 'H:0.002, H2:1, CH4:0.01, CH3:0.0002' gas2.TPX = 900, 101325, 'H2:0.1, OH:1e-7, O2:0.1, AR:1e-5' net = ct.ReactorNet() rA = ct.Reactor(gas1) rB = ct.Reactor(gas2) if order % 2 == 0: wA = ct.Wall(rA, rB) wB = ct.Wall(rB, rA) else: wB = ct.Wall(rB, rA) wA = ct.Wall(rA, rB) wA.left.kinetics = interface wB.right.kinetics = interface wA.area = 0.1 wB.area = 10 C1 = np.zeros(interface.nSpecies) C2 = np.zeros(interface.nSpecies) C1[0] = 0.3 C1[4] = 0.7 C2[0] = 0.9 C2[4] = 0.1 wA.left.coverages = C1 wB.right.coverages = C2 if order // 2 == 0: net.addReactor(rA) net.addReactor(rB) else: net.addReactor(rB) net.addReactor(rA) return rA,rB,wA,wB,net
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])
def test_sensitivities1(self): net = ct.ReactorNet() gas = ct.Solution('gri30.xml') gas.TPX = 1300, 20*101325, 'CO:1.0, H2:0.1, CH4:0.1, H2O:0.5' r1 = ct.Reactor(gas) net.addReactor(r1) self.assertEqual(net.nSensitivityParams, 0) r1.addSensitivityReaction(40) r1.addSensitivityReaction(41) net.advance(0.1) self.assertEqual(net.nSensitivityParams, 2) self.assertEqual(net.nVars, gas.nSpecies + 2) S = net.sensitivities() self.assertEqual(S.shape, (net.nVars, net.nSensitivityParams))
def advance(solution_object): reactor = ct.Reactor(solution_object) sim = ct.ReactorNet([reactor]) current_time = 0.0 end_time = 5.0e-3 time_array = [] temperature_array = [] data_index = 0 while current_time < end_time: data_index += 1 current_time = sim.step(end_time) time_array.append(current_time) temperature_array.append(reactor.T) time_array = np.array(time_array) temperature_array = np.array(temperature_array) temperature_profile = np.vstack((time_array, temperature_array)).T return [temperature_profile, time_array, temperature_array]
def getAI(self): gas = Global.gas ifuel = gas.species_index(self.fuel) io2 = gas.species_index('O2') in2 = gas.species_index('N2') self.putMultiplier(gas) x = np.zeros(gas.n_species) x[ifuel] = self.phi x[io2] = gas.n_atoms(self.fuel, 'C') + 0.25 * \ gas.n_atoms(self.fuel, 'H') x[in2] = x[io2] * self.n2_o2_ratio gas.TPX = self.Tin, self.P, x # Create reactor network r = ct.Reactor(gas) sim = ct.ReactorNet([r]) # Advance the reactor time = 0.0 time0 = 0.0 time1 = 0.0 curT0 = r.T curT1 = r.T #sim.atol = 1e-7 #sim.rtol = 1e-4 while curT1 < self.Ttarget: time = sim.step() curT0 = curT1 curT1 = r.T time0 = time1 time1 = time weight = (self.Ttarget - curT0) / (curT1 - curT0) AItime = (1. - weight) * time0 + weight * time1 logging.debug('Done Ignition time computation') return AItime
def forward(self): estimatedIgnitionDelayTimes = 0.005 igni = [] for i, tem in enumerate(self.tem): ideal_gas = ct.Solution(self.file) # 要不要加呢 reactorTemperature10 = tem # 这里temperature改成每一个温度 ideal_gas.TP = reactorTemperature10, self.p1 ideal_gas.X = self.conditions r = ct.Reactor(contents=ideal_gas) reactorNetwork = ct.ReactorNet([r]) timeHistory = ct.SolutionArray(ideal_gas, extra=['t']) t = 0 counter = 0 while t < estimatedIgnitionDelayTimes: t = reactorNetwork.step() if not counter % 20: timeHistory.append(r.thermo.state, t=t) counter += 1 tau = self.ignitionDelay(timeHistory, 'OH') igni.append(tau) # 工况1的第一个温度的着火延迟 return igni
def run_sim(solution_object, condition, sys_args='none', **usr_args ): """ Function to run Cantera reactor simulation for autoigntion conditions Parameters ---------- solution_object : obj Cantera solution object condition An object contining initial conditions (temperature, pressure, mole fractions) Returns ---------- Output Plot of Temp vs Time Points of interest CSV file Hdf5 file mass_fractions.hdf5 : [initial_condition] [index] [Pressure] [Reaction Rates of Progress] [Species Mass Fractions] [Species Net Production Rates Original] [Temp] [Time] return_obj : obj sim result .time .temp .initial_temperature_array .sp_data .test (h5py object) .tau .Temp .frac Example ------- run_sim(gas_solution, points='y', plot='y', initial_sim='y') """ func_start_time = tm.time() solution = solution_object initial_temperature = float(condition.temperature) pressure = float(condition.pressure)*float(ct.one_atm) #check if species in solution frac = '' for reactant in condition.species.iteritems(): if reactant[0] in solution.species_names: frac += str(reactant[0]) + ':' + str(reactant[1]) + ',' frac = frac[:-1] solution.TPX = initial_temperature, pressure, frac #101.325 kPa species = solution.species() reactions = solution.reactions() #run sim to find ignition delay from dT/dt max reactor = ct.Reactor(solution) simulation = ct.ReactorNet([reactor]) current_time = 0.0 stop_time = 5.0e-3 group_index = 0 times1 = [] temps = [] #first column is time, second is temperature mass = reactor.mass sdata = np.zeros([0, len(reactor.Y)]) production_data = np.zeros([0, len(solution.net_production_rates)]) state_list = list() f1 = h5py.File('mass_fractions.hdf5', 'a') try: group_name = str(initial_temperature) + '_' + str(pressure) + '_' + str(frac) except ValueError: print "Duplicate initial conditions, or check to make sure mass fractions file isn't in directory. If it is, delete it""" individual = f1.create_group(group_name) timer_start =tm.time() while current_time < stop_time: group_index += 1 try: current_time = simulation.step() except Exception: error_string = 'Cantera autoignition_error @ %sK initial temperature' %initial_temperature print error_string return times1.append(current_time) temps.append(reactor.T) species_data = reactor.Y grp = individual.create_group(str(group_index)) grp['Temp'] = reactor.T grp['Time'] = current_time grp['Pressure'] = reactor.thermo.P species_production_rates = reactor.kinetics.net_production_rates net_rates_of_progress = reactor.kinetics.net_rates_of_progress grp.create_dataset('Species Mass Fractions', data=species_data) grp.create_dataset('Reaction Rates of Progress', data=net_rates_of_progress) grp.create_dataset('Species Net Production Rates Original', data=species_production_rates) species_data = species_data[:, np.newaxis].T #translate from [n, 1] to [1,n] sdata = np.vstack((sdata, species_data)) production_rates = np.array(solution.net_production_rates) production_rates = production_rates[:, np.newaxis].T production_data = np.vstack((production_data, production_rates)) sample = get_range(times1, temps, sdata, production_data) timer_stop = tm.time() #strips all data except that within a 40 point sample range around ignition for grp in f1[group_name].keys(): if int(grp) not in range((sample.index-20), (sample.index+20)): f1[group_name].__delitem__(str(grp)) #f1.close() #utility functions def plot(): import matplotlib.pyplot as plt plt.clf() #plot combustion point plt.plot(sample.derivative_max[0], sample.derivative_max[1], 'ro', ms=7, label='ignition point') #plot initial and final sample points plt.plot(sample.initial_point[0], sample.initial_point[1], 'rx', ms=5, mew=2) plt.plot(sample.final_point[0], sample.final_point[1], 'rx', ms=5, mew=2) #plot temp vs time plt.plot(sample.times_total, sample.temps_total) plt.xlabel('Time (s)') plt.title('Mixture Temperature vs Time') plt.legend() plt.ylabel('Temperature (C)') #plt.axis([0, 1.2, 900, 2800]) plt.show() def writecsv(sdata): names = str(solution.species_names) tt = ['Time (s)', 'Temp (K)'] names = solution.species_names name_array = np.append(tt, names) sdata = sdata.astype('|S10') file_data = np.vstack((name_array, sdata)) #open and write to file input_file_name_stripped = os.path.splitext(data_file)[0] output_file_name = os.path.join(input_file_name_stripped + '_species_data.csv') print output_file_name with open(output_file_name, 'wb') as f: np.savetxt(f, file_data, fmt=('%+12s'), delimiter=',') #os.system('atom '+ output_file_name) def writehdf5(sdata): #format matrix for hdf5 names = str(solution.species_names) tt = ['Time (s)', 'Temp (K)'] names = solution.species_names name_array = np.append(tt, names) sdata = sdata.astype('|S10') file_data = np.vstack((name_array, sdata)) #open and write to file input_file_name_stripped = os.path.splitext(data_file)[0] output_file_name = os.path.join(input_file_name_stripped + '_species_data.hdf5') with h5py.File(output_file_name, 'w') as f: Times = f.create_dataset("Times", data=sample.times) Temps = f.create_dataset("Temps", data=sample.temps) sgroup = f.create_group('Species_Data') for i, sp in enumerate(solution.species_names): sgroup.create_dataset(sp, data=sdata[:, i+2]) def points(): print("\nTime[s] Temp[K] Index Point") print(str(sample.initial_point[0]) + " " + str("{0:.2f}".format(sample.initial_point[1]))\ + " " + str(sample.initial_point[2]) + " " + "Initial sample point") print(str(sample.tau) + " " + str("{0:.2f}".format(sample.derivative_max[1])) + " " + str(sample.derivative_max[2])\ + " " + "Ignition point") print(str(sample.final_point[0]) + " " + str("{0:.2f}".format(sample.final_point[1]))\ + " " + str(sample.final_point[2]) + " " + "Final sample point") #terminal use case if sys_args is not 'none': if sys_args.plot: plot() if sys_args.writecsv: writecsv(sample.species_data) if sys_args.writehdf5: writehdf5(sample.species_data) if sys_args.points: points() class return_obj: def __init__(self, time, temp, sp_data, f1, tau, Temp, frac): self.time = time self.temp = temp self.initial_temperature_array = [] self.sp_data = sp_data self.test = f1 self.tau = tau self.Temp = initial_temperature self.frac = frac self.tau_array = [] #print 'autoignition time: %0.5f' %(tm.time()-func_start_time) return return_obj(sample.times, sample.temps, sample.species_data, f1, sample.tau, initial_temperature, frac) "sdata is an array of 40 timesteps, with each instance containing an array of species" "mass fractions at that instant"
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' combustor = ct.Reactor(gas) combustor.volume = 1.0 # create a reservoir for the exhaust exhaust = ct.Reservoir(gas) # lean combustion, phi = 0.5 equiv_ratio = 0.5 # compute fuel and air mass flow rates factor = 0.1 air_mdot = factor * 9.52 * air_mw fuel_mdot = factor * equiv_ratio * 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
length = 2.0 # reactor length [m] area = 7.85398e-5 # cross section area [m2] n_reactor = 200 # number of divided reactor Tout = 100.0 + 273.15 # outer temperature [K] area_wall = 0.0628329 # heat transfer wall area [m2] ht = 700.0 # heat transfer coef. [W/m2/K] # define object gas = ct.Solution('water.cti', 'liquid_water') gas.TPX = Tin, p, comp mdot = vin * area * gas.density dx = length / n_reactor #r = ct.IdealGasReactor(gas) r = ct.Reactor(gas) # since water is not ideal gas r.volume = area * dx upstream = ct.Reservoir(gas, name='upstream') downstream = ct.Reservoir(gas, name='downstream') m = ct.MassFlowController(upstream, r, mdot=mdot) v = ct.PressureController(r, downstream, master=m, K=1.0e-5) gas.TPX = Tout, p, comp outer = ct.Reservoir(gas) wall = ct.Wall(outer, r, U=ht) wall.area = area_wall / n_reactor sim = ct.ReactorNet([r]) # solve
import os import csv import numpy as np 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.Reactor(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 gri3 = ct.Solution('gri30.xml') gri3.TPX = 500.0, 0.2 * ct.one_atm, 'CH4:1.1, O2:2, N2:7.52' # create a reactor for the methane/air side r2 = ct.Reactor(gri3) #----------------------------------------------------------------------------- # Now couple the reactors by defining common walls that may move (a piston) or # conduct heat #-----------------------------------------------------------------------------
import numpy as np import cantera as ct import math import csv import matplotlib.pyplot as plt mech = 'gri30.cti' gas = ct.Solution('gri30.xml') #mieszanka T = 1000.0 P = 200000 X = 'C2H4:0.5 O2:3 N2:11.28' gas.TPX = T, P, X r = ct.Reactor(gas) sim = ct.ReactorNet([r]) times = np.zeros(2000) data = np.zeros([2000, 4]) tk = 0.5 dt = tk / 2000 time = 0 n = 0 while n < 2000: time += dt sim.advance(time) times[n] = time
def run_reactor( cti_file, t_array=[528], p_array=[75], v_array=[0.00424], h2_array=[0.75], co2_array=[0.5], rtol=1.0e-11, atol=1.0e-22, reactor_type=0, energy="off", sensitivity=False, sensatol=1e-6, sensrtol=1e-6, reactime=1e5, ): import pandas as pd import numpy as np import time import cantera as ct from matplotlib import pyplot as plt import csv import math import os import sys import re import itertools import logging from collections import defaultdict import git try: array_i = int(os.getenv("SLURM_ARRAY_TASK_ID")) except TypeError: array_i = 0 # get git commit hash and message repo = git.Repo("/work/westgroup/lee.ting/cantera/ammonia/") git_sha = str(repo.head.commit)[0:6] git_msg = str(repo.head.commit.message)[0:20].replace(" ", "_").replace( "'", "_") # this should probably be outside of function settings = list( itertools.product(t_array, p_array, v_array, h2_array, co2_array)) # constants pi = math.pi # set initial temps, pressures, concentrations temp = settings[array_i][0] # kelvin temp_str = str(temp)[0:3] pressure = settings[array_i][1] * ct.one_atm # Pascals X_h2 = settings[array_i][3] x_h2_str = str(X_h2)[0:3].replace(".", "_") x_CO_CO2_str = str(settings[array_i][4])[0:3].replace(".", "_") if X_h2 == 0.75: X_h2o = 0.05 else: X_h2o = 0 X_co = (1 - (X_h2 + X_h2o)) * (settings[array_i][4]) X_co2 = (1 - (X_h2 + X_h2o)) * (1 - settings[array_i][4]) # normalize mole fractions just in case # X_co = X_co/(X_co+X_co2+X_h2) # X_co2= X_co2/(X_co+X_co2+X_h2) # X_h2 = X_h2/(X_co+X_co2+X_h2) mw_co = 28.01e-3 # [kg/mol] mw_co2 = 44.01e-3 # [kg/mol] mw_h2 = 2.016e-3 # [kg/mol] mw_h2o = 18.01528e-3 # [kg/mol] co2_ratio = X_co2 / (X_co + X_co2) h2_ratio = (X_co2 + X_co) / X_h2 # CO/CO2/H2/H2: typical is concentrations_rmg = {"O2(2)": X_co, "NH3(6)": X_co2, "He": X_h2} # initialize cantera gas and surface gas = ct.Solution(cti_file, "gas") # surf_grab = ct.Interface(cti_file,'surface1_grab', [gas_grab]) surf = ct.Interface(cti_file, "surface1", [gas]) # gas_grab.TPX = gas.TPX = temp, pressure, concentrations_rmg surf.TP = temp, pressure # create gas inlet inlet = ct.Reservoir(gas) # create gas outlet exhaust = ct.Reservoir(gas) # Reactor volume rradius = 35e-3 rlength = 70e-3 rvol = (rradius**2) * pi * rlength # Catalyst Surface Area site_density = (surf.site_density * 1000 ) # [mol/m^2]cantera uses kmol/m^2, convert to mol/m^2 cat_weight = 4.24e-3 # [kg] cat_site_per_wt = (300 * 1e-6) * 1000 # [mol/kg] 1e-6mol/micromole, 1000g/kg cat_area = site_density / (cat_weight * cat_site_per_wt) # [m^3] # reactor initialization if reactor_type == 0: r = ct.Reactor(gas, energy=energy) reactor_type_str = "Reactor" elif reactor_type == 1: r = ct.IdealGasReactor(gas, energy=energy) reactor_type_str = "IdealGasReactor" elif reactor_type == 2: r = ct.ConstPressureReactor(gas, energy=energy) reactor_type_str = "ConstPressureReactor" elif reactor_type == 3: r = ct.IdealGasConstPressureReactor(gas, energy=energy) reactor_type_str = "IdealGasConstPressureReactor" rsurf = ct.ReactorSurface(surf, r, A=cat_area) r.volume = rvol surf.coverages = "X(1):1.0" # flow controllers (Graaf measured flow at 293.15 and 1 atm) one_atm = ct.one_atm FC_temp = 293.15 volume_flow = settings[array_i][2] # [m^3/s] molar_flow = volume_flow * one_atm / (8.3145 * FC_temp) # [mol/s] mass_flow = molar_flow * (X_co * mw_co + X_co2 * mw_co2 + X_h2 * mw_h2 + X_h2o * mw_h2o) # [kg/s] mfc = ct.MassFlowController(inlet, r, mdot=mass_flow) # A PressureController has a baseline mass flow rate matching the 'master' # MassFlowController, with an additional pressure-dependent term. By explicitly # including the upstream mass flow rate, the pressure is kept constant without # needing to use a large value for 'K', which can introduce undesired stiffness. outlet_mfc = ct.PressureController(r, exhaust, master=mfc, K=0.01) # initialize reactor network sim = ct.ReactorNet([r]) # set relative and absolute tolerances on the simulation sim.rtol = 1.0e-11 sim.atol = 1.0e-22 ################################################# # Run single reactor ################################################# # round numbers so they're easier to read # temp_str = '%s' % '%.3g' % tempn cat_area_str = "%s" % "%.3g" % cat_area results_path = ( os.path.dirname(os.path.abspath(__file__)) + f"/{git_sha}_{git_msg}/{reactor_type_str}/transient/{temp_str}/results" ) # results_path_csp = ( # os.path.dirname(os.path.abspath(__file__)) # + f"/{git_sha}_{git_msg}/{reactor_type_str}/transient/{temp_str}/results/csp" # ) flux_path = ( os.path.dirname(os.path.abspath(__file__)) + f"/{git_sha}_{git_msg}/{reactor_type_str}/transient/{temp_str}/flux_diagrams/{x_h2_str}/{x_CO_CO2_str}" ) try: os.makedirs(results_path, exist_ok=True) except OSError as error: print(error) # try: # os.makedirs(results_path_csp, exist_ok=True) # except OSError as error: # print(error) try: os.makedirs(flux_path, exist_ok=True) except OSError as error: print(error) gas_ROP_str = [i + " ROP [kmol/m^3 s]" for i in gas.species_names] # surface ROP reports gas and surface ROP. these values might be redundant, not sure. gas_surf_ROP_str = [ i + " surface ROP [kmol/m^2 s]" for i in gas.species_names ] surf_ROP_str = [i + " ROP [kmol/m^2 s]" for i in surf.species_names] gasrxn_ROP_str = [ i + " ROP [kmol/m^3 s]" for i in gas.reaction_equations() ] surfrxn_ROP_str = [ i + " ROP [kmol/m^2 s]" for i in surf.reaction_equations() ] output_filename = ( results_path + f"/Spinning_basket_area_{cat_area_str}_energy_{energy}" + f"_temp_{temp}_h2_{x_h2_str}_COCO2_{x_CO_CO2_str}.csv") # output_filename_csp = ( # results_path_csp # + f"/Spinning_basket_area_{cat_area_str}_energy_{energy}" # + f"_temp_{temp}_h2_{x_h2_str}_COCO2_{x_CO_CO2_str}.csv" # ) outfile = open(output_filename, "w") # outfile_csp = open(output_filename_csp, "w") writer = csv.writer(outfile) # writer_csp = csv.writer(outfile_csp) # Sensitivity atol, rtol, and strings for gas and surface reactions if selected # slows down script by a lot if sensitivity: sim.rtol_sensitivity = sensrtol sim.atol_sensitivity = sensatol sens_species = [ "NH3(6)" ] #change THIS to your species, can add "," and other species # turn on sensitive reactions/species for i in range(gas.n_reactions): r.add_sensitivity_reaction(i) for i in range(surf.n_reactions): rsurf.add_sensitivity_reaction(i) # for i in range(gas.n_species): # r.add_sensitivity_species_enthalpy(i) # for i in range(surf.n_species): # rsurf.add_sensitivity_species_enthalpy(i) for j in sens_species: gasrxn_sens_str = [ j + " sensitivity to " + i for i in gas.reaction_equations() ] surfrxn_sens_str = [ j + " sensitivity to " + i for i in surf.reaction_equations() ] # gastherm_sens_str = [j + " thermo sensitivity to " + i for i in gas.species_names] # surftherm_sens_str = [j + " thermo sensitivity to " + i for i in surf.species_names] sens_list = gasrxn_sens_str + surfrxn_sens_str # + gastherm_sens_str writer.writerow([ "T (C)", "P (atm)", "V (M^3/s)", "X_co initial", "X_co2initial", "X_h2 initial", "X_h2o initial", "CO2/(CO2+CO)", "(CO+CO2/H2)", "T (C) final", "Rtol", "Atol", "reactor type", ] + gas.species_names + surf.species_names + gas_ROP_str + gas_surf_ROP_str + surf_ROP_str + gasrxn_ROP_str + surfrxn_ROP_str + sens_list) else: writer.writerow([ "T (C)", "P (atm)", "V (M^3/s)", "X_co initial", "X_co2 initial", "X_h2 initial", "X_h2o initial", "CO2/(CO2+CO)", "(CO+CO2/H2)", "T (C) final", "Rtol", "Atol", "reactor type", ] + gas.species_names + surf.species_names + gas_ROP_str + gas_surf_ROP_str + surf_ROP_str + gasrxn_ROP_str + surfrxn_ROP_str) # writer_csp.writerow( # ["iter", "t", "dt", "Density[kg/m3]", "Pressure[Pascal]", "Temperature[K]",] # + gas.species_names # + surf.species_names # ) t = 0.0 dt = 0.1 iter_ct = 0 # run the simulation first_run = True while t < reactime: # save flux diagrams at beginning of run if first_run == True: save_flux_diagrams(gas, suffix=flux_path, timepoint="beginning") save_flux_diagrams(surf, suffix=flux_path, timepoint="beginning") first_run = False t += dt sim.advance(t) # if t % 10 < 0.01: if sensitivity: # get sensitivity for sensitive species i (e.g. methanol) in reaction j for i in sens_species: g_nrxn = gas.n_reactions s_nrxn = surf.n_reactions # g_nspec = gas.n_species # s_nspec = surf.n_species gas_sensitivities = [ sim.sensitivity(i, j) for j in range(g_nrxn) ] surf_sensitivities = [ sim.sensitivity(i, j) for j in range(g_nrxn, g_nrxn + s_nrxn) ] # gas_therm_sensitivities = [sim.sensitivity(i,j) # for j in range(g_nrxn+s_nrxn,g_nrxn+s_nrxn+g_nspec)] # surf_therm_sensitivities = [sim.sensitivity(i,j) # for j in range(g_nrxn+s_nrxn+g_nspec,g_nrxn+s_nrxn+g_nspec+s_nspec)] sensitivities_all = ( gas_sensitivities + surf_sensitivities # + gas_therm_sensitivities ) writer.writerow([ temp, pressure, volume_flow, X_co, X_co2, X_h2, X_h2o, co2_ratio, h2_ratio, gas.T, sim.rtol, sim.atol, reactor_type_str, ] + list(gas.X) + list(surf.X) + list(gas.net_production_rates) + list(surf.net_production_rates) + list(gas.net_rates_of_progress) + list(surf.net_rates_of_progress) + sensitivities_all) else: writer.writerow([ temp, pressure, volume_flow, X_co, X_co2, X_h2, X_h2o, co2_ratio, h2_ratio, gas.T, sim.rtol, sim.atol, reactor_type_str, ] + list(gas.X) + list(surf.X) + list(gas.net_production_rates) + list(surf.net_production_rates) + list(gas.net_rates_of_progress) + list(surf.net_rates_of_progress)) # writer_csp.writerow( # [ # iter_ct, # sim.time, # dt, # gas.density, # gas.P, # gas.T, # ] # + list(gas.X) # + list(surf.X) # ) iter_ct += 1 outfile.close() # outfile_csp.close() # save flux diagrams at the end of the run save_flux_diagrams(gas, suffix=flux_path, timepoint="end") save_flux_diagrams(surf, suffix=flux_path, timepoint="end") return
def run_reactor( cti_file, t_array=[548], surf_t_array=[ 548 ], # not used, but will be for different starting temperatures p_array=[1], v_array=[2.771e-10 ], # 14*7*(140e-4)^2*π/2*0.9=0.0002771(cm^3)=2.771e-10(m^3) o2_array=[0.88], nh3_array=[0.066], rtol=1.0e-11, atol=1.0e-22, reactor_type=0, energy="off", sensitivity=False, sensatol=1e-6, sensrtol=1e-6, reactime=1e5, ): # 14 aluminum plates, each of them containing seven semi-cylindrical microchannels of 280 µm width # and 140 µm depth, 9 mm long, arranged at equal distances of 280 µm try: array_i = int(os.getenv("SLURM_ARRAY_TASK_ID")) except TypeError: array_i = 0 # get git commit hash and message rmg_model_path = "../ammonia" repo = git.Repo(rmg_model_path) date = time.localtime(repo.head.commit.committed_date) git_date = f"{date[0]}_{date[1]}_{date[2]}_{date[3]}{date[4]}" git_sha = str(repo.head.commit)[0:6] git_msg = str(repo.head.commit.message)[0:50].replace(" ", "_").replace( "'", "_").replace("\n", "") git_file_string = f"{git_date}_{git_sha}_{git_msg}" # set sensitivity string for file path name if sensitivity: sensitivity_str = "on" else: sensitivity_str = "off" # this should probably be outside of function settings = list( itertools.product(t_array, surf_t_array, p_array, v_array, o2_array, nh3_array)) # constants pi = math.pi # set initial temps, pressures, concentrations temp = settings[array_i][1] # kelvin temp_str = str(temp)[0:3] pressure = settings[array_i][2] * ct.one_atm # Pascals surf_temp = temp X_o2 = settings[array_i][4] x_O2_str = str(X_o2)[0].replace(".", "_") X_nh3 = (settings[array_i][5]) x_NH3_str = str(X_nh3)[0:11].replace(".", "_") X_he = 1 - X_o2 - X_nh3 mw_nh3 = 17.0306e-3 # [kg/mol] mw_o2 = 31.999e-3 # [kg/mol] mw_he = 4.002602e-3 # [kg/mol] o2_ratio = X_nh3 / X_o2 # O2/NH3/He: typical is concentrations_rmg = {"O2(2)": X_o2, "NH3(6)": X_nh3, "He": X_he} # initialize cantera gas and surface gas = ct.Solution(cti_file, "gas") surf = ct.Interface(cti_file, "surface1", [gas]) # initialize temperatures gas.TPX = temp, pressure, concentrations_rmg surf.TP = temp, pressure # change this to surf_temp when we want a different starting temperature for the surface # if a mistake is made with the input, # cantera will normalize the mole fractions. # make sure that we are reporting/using # the normalized values X_o2 = float(gas["O2(2)"].X) X_nh3 = float(gas["NH3(6)"].X) X_he = float(gas["He"].X) # create gas inlet inlet = ct.Reservoir(gas) # create gas outlet exhaust = ct.Reservoir(gas) # Reactor volume number_of_reactors = 1001 rradius = 1.4e-4 #140µm to 0.00014m rtotal_length = 9e-3 #9mm to 0.009m rtotal_vol = (rradius**2) * pi * rtotal_length / 2 rlength = rtotal_length / 1001 # divide totareactor total volume rvol = (rtotal_vol) / number_of_reactors # Catalyst Surface Area site_density = (surf.site_density * 1000 ) # [mol/m^2] cantera uses kmol/m^2, convert to mol/m^2 cat_area_total = rradius * 2 / 2 * pi * rtotal_length # [m^3] cat_area = cat_area_total / number_of_reactors # reactor initialization if reactor_type == 0: r = ct.Reactor(gas, energy=energy) reactor_type_str = "Reactor" elif reactor_type == 1: r = ct.IdealGasReactor(gas, energy=energy) reactor_type_str = "IdealGasReactor" elif reactor_type == 2: r = ct.ConstPressureReactor(gas, energy=energy) reactor_type_str = "ConstPressureReactor" elif reactor_type == 3: r = ct.IdealGasConstPressureReactor(gas, energy=energy) reactor_type_str = "IdealGasConstPressureReactor" # calculate the available catalyst area in a differential reactor rsurf = ct.ReactorSurface(surf, r, A=cat_area) r.volume = rvol surf.coverages = "X(1):1.0" # flow controllers one_atm = ct.one_atm FC_temp = 293.15 volume_flow = settings[array_i][3] # [m^3/s] molar_flow = volume_flow * one_atm / (8.3145 * FC_temp) # [mol/s] mass_flow = molar_flow * (X_nh3 * mw_nh3 + X_o2 * mw_o2 + X_he * mw_he ) # [kg/s] mfc = ct.MassFlowController(inlet, r, mdot=mass_flow) # A PressureController has a baseline mass flow rate matching the 'master' # MassFlowController, with an additional pressure-dependent term. By explicitly # including the upstream mass flow rate, the pressure is kept constant without # needing to use a large value for 'K', which can introduce undesired stiffness. outlet_mfc = ct.PressureController(r, exhaust, master=mfc, K=0.01) # initialize reactor network sim = ct.ReactorNet([r]) # set relative and absolute tolerances on the simulation sim.rtol = 1.0e-8 sim.atol = 1.0e-16 ################################################# # Run single reactor ################################################# # round numbers for filepath strings so they're easier to read # temp_str = '%s' % '%.3g' % tempn cat_area_str = "%s" % "%.3g" % cat_area # if it doesn't already exist, g species_path = (os.path.dirname(os.path.abspath(__file__)) + f"/{git_file_string}/species_pictures") results_path = ( os.path.dirname(os.path.abspath(__file__)) + f"/{git_file_string}/{reactor_type_str}/energy_{energy}/sensitivity_{sensitivity_str}/{temp_str}/results" ) flux_path = ( os.path.dirname(os.path.abspath(__file__)) + f"/{git_file_string}/{reactor_type_str}/energy_{energy}/sensitivity_{sensitivity_str}/{temp_str}/flux_diagrams/{x_O2_str}/{x_NH3_str}" ) # create species folder for species pictures if it does not already exist try: os.makedirs(species_path, exist_ok=True) save_pictures(git_path=rmg_model_path, species_path=species_path) except OSError as error: print(error) try: os.makedirs(results_path, exist_ok=True) except OSError as error: print(error) try: os.makedirs(flux_path, exist_ok=True) except OSError as error: print(error) gas_ROP_str = [i + " ROP [kmol/m^3 s]" for i in gas.species_names] # surface ROP reports gas and surface ROP. these values are not redundant gas_surf_ROP_str = [ i + " surface ROP [kmol/m^2 s]" for i in gas.species_names ] surf_ROP_str = [i + " ROP [kmol/m^2 s]" for i in surf.species_names] gasrxn_ROP_str = [ i + " ROP [kmol/m^3 s]" for i in gas.reaction_equations() ] surfrxn_ROP_str = [ i + " ROP [kmol/m^2 s]" for i in surf.reaction_equations() ] output_filename = ( results_path + f"/Spinning_basket_area_{cat_area_str}_energy_{energy}" + f"_temp_{temp}_O2_{x_O2_str}_NH3_{x_NH3_str}.csv") outfile = open(output_filename, "w") writer = csv.writer(outfile) # Sensitivity atol, rtol, and strings for gas and surface reactions if selected # slows down script by a lot if sensitivity: sim.rtol_sensitivity = sensrtol sim.atol_sensitivity = sensatol sens_species = [ "NH3(6)", "O2(2)", "N2(4)", "NO(5)", "N2O(7)" ] #change THIS to your species, can add "," and other species # turn on sensitive reactions for i in range(gas.n_reactions): r.add_sensitivity_reaction(i) for i in range(surf.n_reactions): rsurf.add_sensitivity_reaction(i) # thermo sensitivities. leave off for now as they can cause solver crashes # for i in range(gas.n_species): # r.add_sensitivity_species_enthalpy(i) # for i in range(surf.n_species): # rsurf.add_sensitivity_species_enthalpy(i) for j in sens_species: gasrxn_sens_str = [ j + " sensitivity to " + i for i in gas.reaction_equations() ] surfrxn_sens_str = [ j + " sensitivity to " + i for i in surf.reaction_equations() ] # gastherm_sens_str = [j + " thermo sensitivity to " + i for i in gas.species_names] # surftherm_sens_str = [j + " thermo sensitivity to " + i for i in surf.species_names] sens_list = gasrxn_sens_str + surfrxn_sens_str # + gastherm_sens_str writer.writerow([ "Distance (mm)", "T (C)", "P (Pa)", "V (M^3/s)", "X_nh3 initial", "X_o2 initial", "X_he initial", "(NH3/O2)", "T (C) final", "Rtol", "Atol", "reactor type", "energy on?" ] + gas.species_names + surf.species_names + gas_ROP_str + gas_surf_ROP_str + surf_ROP_str + gasrxn_ROP_str + surfrxn_ROP_str + sens_list) else: writer.writerow([ "Distance (mm)", "T (C)", "P (Pa)", "V (M^3/s)", "X_nh3 initial", "X_o2 initial", "X_he initial", "(NH3/O2)", "T (C) final", "Rtol", "Atol", "reactor type", "energy on?" ] + gas.species_names + surf.species_names + gas_ROP_str + gas_surf_ROP_str + surf_ROP_str + gasrxn_ROP_str + surfrxn_ROP_str) t = 0.0 dt = 0.1 iter_ct = 0 # run the simulation first_run = True distance_mm = 0 for n in range(number_of_reactors): # Set the state of the reservoir to match that of the previous reactor gas.TDY = TDY = r.thermo.TDY inlet.syncState() sim.reinitialize() previous_coverages = surf.coverages # in case we want to retry if n > 0: # Add a first row in the CSV with just the feed try: sim.advance_to_steady_state() except ct.CanteraError: t = sim.time sim.set_initial_time(0) gas.TDY = TDY surf.coverages = previous_coverages r.syncState() sim.reinitialize() new_target_time = 0.01 * t logging.warning( f"Couldn't reach {t:.1g} s so going to try {new_target_time:.1g} s" ) try: sim.advance(new_target_time) except ct.CanteraError: outfile.close() raise # save flux diagrams at beginning of run if first_run == True: save_flux_diagrams(gas, suffix=flux_path, timepoint="beginning", species_path=species_path) save_flux_diagrams(surf, suffix=flux_path, timepoint="beginning", species_path=species_path) first_run = False if sensitivity: # get sensitivity for sensitive species i (e.g. methanol) in reaction j for i in sens_species: g_nrxn = gas.n_reactions s_nrxn = surf.n_reactions # g_nspec = gas.n_species # s_nspec = surf.n_species gas_sensitivities = [ sim.sensitivity(i, j) for j in range(g_nrxn) ] surf_sensitivities = [ sim.sensitivity(i, j) for j in range(g_nrxn, g_nrxn + s_nrxn) ] # gas_therm_sensitivities = [sim.sensitivity(i,j) # for j in range(g_nrxn+s_nrxn,g_nrxn+s_nrxn+g_nspec)] # surf_therm_sensitivities = [sim.sensitivity(i,j) # for j in range(g_nrxn+s_nrxn+g_nspec,g_nrxn+s_nrxn+g_nspec+s_nspec)] sensitivities_all = ( gas_sensitivities + surf_sensitivities # + gas_therm_sensitivities ) writer.writerow([ distance_mm, temp, gas.P, volume_flow, X_nh3, X_o2, X_he, o2_ratio, gas.T, sim.rtol, sim.atol, reactor_type_str, energy, ] + list(gas.X) + list(surf.X) + list(gas.net_production_rates) + list(surf.net_production_rates) + list(gas.net_rates_of_progress) + list(surf.net_rates_of_progress) + sensitivities_all, ) else: writer.writerow([ distance_mm, temp, gas.P, volume_flow, X_nh3, X_o2, X_he, o2_ratio, gas.T, sim.rtol, sim.atol, reactor_type_str, energy, ] + list(gas.X) + list(surf.X) + list(gas.net_production_rates) + list(surf.net_production_rates) + list(gas.net_rates_of_progress) + list(surf.net_rates_of_progress)) iter_ct += 1 distance_mm = n * rlength * 1.0e3 # distance in mm outfile.close() # save flux diagrams at the end of the run save_flux_diagrams(gas, suffix=flux_path, timepoint="end", species_path=species_path) save_flux_diagrams(surf, suffix=flux_path, timepoint="end", species_path=species_path) return
import sys import cantera as ct fmt = '%10.3f %10.1f %10.4f %10.4g %10.4g %10.4g %10.4g' print('%10s %10s %10s %10s %10s %10s %10s' % ('time [s]', 'T1 [K]', 'T2 [K]', 'V1 [m^3]', 'V2 [m^3]', 'V1+V2 [m^3]', 'X(CO)')) gas1 = ct.Solution('h2o2.cti') gas1.TPX = 900.0, ct.one_atm, 'H2:2, O2:1, AR:20' gas2 = ct.Solution('gri30.xml') gas2.TPX = 900.0, ct.one_atm, 'CO:2, H2O:0.01, O2:5' r1 = ct.Reactor(gas1) r1.volume = 0.5 r2 = ct.Reactor(gas2) r2.volume = 0.1 w = ct.Wall(r1, r2, K=1.0e3) net = ct.ReactorNet([r1, r2]) tim = [] t1 = [] t2 = [] v1 = [] v2 = [] v = [] xco = [] xh2 = []
real_gas = ct.Solution('nDodecane_Reitz.cti', 'nDodecane_RK') # Set the state of the gas object: real_gas.TP = reactorTemperature, reactorPressure # Define the fuel, oxidizer and set the stoichiometry: real_gas.set_equivalence_ratio(phi=1.0, fuel='c12h26', oxidizer={ 'o2': 1.0, 'n2': 3.76 }) # Create a reactor object and add it to a reactor network # In this example, this will be the only reactor in the network r = ct.Reactor(contents=real_gas) reactorNetwork = ct.ReactorNet([r]) timeHistory_RG = ct.SolutionArray(real_gas, extra=['t']) # Tic t0 = time.time() # This is a starting estimate. If you do not get an ignition within this time, # increase it estimatedIgnitionDelayTime = 0.005 t = 0 counter = 1 while (t < estimatedIgnitionDelayTime): t = reactorNetwork.step() if (counter % 20 == 0): # We will save only every 20th value. Otherwise, this takes too long
def run_reactor_ss( cti_file, t_array=[528], p_array=[75], v_array=[0.00424], h2_array=[0.75], co2_array=[0.5], rtol=1.0e-11, atol=1.0e-22, reactor_type=0, energy="off", sensitivity=False, sensatol=1e-6, sensrtol=1e-6, reactime=1e5, ): ''' run the reactor to steady state. saves a single CSV output file with one row of data. results saved in new folder marked "steady state" under reactor type ''' import pandas as pd import numpy as np import time import cantera as ct from matplotlib import pyplot as plt import csv import math import os import sys import re import itertools import logging from collections import defaultdict import git try: array_i = int(os.getenv("SLURM_ARRAY_TASK_ID")) except TypeError: array_i = 0 # get git commit hash and message repo = git.Repo("/work/westgroup/lee.ting/cantera/ammonia") git_sha = str(repo.head.commit)[0:6] git_msg = str(repo.head.commit.message)[0:20].replace(" ", "_").replace( "'", "_") # this should probably be outside of function settings = list( itertools.product(t_array, p_array, v_array, h2_array, co2_array)) # constants pi = math.pi # set initial temps, pressures, concentrations temp = settings[array_i][0] # kelvin temp_str = str(temp)[0:3] pressure = settings[array_i][1] * ct.one_atm # Pascals X_h2 = settings[array_i][3] x_h2_str = str(X_h2)[0:3].replace(".", "_") x_CO_CO2_str = str(settings[array_i][4])[0:3].replace(".", "_") if X_h2 == 0.75: X_h2o = 0.05 else: X_h2o = 0 X_co = (1 - (X_h2 + X_h2o)) * (settings[array_i][4]) X_co2 = (1 - (X_h2 + X_h2o)) * (1 - settings[array_i][4]) # normalize mole fractions just in case # X_co = X_co/(X_co+X_co2+X_h2) # X_co2= X_co2/(X_co+X_co2+X_h2) # X_h2 = X_h2/(X_co+X_co2+X_h2) mw_co = 28.01e-3 # [kg/mol] mw_co2 = 44.01e-3 # [kg/mol] mw_h2 = 2.016e-3 # [kg/mol] mw_h2o = 18.01528e-3 # [kg/mol] co2_ratio = X_co2 / (X_co + X_co2) h2_ratio = (X_co2 + X_co) / X_h2 # CO/CO2/H2/H2: typical is concentrations_rmg = {"O2(2)": X_co, "NH3(6)": X_co2, "He": X_h2} # initialize cantera gas and surface gas = ct.Solution(cti_file, "gas") # surf_grab = ct.Interface(cti_file,'surface1_grab', [gas_grab]) surf = ct.Interface(cti_file, "surface1", [gas]) # gas_grab.TPX = gas.TPX = temp, pressure, concentrations_rmg surf.TP = temp, pressure # create gas inlet inlet = ct.Reservoir(gas) # create gas outlet exhaust = ct.Reservoir(gas) # Reactor volume rradius = 35e-3 rlength = 70e-3 rvol = (rradius**2) * pi * rlength # Catalyst Surface Area site_density = (surf.site_density * 1000 ) # [mol/m^2]cantera uses kmol/m^2, convert to mol/m^2 cat_weight = 4.24e-3 # [kg] cat_site_per_wt = (300 * 1e-6) * 1000 # [mol/kg] 1e-6mol/micromole, 1000g/kg cat_area = site_density / (cat_weight * cat_site_per_wt) # [m^3] # reactor initialization if reactor_type == 0: r = ct.Reactor(gas, energy=energy) reactor_type_str = "Reactor" elif reactor_type == 1: r = ct.IdealGasReactor(gas, energy=energy) reactor_type_str = "IdealGasReactor" elif reactor_type == 2: r = ct.ConstPressureReactor(gas, energy=energy) reactor_type_str = "ConstPressureReactor" elif reactor_type == 3: r = ct.IdealGasConstPressureReactor(gas, energy=energy) reactor_type_str = "IdealGasConstPressureReactor" rsurf = ct.ReactorSurface(surf, r, A=cat_area) r.volume = rvol surf.coverages = "X(1):1.0" # flow controllers (Graaf measured flow at 293.15 and 1 atm) one_atm = ct.one_atm FC_temp = 293.15 volume_flow = settings[array_i][2] # [m^3/s] molar_flow = volume_flow * one_atm / (8.3145 * FC_temp) # [mol/s] mass_flow = molar_flow * (X_co * mw_co + X_co2 * mw_co2 + X_h2 * mw_h2 + X_h2o * mw_h2o) # [kg/s] mfc = ct.MassFlowController(inlet, r, mdot=mass_flow) # A PressureController has a baseline mass flow rate matching the 'master' # MassFlowController, with an additional pressure-dependent term. By explicitly # including the upstream mass flow rate, the pressure is kept constant without # needing to use a large value for 'K', which can introduce undesired stiffness. outlet_mfc = ct.PressureController(r, exhaust, master=mfc, K=0.01) # initialize reactor network sim = ct.ReactorNet([r]) # set relative and absolute tolerances on the simulation sim.rtol = 1.0e-11 sim.atol = 1.0e-22 ################################################# # Run single reactor ################################################# # round numbers so they're easier to read # temp_str = '%s' % '%.3g' % tempn cat_area_str = "%s" % "%.3g" % cat_area results_path = ( os.path.dirname(os.path.abspath(__file__)) + f"/{git_sha}_{git_msg}/{reactor_type_str}/steady_state/{temp_str}/results" ) flux_path = ( os.path.dirname(os.path.abspath(__file__)) + f"/{git_sha}_{git_msg}/{reactor_type_str}/steady_state/{temp_str}/flux_diagrams/{x_h2_str}/{x_CO_CO2_str}" ) try: os.makedirs(results_path, exist_ok=True) except OSError as error: print(error) try: os.makedirs(flux_path, exist_ok=True) except OSError as error: print(error) gas_ROP_str = [i + " ROP [kmol/m^3 s]" for i in gas.species_names] # surface ROP reports gas and surface ROP. these values are not redundant. gas_surf_ROP_str = [ i + " surface ROP [kmol/m^2 s]" for i in gas.species_names ] surf_ROP_str = [i + " ROP [kmol/m^2 s]" for i in surf.species_names] gasrxn_ROP_str = [ i + " ROP [kmol/m^3 s]" for i in gas.reaction_equations() ] surfrxn_ROP_str = [ i + " ROP [kmol/m^2 s]" for i in surf.reaction_equations() ] output_filename = ( results_path + f"/Spinning_basket_area_{cat_area_str}_energy_{energy}" + f"_temp_{temp}_h2_{x_h2_str}_COCO2_{x_CO_CO2_str}.csv") outfile = open(output_filename, "w") writer = csv.writer(outfile) writer.writerow([ "T (C)", "P (atm)", "V (M^3/s)", "X_co initial", "X_co2 initial", "X_h2 initial", "X_h2o initial", "CO2/(CO2+CO)", "(CO+CO2/H2)", "T (C) final", "Rtol", "Atol", "reactor type", ] + gas.species_names + surf.species_names + gas_ROP_str + gas_surf_ROP_str + surf_ROP_str + gasrxn_ROP_str + surfrxn_ROP_str) # Run Simulation to steady state sim.advance_to_steady_state() # Record steady state data to CSV writer.writerow([ temp, pressure, volume_flow, X_co, X_co2, X_h2, X_h2o, co2_ratio, h2_ratio, gas.T, sim.rtol, sim.atol, reactor_type_str, ] + list(gas.X) + list(surf.X) + list(gas.net_production_rates) + list(surf.net_production_rates) + list(gas.net_rates_of_progress) + list(surf.net_rates_of_progress)) outfile.close() # save flux diagrams at the end of the run save_flux_diagrams(gas, suffix=flux_path, timepoint="end") save_flux_diagrams(surf, suffix=flux_path, timepoint="end") return
# Create reservoirs for the two inlet streams and for the outlet stream. The # upsteam reservoirs could be replaced by reactors, which might themselves be # connected to reactors further upstream. The outlet reservoir could be # replaced with a reactor with no outlet, if it is desired to integrate the # composition leaving the mixer in time, or by an arbitrary network of # downstream reactors. res_a = ct.Reservoir(gas_a) res_b = ct.Reservoir(gas_b) downstream = ct.Reservoir(gas_b) # Create a reactor for the mixer. A reactor is required instead of a # reservoir, since the state will change with time if the inlet mass flow # rates change or if there is chemistry occurring. gas_b.TPX = 300.0, ct.one_atm, 'O2:0.21, N2:0.78, AR:0.01' mixer = ct.Reactor(gas_b) # create two mass flow controllers connecting the upstream reservoirs to the # mixer, and set their mass flow rates to values corresponding to # stoichiometric combustion. mfc1 = ct.MassFlowController(res_a, mixer, mdot=rho_a * 2.5 / 0.21) mfc2 = ct.MassFlowController(res_b, mixer, mdot=rho_b * 1.0) # connect the mixer to the downstream reservoir with a valve. outlet = ct.Valve(mixer, downstream, K=10.0) sim = ct.ReactorNet([mixer]) # Since the mixer is a reactor, we need to integrate in time to reach steady # state. A few residence times should be enough. print('{:>14s} {:>14s} {:>14s} {:>14s} {:>14s}'.format(
""" Constant-pressure, adiabatic kinetics simulation with sensitivity analysis """ import sys import numpy as np import cantera as ct gri3 = ct.Solution('gri30.xml') temp = 1500.0 pres = ct.one_atm gri3.TPX = temp, pres, 'CH4:0.1, O2:2, N2:7.52' r = ct.Reactor(gri3) air = ct.Solution('air.xml') air.TP = temp, pres env = ct.Reservoir(air) # 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. w = ct.Wall(r, env) w.expansion_rate_coeff = 1.0e6 # set expansion parameter. dV/dt = KA(P_1 - P_2) w.area = 1.0 sim = ct.ReactorNet([r]) # enable sensitivity with respect to the rates of the first 10 # reactions (reactions 0 through 9) for i in range(10):