예제 #1
0
    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])
예제 #2
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}
예제 #3
0
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
예제 #4
0
    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
예제 #5
0
    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])
예제 #6
0
 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)
예제 #7
0
 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)
예제 #8
0
        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)
예제 #9
0
    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))
예제 #10
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
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
    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)
예제 #14
0
 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)
예제 #15
0
    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)
예제 #16
0
    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)
예제 #17
0
    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)
예제 #18
0
    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)
예제 #19
0
    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)
예제 #20
0
    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)
예제 #21
0
    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
예제 #22
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)
예제 #23
0
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
    }
예제 #24
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.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)
예제 #25
0
    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)
예제 #26
0
    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)
예제 #27
0
            '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))
예제 #28
0
    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)
예제 #29
0
    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')
예제 #30
0
    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)