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()
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 compute_high_p_rate_coefficient(self) -> None: """ Generate a high pressure rate coefficient for a reaction. Populates the reaction.kinetics attribute. """ ts_species = self.species_dict[self.reaction.ts_label] if self.output_dict[ts_species.label]['convergence']: success = True arkane_output_path = self.generate_arkane_species_file(species=ts_species, bac_type=None) arkane_ts_species = arkane_transition_state(ts_species.label, ts_species.arkane_file) statmech_success = self.run_statmech(arkane_species=arkane_ts_species, arkane_file_path=ts_species.arkane_file, arkane_output_path=arkane_output_path, bac_type=None, sp_level=self.sp_level, plot=False) if not statmech_success: logger.error(f'Could not run statmech job for TS species {ts_species.label} ' f'of reaction {self.reaction.label}') else: ts_species.e0 = arkane_ts_species.conformer.E0.value_si * 0.001 # convert to kJ/mol self.reaction.check_ts() self.reaction.dh_rxn298 = \ sum([product.thermo.get_enthalpy(298) * self.reaction.get_species_count(product, well=1) for product in self.reaction.p_species]) \ - sum([reactant.thermo.get_enthalpy(298) * self.reaction.get_species_count(reactant, well=0) for reactant in self.reaction.r_species]) reactant_labels, product_labels = list(), list() for reactant in self.reaction.r_species: reactant_labels.extend([reactant.label] * self.reaction.get_species_count(reactant, well=0)) for product in self.reaction.p_species: product_labels.extend([product.label] * self.reaction.get_species_count(product, well=1)) arkane_rxn = arkane_reaction(label=self.reaction.label, reactants=reactant_labels, products=product_labels, transitionState=self.reaction.ts_label, tunneling='Eckart') kinetics_job = KineticsJob(reaction=arkane_rxn, Tmin=self.T_min, Tmax=self.T_max, Tcount=self.T_count, three_params=self.three_params) if self.three_params: msg = 'using the modified three-parameter Arrhenius equation k = A * (T/T0)^n * exp(-Ea/RT)' else: msg = 'using the classical two-parameter Arrhenius equation k = A * exp(-Ea/RT)' logger.info(f'Calculating rate for reaction {self.reaction.label} {msg}.') try: kinetics_job.execute(output_directory=arkane_output_path, plot=True) 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 "RMG-Py/arkane/kinetics.py", line 136, in execute # generateKinetics(Tlist.value_si) # File "RMG-Py/arkane/kinetics.py", line 179, in generateKinetics # klist[i] = 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(f'Failed to generate kinetics for {self.reaction.label}, got:\n{e}') success = False if success: self.reaction.kinetics = kinetics_job.reaction.kinetics plotter.log_kinetics(ts_species.label, path=arkane_output_path) # initialize the Arkane species_dict in case another reaction uses the same species arkane.input.species_dict = dict() clean_output_directory(species_path=os.path.join(self.output_directory, 'rxns', ts_species.label), is_ts=True)