def save_flux_diagrams(solution, times, conditions=None, condition_type='adiabatic-constant-volume', path='.', element='C', filename='flux_diagram', filetype='png'): """ This method is similar to run_simulation but it saves reaction path diagrams instead of returning objects. """ if conditions is not None: solution.TPX = conditions if condition_type == 'adiabatic-constant-volume': reactor = ct.IdealGasReactor(solution) elif condition_type == 'constant-temperature-and-pressure': reactor = ct.IdealGasConstPressureReactor(solution, energy='off') else: raise NotImplementedError( 'only "adiabatic-constant-volume" or "constant-temperature-and-pressure" is supported. {} input' .format(condition_type)) simulator = ct.ReactorNet([reactor]) solution = reactor.kinetics for time in times: simulator.advance(time) save_flux_diagram(solution, filename=filename + '_{:.2e}s'.format(simulator.time), path=path, element=element, filetype=filetype)
def averageChemicalPower(gas, tMax): ''' Function: averageChemicalPower ====================================================================== This function returns the average chemical Power of a HP reaction with respect to the temperature ''' #find the equilibrium value (T0, p0, X0) = gas.TPX gas.equilibrate('HP') try: iH2O = gas.species_index('H2O') H2O = 'H2O' except: iH2O = gas.species_index('h2o') H2O = 'h2o' H2Oeq = gas.Y[iH2O] gas.TPX = (T0, p0, X0) alpha = 0.98 #arbitrary percentage #initiate the reactor network r = ct.IdealGasConstPressureReactor(gas) sim = ct.ReactorNet([r]) time = 0.0 qDotMean = 0.0 T = gas.T dt = tMax / 100.0 #advance simulation with guessed timestep while r.thermo[H2O].Y < (alpha * H2Oeq): time += dt sim.advance(time) qDotMean += (gas.T - T) * chemicalPower(gas, 'hp') T = gas.T return qDotMean / (gas.T - T0)
def states_new_init(A): R_new = ct.Reaction.fromCti('''reaction('O2 + 2 H2 => 2 H2O', [%e, 0.0, 0.0])''' % (A)) #print(type(R_new)) #print(type(gas.reactions())) gas2 = ct.Solution(thermo='IdealGas', kinetics='GasKinetics', species=gas.species(), reactions=[R_new]) gas2.TPX = initial_state r_new = ct.IdealGasConstPressureReactor(gas2, energy='off') t_new = 0.0 states_new = ct.SolutionArray(gas2, extra=['t']) sim_new = ct.ReactorNet([r_new]) tt = [] TT = [] for n in range(100): '''t_new += 1.e-5 sim_new.advance(t_new) #print(t_new) tt.append(1000 * t_new*1000) TT.append(r_new.T)''' t_new += 1.e-5 sim_new.advance(t_new) states_new.append(r_new.thermo.state, t=t_new * 1e3) return states_new, gas2
def run(self, reactor_choice, t_end, T_reac, P_reac, mix, **kwargs): def list2ct_mixture( mix ): # list in the form of [[species, mol_frac], [species, mol_frac],...] return ', '.join("{!s}:{!r}".format(species, mol_frac) for (species, mol_frac) in mix) details = {'success': False, 'message': []} if isinstance(mix, list): mix = list2ct_mixture(mix) mech_out = self.mech.set_TPX(T_reac, P_reac, mix) if not mech_out['success']: details['success'] = False details['message'] = mech_out['message'] return None, mech_out #start = timer() if reactor_choice == 'Incident Shock Reactor': SIM, details = self.incident_shock_reactor(self.mech.gas, details, t_end, **kwargs) elif '0d Reactor' in reactor_choice: if reactor_choice == '0d Reactor - Constant Volume': reactor = ct.IdealGasReactor(self.mech.gas) elif reactor_choice == '0d Reactor - Constant Pressure': reactor = ct.IdealGasConstPressureReactor(self.mech.gas) SIM, details = self.zero_d_ideal_gas_reactor( self.mech.gas, reactor, details, t_end, **kwargs) #print('{:0.1f} us'.format((timer() - start)*1E3)) return SIM, details
def simulate_branching_various_conditions_3D( cantera_input_path, HO2_frac, conversion_species=['npropyloo', 'npropyl'], desired_conversion=0.95, starting_alkyl_radical='npropyl', expected_products=None, peroxy_frac=1e-17, temperatures=np.linspace(250, 1250, 25), pressures=np.logspace(3, 7, 15), NO_fracs=np.logspace(-12, -4, 15)): combs = [{ 'temp (K)': f1, 'NO (fraction)': f2, 'pres (Pa)': f3 } for f1 in temperatures for f2 in NO_fracs for f3 in pressures] df = pd.DataFrame(combs) for index in df.index: initialMoleFractions = { "NO": df.loc[index, 'NO (fraction)'], "HO2": HO2_frac, starting_alkyl_radical: peroxy_frac, 'O2': 0.21, "N2": 0.79, } solution = ctt.create_mechanism(cantera_input_path) conditions = df.loc[index, 'temp (K)'], df.loc[ index, 'pres (Pa)'], initialMoleFractions solution.TPX = conditions reactor = ct.IdealGasConstPressureReactor(solution, energy='off') simulator = ct.ReactorNet([reactor]) solution = reactor.kinetics peroxy_conc = sum([ solution.concentrations[solution.species_index(s)] for s in conversion_species ]) outputs = ctt.run_simulation_till_conversion( solution=solution, conditions=conditions, species=conversion_species, conversion=desired_conversion, condition_type='constant-temperature-and-pressure', output_reactions=False, atol=1e-25, ) species = outputs['species'] for name, conc in species.iteritems(): if not expected_products or name in expected_products: df.loc[index, name] = (conc / peroxy_conc).values[-1] df.fillna(value=0, inplace=True) return df
def totaldelaydata1(ITemp, IPressure, Ifraction, IER): Temp = np.zeros(ITemp) a = np.zeros(Ifraction) pressure = np.zeros(IPressure) ER = np.zeros(IER) # write output CSV file for importing into Excel gas = ct.Solution('gri30.xml') #writer.writerow(gas.species_names) for i in range(ITemp): Temp[i] = 1000.0 + 50 * i for m in range(IPressure): pressure[m] = 1 * ct.one_atm + 5.0 * m * ct.one_atm for n in range(Ifraction): a[n] = 0.1 * n for e in range(IER): gas.TP = Temp[i], pressure[m] ER[e] = 0.5 + 0.1 * e fO2 = ((1 - a[n]) * 2.0 + a[n] * 0.5) * (1 / ER[e]) CH4_P = 1 - a[n] H2_P = a[n] O2_P = fO2 N2_P = 3.76 * fO2 gas.X = { 'CH4': 1 - a[n], 'H2': a[n], 'O2': fO2, 'N2': 3.76 * fO2 } r = ct.IdealGasConstPressureReactor(gas) sim = ct.ReactorNet([r]) time = 0.0 states = ct.SolutionArray(gas, extra=['t']) #print('%10s %10s %10s %14s' % ('t [s]','T [K]','P [Pa]','u [J/kg]')) for number in range(10000): time += 1.e-6 sim.advance(time) states.append(r.thermo.state, t=time * 1e3) #print('%10.3e %10.3f %10.3f %14.6e' % (sim.time, r.T,r.thermo.P, r.thermo.u)) X_OH = np.max(states.X[:, gas.species_index('OH')]) X_HO2 = np.max(states.X[:, gas.species_index('HO2')]) # We will use the 'OH' species to compute the ignition delay max_index = np.argmax(states.X[:, gas.species_index('OH')]) Tau1 = states.t[max_index] # We will use the 'HO2' species to compute the ignition delay #max_index = np.argmax(states.X[:, gas.species_index('HO2')]) #Tau2[i] = states.t[max_index] # writer.writerow([pressure, Temp[i], CH4_P, H2_P, # O2_P, N2_P, ER, X_OH[i], X_HO2[i], Tau1[i]]) yield pressure[m], Temp[ i], CH4_P, H2_P, O2_P, N2_P, X_OH, X_HO2, Tau1 gas = ct.Solution('gri30.xml')
def runsim(times): if (pressureflag == 0): if (energyflag == 1): r = ct.IdealGasReactor(gas, name='R1') else: r = ct.IdealGasReactor(gas, name='R1', energy='off') else: if (energyflag == 1): r = ct.IdealGasConstPressureReactor(gas, name='R1') else: r = ct.IdealGasConstPressureReactor(gas, name='R1', energy='off') sim = ct.ReactorNet([r]) states = ct.SolutionArray(gas, extra=['t']) for t in times: sim.advance(t) norm = 0 states.append(r.thermo.state, t=t) return states
def set_case(self, problem): ''' function that set up the scenario''' if isinstance(problem[0], str) is False: problem[0] = '0D' if isinstance(problem[1], str) is False: problem[1] = 'volume' if problem[0].lower() == '0d': if problem[1].lower() == 'pressure': self.reactor = ct.IdealGasConstPressureReactor(self.gas) self.problemis = '0D, iso bar' if problem[1].lower() == 'volume': self.reactor = ct.IdealGasReactor(self.gas) self.reactor.volume = self.V self.problemis = '0D, iso volume' self.system = ct.ReactorNet((self.reactor, ))
def run(chemistry=None, initial=None, settings=None): """Function handling reactor simulation. The function uses the class 'ctwrap.Parser' in conjunction with 'pint.Quantity' for handling and conversion of units. Arguments: chemistry (Parser): overloads 'defaults.chemistry' initial (Parser): overloads 'defaults.initial' settings (Parser): overloads 'defaults.settings' Returns: Cantera SolutionArray """ # initialize gas object gas = ct.Solution(chemistry.mechanism) # set temperature, pressure, and composition T = initial.T.m_as('kelvin') P = initial.P.m_as('pascal') gas.TP = T, P phi = initial['phi'] gas.set_equivalence_ratio(phi, initial['fuel'], initial['oxidizer']) # define a reactor network reactor = ct.IdealGasConstPressureReactor(gas) sim = ct.ReactorNet([reactor]) delta_T_max = 20. reactor.set_advance_limit('temperature', delta_T_max) # set simulation parameters sim.atol = settings['atol'] sim.rtol = settings['rtol'] sim.max_time_step = settings['max_time_step'] delta_t = settings['delta_t'] n_points = settings['n_points'] # define SolutionArray and run simulation states = ct.SolutionArray(gas, extra=['t']) time = sim.time for _ in range(n_points): time += delta_t sim.advance(time) states.append(reactor.thermo.state, t=time) return states
def reinitialize_simulation( self, T0=None, P0=None, X0=None, V0=None, ): """ Re-initializes the cantera solution object (self.model) and cantera reactor object (self.cantera_reactor). This method is called at the start of other methods in this class. Args: T0 (float): Initial temperature in Kelvin. P0 (float): Initial pressure in Pascals. X0 (dict): Initial mole fractions. V0 (float): Initial volume in m3. """ # assign initial conditions if V0 is None: self.model.TPX = T0, P0, X0 elif P0 is None: self.model.TDX = T0, 1 / V0, X0 self.cantera_reactor = ct.IdealGasConstPressureReactor( contents=self.model) # Run this individual condition as a simulation self.cantera_simulation = ct.ReactorNet([self.cantera_reactor]) # set simulation tolerance self.cantera_simulation.atol = self.atol self.cantera_simulation.rtol = self.rtol if self.sensitive_species: if ct.__version__ == '2.2.1': self.logger.warning( 'Cantera version 2.2.1 may not support sensitivity analysis unless SUNDIALS ' 'was used during compilation.') self.logger.warning( 'Upgrade to newer of Cantera in anaconda using the command ' '"conda update -c rmg cantera"') # Add all the reactions as part of SA for i in range(self.num_ct_reactions): self.cantera_reactor.add_sensitivity_reaction(i) # add all species enthalpies as part of SA for i in range(self.num_ct_species): self.cantera_reactor.add_sensitivity_species_enthalpy(i) # Set the tolerances for the sensitivity coefficients self.cantera_simulation.rtol_sensitivity = self.sa_atol self.cantera_simulation.atol_sensitivity = self.sa_rtol
def setup_case(self): """Initialize simulation case. """ self.gas = ct.Solution(self.model, self.phase_name) # Default maximum number of steps self.max_steps = 10000 if self.properties.max_steps: self.max_steps = self.properties.max_steps # By default, simulations will run to steady state, with the maximum number of steps # given by ``self.max_steps``. Alternatively, an end time (in seconds) can be # given in cases where something specific is needed (e.g., longer than normal) self.time_end = 0.0 if self.properties.end_time: self.time_end = self.properties.end_time self.gas.TP = (self.properties.temperature, self.properties.pressure * ct.one_atm) # set initial composition using either equivalence ratio or general reactant composition if self.properties.equivalence_ratio: self.gas.set_equivalence_ratio(self.properties.equivalence_ratio, self.properties.fuel, self.properties.oxidizer) else: if self.properties.composition_type == 'mole': self.gas.TPX = (self.properties.temperature, self.properties.pressure * ct.one_atm, self.properties.reactants) else: self.gas.TPY = (self.properties.temperature, self.properties.pressure * ct.one_atm, self.properties.reactants) if self.properties.kind == 'constant pressure': self.reac = ct.IdealGasConstPressureReactor(self.gas) else: self.reac = ct.IdealGasReactor(self.gas) # Create ``ReactorNet`` newtork self.sim = ct.ReactorNet([self.reac]) # Set file for later data file self.save_file = os.path.join(self.path, str(self.idx) + '.h5') self.sample_points = [] self.ignition_delay = 0.0
def __init__(self, gas): """Initialize particle object with thermochemical state. Parameters ---------- gas : `cantera.Solution` Initial thermochemical state of particle Returns ------- None """ self.gas = gas self.reac = ct.IdealGasConstPressureReactor(self.gas) self.netw = ct.ReactorNet([self.reac])
def fitness(indv): tmp_parameters = indv.solution tmp_reactions = R.copy() for i in range(len(tmp_reactions)): if tmp_reactions[i].reaction_type !=4: tmp_reactions[i].rate = ct.Arrhenius(A = tmp_parameters[3*i], \ b = tmp_parameters[3*i+1], E = tmp_parameters[3*i+2]) else: tmp_reactions[i].low_rate = ct.Arrhenius(A = tmp_parameters[3*i], \ b = tmp_parameters[3*i+1], E = tmp_parameters[3*i+2]) gas2 = ct.Solution(thermo='IdealGas', kinetics='GasKinetics',species=gas.species(),reactions=tmp_reactions) gas2.TPX = temp, pres, 'CH4:1, O2:2' r = ct.IdealGasConstPressureReactor(gas2) sim = ct.ReactorNet([r]) states = ct.SolutionArray(gas2, extra=['t']) try: for t in np.arange(0, end_time, step_time): sim.advance(t) states.append(r.thermo.state, t=1000*t) except: return 1e8 max_delta = 0 index_temp = 0 for i in range(len(states.T)-2): if(states.T[i+1] - states.T[i] > max_delta): max_delta = states.T[i+1] - states.T[i] index_temp = i ignite_time_optimised = float(states.t[index_temp]) optimised_T = float(states.T[-1] ) optimised_CH4 = float(states('CH4').X[-1] ) optimised_O2 = float(states('O2').X[-1] ) optimised_CO2 = float(states('CO2').X[-1] ) optimised_H2O = float(states('H2O').X[-1] ) optimised_H = float(states('H').X[-1] ) optimised_OH = float(states('OH').X[-1] ) # return ((ignite_time_optimised - ignite_time_precise)/ignite_time_precise)**2\ # + ((optimised_T - precise_T)/precise_T)**2\ # + ((optimised_O2 - precise_O2)/precise_O2)**2\ # + ((optimised_CO2 - precise_CO2)/precise_CO2)**2\ # + ((optimised_H2O - precise_H2O)/precise_H2O)**2\ return 1e8*abs(ignite_time_optimised - ignite_time_precise) + abs(optimised_T - precise_T)
def react(self, dt): """Perform reaction timestep by advancing network. Parameters ---------- dt : float Reaction timestep [seconds] Returns ------- None """ reac = ct.IdealGasConstPressureReactor(self.gas, volume=Particle.particle_mass/self.gas.density) netw = ct.ReactorNet([reac]) netw.advance(netw.time + dt)
def ODE_integrate(self, Y, T, p, steps): # do the ODE integration # Y is the species vector, T temperature, p pressure #self.gas = ct.Solution('utils/lu19.cti') self.gas.TPY = T, p, Y current_rho = self.gas.density r = ct.IdealGasConstPressureReactor(self.gas) sim = ct.ReactorNet([r]) time = 0.0 # do 10 small integration steps to get to dt! --> makes it less stiff for n in range(steps): time += self.dt / steps sim.advance(time) T_after = r.thermo.T Y_after = r.thermo.Y # mass fraction reaction rate dY/dt [1/s] same as in Cantera OF: RR_Y = (Y_after - Y) * current_rho / self.dt return T_after, Y_after, RR_Y, current_rho
def test_equilibrium_HP(self): # Adiabatic, constant pressure combustion should proceed to equilibrum # at constant enthalpy and pressure. P0 = 10 * ct.one_atm T0 = 1100 X0 = 'H2:1.0, O2:0.5, AR:8.0' gas1 = ct.Solution('h2o2.xml') gas1.TPX = T0, P0, X0 r1 = ct.IdealGasConstPressureReactor(gas1) net = ct.ReactorNet() net.add_reactor(r1) net.advance(1.0) gas2 = ct.Solution('h2o2.xml') gas2.TPX = T0, P0, X0 gas2.equilibrate('HP') self.assertNear(r1.T, gas2.T) self.assertNear(r1.thermo.P, P0) self.assertNear(r1.thermo.density, gas2.density) self.assertArrayNear(r1.thermo.X, gas2.X)
def ShockTube(ctiFile, speciesNames, pressure, temperature, conditions, initialTime, finalTime, thermalBoundary, observables=[], physical_params=[], kinetic_sens=0, physical_sens=0, reactorType='cv'): #gas = ct.Solution('AramcoMech2.0.cti') # 'GRI30-1999.cti' for s in ['Ar', 'AR', 'He', 'HE', 'n2', 'N2']: if s in speciesNames: addBackin = s speciesNames.remove(s) break gas = ct.Solution(ctiFile) gas.TPX = temperature, pressure * 101325, conditions physicalParamsSpecies = ['X' + species for species in speciesNames] physical_params = ['P', 'T', 'X'] if thermalBoundary == 'adiabatic': if reactorType == 'cv': shockTube = ct.IdealGasReactor(gas, name='R1', energy='on') elif reactorType == 'cp': shockTube = ct.IdealGasConstPressureReactor(gas, name='R1', energy='on') elif thermalBoundary == 'isothermal': if reactorType == 'cv': shockTube = ct.IdealGasReactor(gas, name='R1', energy='off') elif reactorType == 'cp': shockTube = ct.IdealGasConstPressureReactor(gas, name='R1', energy='off') else: raise Exception( 'Please enter adiabatic or isothermal for the thermal boundary layer' ) sim = ct.ReactorNet([shockTube]) if kinetic_sens == 1 and bool(observables) == False: raise Exception( 'Please supply a non-empty list of observables for sensitivity analysis or set kinetic_sens=0' ) if physical_sens == 1 and bool(observables) == False: raise Exception( 'Please supply a non-empty list of observables for sensitivity analysis or set physical_sens=0' ) if kinetic_sens == 1 and bool(observables): [shockTube.add_sensitivity_reaction(i) for i in range(gas.n_reactions)] dfs = [pd.DataFrame() for x in range(len(observables))] tempArray = [ np.zeros(gas.n_reactions) for x in range(len(observables)) ] if physical_sens == 1 and bool(observables): baseConditions = gas.TPX originalConditions = conditions columnNames = [ shockTube.component_name(item) for item in range(shockTube.n_vars) ] columnNames = ['time'] + ['pressure'] + columnNames timeHistory = pd.DataFrame(columns=columnNames) timeHistorytest = pd.DataFrame(columns=columnNames) timeHistorytest2 = pd.DataFrame(columns=columnNames) timeHistorytest4 = [ pd.DataFrame(columns=columnNames) for item in range(len(physicalParamsSpecies)) ] t = initialTime counter = 0 #commenting out volume while t < finalTime: t = sim.step() state = np.hstack([ t, shockTube.thermo.P, shockTube.mass, shockTube.volume, shockTube.T, shockTube.thermo.X ]) timeHistory.loc[counter] = state if kinetic_sens == 1 and bool(observables): newcounter = 0 for observable, reaction in itertools.product( observables, range(gas.n_reactions)): tempArray[observables.index( observable)][reaction] = sim.sensitivity( observable, reaction) newcounter += 1 if (newcounter % gas.n_reactions == 0): dfs[observables.index(observable)] = dfs[observables.index( observable)].append(((pd.DataFrame( tempArray[observables.index(observable)]) ).transpose()), ignore_index=True) counter += 1 if kinetic_sens == 1 and bool(observables): ksensIndex = [ timeHistory['time'].as_matrix(), gas.reaction_equations(), observables ] numpyMatrixsksens = [ dfs[dataframe].as_matrix() for dataframe in range(len(dfs)) ] numpyMatrixsBsens = [ numpyMatrixsksens[x] * (np.log( timeHistory['temperature'].as_matrix().flatten()))[:, np.newaxis] for x in range(len(numpyMatrixsksens)) ] numpyMatrixsEsens = [ numpyMatrixsksens[x] * (np.true_divide(-1, timeHistory['temperature'].as_matrix().flatten( )))[:, np.newaxis] for x in range(len(numpyMatrixsksens)) ] S = np.dstack(numpyMatrixsksens) Sa = S Sb = np.dstack(numpyMatrixsBsens) Se = np.dstack(numpyMatrixsEsens) S = np.dstack(numpyMatrixsksens) if physical_sens == 1 and bool(observables): dk = .01 originalPsens = (timeHistory[observables]).applymap(np.log) for numOfPhyParams in range(len(physical_params)): if physical_params[numOfPhyParams] == 'T': gas2 = ct.Solution(ctiFile) gas2.TPX = baseConditions[0] + dk, baseConditions[ 1], baseConditions[2] if thermalBoundary == 'adiabatic': if reactorType == 'cv': shockTube2 = ct.IdealGasReactor(gas2, name='R1', energy='on') elif reactorType == 'cp': shockTube2 = ct.IdealGasConstPressureReactor( gas2, name='R1', energy='on') sim2 = ct.ReactorNet([shockTube2]) if thermalBoundary == 'isothermal': if reactorType == 'cv': shockTube2 = ct.IdealGasReactor(gas2, name='R1', energy='off') elif reactorType == 'cp': shockTube2 = ct.IdealGasConstPressureReactor( gas2, name='R1', energy='off') sim2 = ct.ReactorNet([shockTube2]) newTime = 0 newCounter = 0 while newTime < finalTime: newTime = sim2.step() state = np.hstack([ newTime, shockTube2.thermo.P, shockTube2.mass, shockTube2.volume, shockTube2.T, shockTube2.thermo.X ]) timeHistorytest.loc[newCounter] = state newCounter += 1 newTimeArray = timeHistorytest['time'] temperatureForMappingPhysicalSensT = timeHistorytest[ 'temperature'].values pressureForMappingPhysicalSensT = timeHistorytest[ 'pressure'].values tempForInterp = timeHistorytest[observables] tempForInterplstT = [ tempForInterp.ix[:, x].values for x in range(tempForInterp.shape[1]) ] interpolatedData = [ np.interp(timeHistory['time'].values, newTimeArray.values, tempForInterplstT[x]) for x in range(len(tempForInterplstT)) ] interpolatedTemperatureForMappingPhysicalSensT = [ np.interp(timeHistory['time'].values, newTimeArray.values, temperatureForMappingPhysicalSensT) ] interpolatedPressureForMappingPhysicalSensT = [ np.interp(timeHistory['time'].values, newTimeArray.values, pressureForMappingPhysicalSensT) ] interpolatedData = [ pd.DataFrame(interpolatedData[x]) for x in range(len(interpolatedData)) ] interpolatedData = pd.concat(interpolatedData, axis=1, ignore_index=True) concentrationOfAbsorbanceObservablesForSensT = interpolatedData concentrationOfAbsorbanceObservablesForSensT.columns = observables concentrationOfAbsorbanceObservablesForSensT = [ concentrationOfAbsorbanceObservablesForSensT ] tempT = interpolatedData.applymap(np.log) tempT.columns = observables tempT = (originalPsens.subtract(tempT)) / np.log(dk) tempTlst = [tempT.ix[:, idx] for idx in range(tempT.shape[1])] if physical_params[numOfPhyParams] == 'P': gas3 = ct.Solution(ctiFile) gas3.TPX = baseConditions[ 0], baseConditions[1] + dk, baseConditions[2] if thermalBoundary == 'adiabatic': if reactorType == 'cv': shockTube3 = ct.IdealGasReactor(gas3, name='R1', energy='on') elif reactorType == 'cp': shockTube3 = ct.IdealGasConstPressureReactor( gas3, name='R1', energy='on') sim3 = ct.ReactorNet([shockTube3]) if thermalBoundary == 'isothermal': if reactorType == 'cv': shockTube3 = ct.IdealGasReactor(gas3, name='R1', energy='off') elif reactorType == 'cp': shockTube3 = ct.IdealGasConstPressureReactor( gas3, name='R1', energy='off') sim3 = ct.ReactorNet([shockTube3]) newTime2 = 0 newCounter2 = 0 while newTime2 < finalTime: newTime2 = sim3.step() state = np.hstack([ newTime2, shockTube3.thermo.P, shockTube3.mass, shockTube3.volume, shockTube3.T, shockTube3.thermo.X ]) timeHistorytest2.loc[newCounter2] = state newCounter2 += 1 newTimeArray2 = timeHistorytest2['time'] temperatureForMappingPhysicalSensP = timeHistorytest2[ 'temperature'].values pressureForMappingPhysicalSensP = timeHistorytest2[ 'pressure'].values tempForInterp = timeHistorytest2[observables] tempForInterplstP = [ tempForInterp.ix[:, x].values for x in range(tempForInterp.shape[1]) ] interpolatedData2 = [ np.interp(timeHistory['time'].values, newTimeArray2.values, tempForInterplstP[x]) for x in range(len(tempForInterplstP)) ] interpolatedTemperatureForMappingPhysicalSensP = [ np.interp(timeHistory['time'].values, newTimeArray2.values, temperatureForMappingPhysicalSensP) ] interpolatedPressureForMappingPhysicalSensP = [ np.interp(timeHistory['time'].values, newTimeArray2.values, pressureForMappingPhysicalSensP) ] interpolatedData2 = [ pd.DataFrame(interpolatedData2[x]) for x in range(len(interpolatedData2)) ] interpolatedData2 = pd.concat(interpolatedData2, axis=1, ignore_index=True) concentrationOfAbsorbanceObservablesForSensP = interpolatedData2 concentrationOfAbsorbanceObservablesForSensP.columns = observables concentrationOfAbsorbanceObservablesForSensP = [ concentrationOfAbsorbanceObservablesForSensP ] tempP = interpolatedData2.applymap(np.log) tempP.columns = observables tempP = (originalPsens.subtract(tempP)) / np.log(dk) tempPlst = [tempP.ix[:, idx] for idx in range(tempP.shape[1])] if physical_params[numOfPhyParams] == 'X': for simulationNumber, speciesName in enumerate(speciesNames): newConditions = originalConditions gas4 = ct.Solution(ctiFile) originalValue = conditions[speciesName] newValue = originalValue + dk newConditions.update({speciesName: newValue}) gas4.TPX = baseConditions[0], baseConditions[ 1], newConditions if thermalBoundary == 'adiabatic': if reactorType == 'cv': shockTube4 = ct.IdealGasReactor(gas4, name='R1', energy='on') elif reactorType == 'cp': shockTube4 = ct.IdealGasConstPressureReactor( gas4, name='R1', energy='on') sim4 = ct.ReactorNet([shockTube4]) if thermalBoundary == 'isothermal': if reactorType == 'cv': shockTube4 = ct.IdealGasReactor(gas4, name='R1', energy='off') elif reactorType == 'cp': shockTube4 = ct.IdealGasConstPressureReactor( gas4, name='R1', energy='off') sim4 = ct.ReactorNet([shockTube4]) newTime3 = 0 newCounter3 = 0 while newTime3 < finalTime: newTime3 = sim4.step() state = np.hstack([ newTime3, shockTube4.thermo.P, shockTube4.mass, shockTube4.volume, shockTube4.T, shockTube4.thermo.X ]) timeHistorytest4[simulationNumber].loc[ newCounter3] = state newCounter3 += 1 newConditions.update({speciesName: originalValue}) newTimeArrays3 = [ timeHistorytest4[simulationNumber]['time'] for simulationNumber in range(len(timeHistorytest4)) ] temperatureForMappingPhysicalSensX = [ timeHistorytest4[simulationNumber]['temperature'] for simulationNumber in range(len(timeHistorytest4)) ] pressureForMappingPhysicalSensX = [ timeHistorytest4[simulationNumber]['pressure'] for simulationNumber in range(len(timeHistorytest4)) ] tempForInterps = [ timeHistorytest4[simulationNumber][observables] for simulationNumber in range(len(timeHistorytest4)) ] tempForInterplstXs = [[] for x in range(len(timeHistorytest4))] for simulationNumber in range(len(timeHistorytest4)): for x in range(tempForInterps[simulationNumber].shape[1]): tempForInterplstXs[simulationNumber].append( tempForInterps[simulationNumber].ix[:, x].values) interpolatedData3 = [[] for x in range(len(timeHistorytest4))] interpolatedTemperatureForMappingPhysicalSensX = [] interpolatedPressureForMappingPhysicalSensX = [] for simulationNumber in range(len(timeHistorytest4)): for x in range(tempForInterps[simulationNumber].shape[1]): interpolatedData3[simulationNumber].append( np.interp(timeHistory['time'].values, newTimeArrays3[simulationNumber].values, tempForInterplstXs[simulationNumber][x])) for simulationNumber in range(len(timeHistorytest4)): interpolatedTemperatureForMappingPhysicalSensX.append( np.interp( timeHistory['time'].values, newTimeArrays3[simulationNumber].values, temperatureForMappingPhysicalSensX[ simulationNumber])) for simulationNumber in range(len(timeHistorytest4)): interpolatedPressureForMappingPhysicalSensX.append( np.interp( timeHistory['time'].values, newTimeArrays3[simulationNumber].values, pressureForMappingPhysicalSensX[simulationNumber])) interpolatedDataFrames = [[] for x in range(len(timeHistorytest4)) ] #print(interpolatedData3) for simulationNumber in range(len(timeHistorytest4)): for x in range(tempForInterps[simulationNumber].shape[1]): interpolatedDataFrames[simulationNumber].append( pd.DataFrame( interpolatedData3[simulationNumber][x])) interpolatedDataFrames = [ pd.concat(interpolatedDataFrames[simulationNumber], axis=1, ignore_index=True) for simulationNumber in range(len(timeHistorytest4)) ] concentrationOfAbsorbanceObservablesForSensX = interpolatedDataFrames for simulationNumber in range(len(timeHistorytest4)): concentrationOfAbsorbanceObservablesForSensX[ simulationNumber].columns = observables interpolatedDataFrames = [ interpolatedDataFrames[simulationNumber].applymap(np.log) for simulationNumber in range(len(timeHistorytest4)) ] for simulationNumber in range(len(timeHistorytest4)): interpolatedDataFrames[ simulationNumber].columns = observables interpolatedDataFrames = [ (originalPsens.subtract( interpolatedDataFrames[simulationNumber])) / np.log(dk) for simulationNumber in range(len(timeHistorytest4)) ] tempXlst = [[] for x in range(len(timeHistorytest4))] for simulationNumber in range(len(timeHistorytest4)): for x in range( interpolatedDataFrames[simulationNumber].shape[1]): tempXlst[simulationNumber].append( interpolatedDataFrames[simulationNumber].ix[:, x]) tempXlsts = [[] for x in range(len(observables))] for lengthOfList in range(len(observables)): for dfInList in range(len(timeHistorytest4)): tempXlsts[lengthOfList].append( tempXlst[dfInList][lengthOfList]) tempXlsts = [ pd.concat(tempXlsts[simulationNumber], axis=1, ignore_index=True) for simulationNumber in range(len(tempXlsts)) ] if physical_sens == 1 and bool(observables): speciesNames.append(addBackin) if 'T' in physical_params and 'P' in physical_params and 'X' in physical_params: t = [tempTlst, tempPlst, tempXlsts] psensIndex = [ timeHistory['time'].as_matrix(), ['T', 'P'] + physicalParamsSpecies, observables ] psensdfs = [ pd.concat([t[0][x], t[1][x], t[2][x]], ignore_index=True, axis=1) for x in range(len(tempXlsts)) ] numpyMatrixspsens = [ psensdfs[dataframe].as_matrix() for dataframe in range(len(psensdfs)) ] interpolatedTemperatureForMappingPhysicalSens = [ interpolatedTemperatureForMappingPhysicalSensT + interpolatedTemperatureForMappingPhysicalSensP + interpolatedTemperatureForMappingPhysicalSensX ] interpolatedPressureForMappingPhysicalSens = [ interpolatedPressureForMappingPhysicalSensT + interpolatedPressureForMappingPhysicalSensP + interpolatedPressureForMappingPhysicalSensX ] concentrationOfAbsorbanceObservablesForSens = [ concentrationOfAbsorbanceObservablesForSensT + concentrationOfAbsorbanceObservablesForSensP + concentrationOfAbsorbanceObservablesForSensX ] pS = np.dstack(numpyMatrixspsens) # elif 'T' in physical_params and 'P' in physical_params: t = [tempTlst, tempPlst] psensIndex = [ timeHistory['time'].as_matrix(), ['T', 'P'], observables ] psensdfs = [ pd.concat([t[0][x], t[1][x]], ignore_index=True, axis=1) for x in range(len(tempTlst)) ] numpyMatrixspsens = [ psensdfs[dataframe].as_matrix() for dataframe in range(len(psensdfs)) ] interpolatedTemperatureForMappingPhysicalSens = [ interpolatedTemperatureForMappingPhysicalSensT + interpolatedTemperatureForMappingPhysicalSensP ] interpolatedPressureForMappingPhysicalSens = [ interpolatedPressureForMappingPhysicalSensT + interpolatedPressureForMappingPhysicalSensP ] concentrationOfAbsorbanceObservablesForSens = [ concentrationOfAbsorbanceObservablesForSensT + concentrationOfAbsorbanceObservablesForSensP ] pS = np.dstack(numpyMatrixspsens) elif 'T' in physical_params and 'X' in physical_params: t = [tempTlst, tempXlsts] psensIndex = [ timeHistory['time'].as_matrix(), ['T'] + physicalParamsSpecies, observables ] psensdfs = [ pd.concat([t[0][x], t[1][x]], ignore_index=True, axis=1) for x in range(len(tempTlst)) ] numpyMatrixspsens = [ psensdfs[dataframe].as_matrix() for dataframe in range(len(psensdfs)) ] interpolatedTemperatureForMappingPhysicalSens = [ interpolatedTemperatureForMappingPhysicalSensT + interpolatedTemperatureForMappingPhysicalSensX ] interpolatedPressureForMappingPhysicalSens = [ interpolatedPressureForMappingPhysicalSensT + interpolatedPressureForMappingPhysicalSensX ] concentrationOfAbsorbanceObservablesForSens = [ concentrationOfAbsorbanceObservablesForSensT + concentrationOfAbsorbanceObservablesForSensX ] pS = np.dstack(numpyMatrixspsens) # elif 'P' in physical_params and 'X' in physical_params: t = [tempPlst, tempXlsts] psensIndex = [ timeHistory['time'].as_matrix(), ['P'] + physicalParamsSpecies, observables ] psensdfs = [ pd.concat([t[0][x], t[1][x]], ignore_index=True, axis=1) for x in range(len(tempPlst)) ] numpyMatrixspsens = [ psensdfs[dataframe].as_matrix() for dataframe in range(len(psensdfs)) ] interpolatedTemperatureForMappingPhysicalSens = [ interpolatedTemperatureForMappingPhysicalSensP + interpolatedTemperatureForMappingPhysicalSensX ] interpolatedPressureForMappingPhysicalSens = [ interpolatedPressureForMappingPhysicalSensP + interpolatedPressureForMappingPhysicalSensX ] concentrationOfAbsorbanceObservablesForSens = [ concentrationOfAbsorbanceObservablesForSensP + concentrationOfAbsorbanceObservablesForSensX ] pS = np.dstack(numpyMatrixspsens) elif 'T' in physical_params: t = [tempTlst] psensIndex = [timeHistory['time'].as_matrix(), ['T'], observables] numpyMatrixspsens = [ tempTlst[dataframe].as_matrix() for dataframe in range(len(tempTlst)) ] interpolatedTemperatureForMappingPhysicalSens = [ interpolatedTemperatureForMappingPhysicalSensT ] interpolatedPressureForMappingPhysicalSens = [ interpolatedPressureForMappingPhysicalSensT ] concentrationOfAbsorbanceObservablesForSens = [ concentrationOfAbsorbanceObservablesForSensT ] pS = np.dstack(numpyMatrixspsens) elif 'P' in physical_params: t = [tempPlst] psensIndex = [timeHistory['time'].as_matrix(), ['P'], observables] numpyMatrixspsens = [ tempPlst[dataframe].as_matrix() for dataframe in range(len(tempPlst)) ] interpolatedTemperatureForMappingPhysicalSens = [ interpolatedTemperatureForMappingPhysicalSensP ] interpolatedPressureForMappingPhysicalSens = [ interpolatedPressureForMappingPhysicalSensP ] concentrationOfAbsorbanceObservablesForSens = [ concentrationOfAbsorbanceObservablesForSensP ] pS = np.dstack(numpyMatrixspsens) elif 'X' in physical_params: t = [tempXlsts] psensIndex = [ timeHistory['time'].as_matrix(), [physicalParamsSpecies], observables ] numpyMatrixspsens = [ tempXlsts[dataframe].as_matrix() for dataframe in range(len(tempXlsts)) ] interpolatedTemperatureForMappingPhysicalSens = [ interpolatedTemperatureForMappingPhysicalSensX ] interpolatedPressureForMappingPhysicalSens = [ interpolatedPressureForMappingPhysicalSensX ] concentrationOfAbsorbanceObservablesForSens = [ concentrationOfAbsorbanceObservablesForSensX ] pS = np.dstack(numpyMatrixspsens) if kinetic_sens == 1 and bool(observables) and physical_sens == 0: results = simulations.model_data('Shock-Tube', kinetic_sens=S, Solution=timeHistory, Index=ksensIndex) results.assign_ksens_mappings(Sa, Sb, Se) return results if kinetic_sens == 0 and bool(physical_params) and physical_sens == 1: results = simulations.model_data('Shock-Tube', physical_sens=pS, Solution=timeHistory, pIndex=psensIndex) results.add_interpolated_temps_for_physical_sens( interpolatedTemperatureForMappingPhysicalSens) results.add_interpolated_pressure_for_physical_sens( interpolatedPressureForMappingPhysicalSens) results.add_interpolated_concentration_for_physical_sens( concentrationOfAbsorbanceObservablesForSens) return results if physical_sens == 1 and bool(observables) and kinetic_sens == 1: results = simulations.model_data('Shock-Tube', kinetic_sens=S, physical_sens=pS, Solution=timeHistory, Index=ksensIndex, pIndex=psensIndex) results.assign_ksens_mappings(Sa, Sb, Se) results.add_interpolated_temps_for_physical_sens( interpolatedTemperatureForMappingPhysicalSens) results.add_interpolated_pressure_for_physical_sens( interpolatedPressureForMappingPhysicalSens) results.add_interpolated_concentration_for_physical_sens( concentrationOfAbsorbanceObservablesForSens) return results # if physical_sens == 0 and kinetic_sens == 0: results = simulations.model_data('Shock-Tube', Solution=timeHistory) return results
def simulate(self): """ Run all the conditions as a cantera simulation. Returns the data as a list of tuples containing: (time, [list of temperature, pressure, and species data]) for each reactor condition """ # Get all the cantera names for the species speciesNamesList = [ getSpeciesIdentifier(species) for species in self.speciesList ] inertIndexList = [ self.speciesList.index(species) for species in self.speciesList if species.index == -1 ] allData = [] for condition in self.conditions: # First translate the molFrac from species objects to species names newMolFrac = {} for key, value in condition.molFrac.iteritems(): newkey = getSpeciesIdentifier(key) newMolFrac[newkey] = value # Set Cantera simulation conditions if condition.V0 is None: self.model.TPX = condition.T0.value_si, condition.P0.value_si, newMolFrac elif condition.P0 is None: self.model.TDX = condition.T0.value_si, 1.0 / condition.V0.value_si, newMolFrac else: raise Exception( "Cantera conditions in which T0 and P0 or T0 and V0 are not the specified state variables are not yet implemented." ) # Choose reactor if condition.reactorType == 'IdealGasReactor': canteraReactor = ct.IdealGasReactor(self.model) elif condition.reactorType == 'IdealGasConstPressureReactor': canteraReactor = ct.IdealGasConstPressureReactor( contents=self.model) elif condition.reactorType == 'IdealGasConstPressureTemperatureReactor': canteraReactor = ct.IdealGasConstPressureReactor( contents=self.model, energy='off') else: raise Exception( 'Other types of reactor conditions are currently not supported' ) # Run this individual condition as a simulation canteraSimulation = ct.ReactorNet([canteraReactor]) numCtReactions = len(self.model.reactions()) if self.sensitiveSpecies: if ct.__version__ == '2.2.1': print 'Warning: Cantera version 2.2.1 may not support sensitivity analysis unless SUNDIALS was used during compilation.' print 'Warning: Upgrade to newer of Cantera in anaconda using the command "conda update -c rmg cantera"' # Add all the reactions as part of the analysis for i in range(numCtReactions): canteraReactor.add_sensitivity_reaction(i) # Set the tolerances for the sensitivity coefficients canteraSimulation.rtol_sensitivity = 1e-4 canteraSimulation.atol_sensitivity = 1e-6 # Initialize the variables to be saved times = [] temperature = [] pressure = [] speciesData = [] sensitivityData = [] # Begin integration time = 0.0 # Run the simulation over 100 time points while canteraSimulation.time < condition.reactionTime.value_si: # Advance the state of the reactor network in time from the current time to time t [s], taking as many integrator timesteps as necessary. canteraSimulation.step(condition.reactionTime.value_si) times.append(canteraSimulation.time) temperature.append(canteraReactor.T) pressure.append(canteraReactor.thermo.P) speciesData.append(canteraReactor.thermo[speciesNamesList].X) if self.sensitiveSpecies: # Cantera returns mass-based sensitivities rather than molar concentration or mole fraction based sensitivities. # The equation for converting between them is: # # d ln xi = d ln wi - sum_(species i) (dln wi) (xi) # # where xi is the mole fraction of species i and wi is the mass fraction of species i massFracSensitivityArray = canteraSimulation.sensitivities( ) if condition.reactorType == 'IdealGasReactor': # Row 0: mass, Row 1: volume, Row 2: internal energy or temperature, Row 3+: mass fractions of species massFracSensitivityArray = massFracSensitivityArray[ 3:, :] elif condition.reactorType == 'IdealGasConstPressureReactor' or condition.reactorType == 'IdealGasConstPressureTemperatureReactor': # Row 0: mass, Row 1: enthalpy or temperature, Row 2+: mass fractions of the species massFracSensitivityArray = massFracSensitivityArray[ 2:, :] else: raise Exception( 'Other types of reactor conditions are currently not supported' ) for i in range(len(massFracSensitivityArray)): massFracSensitivityArray[i] *= speciesData[-1][i] sensitivityArray = np.zeros( len(self.sensitiveSpecies) * len(self.model.reactions())) for index, species in enumerate(self.sensitiveSpecies): for j in range(numCtReactions): sensitivityArray[ numCtReactions * index + j] = canteraSimulation.sensitivity( species.toChemkin(), j) for i in range(len(massFracSensitivityArray)): if i not in inertIndexList: # massFracSensitivity for inerts are returned as nan in Cantera, so we must not include them here sensitivityArray[ numCtReactions * index + j] -= massFracSensitivityArray[i][j] sensitivityData.append(sensitivityArray) # Convert speciesData and sensitivityData to a numpy array speciesData = np.array(speciesData) sensitivityData = np.array(sensitivityData) # Resave data into generic data objects time = GenericData(label='Time', data=times, units='s') temperature = GenericData(label='Temperature', data=temperature, units='K') pressure = GenericData(label='Pressure', data=pressure, units='Pa') conditionData = [] conditionData.append(temperature) conditionData.append(pressure) for index, species in enumerate(self.speciesList): # Create generic data object that saves the species object into the species object. To allow easier manipulate later. speciesGenericData = GenericData(label=speciesNamesList[index], species=species, data=speciesData[:, index], index=species.index) conditionData.append(speciesGenericData) reactionSensitivityData = [] for index, species in enumerate(self.sensitiveSpecies): for j in range(numCtReactions): reactionSensitivityGenericData = GenericData( label='dln[{0}]/dln[k{1}]: {2}'.format( species.toChemkin(), j + 1, self.model.reactions()[j]), species=species, reaction=self.model.reactions()[j], data=sensitivityData[:, numCtReactions * index + j], index=j + 1, ) reactionSensitivityData.append( reactionSensitivityGenericData) allData.append((time, conditionData, reactionSensitivityData)) return allData
# %% import cantera as ct # %% gas = ct.Solution('h2_Burke_n2.cti') r = ct.IdealGasConstPressureReactor(gas) # %% dt = 1e-5 t = 0. # %% r.T t += dt sim = ct.ReactorNet([r]) sim.advance(t) r.T # %% gas.TPX = 300, 101325, {'H': 1.} r.syncState() r.T # %% sim.reinitialize() # %% t += dt sim.advance(t) r.T # %%
""" 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.IdealGasConstPressureReactor(gri3, name='R1') 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): r.add_sensitivity_reaction(i) # set the tolerances for the solution and for the sensitivity coefficients sim.rtol = 1.0e-6 sim.atol = 1.0e-15 sim.rtol_sensitivity = 1.0e-6 sim.atol_sensitivity = 1.0e-6 n_times = 400 tim = np.zeros(n_times) data = np.zeros((n_times, 6))
import itertools import cantera as ct import pandas as pd import numpy as np gas = ct.Solution('MSI/data/test_data/FFCM1.cti') gas.TPX = 1880, 1.74*101325, {'H2O':.013,'O2':.0099,'H':.0000007,'Ar':0.9770993} observables = ['OH','H2O'] shockTube = ct.IdealGasConstPressureReactor(gas,name = 'R1',energy= 'on') dfs = [pd.DataFrame() for x in range(len(observables))] tempArray = [np.zeros(gas.n_reactions) for x in range(len(observables))] kineticSens =1 sim=ct.ReactorNet([shockTube]) for i in range(gas.n_reactions): shockTube.add_sensitivity_reaction(i) t = 0 counter = 0 while t < .1: t = sim.step() if kineticSens == 1: counter_1 = 0 for observable,reaction in itertools.product(observables, range(gas.n_reactions)): tempArray[observables.index(observable)][reaction] = sim.sensitivity(observable, reaction) counter_1 +=1 if(counter_1 % gas.n_reactions == 0): dfs[observables.index(observable)] = dfs[observables.index(observable)].append(((pd.DataFrame(tempArray[observables.index(observable)])).transpose()),ignore_index=True) counter+=1 if kineticSens == 1: numpyMatrixsksens = [dfs[dataframe].as_matrix() for dataframe in range(len(dfs))] S = np.dstack(numpyMatrixsksens)
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
import sys import numpy as np import cantera as ct import matplotlib.pyplot as plt import re gas = ct.Solution('gri30.cti') temp = 1200.0 pres = ct.one_atm gas.TPX = temp, pres, 'CH4:1, O2:2' r = ct.IdealGasConstPressureReactor(gas, name='R1') sim = ct.ReactorNet([r]) # enable sensitivity with respect to the rates of the first 10 # reactions (reactions 0 through 9) for i in range(gas.n_reactions): r.add_sensitivity_reaction(i) # set the tolerances for the solution and for the sensitivity coefficients sim.rtol = 1.0e-6 sim.atol = 1.0e-15 sim.rtol_sensitivity = 1.0e-6 sim.atol_sensitivity = 1.0e-6 states = ct.SolutionArray(gas, extra=['t']) sCH4 = [] sO2 = [] sCO2 = []
def run_simulation(solution, times, conditions=None, condition_type = 'adiabatic-constant-volume', output_species = True, output_reactions = True, output_directional_reactions = False, output_rop_roc = False, atol = 1e-15, rtol = 1e-9, temperature_values=None): """ This method iterates through the cantera solution object and outputs information about the simulation as a pandas.DataFrame object. This method returns a dictionary with the reaction conditions data, species data, net reaction data, forward/reverse reaction data, and the rate of production and consumption (or `None` if a variable not specified). `solution` = Cantera.Solution object `conditions` = tuple of temperature, pressure, and mole fraction initial species (will be deprecated. Set parameters before running) `times` = an iterable of times which you would like to store information in `condition_type` = string describing the run type `output_species` = output a DataFrame of species' concentrations `output_reactions` = output a DataFrame of net reaction rates `output_directional_reactions` = output a DataFrame of directional reaction rates `output_rop_roc` = output a DataFrame of species rates of consumption & production condition_types supported ######################### 'adiabatic-constant-volume' - assumes no heat transfer and no volume change 'constant-temperature-and-pressure' - no solving energy equation or changing rate constants 'constant-temperature-and-volume' - no solving energy equation but allows for pressure to change with reactions 'specified-temperature-constant-volume' - the temperature profile specified `temperature_values`, which corresponds to the input `times`, alters the temperature right before the next time step is taken. Constant volume is assumed. """ if conditions is not None: solution.TPX = conditions if condition_type == 'adiabatic-constant-volume': reactor = ct.IdealGasReactor(solution) elif condition_type == 'constant-temperature-and-pressure': reactor = ct.IdealGasConstPressureReactor(solution, energy='off') elif condition_type == 'constant-temperature-and-volume': reactor = ct.IdealGasReactor(solution, energy='off') elif condition_type == 'specified-temperature-constant-volume': reactor = ct.IdealGasReactor(solution, energy='off') if temperature_values is None: raise AttributeError('Must specify temperature with `temperature_values` parameter') elif len(times) != len(temperature_values): raise AttributeError('`times` (len {0}) and `temperature_values` (len {1}) must have the same length.'.format(len(times),len(temperature_values))) else: supported_types = ['adiabatic-constant-volume','constant-temperature-and-pressure', 'constant-temperature-and-volume','specified-temperature-constant-volume'] raise NotImplementedError('only {0} are supported. {1} input'.format(supported_types, condition_type)) simulator = ct.ReactorNet([reactor]) solution = reactor.kinetics simulator.atol = atol simulator.rtol = rtol # setup data storage outputs = {} outputs['conditions'] = pd.DataFrame() if output_species: outputs['species'] = pd.DataFrame() if output_reactions: outputs['net_reactions'] = pd.DataFrame() if output_directional_reactions: outputs['directional_reactions'] = pd.DataFrame() if output_rop_roc: outputs['rop'] = pd.DataFrame() for time_index, time in enumerate(times): if condition_type == 'specified-temperature-constant-volume': solution.TD = temperature_values[time_index], solution.density reactor = ct.IdealGasReactor(solution, energy='off') simulator = ct.ReactorNet([reactor]) solution = reactor.kinetics simulator.atol = atol simulator.rtol = rtol if time_index > 0: simulator.set_initial_time(times[time_index-1]) simulator.advance(time) # save data outputs['conditions'] = outputs['conditions'].append( get_conditions_series(simulator,reactor,solution), ignore_index = True) if output_species: outputs['species'] = outputs['species'].append( get_species_series(solution), ignore_index = True) if output_reactions: outputs['net_reactions'] = outputs['net_reactions'].append( get_reaction_series(solution), ignore_index = True) if output_directional_reactions: outputs['directional_reactions'] = outputs['directional_reactions'].append( get_forward_and_reverse_reactions_series(solution), ignore_index = True) if output_rop_roc: outputs['rop'] = outputs['rop'].append( get_rop_and_roc_series(solution), ignore_index = True) # set indexes as time time_vector = outputs['conditions']['time (s)'] for output in outputs.values(): output.set_index(time_vector,inplace=True) return outputs
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
def execute(): #============================================================================== # set up the cantera gases and reactors #============================================================================== drop = droplet(50e-6, 'A2', 300, 1) #drop is defined only to use the drop properties #environment air gas_env = ct.Solution('a2.cti') gas_env.TPX = 300, ct.one_atm, 'O2:29,N2:71' gas_fuel = ct.Solution('a2.cti') gas_fuel.TPX = drop.ABP, ct.one_atm, 'POSF10325:1' #gaseous fuel at average boiling temperature gas_kernel = ct.Solution('a2.cti') gas_kernel.TPX = 4000, ct.one_atm, 'O2:29,N2:71' gas_kernel.equilibrate('HP') res_air = ct.Reservoir(gas_env) res_fuel = ct.Reservoir(gas_fuel) kernel = ct.IdealGasConstPressureReactor(gas_kernel) kernel.volume = 2.4e-8 #m^3 mfc1 = ct.MassFlowController(res_air, kernel) #connect air reservoir to kernel mfc2 = ct.MassFlowController(res_fuel, kernel) #connect fuel reservoir to kernel mfc1.set_mass_flow_rate(6e-5) mfc2.set_mass_flow_rate(0) w = ct.Wall(kernel, res_fuel) w.set_heat_flux(0) w.expansion_rate_coeff = 1e8 net = ct.ReactorNet({kernel}) net.atol = 1e-10 #absolute tolerance net.rtol = 1e-10 #relative tolerance #============================================================================== # endtime, time steps, and data to be stored #============================================================================== dt = 1e-6 #change time step for advancing the reactor endtime = 1000e-6 mdot_fuel = 1.98e-6 #this number should be calculated based on equivalence ratio, kg/s droplets = [] T = [] time = [] m = [] m_dot = [] q_dot = [] droplet_count = [] X_fuel = [] X_O = [] X_CO2 = [] num_d = [] #============================================================================== # advance reaction #============================================================================== print("Running simulation") for i in range(1,int(endtime/dt)): print (int(endtime/dt) - i) #entrain droplets every 1 microsecond droplets.extend(entrainer(400, 5.*mdot_fuel)) mdot, qdot = vaporize(gas_kernel.T, droplets, dt) # print(gas_kernel.T, mdot, qdot, len(droplets)) # print(str(mdot) + str(qdot) + str(gas_kernel.T)+' '+str(len(droplets))) mfc2.set_mass_flow_rate(mdot) w.set_heat_flux(qdot) #heat required to heat up the droplets during that time step net.advance(i*dt) num_d.append(len(droplets)) #storing variables T.append(gas_kernel.T) time.append(net.time) m.append(kernel.mass) m_dot.append(mdot) q_dot.append(qdot) droplet_count.append(len(droplets)) if gas_kernel.X[0] < 0: gas_kernel.X[0] = 0 X_fuel.append(gas_kernel.X[gas_kernel.species_index("POSF10325")]) X_O.append(gas_kernel.X[gas_kernel.species_index("O")]) X_CO2.append(gas_kernel.X[gas_kernel.species_index("CO2")]) #============================================================================== # plotting important information #============================================================================== plt.plot([t*1e3 for t in time],T, linewidth=3) plt.xlabel('time(ms)', FontSize=15) plt.ylabel('Temperature (K)', FontSize=15) plt.show() fig, ax1 = plt.subplots() ax2 = ax1.twinx() ax1.plot([t*1e3 for t in time], X_fuel, color = 'red', linewidth = 3) ax1.set_xlabel('time (ms)', FontSize=15) ax1.set_ylabel('X_fuel', color='red', FontSize=15) # ax2.plot([t*1e3 for t in time], X_O, color = 'green', linewidth = 3) ax2.set_ylabel('X_CO2', color='green', FontSize=15) ax2.plot([t*1e3 for t in time], X_CO2, color = 'blue', linewidth = 3) plt.show() fig, ax1 = plt.subplots() ax2 = ax1.twinx() ax1.plot([t*1e3 for t in time], m_dot, color = 'red', linewidth = 3) ax1.set_xlabel('time (ms)', FontSize=15) ax1.set_ylabel('m_dot', color='red', FontSize=15) ax2.plot([t*1e3 for t in time], q_dot, color = 'green', linewidth = 3) ax2.set_ylabel('q_dot', color='green', FontSize=15) plt.show() fig,ax1 = plt.subplots() ax1.plot([t*1e3 for t in time], num_d, linewidth=3) ax1.set_xlabel('time(ms)', FontSize=15) ax1.set_ylabel('#droplets', FontSize=15) plt.show()
fullOutput=False) # calculate postshock gas condition postshockgas = PostShock_fr(cj_speed, initpress * ct.one_atm, inittemp, q, mech) # save and print initial shock temp and pressure shockedpress = postshockgas.P / 101325 shockedtemp = postshockgas.T print(f' PostShock Pressure: {postshockgas.P/101325} atm') print(f' PostShock Temperature: {postshockgas.T} K') # Resolution: The PFR will be simulated by 'n_steps' time steps n_steps = 3000000 # create a new reactor r1 = ct.IdealGasConstPressureReactor(postshockgas) # create a reactor network for performing time integration sim1 = ct.ReactorNet([r1]) # approximate a time step to achieve a similar resolution as in the next method dt = 0.25 / n_steps det_time = 0 # define timesteps timesteps = (np.arange(n_steps) + 1) * dt for t_i in timesteps: # perform time integration sim1.advance(t_i) # store current time det_time = t_i # compute velocity and transform into space
def run_simulation_till_conversion(solution, species, conversion,conditions=None, condition_type = 'adiabatic-constant-volume', output_species = True, output_reactions = True, output_directional_reactions = False, output_rop_roc = False, skip_data = 150, atol = 1e-15, rtol = 1e-9,): """ This method iterates through the cantera solution object and outputs information about the simulation as a pandas.DataFrame object. This method returns a dictionary with the reaction conditions data, species data, net reaction data, forward/reverse reaction data, and the rate of production and consumption (or `None` if a variable not specified) at the specified conversion value. `solution` = Cantera.Solution object `conditions` = tuple of temperature, pressure, and mole fraction initial species `species` = a string of the species label (or list of strings) to be used in conversion calculations `conversion` = a float of the fraction conversion to stop the simulation at `condition_type` = string describing the run type, currently supports 'adiabatic-constant-volume' and 'constant-temperature-and-pressure' `output_species` = output a Series of species' concentrations `output_reactions` = output a Series of net reaction rates `output_directional_reactions` = output a Series of directional reaction rates `output_rop_roc` = output a DataFrame of species rates of consumption & production `skip_data` = an integer which reduces storing each point of data. storage space scales as 1/`skip_data` """ if conditions is not None: solution.TPX = conditions if condition_type == 'adiabatic-constant-volume': reactor = ct.IdealGasReactor(solution) if condition_type == 'constant-temperature-and-pressure': reactor = ct.IdealGasConstPressureReactor(solution, energy='off') else: raise NotImplementedError('only adiabatic constant volume is supported') simulator = ct.ReactorNet([reactor]) solution = reactor.kinetics simulator.atol = atol simulator.rtol = rtol # setup data storage outputs = {} outputs['conditions'] = pd.DataFrame() if output_species: outputs['species'] = pd.DataFrame() if output_reactions: outputs['net_reactions'] = pd.DataFrame() if output_directional_reactions: outputs['directional_reactions'] = pd.DataFrame() if output_rop_roc: outputs['rop'] = pd.DataFrame() if isinstance(species,str): target_species_indexes = [solution.species_index(species)] else: # must be a list or tuple target_species_indexes = [solution.species_index(s) for s in species] starting_concentration = sum([solution.concentrations[target_species_index] for target_species_index in target_species_indexes]) proper_conversion = False new_conversion = 0 skip_count = 1e8 while not proper_conversion: error_count = 0 while error_count >= 0: try: simulator.step() error_count = -1 except: error_count += 1 if error_count > 10: print('Might not be possible to achieve conversion at T={0}, P={1}, with concentrations of {2} obtaining a conversion of {3} at time {4} s.'.format(solution.T,solution.P,zip(solution.species_names,solution.X), new_conversion,simulator.time)) raise new_conversion = 1-sum([solution.concentrations[target_species_index] for target_species_index in target_species_indexes])/starting_concentration if new_conversion > conversion: proper_conversion = True # save data if skip_count > skip_data or proper_conversion: skip_count = 0 outputs['conditions'] = outputs['conditions'].append( get_conditions_series(simulator,reactor,solution), ignore_index = True) if output_species: outputs['species'] = outputs['species'].append( get_species_series(solution), ignore_index = True) if output_reactions: outputs['net_reactions'] = outputs['net_reactions'].append( get_reaction_series(solution), ignore_index = True) if output_directional_reactions: outputs['directional_reactions'] = outputs['directional_reactions'].append( get_forward_and_reverse_reactions_series(solution), ignore_index = True) if output_rop_roc: outputs['rop'] = outputs['rop'].append( get_rop_and_roc_series(solution), ignore_index = True) skip_count += 1 # set indexes as time time_vector = outputs['conditions']['time (s)'] for output in outputs.values(): output.set_index(time_vector,inplace=True) return outputs
def obj_func(A,states_ref): ret = 0. states_new,gas2 = states_new_init(A) for n in range(100): ret += (states_new.X[n,gas2.species_index('H2')] - states_ref.X[n,gas2.species_index('H2')])**2/100 return ret #return abs(a-b) gas = ct.Solution('gri30.xml') initial_state = 1500, ct.one_atm, 'H2:2,O2:1' gas.TPX = 1500.0, ct.one_atm, 'H2:2,O2:1' r = ct.IdealGasConstPressureReactor(gas,energy = 'off') sim = ct.ReactorNet([r]) time = 0.0 states = ct.SolutionArray(gas, extra=['t']) # i = (j for j in range(0,10)) N = (j for j in range(1,11)) # for n in range(100): time += 1.e-5 sim.advance(time) states.append(r.thermo.state, t=time*1e3) #print('%10.3e %10.3f %10.3f %14.6e' % (sim.time, r.T, # r.thermo.P, r.thermo.u))
def run(self, initialTime: float = -1.0, finalTime: float = -1.0): ''' Run the shock tube simulation ''' if initialTime == -1.0: initialTime = self.initialTime if finalTime == -1.0: finalTime = self.finalTime self.timeHistory = None self.kineticSensitivities = None #3D numpy array, columns are reactions with timehistories, depth gives the observable for those histories conditions = self.settingShockTubeConditions() mechanicalBoundary = conditions[1] #same solution for both cp and cv sims if mechanicalBoundary == 'constant pressure': shockTube = ct.IdealGasConstPressureReactor( self.processor.solution, name='R1', energy=conditions[0]) else: shockTube = ct.IdealGasReactor(self.processor.solution, name='R1', energy=conditions[0]) sim = ct.ReactorNet([shockTube]) columnNames = [ shockTube.component_name(item) for item in range(shockTube.n_vars) ] columnNames = ['time'] + ['pressure'] + columnNames self.timeHistory = pd.DataFrame(columns=columnNames) if self.kineticSens == 1: for i in range(self.processor.solution.n_reactions): shockTube.add_sensitivity_reaction(i) dfs = [pd.DataFrame() for x in range(len(self.observables))] tempArray = [ np.zeros(self.processor.solution.n_reactions) for x in range(len(self.observables)) ] t = self.initialTime counter = 0 while t < self.finalTime: t = sim.step() if mechanicalBoundary == 'constant volume': state = np.hstack([ t, shockTube.thermo.P, shockTube.mass, shockTube.volume, shockTube.T, shockTube.thermo.X ]) else: state = np.hstack([ t, shockTube.thermo.P, shockTube.mass, shockTube.T, shockTube.thermo.X ]) self.timeHistory.loc[counter] = state if self.kineticSens == 1: counter_1 = 0 for observable, reaction in itertools.product( self.observables, range(self.processor.solution.n_reactions)): tempArray[self.observables.index( observable)][reaction] = sim.sensitivity( observable, reaction) counter_1 += 1 if counter_1 % self.processor.solution.n_reactions == 0: dfs[self.observables.index(observable)] = dfs[ self.observables.index(observable)].append( ((pd.DataFrame( tempArray[self.observables.index( observable)])).transpose()), ignore_index=True) counter += 1 if self.timeHistories != None: self.timeHistories.append(self.timeHistory) if self.kineticSens == 1: numpyMatrixsksens = [ dfs[dataframe].values for dataframe in range(len(dfs)) ] self.kineticSensitivities = np.dstack(numpyMatrixsksens) return self.timeHistory, self.kineticSensitivities else: return self.timeHistory