Esempio n. 1
0
    def update(self, reaction_system):
        """
        Opens a file with filename referring to:
            - reaction system
            - number of core species

        Writes to a csv file:
            - header row with species names
            - each row with number of moles of the core species in the given reaction system.
        """

        filename = os.path.join(
            self.output_directory, 'solver',
            'simulation_{0}_{1:d}.csv'.format(self.reaction_sys_index + 1,
                                              len(self.core_species)))

        header = ['Time (s)', 'Volume (m^3)']
        for spc in self.core_species:
            header.append(get_species_identifier(spc))

        with open(filename, 'w') as csvfile:
            worksheet = csv.writer(csvfile)

            # add header row:
            worksheet.writerow(header)

            # add mole fractions:
            worksheet.writerows(reaction_system.snapshots)
Esempio n. 2
0
    def test_reactant_n2_is_reactive_and_gets_right_species_identifier(self):
        """
        Test that after loading chemkin files, species such as N2, which is in the default
        inert list of RMG, should be treated as reactive species and given right species
        Identifier when it's reacting in reactions.
        """
        folder = os.path.join(os.path.dirname(rmgpy.__file__), 'test_data/chemkin/chemkin_py')

        chemkin_path = os.path.join(folder, 'NC', 'chem.inp')
        dictionary_path = os.path.join(folder, 'NC', 'species_dictionary.txt')

        # load_chemkin_file
        species, reactions = load_chemkin_file(chemkin_path, dictionary_path, use_chemkin_names=True)

        for n2 in species:
            if n2.label == 'N2':
                break
        self.assertTrue(n2.reactive)

        self.assertEqual(get_species_identifier(n2), 'N2(35)')
Esempio n. 3
0
def get_flux_graph_edges_dict(spc_rop_dict, core_reactions):
    graph_edges_dict = {}
    for rxn in core_reactions:
        for pair in rxn.pairs:
            if pair in graph_edges_dict:
                # get flux from spc_rop_dict
                species_string = get_species_identifier(pair[0])
                flux = get_rop_flux(spc_rop_dict, species_string, rxn.index)
                if len(flux) > 0:
                    graph_edges_dict[pair][rxn] = flux
                else:
                    # for rxns like PDD + rad4 == PDD + rad1
                    species_string = get_species_identifier(pair[1])
                    flux = get_rop_flux(spc_rop_dict, species_string,
                                        rxn.index)
                    if len(flux) > 0:
                        graph_edges_dict[pair][rxn] = -flux
            elif (pair[1], pair[0]) in graph_edges_dict:
                # get flux from spc_rop_dict
                species_string = get_species_identifier(pair[1])
                flux = get_rop_flux(spc_rop_dict, species_string, rxn.index)
                if len(flux) > 0:
                    graph_edges_dict[(pair[1], pair[0])][rxn] = flux
                else:
                    species_string = get_species_identifier(pair[0])
                    flux = get_rop_flux(spc_rop_dict, species_string,
                                        rxn.index)
                    if len(flux) > 0:
                        graph_edges_dict[(pair[1], pair[0])][rxn] = -flux
            else:
                # get flux from spc_rop_dict
                graph_edges_dict[pair] = {}
                species_string = get_species_identifier(pair[0])
                flux = get_rop_flux(spc_rop_dict, species_string, rxn.index)
                if len(flux) > 0:
                    graph_edges_dict[pair][rxn] = flux
                else:
                    species_string = get_species_identifier(pair[1])
                    flux = get_rop_flux(spc_rop_dict, species_string,
                                        rxn.index)
                    if len(flux) > 0:
                        graph_edges_dict[pair][rxn] = -flux
    return graph_edges_dict
Esempio n. 4
0
 def to_chemkin(self):
     """
     Return the chemkin-formatted string for this species.
     """
     from rmgpy.chemkin import get_species_identifier
     return get_species_identifier(self)
