def compare_rates( rxns_for_kinetics_lib: list, rmg_database: Type[RMGDatabase], output_directory: str, T_min: tuple = None, T_max: tuple = None, T_count: int = 50, ) -> None: """ Compare the calculates thermo with RMG's estimations. Args: rxns_for_kinetics_lib (list): Reactions for which rate coefficients were computed. rmg_database (RMGDatabase, optional): The RMG database object. output_directory (str): The path to the project's output folder. T_min (tuple, optional): The minimum temperature for kinetics computations, e.g., (500, 'K'). T_max (tuple, optional): The maximum temperature for kinetics computations, e.g., (3000, 'K'). T_count (int, optional): The number of temperature points between ``T_min`` and ``T_max``. """ reactions_to_compare = list( ) # reactions for which a rate was both calculated and estimated. for reaction in rxns_for_kinetics_lib: try: reaction.rmg_reactions = rmgdb.determine_rmg_kinetics( rmgdb=rmg_database, reaction=reaction.rmg_reaction, dh_rxn298=reaction.dh_rxn298) except Exception as e: logger.info( f'Could not estimate a rate for reaction {reaction.label} using RMG. ' f'Not generating a comparison plot for this reaction.\nGot: {e}' ) else: reactions_to_compare.append(reaction) if reactions_to_compare: plotter.draw_kinetics_plots(reactions_to_compare, T_min=T_min, T_max=T_max, T_count=T_count, path=output_directory)
def process(self): """ Process ARC outputs and generate thermo and kinetics. """ # Thermo: species_list_for_thermo_parity = list() species_for_thermo_lib = list() species_for_transport_lib = list() unconverged_species = list() for species in self.species_dict.values(): if not species.is_ts and 'ALL converged' in self.output[species.label]['status']: output_path = self._generate_arkane_species_file(species) unique_arkane_species_label = False while not unique_arkane_species_label: try: arkane_spc = arkane_input_species(str(species.label), species.arkane_file) except ValueError: species.label += '_' + str(randint(0, 999)) else: unique_arkane_species_label = True species.rmg_species = Species(molecule=[species.mol]) species.rmg_species.reactive = True if species.mol_list: arkane_spc.molecule = species.mol_list species.rmg_species.molecule = species.mol_list # add resonance structures for thermo determination statmech_success = self._run_statmech(arkane_spc, species.arkane_file, output_path, use_bac=self.use_bac) if not statmech_success: continue if species.generate_thermo: thermo_job = ThermoJob(arkane_spc, 'NASA') thermo_job.execute(output_directory=output_path, plot=False) species.thermo = arkane_spc.getThermoData() plotter.log_thermo(species.label, path=output_path) species_for_thermo_lib.append(species) if self.use_bac and self.sp_level: # If BAC was used, save another Arkane YAML file of this species with no BAC, so it can be used # for further rate calculations if needed (where the conformer.E0 has no BAC) statmech_success = self._run_statmech(arkane_spc, species.arkane_file, output_path, use_bac=False) # if statmech_success: # arkane_spc.label += str('_no_BAC') # arkane_spc.thermo = None # otherwise thermo won't be calculated, although we don't really care # thermo_job = ThermoJob(arkane_spc, 'NASA') # thermo_job.execute(output_directory=output_path, plot=False) try: species.rmg_thermo = self.rmgdb.thermo.getThermoData(species.rmg_species) except (ValueError, AttributeError) as e: logger.info('Could not retrieve RMG thermo for species {0}, possibly due to missing 2D structure ' '(bond orders). Not including this species in the parity plots.' '\nGot: {1}'.format(species.label, e.message)) else: if species.generate_thermo: species_list_for_thermo_parity.append(species) if 'onedmin converged' in self.output[species.label]['status'].lower(): species_for_transport_lib.append(species) elif 'ALL converged' not in self.output[species.label]['status']: unconverged_species.append(species) # Kinetics: rxn_list_for_kinetics_plots = list() arkane_spc_dict = dict() # a dictionary with all species and the TSs for rxn in self.rxn_list: logger.info('\n\n') species = self.species_dict[rxn.ts_label] # The TS if 'ALL converged' in self.output[species.label]['status'] and rxn.check_ts(): self.copy_freq_output_for_ts(species.label) success = True rxn_list_for_kinetics_plots.append(rxn) output_path = self._generate_arkane_species_file(species) arkane_ts = arkane_transition_state(str(species.label), species.arkane_file) arkane_spc_dict[species.label] = arkane_ts self._run_statmech(arkane_ts, species.arkane_file, kinetics=True) for spc in rxn.r_species + rxn.p_species: if spc.label not in arkane_spc_dict.keys(): # add an extra character to the arkane_species label to distinguish between species calculated # for thermo and species calculated for kinetics (where we don't want to use BAC) arkane_spc = arkane_input_species(str(spc.label + '_'), spc.arkane_file) self._run_statmech(arkane_spc, spc.arkane_file, kinetics=True) rxn.dh_rxn298 = sum([product.thermo.getEnthalpy(298) for product in arkane_spc_dict.values() if product.label in rxn.products])\ - sum([reactant.thermo.getEnthalpy(298) for reactant in arkane_spc_dict.values() if reactant.label in rxn.reactants]) arkane_rxn = arkane_reaction(label=str(rxn.label), reactants=[str(label + '_') for label in arkane_spc_dict.keys() if label in rxn.reactants], products=[str(label + '_') for label in arkane_spc_dict.keys() if label in rxn.products], transitionState=rxn.ts_label, tunneling='Eckart') kinetics_job = KineticsJob(reaction=arkane_rxn, Tmin=self.t_min, Tmax=self.t_max, Tcount=self.t_count) logger.info('Calculating rate for reaction {0}'.format(rxn.label)) try: kinetics_job.execute(output_directory=output_path, plot=False) except (ValueError, OverflowError) as e: # ValueError: One or both of the barrier heights of -9.3526 and 62.683 kJ/mol encountered in Eckart # method are invalid. # # File "/home/alongd/Code/RMG-Py/arkane/kinetics.py", line 136, in execute # self.generateKinetics(self.Tlist.value_si) # File "/home/alongd/Code/RMG-Py/arkane/kinetics.py", line 179, in generateKinetics # klist[i] = self.reaction.calculateTSTRateCoefficient(Tlist[i]) # File "rmgpy/reaction.py", line 818, in rmgpy.reaction.Reaction.calculateTSTRateCoefficient # File "rmgpy/reaction.py", line 844, in rmgpy.reaction.Reaction.calculateTSTRateCoefficient # OverflowError: math range error logger.error('Failed to generate kinetics for {0} with message:\n{1}'.format(rxn.label, e)) success = False if success: rxn.kinetics = kinetics_job.reaction.kinetics plotter.log_kinetics(species.label, path=output_path) rxn.rmg_reactions = rmgdb.determine_rmg_kinetics(rmgdb=self.rmgdb, reaction=rxn.rmg_reaction, dh_rxn298=rxn.dh_rxn298) logger.info('\n\n') output_dir = os.path.join(self.project_directory, 'output') libraries_path = os.path.join(output_dir, 'RMG libraries') if species_list_for_thermo_parity: plotter.draw_thermo_parity_plots(species_list_for_thermo_parity, path=output_dir) plotter.save_thermo_lib(species_for_thermo_lib, path=libraries_path, name=self.project, lib_long_desc=self.lib_long_desc) if species_for_transport_lib: plotter.save_transport_lib(species_for_thermo_lib, path=libraries_path, name=self.project) if rxn_list_for_kinetics_plots: plotter.draw_kinetics_plots(rxn_list_for_kinetics_plots, path=output_dir, t_min=self.t_min, t_max=self.t_max, t_count=self.t_count) plotter.save_kinetics_lib(rxn_list=rxn_list_for_kinetics_plots, path=libraries_path, name=self.project, lib_long_desc=self.lib_long_desc) self._clean_output_directory() if unconverged_species: if not os.path.isdir(output_dir): os.makedirs(output_dir) with open(os.path.join(output_dir, 'unconverged_species.log'), 'w') as f: for spc in unconverged_species: f.write(spc.label) if spc.is_ts: f.write(str(' rxn: {0}'.format(spc.rxn_label))) elif spc.mol is not None: f.write(str(' SMILES: {0}'.format(spc.mol.toSMILES()))) f.write(str('\n'))
def process(self): """Process ARC outputs and generate thermo and kinetics""" # Thermo: species_list_for_thermo_parity = list() species_for_thermo_lib = list() for species in self.species_dict.values(): if not species.is_ts and 'ALL converged' in self.output[ species.label]['status']: species_for_thermo_lib.append(species) output_file_path = self._generate_arkane_species_file(species) arkane_spc = arkane_species(str(species.label), species.arkane_file) if species.mol_list: arkane_spc.molecule = species.mol_list stat_mech_job = StatMechJob(arkane_spc, species.arkane_file) stat_mech_job.applyBondEnergyCorrections = self.use_bac stat_mech_job.modelChemistry = self.model_chemistry stat_mech_job.frequencyScaleFactor = assign_frequency_scale_factor( self.model_chemistry) stat_mech_job.execute(outputFile=output_file_path, plot=False) if species.generate_thermo: thermo_job = ThermoJob(arkane_spc, 'NASA') thermo_job.execute(outputFile=output_file_path, plot=False) species.thermo = arkane_spc.getThermoData() plotter.log_thermo(species.label, path=output_file_path) species.rmg_species = Species(molecule=[species.mol]) species.rmg_species.reactive = True if species.mol_list: species.rmg_species.molecule = species.mol_list # add resonance structures for thermo determination try: species.rmg_thermo = self.rmgdb.thermo.getThermoData( species.rmg_species) except ValueError: logging.info( 'Could not retrieve RMG thermo for species {0}, possibly due to missing 2D structure ' '(bond orders). Not including this species in the parity plots.' .format(species.label)) else: if species.generate_thermo: species_list_for_thermo_parity.append(species) # Kinetics: rxn_list_for_kinetics_plots = list() arkane_spc_dict = dict() # a dictionary with all species and the TSs for rxn in self.rxn_list: logging.info('\n\n') species = self.species_dict[rxn.ts_label] # The TS if 'ALL converged' in self.output[ species.label]['status'] and rxn.check_ts(): self.copy_freq_output_for_ts(species.label) success = True rxn_list_for_kinetics_plots.append(rxn) output_file_path = self._generate_arkane_species_file(species) arkane_ts = arkane_transition_state(str(species.label), species.arkane_file) arkane_spc_dict[species.label] = arkane_ts stat_mech_job = StatMechJob(arkane_ts, species.arkane_file) stat_mech_job.applyBondEnergyCorrections = False if not self.model_chemistry: stat_mech_job.modelChemistry = self.model_chemistry else: stat_mech_job.applyAtomEnergyCorrections = False stat_mech_job.frequencyScaleFactor = assign_frequency_scale_factor( self.model_chemistry) stat_mech_job.execute(outputFile=None, plot=False) for spc in rxn.r_species + rxn.p_species: if spc.label not in arkane_spc_dict.keys(): # add an extra character to the arkane_species label to distinguish between species calculated # for thermo and species calculated for kinetics (where we don't want to use BAC) arkane_spc = arkane_species(str(spc.label + '_'), spc.arkane_file) stat_mech_job = StatMechJob(arkane_spc, spc.arkane_file) arkane_spc_dict[spc.label] = arkane_spc stat_mech_job.applyBondEnergyCorrections = False if not self.model_chemistry: stat_mech_job.modelChemistry = self.model_chemistry else: stat_mech_job.applyAtomEnergyCorrections = False stat_mech_job.frequencyScaleFactor = assign_frequency_scale_factor( self.model_chemistry) stat_mech_job.execute(outputFile=None, plot=False) # thermo_job = ThermoJob(arkane_spc, 'NASA') # thermo_job.execute(outputFile=None, plot=False) # arkane_spc.thermo = arkane_spc.getThermoData() rxn.dh_rxn298 = sum([product.thermo.getEnthalpy(298) for product in arkane_spc_dict.values() if product.label in rxn.products])\ - sum([reactant.thermo.getEnthalpy(298) for reactant in arkane_spc_dict.values() if reactant.label in rxn.reactants]) arkane_rxn = arkane_reaction( label=str(rxn.label), reactants=[ str(label + '_') for label in arkane_spc_dict.keys() if label in rxn.reactants ], products=[ str(label + '_') for label in arkane_spc_dict.keys() if label in rxn.products ], transitionState=rxn.ts_label, tunneling='Eckart') kinetics_job = KineticsJob(reaction=arkane_rxn, Tmin=self.t_min, Tmax=self.t_max, Tcount=self.t_count) logging.info('Calculating rate for reaction {0}'.format( rxn.label)) try: kinetics_job.execute(outputFile=output_file_path, plot=False) except ValueError as e: """ ValueError: One or both of the barrier heights of -9.35259 and 62.6834 kJ/mol encountered in Eckart method are invalid. """ logging.error( 'Failed to generate kinetics for {0} with message:\n{1}' .format(rxn.label, e)) success = False if success: rxn.kinetics = kinetics_job.reaction.kinetics plotter.log_kinetics(species.label, path=output_file_path) rxn.rmg_reactions = rmgdb.determine_rmg_kinetics( rmgdb=self.rmgdb, reaction=rxn.rmg_reaction, dh_rxn298=rxn.dh_rxn298) logging.info('\n\n') output_dir = os.path.join(self.project_directory, 'output') if species_list_for_thermo_parity: plotter.draw_thermo_parity_plots(species_list_for_thermo_parity, path=output_dir) libraries_path = os.path.join(output_dir, 'RMG libraries') # species_list = [spc for spc in self.species_dict.values()] plotter.save_thermo_lib(species_for_thermo_lib, path=libraries_path, name=self.project, lib_long_desc=self.lib_long_desc) if rxn_list_for_kinetics_plots: plotter.draw_kinetics_plots(rxn_list_for_kinetics_plots, path=output_dir, t_min=self.t_min, t_max=self.t_max, t_count=self.t_count) libraries_path = os.path.join(output_dir, 'RMG libraries') plotter.save_kinetics_lib(rxn_list=rxn_list_for_kinetics_plots, path=libraries_path, name=self.project, lib_long_desc=self.lib_long_desc) self.clean_output_directory()