예제 #1
0
    def test_solve(self):
        """
        Test the simple batch reactor with a simple kinetic model. Here we
        choose a kinetic model consisting of the hydrogen abstraction reaction
        CH4 + C2H5 <=> CH3 + C2H6.
        """
        ch4 = Species(
            molecule=[Molecule().from_smiles("C")],
            thermo=ThermoData(
                Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"),
                Cpdata=([8.615, 9.687, 10.963, 12.301, 14.841, 16.976,
                         20.528], "cal/(mol*K)"),
                H298=(-17.714, "kcal/mol"),
                S298=(44.472, "cal/(mol*K)")))
        ch3 = Species(molecule=[Molecule().from_smiles("[CH3]")],
                      thermo=ThermoData(
                          Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"),
                          Cpdata=([
                              9.397, 10.123, 10.856, 11.571, 12.899, 14.055,
                              16.195
                          ], "cal/(mol*K)"),
                          H298=(9.357, "kcal/mol"),
                          S298=(45.174, "cal/(mol*K)")))
        c2h6 = Species(molecule=[Molecule().from_smiles("CC")],
                       thermo=ThermoData(
                           Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"),
                           Cpdata=([
                               12.684, 15.506, 18.326, 20.971, 25.500, 29.016,
                               34.595
                           ], "cal/(mol*K)"),
                           H298=(-19.521, "kcal/mol"),
                           S298=(54.799, "cal/(mol*K)")))
        c2h5 = Species(molecule=[Molecule().from_smiles("C[CH2]")],
                       thermo=ThermoData(
                           Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"),
                           Cpdata=([
                               11.635, 13.744, 16.085, 18.246, 21.885, 24.676,
                               29.107
                           ], "cal/(mol*K)"),
                           H298=(29.496, "kcal/mol"),
                           S298=(56.687, "cal/(mol*K)")))

        rxn1 = Reaction(reactants=[c2h6, ch3],
                        products=[c2h5, ch4],
                        kinetics=Arrhenius(A=(686.375 * 6, 'm^3/(mol*s)'),
                                           n=4.40721,
                                           Ea=(7.82799, 'kcal/mol'),
                                           T0=(298.15, 'K')))

        core_species = [ch4, ch3, c2h6, c2h5]
        edge_species = []
        core_reactions = [rxn1]
        edge_reactions = []

        T = 1000
        P = 1.0e5
        rxn_system = SimpleReactor(T,
                                   P,
                                   initial_mole_fractions={
                                       c2h5: 0.1,
                                       ch3: 0.1,
                                       ch4: 0.4,
                                       c2h6: 0.4
                                   },
                                   n_sims=1,
                                   termination=[])

        rxn_system.initialize_model(core_species, core_reactions, edge_species,
                                    edge_reactions)

        tlist = np.array([10**(i / 10.0) for i in range(-130, -49)],
                         np.float64)

        # Integrate to get the solution at each time point
        t = []
        y = []
        reaction_rates = []
        species_rates = []
        for t1 in tlist:
            rxn_system.advance(t1)
            t.append(rxn_system.t)
            # You must make a copy of y because it is overwritten by DASSL at
            # each call to advance()
            y.append(rxn_system.y.copy())
            reaction_rates.append(rxn_system.core_reaction_rates.copy())
            species_rates.append(rxn_system.core_species_rates.copy())

        # Convert the solution vectors to np arrays
        t = np.array(t, np.float64)
        y = np.array(y, np.float64)
        reaction_rates = np.array(reaction_rates, np.float64)
        species_rates = np.array(species_rates, np.float64)
        V = constants.R * rxn_system.T.value_si * np.sum(
            y) / rxn_system.P.value_si

        # Check that we're computing the species fluxes correctly
        for i in range(t.shape[0]):
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   species_rates[i, 0],
                                   delta=1e-6 * reaction_rates[i, 0])
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   -species_rates[i, 1],
                                   delta=1e-6 * reaction_rates[i, 0])
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   -species_rates[i, 2],
                                   delta=1e-6 * reaction_rates[i, 0])
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   species_rates[i, 3],
                                   delta=1e-6 * reaction_rates[i, 0])

        # Check that we've reached equilibrium
        self.assertAlmostEqual(reaction_rates[-1, 0], 0.0, delta=1e-2)

        # Unit test for the jacobian function:
        # Solve a reaction system and check if the analytical jacobian matches the finite difference jacobian

        h2 = Species(molecule=[Molecule().from_smiles("[H][H]")],
                     thermo=ThermoData(
                         Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"),
                         Cpdata=([6.89, 6.97, 6.99, 7.01, 7.08, 7.22,
                                  7.72], "cal/(mol*K)"),
                         H298=(0, "kcal/mol"),
                         S298=(31.23, "cal/(mol*K)")))

        rxn_list = [
            Reaction(reactants=[c2h6],
                     products=[ch3, ch3],
                     kinetics=Arrhenius(A=(686.375 * 6, '1/s'),
                                        n=4.40721,
                                        Ea=(7.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[ch3, ch3],
                     products=[c2h6],
                     kinetics=Arrhenius(A=(686.375 * 6, 'm^3/(mol*s)'),
                                        n=4.40721,
                                        Ea=(7.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h6, ch3],
                     products=[c2h5, ch4],
                     kinetics=Arrhenius(A=(46.375 * 6, 'm^3/(mol*s)'),
                                        n=3.40721,
                                        Ea=(6.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h5, ch4],
                     products=[c2h6, ch3],
                     kinetics=Arrhenius(A=(46.375 * 6, 'm^3/(mol*s)'),
                                        n=3.40721,
                                        Ea=(6.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h5, ch4],
                     products=[ch3, ch3, ch3],
                     kinetics=Arrhenius(A=(246.375 * 6, 'm^3/(mol*s)'),
                                        n=1.40721,
                                        Ea=(3.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[ch3, ch3, ch3],
                     products=[c2h5, ch4],
                     kinetics=Arrhenius(A=(246.375 * 6, 'm^6/(mol^2*s)'),
                                        n=1.40721,
                                        Ea=(3.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h6, ch3, ch3],
                     products=[c2h5, c2h5, h2],
                     kinetics=Arrhenius(A=(146.375 * 6, 'm^6/(mol^2*s)'),
                                        n=2.40721,
                                        Ea=(8.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h5, c2h5, h2],
                     products=[c2h6, ch3, ch3],
                     kinetics=Arrhenius(A=(146.375 * 6, 'm^6/(mol^2*s)'),
                                        n=2.40721,
                                        Ea=(8.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h6, c2h6],
                     products=[ch3, ch4, c2h5],
                     kinetics=Arrhenius(A=(1246.375 * 6, 'm^3/(mol*s)'),
                                        n=0.40721,
                                        Ea=(8.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[ch3, ch4, c2h5],
                     products=[c2h6, c2h6],
                     kinetics=Arrhenius(A=(46.375 * 6, 'm^6/(mol^2*s)'),
                                        n=0.10721,
                                        Ea=(8.82799, 'kcal/mol'),
                                        T0=(298.15, 'K')))
        ]

        for rxn in rxn_list:
            core_species = [ch4, ch3, c2h6, c2h5, h2]
            edge_species = []
            core_reactions = [rxn]

            rxn_system0 = SimpleReactor(T,
                                        P,
                                        initial_mole_fractions={
                                            ch4: 0.2,
                                            ch3: 0.1,
                                            c2h6: 0.35,
                                            c2h5: 0.15,
                                            h2: 0.2
                                        },
                                        n_sims=1,
                                        termination=[])
            rxn_system0.initialize_model(core_species, core_reactions,
                                         edge_species, edge_reactions)
            dydt0 = rxn_system0.residual(0.0, rxn_system0.y,
                                         np.zeros(rxn_system0.y.shape))[0]
            num_core_species = len(core_species)
            dN = .000001 * sum(rxn_system0.y)
            dN_array = dN * np.eye(num_core_species)

            dydt = []
            for i in range(num_core_species):
                rxn_system0.y[i] += dN
                dydt.append(
                    rxn_system0.residual(0.0, rxn_system0.y,
                                         np.zeros(rxn_system0.y.shape))[0])
                rxn_system0.y[i] -= dN  # reset y to original y0

            # Let the solver compute the jacobian
            solver_jacobian = rxn_system0.jacobian(0.0, rxn_system0.y, dydt0,
                                                   0.0)
            # Compute the jacobian using finite differences
            jacobian = np.zeros((num_core_species, num_core_species))
            for i in range(num_core_species):
                for j in range(num_core_species):
                    jacobian[i, j] = (dydt[j][i] - dydt0[i]) / dN
                    self.assertAlmostEqual(jacobian[i, j],
                                           solver_jacobian[i, j],
                                           delta=abs(1e-4 * jacobian[i, j]))

        # print 'Solver jacobian'
        # print solver_jacobian
        # print 'Numerical jacobian'
        # print jacobian

        # Unit test for the compute rate derivative
        rxn_list = [
            Reaction(reactants=[c2h6],
                     products=[ch3, ch3],
                     kinetics=Arrhenius(A=(686.375e6, '1/s'),
                                        n=4.40721,
                                        Ea=(7.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h6, ch3],
                     products=[c2h5, ch4],
                     kinetics=Arrhenius(A=(46.375 * 6, 'm^3/(mol*s)'),
                                        n=3.40721,
                                        Ea=(6.82799, 'kcal/mol'),
                                        T0=(298.15, 'K'))),
            Reaction(reactants=[c2h6, ch3, ch3],
                     products=[c2h5, c2h5, h2],
                     kinetics=Arrhenius(A=(146.375 * 6, 'm^6/(mol^2*s)'),
                                        n=2.40721,
                                        Ea=(8.82799, 'kcal/mol'),
                                        T0=(298.15, 'K')))
        ]

        core_species = [ch4, ch3, c2h6, c2h5, h2]
        edge_species = []
        core_reactions = rxn_list

        rxn_system0 = SimpleReactor(T,
                                    P,
                                    initial_mole_fractions={
                                        ch4: 0.2,
                                        ch3: 0.1,
                                        c2h6: 0.35,
                                        c2h5: 0.15,
                                        h2: 0.2
                                    },
                                    n_sims=1,
                                    termination=[])
        rxn_system0.initialize_model(core_species, core_reactions,
                                     edge_species, edge_reactions)
        dfdt0 = rxn_system0.residual(0.0, rxn_system0.y,
                                     np.zeros(rxn_system0.y.shape))[0]
        solver_dfdk = rxn_system0.compute_rate_derivative()
        # print 'Solver d(dy/dt)/dk'
        # print solver_dfdk

        integration_time = 1e-8
        rxn_system0.termination.append(TerminationTime(
            (integration_time, 's')))
        model_settings = ModelSettings(tol_keep_in_edge=0,
                                       tol_move_to_core=1,
                                       tol_interrupt_simulation=0)
        simulator_settings = SimulatorSettings()
        rxn_system0.simulate(core_species,
                             core_reactions, [], [], [], [],
                             model_settings=model_settings,
                             simulator_settings=simulator_settings)

        y0 = rxn_system0.y

        dfdk = np.zeros((num_core_species, len(rxn_list)))  # d(dy/dt)/dk

        for i in range(len(rxn_list)):
            k0 = rxn_list[i].get_rate_coefficient(T, P)
            rxn_list[i].kinetics.A.value_si = rxn_list[
                i].kinetics.A.value_si * (1 + 1e-3)
            dk = rxn_list[i].get_rate_coefficient(T, P) - k0

            rxn_system = SimpleReactor(T,
                                       P,
                                       initial_mole_fractions={
                                           ch4: 0.2,
                                           ch3: 0.1,
                                           c2h6: 0.35,
                                           c2h5: 0.15,
                                           h2: 0.2
                                       },
                                       n_sims=1,
                                       termination=[])
            rxn_system.initialize_model(core_species, core_reactions,
                                        edge_species, edge_reactions)

            dfdt = rxn_system.residual(0.0, rxn_system.y,
                                       np.zeros(rxn_system.y.shape))[0]
            dfdk[:, i] = (dfdt - dfdt0) / dk

            rxn_system.termination.append(
                TerminationTime((integration_time, 's')))
            model_settings = ModelSettings(tol_keep_in_edge=0,
                                           tol_move_to_core=1,
                                           tol_interrupt_simulation=0)
            simulator_settings = SimulatorSettings()

            rxn_system.simulate(core_species,
                                core_reactions, [], [], [], [],
                                model_settings=model_settings,
                                simulator_settings=simulator_settings)

            rxn_list[i].kinetics.A.value_si = rxn_list[
                i].kinetics.A.value_si / (1 + 1e-3)  # reset A factor

        for i in range(num_core_species):
            for j in range(len(rxn_list)):
                self.assertAlmostEqual(dfdk[i, j],
                                       solver_dfdk[i, j],
                                       delta=abs(1e-3 * dfdk[i, j]))
예제 #2
0
    def test_specific_collider_model(self):
        """
        Test the solver's ability to simulate a model with specific third body species collision efficiencies.
        """
        chem_file = os.path.join(os.path.dirname(__file__), 'files',
                                 'specific_collider_model', 'chem.inp')
        dictionary_file = os.path.join(os.path.dirname(__file__), 'files',
                                       'specific_collider_model',
                                       'species_dictionary.txt')
        species_list, reaction_list = load_chemkin_file(
            chem_file, dictionary_file)

        smiles_dict = {
            'Ar': '[Ar]',
            'N2(1)': 'N#N',
            'O2': '[O][O]',
            'H': '[H]',
            'CH3': '[CH3]',
            'CH4': 'C'
        }
        species_dict = {}
        for name, smiles in smiles_dict.items():
            mol = Molecule(smiles=smiles)
            for species in species_list:
                if species.is_isomorphic(mol):
                    species_dict[name] = species
                    break

        T = 1000  # K
        P = 10  # Pa
        initial_mole_fractions = {
            species_dict['Ar']: 2.0,
            species_dict['N2(1)']: 1.0,
            species_dict['O2']: 0.5,
            species_dict['H']: 0.1,
            species_dict['CH3']: 0.1,
            species_dict['CH4']: 0.001
        }

        # Initialize the model
        rxn_system = SimpleReactor(
            T,
            P,
            initial_mole_fractions=initial_mole_fractions,
            n_sims=1,
            termination=None)
        rxn_system.initialize_model(species_list, reaction_list, [], [])

        # Advance to time = 0.1 s
        rxn_system.advance(0.1)
        # Compare simulated mole fractions with expected mole fractions from CHEMKIN
        simulated_mole_fracs = rxn_system.y / np.sum(rxn_system.y)
        expected_mole_fracs = np.array([
            0.540394532, 0.270197216, 0.135098608, 0.027019722, 0.027019722,
            0.000270202
        ])
        # order: Ar, N2, O2, H, CH3, CH4
        for i in range(len(simulated_mole_fracs)):
            self.assertAlmostEqual(simulated_mole_fracs[i],
                                   expected_mole_fracs[i], 6)

        # Advance to time = 5 s
        rxn_system.advance(5)
        # Compare simulated mole fractions with expected mole fractions from CHEMKIN
        expected_mole_fracs = np.array([
            0.540394573, 0.270197287, 0.135098693, 0.027019519, 0.027019519,
            0.00027041
        ])
        # order: Ar, N2, O2, H, CH3, CH4
        for i in range(len(simulated_mole_fracs)):
            self.assertAlmostEqual(simulated_mole_fracs[i],
                                   expected_mole_fracs[i], 6)

        # Try a new set of conditions
        T = 850  # K
        P = 200  # Pa
        initial_mole_fractions = {
            species_dict['Ar']: 1.0,
            species_dict['N2(1)']: 0.5,
            species_dict['O2']: 0.5,
            species_dict['H']: 0.001,
            species_dict['CH3']: 0.01,
            species_dict['CH4']: 0.5
        }

        # Initialize the model
        rxn_system = SimpleReactor(
            T,
            P,
            initial_mole_fractions=initial_mole_fractions,
            n_sims=1,
            termination=None)
        rxn_system.initialize_model(species_list, reaction_list, [], [])

        # Advance to time = 5 s
        rxn_system.advance(5)
        # Compare simulated mole fractions with expected mole fractions from CHEMKIN
        simulated_mole_fracs = rxn_system.y / np.sum(rxn_system.y)
        expected_mole_fracs = np.array([
            0.398247713, 0.199123907, 0.199123907, 0.000398169, 0.003982398,
            0.199123907
        ])
        # order: Ar, N2, O2, H, CH3, CH4
        for i in range(len(simulated_mole_fracs)):
            self.assertAlmostEqual(simulated_mole_fracs[i],
                                   expected_mole_fracs[i], 6)
예제 #3
0
    def test_collider_model(self):
        """
        Test the solver's ability to simulate a model with collision efficiencies.
        """
        chem_file = os.path.join(os.path.dirname(__file__), 'files',
                                 'collider_model', 'chem.inp')
        dictionary_file = os.path.join(os.path.dirname(__file__), 'files',
                                       'collider_model',
                                       'species_dictionary.txt')
        species_list, reaction_list = load_chemkin_file(
            chem_file, dictionary_file)

        smiles_dict = {
            'H': '[H]',
            'HO2': '[O]O',
            'O2': '[O][O]',
            'Ar': '[Ar]',
            'N2': 'N#N',
            'CO2': 'O=C=O',
            'CH3': '[CH3]',
            'CH4': 'C'
        }
        species_dict = {}
        for name, smiles in smiles_dict.items():
            mol = Molecule(smiles=smiles)
            for species in species_list:
                if species.is_isomorphic(mol):
                    species_dict[name] = species
                    break

        T = 1000  # K
        P = 10  # Pa
        initial_mole_fractions = {
            species_dict['O2']: 0.5,
            species_dict['H']: 0.5,
            species_dict['CO2']: 1.0,
            species_dict['Ar']: 4.0
        }

        # Initialize the model
        rxn_system = SimpleReactor(
            T,
            P,
            initial_mole_fractions=initial_mole_fractions,
            n_sims=1,
            termination=None)
        rxn_system.initialize_model(species_list, reaction_list, [], [])

        # Advance to time = 0.1 s
        rxn_system.advance(0.1)
        # Compare simulated mole fractions with expected mole fractions from CHEMKIN
        simulated_mole_fracs = rxn_system.y / np.sum(rxn_system.y)
        expected_mole_fracs = np.array([
            0.6666667, 0, 0, 0, 0.1666667, 0, 0.08333333, 0.08333333,
            2.466066000000000E-10, 0, 0, 0, 0, 0
        ])
        for i in range(len(simulated_mole_fracs)):
            self.assertAlmostEqual(simulated_mole_fracs[i],
                                   expected_mole_fracs[i])

        # Advance to time = 5 s
        rxn_system.advance(5)
        # Compare simulated mole fractions with expected mole fractions from CHEMKIN
        expected_mole_fracs = np.array([
            0.6666667, 0, 0, 0, 0.1666667, 0, 0.08333332, 0.08333332,
            1.233033000000000E-08, 0, 0, 0, 0, 0
        ])
        for i in range(len(simulated_mole_fracs)):
            self.assertAlmostEqual(simulated_mole_fracs[i],
                                   expected_mole_fracs[i])

        # Try a new set of conditions

        T = 850  # K
        P = 200  # Pa
        initial_mole_fractions = {
            species_dict['O2']: 0.5,
            species_dict['H']: 1,
            species_dict['CO2']: 1,
            species_dict['N2']: 4,
            species_dict['CH3']: 1
        }

        # Initialize the model
        rxn_system = SimpleReactor(
            T,
            P,
            initial_mole_fractions=initial_mole_fractions,
            n_sims=1,
            termination=None)
        rxn_system.initialize_model(species_list, reaction_list, [], [])

        # Advance to time = 5 s
        rxn_system.advance(5)

        # Compare simulated mole fractions with expected mole fractions from CHEMKIN
        simulated_mole_fracs = rxn_system.y / np.sum(rxn_system.y)
        expected_mole_fracs = np.array([
            0, 0, 0, 0.5487241, 0.137181, 0, 0.1083234, 0.0685777,
            1.280687000000000E-05, 0, 0, 0, 0.1083362, 0.02884481
        ])
        for i in range(len(simulated_mole_fracs)):
            self.assertAlmostEqual(simulated_mole_fracs[i],
                                   expected_mole_fracs[i])