Esempio n. 5
0
    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
        species_names_list = [
            get_species_identifier(species) for species in self.species_list
        ]
        inert_index_list = [
            self.species_list.index(species) for species in self.species_list
            if species.index == -1
        ]

        all_data = []
        for condition in self.conditions:

            # First translate the mol_frac from species objects to species names
            new_mol_frac = {}
            for key, value in condition.mol_frac.items():
                newkey = get_species_identifier(key)
                new_mol_frac[newkey] = value

            # Set Cantera simulation conditions
            if condition.V0 is None:
                self.model.TPX = condition.T0.value_si, condition.P0.value_si, new_mol_frac
            elif condition.P0 is None:
                self.model.TDX = condition.T0.value_si, 1.0 / condition.V0.value_si, new_mol_frac
            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.reactor_type == 'IdealGasReactor':
                cantera_reactor = ct.IdealGasReactor(self.model)
            elif condition.reactor_type == 'IdealGasConstPressureReactor':
                cantera_reactor = ct.IdealGasConstPressureReactor(
                    contents=self.model)
            elif condition.reactor_type == 'IdealGasConstPressureTemperatureReactor':
                cantera_reactor = 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
            cantera_simulation = ct.ReactorNet([cantera_reactor])

            num_ct_reactions = len(self.model.reactions())
            num_ct_species = len(self.model.species())
            if self.sensitive_species:
                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(num_ct_reactions):
                    cantera_reactor.add_sensitivity_reaction(i)
                # if thermo SA is requested, add all species enthalpies
                if self.thermo_SA:
                    for i in range(num_ct_species):
                        cantera_reactor.add_sensitivity_species_enthalpy(i)
                # Set the tolerances for the sensitivity coefficients
                cantera_simulation.rtol_sensitivity = 1e-4
                cantera_simulation.atol_sensitivity = 1e-6

            # Initialize the variables to be saved
            times = []
            temperature = []
            pressure = []
            species_data = []
            kinetic_sensitivity_data = []
            thermo_sensitivity_data = []

            # Begin integration
            time = 0.0
            # Run the simulation over 100 time points
            while cantera_simulation.time < condition.reaction_time.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.
                cantera_simulation.step()
                times.append(cantera_simulation.time)
                temperature.append(cantera_reactor.T)
                pressure.append(cantera_reactor.thermo.P)
                species_data.append(
                    cantera_reactor.thermo[species_names_list].X)

                if self.sensitive_species:
                    # 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

                    mass_frac_sensitivity_array = cantera_simulation.sensitivities(
                    )
                    if condition.reactor_type == 'IdealGasReactor':
                        # Row 0: mass, Row 1: volume, Row 2: internal energy or temperature, Row 3+: mass fractions of species
                        mass_frac_sensitivity_array = mass_frac_sensitivity_array[
                            3:, :]
                    elif condition.reactor_type == 'IdealGasConstPressureReactor' or condition.reactor_type == 'IdealGasConstPressureTemperatureReactor':
                        # Row 0: mass, Row 1: enthalpy or temperature, Row 2+: mass fractions of the species
                        mass_frac_sensitivity_array = mass_frac_sensitivity_array[
                            2:, :]
                    else:
                        raise Exception(
                            'Other types of reactor conditions are currently not supported'
                        )

                    for i in range(len(mass_frac_sensitivity_array)):
                        mass_frac_sensitivity_array[i] *= species_data[-1][i]

                    # extract kinetics SA
                    kinetics_mass_frac_sa = mass_frac_sensitivity_array[:, 0:
                                                                        num_ct_reactions]
                    sensitivity_array = np.zeros(
                        len(self.sensitive_species) *
                        len(self.model.reactions()))
                    for index, species in enumerate(self.sensitive_species):
                        for j in range(num_ct_reactions):
                            sensitivity_array[
                                num_ct_reactions * index +
                                j] = cantera_simulation.sensitivity(
                                    species.to_chemkin(), j)

                            for i in range(len(kinetics_mass_frac_sa)):
                                if i not in inert_index_list:
                                    # massFracSensitivity for inerts are returned as 0.0 in Cantera, so we do not include them here
                                    sensitivity_array[
                                        num_ct_reactions * index +
                                        j] -= kinetics_mass_frac_sa[i][j]
                    kinetic_sensitivity_data.append(sensitivity_array)

                    # extract thermo SA if requested
                    if self.thermo_SA:
                        # extract thermo SA
                        thermo_mass_frac_sa = mass_frac_sensitivity_array[:,
                                                                          num_ct_reactions:]
                        sensitivity_array = np.zeros(
                            len(self.sensitive_species) * num_ct_species)
                        for index, species in enumerate(
                                self.sensitive_species):
                            for j in range(num_ct_species):
                                sensitivity_array[
                                    num_ct_species * index +
                                    j] = cantera_simulation.sensitivity(
                                        species.to_chemkin(),
                                        j + num_ct_reactions)

                                for i in range(
                                        len(mass_frac_sensitivity_array)):
                                    if i not in inert_index_list:
                                        # massFracSensitivity for inerts are returned as 0.0 in Cantera, so we must not include them here
                                        sensitivity_array[
                                            num_ct_species * index +
                                            j] -= thermo_mass_frac_sa[i][j]
                        thermo_sensitivity_data.append(sensitivity_array)

            # Convert species_data and sensitivity data to numpy arrays
            species_data = np.array(species_data)
            kinetic_sensitivity_data = np.array(kinetic_sensitivity_data)
            thermo_sensitivity_data = np.array(thermo_sensitivity_data)

            # 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')
            condition_data = []
            condition_data.append(temperature)
            condition_data.append(pressure)

            for index, species in enumerate(self.species_list):
                # Create generic data object that saves the species object into the species object.  To allow easier manipulate later.
                species_generic_data = GenericData(
                    label=species_names_list[index],
                    species=species,
                    data=species_data[:, index],
                    index=species.index)
                condition_data.append(species_generic_data)

            # save kinetic data as generic data object
            reaction_sensitivity_data = []
            for index, species in enumerate(self.sensitive_species):
                for j in range(num_ct_reactions):
                    reaction_sensitivity_generic_data = GenericData(
                        label='dln[{0}]/dln[k{1}]: {2}'.format(
                            species.to_chemkin(), j + 1,
                            self.model.reactions()[j]),
                        species=species,
                        reaction=self.model.reactions()[j],
                        data=kinetic_sensitivity_data[:, num_ct_reactions *
                                                      index + j],
                        index=j + 1,
                    )
                    reaction_sensitivity_data.append(
                        reaction_sensitivity_generic_data)

            # save thermo data as generic data object
            thermodynamic_sensitivity_data = []
            if self.thermo_SA:
                for index, species in enumerate(self.sensitive_species):
                    for j in range(num_ct_species):
                        thermo_sensitivity_generic_data = GenericData(
                            label='dln[{0}]/dH[{1}]'.format(
                                species,
                                self.model.species()[j].name),
                            species=species,
                            data=thermo_sensitivity_data[:, num_ct_species *
                                                         index + j],
                            index=j + 1,
                        )
                        thermodynamic_sensitivity_data.append(
                            thermo_sensitivity_generic_data)

            all_data.append((time, condition_data, reaction_sensitivity_data,
                             thermodynamic_sensitivity_data))

        return all_data