def test_interface(self): surf_species = ct.Species.listFromFile('ptcombust.xml') gas = ct.Solution('ptcombust.xml', 'gas') surf1 = ct.Interface('ptcombust.xml', 'Pt_surf', [gas]) r1 = ct.InterfaceReaction() r1.reactants = 'H(S):2' r1.products = 'H2:1, PT(S):2' r1.rate = ct.Arrhenius(3.7e20, 0, 67.4e6) r1.coverage_deps = {'H(S)': (0, 0, -6e6)} self.assertNear(r1.coverage_deps['H(S)'][2], -6e6) surf2 = ct.Interface(thermo='Surface', species=surf_species, kinetics='interface', reactions=[r1], phases=[gas]) surf2.site_density = surf1.site_density surf1.coverages = surf2.coverages = 'PT(S):0.7, H(S):0.3' gas.TP = surf2.TP = surf1.TP for T in [300, 500, 1500]: gas.TP = surf1.TP = surf2.TP = T, 5 * ct.one_atm self.assertNear(surf1.forward_rate_constants[1], surf2.forward_rate_constants[0]) self.assertNear(surf1.net_rates_of_progress[1], surf2.net_rates_of_progress[0])
def load_phases(self, ctifile): """ Import phases and create interface wrappers Parameters: ----------- ctifile: CTI file from which to import """ self.ctifile = ctifile gas_ca = ct.Solution(ctifile, 'gas_ca') BCFZY_bulk = ct.Solution(ctifile, 'BCFZY_bulk') transition_metal = ct.Solution(ctifile, 'transition_metal') elyte = ct.Solution(ctifile, 'elyte') BCFZY_gas_phases = [gas_ca, BCFZY_bulk, transition_metal] BCFZY_gas = ct.Interface(ctifile, 'BCFZY_gas', BCFZY_gas_phases) BCFZY_elyte_phases = [elyte, BCFZY_bulk] BCFZY_elyte = ct.Interface(ctifile, 'BCFZY_elyte', BCFZY_elyte_phases) #phase and interface dicts phase_objs = [gas_ca, BCFZY_bulk, elyte] phase_names = [p.name for p in phase_objs] self.phases = dict(zip(phase_names, phase_objs)) self.interfaces = {'BCFZY_gas': BCFZY_gas, 'BCFZY_elyte': BCFZY_elyte}
def create_cti_and_cantera_phases(model_name, reactions_parameters_array, simulation_settings_module, cti_top_info_string = None, write_cti_to_file = False ): #The things that must be defined in advance are... # a) a model name. # b) The simulation settings are set in a python file which then becomes imported and an argument. This can then be changed by a script. # c) The reactions_parameters_array must be fed as an array or as a filename that points to a file that contains such an array with a header. # d) The cti_top_info_string. if type(reactions_parameters_array) == type("string"): reactions_parameters_array = np.genfromtxt(model_name + "_input_reactions_parameters.csv", delimiter=",", dtype="str", skip_header=1) #In our example, the cti_top_info file is already made, and the functions below know where to find that file. #The below function makes a cti_file and then returns the filename. cti_string = canteraKineticsParametersParser.create_full_cti(model_name=model_name, reactions_parameters_array=reactions_parameters_array, cti_top_info_string = cti_top_info_string, write_cti_to_file = write_cti_to_file) canteraPhases = {} #NOTE: the reaction parameters are in the reaction objects. Currently, we cannot update the coverage dependence after cti file creation. That is why they must be created after the cti_file is made. # import the gas model and surface model. from distutils.version import LooseVersion, StrictVersion if LooseVersion(ct.__version__) < LooseVersion('2.5'): canteraPhases['gas'] = ct.Solution(source=cti_string, phaseid='gas') #canteraPhases['gas'].reactionsParametersArray = reactions_parameters_array # import the surface model canteraPhases['surf'] = ct.Interface(source=cti_string,phaseid='surf', phases=[canteraPhases['gas']]) #The word gas here is passing that same gas phase object in that was created above. #canteraPhases['surf'].reactionsParametersArray = reactions_parameters_array if LooseVersion(ct.__version__) >= LooseVersion('2.5'): canteraPhases['gas'] = ct.Solution(source=cti_string, name='gas') #canteraPhases['gas'].reactionsParametersArray = reactions_parameters_array # import the surface model canteraPhases['surf'] = ct.Interface(source=cti_string, name='surf', adjacent=[canteraPhases['gas']]) #The word gas here is passing that same gas phase object in that was created above. #canteraPhases['surf'].reactionsParametersArray = reactions_parameters_array #NOTE: we intentionally use "surf" rather than surface because in principle a person can make a model with more than 1 surface. #The choice of "surf" will make the variables easier to keep track of when it is time to make such a change. return cti_string, canteraPhases
def create_reactors(self, add_Q=False, add_mdot=False, add_surf=False): self.gas = ct.Solution('gri30.xml') self.gas.TPX = 900, 25*ct.one_atm, 'CO:0.5, H2O:0.2' self.gas1 = ct.Solution('gri30.xml') self.gas1.ID = 'gas' self.gas2 = ct.Solution('gri30.xml') self.gas2.ID = 'gas' resGas = ct.Solution('gri30.xml') solid = ct.Solution('diamond.xml', 'diamond') T0 = 1200 P0 = 25*ct.one_atm X0 = 'CH4:0.5, H2O:0.2, CO:0.3' self.gas1.TPX = T0, P0, X0 self.gas2.TPX = T0, P0, X0 self.r1 = ct.IdealGasReactor(self.gas1) self.r2 = self.reactorClass(self.gas2) self.r1.volume = 0.2 self.r2.volume = 0.2 resGas.TP = T0 - 300, P0 env = ct.Reservoir(resGas) U = 300 if add_Q else 0 self.w1 = ct.Wall(self.r1, env, K=1e3, A=0.1, U=U) self.w2 = ct.Wall(self.r2, env, A=0.1, U=U) if add_mdot: mfc1 = ct.MassFlowController(env, self.r1, mdot=0.05) mfc2 = ct.MassFlowController(env, self.r2, mdot=0.05) if add_surf: self.interface1 = ct.Interface('diamond.xml', 'diamond_100', (self.gas1, solid)) self.interface2 = ct.Interface('diamond.xml', 'diamond_100', (self.gas2, solid)) C = np.zeros(self.interface1.n_species) C[0] = 0.3 C[4] = 0.7 self.surf1 = ct.ReactorSurface(self.interface1, A=0.2) self.surf2 = ct.ReactorSurface(self.interface2, A=0.2) self.surf1.coverages = C self.surf2.coverages = C self.surf1.install(self.r1) self.surf2.install(self.r2) self.net1 = ct.ReactorNet([self.r1]) self.net2 = ct.ReactorNet([self.r2]) self.net1.set_max_time_step(0.05) self.net2.set_max_time_step(0.05) self.net2.max_err_test_fails = 10
def test_surface(self): gas_species = ct.Species.listFromFile('gri30.xml') surf_species = ct.Species.listFromFile('ptcombust.xml') reactions = ct.Reaction.listFromFile('ptcombust.xml') gas = ct.Solution('ptcombust.xml', 'gas') surf1 = ct.Interface('ptcombust.xml', 'Pt_surf', [gas]) surf2 = ct.Interface(thermo='Surface', kinetics='interface', species=surf_species, reactions=reactions, phases=[gas]) surf1.site_density = surf2.site_density = 5e-9 gas.TP = surf2.TP = surf1.TP = 900, 2 * ct.one_atm surf2.concentrations = surf1.concentrations self.assertEqual(surf1.n_reactions, surf2.n_reactions) for k, i in itertools.product(['PT(S)', 'H2', 'OH', 'OH(S)'], range(surf1.n_species)): self.assertEqual(surf1.reactant_stoich_coeff(k, i), surf2.reactant_stoich_coeff(k, i)) self.assertEqual(surf1.product_stoich_coeff(k, i), surf2.product_stoich_coeff(k, i)) for i in range(surf1.n_reactions): r1 = surf1.reaction(i) r2 = surf2.reaction(i) self.assertEqual(r1.reactants, r2.reactants) self.assertEqual(r1.products, r2.products) self.assertEqual(r1.rate.pre_exponential_factor, r2.rate.pre_exponential_factor) self.assertEqual(r1.rate.temperature_exponent, r2.rate.temperature_exponent) self.assertEqual(r1.rate.activation_energy, r2.rate.activation_energy) self.assertArrayNear(surf1.delta_enthalpy, surf2.delta_enthalpy) self.assertArrayNear(surf1.forward_rate_constants, surf2.forward_rate_constants) self.assertArrayNear(surf1.reverse_rate_constants, surf2.reverse_rate_constants) rop1 = surf1.net_production_rates rop2 = surf2.net_production_rates for k in gas.species_names + surf1.species_names: k1 = surf1.kinetics_species_index(k) k2 = surf2.kinetics_species_index(k) self.assertNear(rop1[k1], rop2[k2])
def test_yaml_surface_adjacent(self): surf = ct.Interface("ptcombust.yaml", "Pt_surf") gas = surf.adjacent["gas"] gas.TPY = 900, ct.one_atm, np.ones(gas.n_species) surf.coverages = np.ones(surf.n_species) surf.write_yaml(self.test_work_path / "ptcombust-generated.yaml") self.check_ptcombust(gas, surf)
def test_yaml_surface_explicit(self): gas = ct.Solution("ptcombust.yaml", "gas") surf = ct.Interface("ptcombust.yaml", "Pt_surf", [gas]) gas.TPY = 900, ct.one_atm, np.ones(gas.n_species) surf.coverages = np.ones(surf.n_species) surf.write_yaml(self.test_work_path / "ptcombust-generated.yaml") self.check_ptcombust(gas, surf)
def loader(self, path): # path is assumed to be the path dictionary surfaces = [] if path['mech'].suffix in ['.yaml', '.yml' ]: # check if it's a yaml cantera file mech_path = str(path['mech']) else: # if not convert into yaml cantera file mech_path = str(path['Cantera_Mech']) if path['mech'].suffix == '.cti': cti2yaml.convert(path['mech'], path['Cantera_Mech']) elif path['mech'].suffix in ['.ctml', '.xml']: raise Exception('not implemented') #ctml2yaml.convert(path['mech'], path['Cantera_Mech']) else: # if not a cantera file, assume chemkin surfaces = self.chemkin2cantera(path) print('Validating mechanism...', end='') try: # This test taken from ck2cti self.yaml_txt = path['Cantera_Mech'].read_text( ) # Storing full text could be bad if large self.gas = ct.Solution(yaml=self.yaml_txt) for surfname in surfaces: phase = ct.Interface(outName, surfname, [self.gas]) print('PASSED.') except RuntimeError as e: print('FAILED.') print(e)
def run_reacting_surface(self, xch4, tsurf, mdot, width): # Simplified version of the example 'catalytic_combustion.py' gas = ct.Solution('ptcombust-simple.cti', 'gas') surf_phase = ct.Interface('ptcombust-simple.cti', 'Pt_surf', [gas]) tinlet = 300.0 # inlet temperature comp = {'CH4': xch4, 'O2': 0.21, 'N2': 0.79} gas.TPX = tinlet, ct.one_atm, comp surf_phase.TP = tsurf, ct.one_atm # integrate the coverage equations holding the gas composition fixed # to generate a good starting estimate for the coverages. surf_phase.advance_coverages(1.) sim = ct.ImpingingJet(gas=gas, width=width, surface=surf_phase) sim.set_refine_criteria(10.0, 0.3, 0.4, 0.0) sim.inlet.mdot = mdot sim.inlet.T = tinlet sim.inlet.X = comp sim.surface.T = tsurf sim.solve(loglevel=0, auto=True) self.assertTrue(all(np.diff(sim.T) > 0)) self.assertTrue(all(np.diff(sim.Y[gas.species_index('CH4')]) < 0)) self.assertTrue(all(np.diff(sim.Y[gas.species_index('CO2')]) > 0))
def test_surface_mech(self): convertMech(pjoin(self.test_data_dir, 'surface1-gas.inp'), surfaceFile=pjoin(self.test_data_dir, 'surface1.inp'), outName=pjoin(self.test_work_dir, 'surface1.cti'), quiet=True) gas = ct.Solution('surface1.cti', 'gas') surf = ct.Interface('surface1.cti', 'PT_SURFACE', [gas]) self.assertEqual(gas.n_reactions, 11) self.assertEqual(surf.n_reactions, 15) self.assertEqual(surf.species('O2_Pt').size, 3) # Different units for rate constants in each input file # 62.1 kJ/gmol = 6.21e7 J/kmol self.assertNear(gas.reaction(0).rate.activation_energy, 6.21e7) # 67400 J/mol = 6.74e7 J/kmol self.assertNear(surf.reaction(1).rate.activation_energy, 6.74e7) # Sticking coefficients self.assertFalse(surf.reaction(1).is_sticking_coefficient) self.assertTrue(surf.reaction(2).is_sticking_coefficient) self.assertTrue(surf.reaction(2).use_motz_wise_correction) self.assertTrue(surf.reaction(4).is_sticking_coefficient) self.assertFalse(surf.reaction(4).use_motz_wise_correction) self.assertTrue(surf.reaction(4).duplicate) self.assertTrue(surf.reaction(6).use_motz_wise_correction) # Coverage dependencies covdeps = surf.reaction(1).coverage_deps self.assertEqual(len(covdeps), 2) self.assertIn('H_Pt', covdeps) self.assertEqual(covdeps['OH_Pt'][1], 1.0) self.assertNear(covdeps['H_Pt'][2], -6e6) # 6000 J/gmol = 6e6 J/kmol
def test_pickle_interface(self): gas = ct.Solution("diamond.yaml", "gas") solid = ct.Solution("diamond.yaml", "diamond") interface = ct.Interface("diamond.yaml", "diamond_100", (gas, solid)) with self.assertRaises(NotImplementedError): with open(self.test_work_path / "interface.pkl", "wb") as pkl: pickle.dump(interface, pkl)
def test_surface_mech2(self): self.convert('surface1-gas-noreac.inp', surface='surface1.inp', output='surface1-nogasreac') gas = ct.Solution('surface1-nogasreac' + self.ext, 'gas') surf = ct.Interface('surface1-nogasreac' + self.ext, 'PT_SURFACE', [gas]) self.assertEqual(gas.n_reactions, 0) self.assertEqual(surf.n_reactions, 15)
def test_surface_mech2(self): convertMech(pjoin(self.test_data_dir, 'surface1-gas-noreac.inp'), surfaceFile=pjoin(self.test_data_dir, 'surface1.inp'), outName=pjoin(self.test_work_dir, 'surface1-nogasreac.cti'), quiet=True) gas = ct.Solution('surface1-nogasreac.cti', 'gas') surf = ct.Interface('surface1-nogasreac.cti', 'PT_SURFACE', [gas]) self.assertEqual(gas.n_reactions, 0) self.assertEqual(surf.n_reactions, 15)
def test_edge(self): tpb = ct.Interface("sofc.yaml", "tpb") self.assertEqual(set(tpb.adjacent), {"metal_surface", "oxide_surface", "metal"}) self.assertIsInstance(tpb.adjacent["metal_surface"], ct.Interface) self.assertNotIsInstance(tpb.adjacent["metal"], ct.Interface) gas1 = tpb.adjacent["metal_surface"].adjacent["gas"] gas2 = tpb.adjacent["oxide_surface"].adjacent["gas"] gas1.X = [0.1, 0.4, 0.3, 0.2] self.assertArrayNear(gas1.X, gas2.X)
def create_reacting_surface(self, comp, tsurf, tinlet, width): self.gas = ct.Solution("ptcombust-simple.yaml", "gas") self.surf_phase = ct.Interface("ptcombust-simple.yaml", "Pt_surf", [self.gas]) self.gas.TPX = tinlet, ct.one_atm, comp self.surf_phase.TP = tsurf, ct.one_atm # integrate the coverage equations holding the gas composition fixed # to generate a good starting estimate for the coverages. self.surf_phase.advance_coverages(1.) return ct.ImpingingJet(gas=self.gas, width=width, surface=self.surf_phase)
def create_reacting_surface(self, comp, tsurf, tinlet, width): gas = ct.Solution('ptcombust-simple.cti', 'gas') surf_phase = ct.Interface('ptcombust-simple.cti', 'Pt_surf', [gas]) gas.TPX = tinlet, ct.one_atm, comp surf_phase.TP = tsurf, ct.one_atm # integrate the coverage equations holding the gas composition fixed # to generate a good starting estimate for the coverages. surf_phase.advance_coverages(1.) return ct.ImpingingJet(gas=gas, width=width, surface=surf_phase)
def test_modify_sticking(self): gas = ct.Solution('ptcombust.xml', 'gas') surf = ct.Interface('ptcombust.xml', 'Pt_surf', [gas]) surf.coverages = 'O(S):0.1, PT(S):0.5, H(S):0.4' gas.TP = surf.TP R = surf.reaction(2) R.rate = ct.Arrhenius(0.25, 0, 0) # original sticking coefficient = 1.0 k1 = surf.forward_rate_constants[2] surf.modify_reaction(2, R) k2 = surf.forward_rate_constants[2] self.assertNear(k1, 4*k2)
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 make_reactors(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.IdealGasReactor(self.gas) self.r1.volume = 0.01 self.net.add_reactor(self.r1) self.r2 = ct.IdealGasReactor(self.gas) self.r2.volume = 0.01 self.net.add_reactor(self.r2)
def test_remote_file(self): yaml = """ phases: - name: Pt_surf thermo: ideal-surface adjacent-phases: [{ptcombust.yaml/phases: [gas]}] species: [{ptcombust.yaml/species: all}] kinetics: surface reactions: [{ptcombust.yaml/reactions: all}] site-density: 2.7063e-09 """ surf = ct.Interface(yaml=yaml) self.assertEqual(surf.adjacent["gas"].n_species, 32) self.assertEqual(surf.n_reactions, 24)
def test_motz_wise(self): # Motz & Wise off for all reactions gas1 = ct.Solution('ptcombust.xml', 'gas') surf1 = ct.Interface('ptcombust.xml', 'Pt_surf', [gas1]) surf1.coverages = 'O(S):0.1, PT(S):0.5, H(S):0.4' gas1.TP = surf1.TP # Motz & Wise correction on for some reactions gas2 = ct.Solution('ptcombust-motzwise.cti', 'gas') surf2 = ct.Interface('ptcombust-motzwise.cti', 'Pt_surf', [gas2]) surf2.TPY = surf1.TPY k1 = surf1.forward_rate_constants k2 = surf2.forward_rate_constants # M&W toggled on (globally) for reactions 2 and 7 self.assertNear(2.0 * k1[2], k2[2]) # sticking coefficient = 1.0 self.assertNear(1.6 * k1[7], k2[7]) # sticking coefficient = 0.75 # M&W toggled off (locally) for reaction 4 self.assertNear(k1[4], k2[4]) # M&W toggled on (locally) for reaction 9 self.assertNear(2.0 * k1[9], k2[9]) # sticking coefficient = 1.0
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.IdealGasReactor(gas1) net.add_reactor(r1) net.atol_sensitivity = 1e-10 net.rtol_sensitivity = 1e-8 gas2 = ct.Solution('h2o2.xml') gas2.TPX = 900, 101325, 'H2:0.1, OH:1e-7, O2:0.1, AR:1e-5' r2 = ct.IdealGasReactor(gas2) net.add_reactor(r2) w = ct.Wall(r1, r2) w.area = 1.5 w.left.kinetics = interface C = np.zeros(interface.n_species) C[0] = 0.3 C[4] = 0.7 w.left.coverages = C w.left.add_sensitivity_reaction(2) r2.add_sensitivity_reaction(18) for T in (901, 905, 910, 950, 1500): while r2.T < T: net.step(1.0) S = net.sensitivities() # number of non-species variables in each reactor Ns = r1.component_index(gas1.species_name(0)) # Index of first variable corresponding to r2 K2 = Ns + gas1.n_species + interface.n_species # Constant volume should generate zero sensitivity coefficient self.assertArrayNear(S[1,:], np.zeros(2)) self.assertArrayNear(S[K2+1,:], np.zeros(2)) # Sensitivity coefficients for the disjoint reactors should be zero self.assertNear(np.linalg.norm(S[Ns:K2,1]), 0.0, atol=1e-5) self.assertNear(np.linalg.norm(S[K2+Ns:,0]), 0.0, atol=1e-5)
def setup_ct_solution(path_to_cti): # this chemkin file is from the cti generated by rmg gas = ct.Solution(path_to_cti, 'gas') surf = ct.Interface(path_to_cti, 'surface1', [gas]) print("This mechanism contains {} gas reactions and {} surface reactions". format(gas.n_reactions, surf.n_reactions)) print(f"Thread ID from threading{threading.get_ident()}") i_ar = gas.species_index('Ar') return { 'gas': gas, 'surf': surf, "i_ar": i_ar, "n_surf_reactions": surf.n_reactions }
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 test_modify_interface(self): gas = ct.Solution('ptcombust.xml', 'gas') surf = ct.Interface('ptcombust.xml', 'Pt_surf', [gas]) surf.coverages = 'O(S):0.1, PT(S):0.5, H(S):0.4' gas.TP = surf.TP R = surf.reaction(1) R.coverage_deps = {'O(S)': (0.0, 0.0, -3e6)} surf.modify_reaction(1, R) # Rate constant should now be independent of H(S) coverage, but # dependent on O(S) coverage k1 = surf.forward_rate_constants[1] surf.coverages = 'O(S):0.2, PT(S):0.4, H(S):0.4' k2 = surf.forward_rate_constants[1] surf.coverages = 'O(S):0.2, PT(S):0.6, H(S):0.2' k3 = surf.forward_rate_constants[1] self.assertNotAlmostEqual(k1, k2) self.assertNear(k2, k3)
def test_yaml_surface(self): gas = ct.Solution('ptcombust.yaml', 'gas') surf = ct.Interface('ptcombust.yaml', 'Pt_surf', [gas]) gas.TPY = 900, ct.one_atm, np.ones(gas.n_species) surf.coverages = np.ones(surf.n_species) surf.write_yaml('ptcombust-generated.yaml') generated = utilities.load_yaml("ptcombust-generated.yaml") for key in ('phases', 'species', 'gas-reactions', 'Pt_surf-reactions'): self.assertIn(key, generated) self.assertEqual(len(generated['gas-reactions']), gas.n_reactions) self.assertEqual(len(generated['Pt_surf-reactions']), surf.n_reactions) self.assertEqual(len(generated['species']), surf.n_total_species) gas2 = ct.Solution('ptcombust-generated.yaml', 'gas') surf2 = ct.Solution('ptcombust-generated.yaml', 'Pt_surf', [gas2]) self.assertArrayNear(surf.concentrations, surf2.concentrations) self.assertArrayNear(surf.partial_molar_enthalpies, surf2.partial_molar_enthalpies) self.assertArrayNear(surf.forward_rate_constants, surf2.forward_rate_constants)
'wgs_ni_redux_incomps.pickle') import pickle with open(filename, 'rb') as handle: wgs_data_incomps = pickle.load(handle) #Temperature of WGS data (convert to K) Tdata = wgs_data_incomps['Tout'] + 273.15 #CO/H2O ratio at the inlet Xg_in = wgs_data_incomps['Xg'][:,:,0,:] ratio_data = wgs_data_incomps['ratio'] #Load phases solution objects gas = ct.Solution(input_file) surfCT = ct.Interface(input_file,surf_name,[gas]) #Load in-house surface phase object surf = pfr.SurfacePhase(gas,surfCT, cov_file = cov_file) #Set up equilibrium gas phase gas_eq = ct.Solution(input_file) #Vary the inlet CO:H2O ratio ratio = np.linspace(1,10,10) flipratio = np.flip(ratio,axis=0) #CO and H2O inlet molar fractions co_x = 0.55*(ratio/(ratio+flipratio)) h2o_x = 0.55*(flipratio/(ratio+flipratio))
def test_diamond(self): gas, solid = ct.import_phases('diamond.cti', ['gas', 'diamond']) face = ct.Interface('diamond.cti', 'diamond_100', [gas, solid]) self.assertNear(face.site_density, 3e-8)
def test_sofc(self): mech = 'sofc-test.xml' T = 1073.15 # T in K P = ct.one_atm TPB_length_per_area = 1.0e7 # TPB length per unit area [1/m] def newton_solve(f, xstart, C=0.0): """ Solve f(x) = C by Newton iteration. """ x0 = xstart dx = 1.0e-6 while True: f0 = f(x0) - C x0 -= f0 / (f(x0 + dx) - C - f0) * dx if abs(f0) < 0.00001: return x0 # Anode-side phases gas_a, anode_bulk, oxide_a = ct.import_phases(mech, [ 'gas', 'metal', 'oxide_bulk', ]) anode_surf = ct.Interface(mech, 'metal_surface', [gas_a]) oxide_surf_a = ct.Interface(mech, 'oxide_surface', [gas_a, oxide_a]) tpb_a = ct.Interface(mech, 'tpb', [anode_bulk, anode_surf, oxide_surf_a]) # Cathode-side phases gas_c, cathode_bulk, oxide_c = ct.import_phases( mech, ['gas', 'metal', 'oxide_bulk']) cathode_surf = ct.Interface(mech, 'metal_surface', [gas_c]) oxide_surf_c = ct.Interface(mech, 'oxide_surface', [gas_c, oxide_c]) tpb_c = ct.Interface(mech, 'tpb', [cathode_bulk, cathode_surf, oxide_surf_c]) def anode_curr(E): anode_bulk.electric_potential = E w = tpb_a.net_production_rates return ct.faraday * w[0] * TPB_length_per_area def cathode_curr(E): cathode_bulk.electric_potential = E + oxide_c.electric_potential w = tpb_c.net_production_rates return -ct.faraday * w[0] * TPB_length_per_area # initialization gas_a.TPX = T, P, 'H2:0.97, H2O:0.03' gas_a.equilibrate('TP') gas_c.TPX = T, P, 'O2:1.0, H2O:0.001' gas_c.equilibrate('TP') for p in [ anode_bulk, anode_surf, oxide_surf_a, oxide_a, cathode_bulk, cathode_surf, oxide_surf_c, oxide_c, tpb_a, tpb_c ]: p.TP = T, P for s in [anode_surf, oxide_surf_a, cathode_surf, oxide_surf_c]: s.advance_coverages(50.0) # These values are just a regression test with no theoretical basis self.assertArrayNear(anode_surf.coverages, [ 6.18736755e-01, 3.81123779e-01, 8.63037850e-05, 2.59274708e-06, 5.05702339e-05 ]) self.assertArrayNear( oxide_surf_a.coverages, [4.99435780e-02, 9.48927983e-01, 1.12840577e-03, 3.35936530e-08]) self.assertArrayNear(cathode_surf.coverages, [ 1.48180380e-07, 7.57234727e-14, 9.99999827e-01, 2.49235513e-08, 4.03296469e-13 ]) self.assertArrayNear( oxide_surf_c.coverages, [4.99896947e-02, 9.49804199e-01, 2.06104969e-04, 1.11970271e-09]) Ea0 = newton_solve(anode_curr, xstart=-0.51) Ec0 = newton_solve(cathode_curr, xstart=0.51) data = [] # vary the anode overpotential, from cathodic to anodic polarization for Ea in np.linspace(Ea0 - 0.25, Ea0 + 0.25, 20): anode_bulk.electric_potential = Ea curr = anode_curr(Ea) delta_V = curr * 5.0e-5 / 2.0 phi_oxide_c = -delta_V oxide_c.electric_potential = phi_oxide_c oxide_surf_c.electric_potential = phi_oxide_c Ec = newton_solve(cathode_curr, xstart=Ec0 + 0.1, C=curr) cathode_bulk.electric_potential = phi_oxide_c + Ec data.append([ Ea - Ea0, 0.1 * curr, Ec - Ec0, delta_V, cathode_bulk.electric_potential - anode_bulk.electric_potential ]) self.compare(data, '../data/sofc-test.csv')
def test_parameter_order3(self): # Test including reacting surfaces gas1 = ct.Solution('diamond.xml', 'gas') solid = ct.Solution('diamond.xml', 'diamond') interface = ct.Interface('diamond.xml', 'diamond_100', (gas1, solid)) gas2 = ct.Solution('h2o2.xml') 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 integrate(r, net): net.advance(1e-4) return net.sensitivities() S = [] for order in range(4): rA,rB,wA,wB,net = setup(order) for (obj,k) in [(rB,2), (rB,18), (wA.left,2), (wA.left,0), (wB.right,2)]: obj.addSensitivityReaction(k) integrate(rB, net) S.append(net.sensitivities()) rA,rB,wA,wB,net = setup(order) for (obj,k) in [(wB.right,2), (wA.left,2), (rB,18), (wA.left,0), (rB,2)]: obj.addSensitivityReaction(k) integrate(rB, net) S.append(net.sensitivities()) for a,b in [(0,1),(2,3),(4,5),(6,7)]: for i,j in enumerate((4,2,1,3,0)): self.assertArrayNear(S[a][:,i], S[b][:,j], 1e-2, 1e-3)