def write_output(self): """ Save the results of the ThermoJob to the `output.py` file located in `output_directory`. """ output_file = os.path.join(self.output_directory, 'output.py') logging.info( 'Saving statistical mechanics parameters for {0}...'.format( self.label)) f = open(output_file, 'a') conformer = self.conformer coordinates = conformer.coordinates.value_si * 1e10 f.write( '# Coordinates for {0} in Input Orientation (angstroms):\n'.format( self.label)) for i in range(coordinates.shape[0]): x = coordinates[i, 0] y = coordinates[i, 1] z = coordinates[i, 2] f.write('# {0} {1:9.4f} {2:9.4f} {3:9.4f}\n'.format( self.symbols[i], x, y, z)) f.write('\n') result = 'conformer(label={0!r}, E0={1!r}, modes={2!r}, spin_multiplicity={3:d}, optical_isomers={4:d}'.format( self.label, conformer.E0, conformer.modes, conformer.spin_multiplicity, conformer.optical_isomers, ) try: result += ', frequency={0!r}'.format( self.sampling.imaginary_frequency) except AttributeError: pass result += ')' f.write('{0}\n\n'.format(prettify(result))) if self.coordinate_system in ["E-Optimized", "E'-Optimized"]: from rmgpy.statmech.vibration import HarmonicOscillator vib_freq = [ round((self.mode_dict[key]['K']**0.5) / (2 * np.pi * constants.c * 100), 2) for key in self.mode_dict.keys() ] vibration = HarmonicOscillator(frequencies=(sorted(vib_freq), "cm^-1")) f.write(( '# {0}: Vibrational frequencies of optimal vibrational modes\n' .format(self.coordinate_system))) f.write(prettify('{0!r}\n'.format(vibration))) for line in self.result_info: line = line + '\n' f.write(line) f.write('\n') f.close()
def write_output(self, output_directory): """ Save the results of the thermodynamics job to the `output.py` file located in `output_directory`. """ species = self.species outputFile = os.path.join(output_directory, 'output.py') logging.info('Saving thermo for {0}...'.format(species.label)) with open(outputFile, 'a') as f: f.write('# Thermodynamics for {0}:\n'.format(species.label)) H298 = species.getThermoData().getEnthalpy(298) / 4184. S298 = species.getThermoData().getEntropy(298) / 4.184 f.write('# Enthalpy of formation (298 K) = {0:9.3f} kcal/mol\n'.format(H298)) f.write('# Entropy of formation (298 K) = {0:9.3f} cal/(mol*K)\n'.format(S298)) f.write('# =========== =========== =========== =========== ===========\n') f.write('# Temperature Heat cap. Enthalpy Entropy Free energy\n') f.write('# (K) (cal/mol*K) (kcal/mol) (cal/mol*K) (kcal/mol)\n') f.write('# =========== =========== =========== =========== ===========\n') for T in [300, 400, 500, 600, 800, 1000, 1500, 2000, 2400]: try: Cp = species.getThermoData().getHeatCapacity(T) / 4.184 H = species.getThermoData().getEnthalpy(T) / 4184. S = species.getThermoData().getEntropy(T) / 4.184 G = species.getThermoData().getFreeEnergy(T) / 4184. f.write('# {0:11g} {1:11.3f} {2:11.3f} {3:11.3f} {4:11.3f}\n'.format(T, Cp, H, S, G)) except ValueError: logging.debug("Valid thermo for {0} is outside range for temperature {1}".format(species, T)) f.write('# =========== =========== =========== =========== ===========\n') thermo_string = 'thermo(label={0!r}, thermo={1!r})'.format(species.label, species.getThermoData()) f.write('{0}\n\n'.format(prettify(thermo_string)))
def save(self, outputFile): """ Save the results of the thermodynamics job to the file located at `path` on disk. """ species = self.species logging.info('Saving thermo for {0}...'.format(species.label)) f = open(outputFile, 'a') f.write('# Thermodynamics for {0}:\n'.format(species.label)) H298 = species.getThermoData().getEnthalpy(298) / 4184. S298 = species.getThermoData().getEntropy(298) / 4.184 f.write('# Enthalpy of formation (298 K) = {0:9.3f} kcal/mol\n'.format(H298)) f.write('# Entropy of formation (298 K) = {0:9.3f} cal/(mol*K)\n'.format(S298)) f.write('# =========== =========== =========== =========== ===========\n') f.write('# Temperature Heat cap. Enthalpy Entropy Free energy\n') f.write('# (K) (cal/mol*K) (kcal/mol) (cal/mol*K) (kcal/mol)\n') f.write('# =========== =========== =========== =========== ===========\n') for T in [300,400,500,600,800,1000,1500,2000,2400]: try: Cp = species.getThermoData().getHeatCapacity(T) / 4.184 H = species.getThermoData().getEnthalpy(T) / 4184. S = species.getThermoData().getEntropy(T) / 4.184 G = species.getThermoData().getFreeEnergy(T) / 4184. f.write('# {0:11g} {1:11.3f} {2:11.3f} {3:11.3f} {4:11.3f}\n'.format(T, Cp, H, S, G)) except ValueError: logging.debug("Valid thermo for {0} is outside range for temperature {1}".format(species,T)) f.write('# =========== =========== =========== =========== ===========\n') thermo_string = 'thermo(label={0!r}, thermo={1!r})'.format(species.label, species.getThermoData()) f.write('{0}\n\n'.format(prettify(thermo_string))) f.close() # write chemkin file f = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') if isinstance(species, Species): if species.molecule and isinstance(species.molecule[0], Molecule): elementCounts = retrieveElementCount(species.molecule[0]) else: try: elementCounts = species.props['elementCounts'] except KeyError: elementCounts = {'C': 0, 'H': 0} else: elementCounts = {'C': 0, 'H': 0} chemkin_thermo_string = writeThermoEntry(species, elementCounts=elementCounts, verbose=True) f.write('{0}\n'.format(chemkin_thermo_string)) f.close() # write species dictionary if isinstance(species, Species): if species.molecule and isinstance(species.molecule[0], Molecule): with open(os.path.join(os.path.dirname(outputFile), 'species_dictionary.txt'), 'a') as f: f.write(species.molecule[0].toAdjacencyList(removeH=False, label=species.label)) f.write('\n') return chemkin_thermo_string
def test_prettify(self): """Test that ``prettify`` returns the expected result""" input_str = ( "conformer(label='C7H7', E0=(193.749,'kJ/mol'), modes=[IdealGasTranslation(mass=(91.0548,'amu')), " "NonlinearRotor(inertia=([91.0567,186.675,277.733],'amu*angstrom^2'), symmetry=2), " "HarmonicOscillator(frequencies=([199.381,360.536,413.795,480.347,536.285,630.723,687.118,709.613," "776.662,830.404,834.386,901.841,973.498,975.148,993.349,998.606,1040.14,1120.69,1179.22,1189.07," "1292.86,1332.91,1357.18,1479.46,1495.36,1507.91,1583.14,1604.63,3156.85,3170.22,3172.78,3185.05," "3189.8,3203.23,3253.99],'cm^-1')), HinderedRotor(inertia=(1.70013,'amu*angstrom^2'), symmetry=2, " "fourier=([[-0.315923,-27.7665,0.177678,3.2437,0.0509515],[-0.00164953,-0.0021925,-0.00386396," "-0.000912068,0.00274206]],'kJ/mol'), quantum=True, semiclassical=False)], spin_multiplicity=2, " "optical_isomers=1)") expected_output = """conformer( label = 'C7H7', E0 = (193.749, 'kJ/mol'), modes = [ IdealGasTranslation(mass=(91.0548, 'amu')), NonlinearRotor( inertia = ([91.0567, 186.675, 277.733], 'amu*angstrom^2'), symmetry = 2, ), HarmonicOscillator( frequencies = ([199.381, 360.536, 413.795, 480.347, 536.285, 630.723, 687.118, 709.613, 776.662, 830.404, 834.386, 901.841, 973.498, 975.148, 993.349, 998.606, 1040.14, 1120.69, 1179.22, 1189.07, 1292.86, 1332.91, 1357.18, 1479.46, 1495.36, 1507.91, 1583.14, 1604.63, 3156.85, 3170.22, 3172.78, 3185.05, 3189.8, 3203.23, 3253.99], 'cm^-1'), ), HinderedRotor( inertia = (1.70013, 'amu*angstrom^2'), symmetry = 2, fourier = ( [ [-0.315923, -27.7665, 0.177678, 3.2437, 0.0509515], [-0.00164953, -0.0021925, -0.00386396, -0.000912068, 0.00274206], ], 'kJ/mol', ), quantum = None, semiclassical = None, ), ], spin_multiplicity = 2, optical_isomers = 1, )""" self.assertEqual(prettify(input_str), expected_output)
def write_output(self): """ Save the results of the ThermoJob to the `output.py` file located in `output_directory`. """ output_file = os.path.join(self.output_directory, 'output.py') logging.info('Saving statistical mechanics parameters for {0}...'.format(self.label)) f = open(output_file, 'a') conformer = self.conformer coordinates = conformer.coordinates.value_si * 1e10 number = conformer.number.value_si f.write('# Coordinates for {0} in Input Orientation (angstroms):\n'.format(self.label)) for i in range(coordinates.shape[0]): x = coordinates[i, 0] y = coordinates[i, 1] z = coordinates[i, 2] f.write('# {0} {1:9.4f} {2:9.4f} {3:9.4f}\n'.format(self.symbols[i], x, y, z)) f.write('\n') result = 'conformer(label={0!r}, E0={1!r}, modes={2!r}, spin_multiplicity={3:d}, optical_isomers={4:d}'.format( self.label, conformer.E0, conformer.modes, conformer.spin_multiplicity, conformer.optical_isomers, ) try: result += ', frequency={0!r}'.format(self.sampling.imaginary_frequency) except AttributeError: pass result += ')' f.write('{0}\n\n'.format(prettify(result))) for line in self.result_info: line = line + '\n' f.write(line) f.write('\n') f.close()
def save(self, output_file): """Save the output of a pressure dependent job""" logging.info( 'Saving pressure dependence results for network {0}...'.format( self.network.label)) f = open(output_file, 'a') f_chemkin = open( os.path.join(os.path.dirname(output_file), 'chem.inp'), 'a') n_reac = self.network.n_isom + self.network.n_reac n_prod = n_reac + self.network.n_prod Tlist = self.Tlist.value_si Plist = self.Plist.value_si Tcount = Tlist.shape[0] Pcount = Plist.shape[0] f.write("#Thermo used: \n") spcs = [] for rxn in self.network.path_reactions: spcs.extend(rxn.reactants) spcs.extend(rxn.products) for spc in spcs: if spc.thermo: f.write("#" + spc.label + " SMILES: " + spc.molecule[0].to_smiles() + "\n") f.write("#" + spc.thermo.comment + "\n") f.write("\n#Path Reactions used: \n") for rxn in self.network.path_reactions: if rxn.kinetics: f.write("#" + str(rxn) + "\n") for s in rxn.kinetics.comment.split("\n"): f.write("#" + s + "\n") f.write("\n") count = 0 printed_reactions = [] # list of rxns already printed for prod in range(n_prod): for reac in range(n_reac): if reac == prod: continue reaction = self.network.net_reactions[count] count += 1 # make sure we aren't double counting any reactions if not any([ reaction.is_isomorphic(other_rxn, check_only_label=True) for other_rxn in printed_reactions ]): duplicate = False # add reaction to printed reaction printed_reactions.append(reaction) else: # comment out the extra reverse reaction duplicate = True # write chemkin output. string = write_kinetics_entry(reaction, species_list=None, verbose=False, commented=duplicate) f_chemkin.write('{0}\n'.format(string)) # write to 'output.py' kdata = self.K[:, :, prod, reac].copy() order = len(reaction.reactants) kdata *= 1e6**(order - 1) k_units = { 1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)' }[order] f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') f.write('# T / P ') f.write(' '.join(['{0:11.3e}'.format(P * 1e-5) for P in Plist])) f.write('\n') f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') for t in range(Tcount): f.write('# {0:11g}'.format(Tlist[t])) for p in range(Pcount): f.write(' {0:11.3e}'.format(kdata[t, p])) f.write('\n') f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') string = 'pdepreaction(reactants={0!r}, products={1!r}, kinetics={2!r})'.format( [reactant.label for reactant in reaction.reactants], [product.label for product in reaction.products], reaction.kinetics, ) pdep_function = '{0}\n\n'.format(prettify(string)) if duplicate: # add comments to the start of the string pdep_function = '# ' + pdep_function.replace( '\n', '\n# ') f.write(pdep_function) f.close() f_chemkin.close()
def saveEntry(f, entry): """ Save an `entry` in the kinetics database by writing a string to the given file object `f`. """ from arkane.output import prettify def sortEfficiencies(efficiencies0): efficiencies = {} for mol, eff in efficiencies0.iteritems(): if isinstance(mol, str): # already in SMILES string format smiles = mol else: smiles = mol.toSMILES() efficiencies[smiles] = eff keys = efficiencies.keys() keys.sort() return [(key, efficiencies[key]) for key in keys] f.write('entry(\n') f.write(' index = {0:d},\n'.format(entry.index)) if entry.label != '': f.write(' label = "{0}",\n'.format(entry.label)) #Entries for kinetic rules, libraries, training reactions #and depositories will have a Reaction object for its item if isinstance(entry.item, Reaction): #Write out additional data if depository or library #kinetic rules would have a Group object for its reactants instead of Species if isinstance(entry.item.reactants[0], Species): # Add degeneracy if the reaction is coming from a depository or kinetics library f.write(' degeneracy = {0:.1f},\n'.format(entry.item.degeneracy)) if entry.item.duplicate: f.write(' duplicate = {0!r},\n'.format(entry.item.duplicate)) if not entry.item.reversible: f.write(' reversible = {0!r},\n'.format(entry.item.reversible)) if entry.item.allow_pdep_route: f.write(' allow_pdep_route = {0!r},\n'.format(entry.item.allow_pdep_route)) if entry.item.elementary_high_p: f.write(' elementary_high_p = {0!r},\n'.format(entry.item.elementary_high_p)) if entry.item.allow_max_rate_violation: f.write(' allow_max_rate_violation = {0!r},\n'.format(entry.item.allow_max_rate_violation)) #Entries for groups with have a group or logicNode for its item elif isinstance(entry.item, Group): f.write(' group = \n') f.write('"""\n') f.write(entry.item.toAdjacencyList()) f.write('""",\n') elif isinstance(entry.item, LogicNode): f.write(' group = "{0}",\n'.format(entry.item)) else: raise DatabaseError("Encountered unexpected item of type {0} while saving database.".format(entry.item.__class__)) # Write kinetics if isinstance(entry.data, str): f.write(' kinetics = "{0}",\n'.format(entry.data)) elif entry.data is not None: efficiencies = None if hasattr(entry.data, 'efficiencies'): efficiencies = entry.data.efficiencies entry.data.efficiencies = dict(sortEfficiencies(entry.data.efficiencies)) kinetics = prettify(repr(entry.data)) kinetics = ' kinetics = {0},\n'.format(kinetics.replace('\n', '\n ')) f.write(kinetics) if hasattr(entry.data, 'efficiencies'): entry.data.efficiencies = efficiencies else: f.write(' kinetics = None,\n') # Write reference if entry.reference is not None: reference = entry.reference.toPrettyRepr() lines = reference.splitlines() f.write(' reference = {0}\n'.format(lines[0])) for line in lines[1:-1]: f.write(' {0}\n'.format(line)) f.write(' ),\n'.format(lines[0])) if entry.referenceType != "": f.write(' referenceType = "{0}",\n'.format(entry.referenceType)) if entry.rank is not None: f.write(' rank = {0},\n'.format(entry.rank)) if entry.shortDesc.strip() !='': f.write(' shortDesc = u"""') try: f.write(entry.shortDesc.encode('utf-8')) except: f.write(entry.shortDesc.strip().encode('ascii', 'ignore')+ "\n") f.write('""",\n') if entry.longDesc.strip() !='': f.write(' longDesc = \n') f.write('u"""\n') try: f.write(entry.longDesc.strip().encode('utf-8') + "\n") except: f.write(entry.longDesc.strip().encode('ascii', 'ignore')+ "\n") f.write('""",\n') f.write(')\n\n')
def save(self, outputFile): """ Save the results of the kinetics job to the file located at `path` on disk. """ reaction = self.reaction ks = [] k0s = [] k0revs = [] krevs = [] logging.info('Saving kinetics for {0}...'.format(reaction)) order = len(self.reaction.reactants) factor = 1e6 ** (order-1) f = open(outputFile, 'a') if self.usedTST: # If TST is not used, eg. it was given in 'reaction', then this will throw an error. f.write('# ======= =========== =========== =========== ===============\n') f.write('# Temp. k (TST) Tunneling k (TST+T) Units\n') f.write('# ======= =========== =========== =========== ===============\n') if self.Tlist is None: Tlist = numpy.array([300,400,500,600,800,1000,1500,2000]) else: Tlist =self.Tlist.value_si for T in Tlist: tunneling = reaction.transitionState.tunneling reaction.transitionState.tunneling = None try: k0 = reaction.calculateTSTRateCoefficient(T) * factor except SpeciesError: k0 = 0 reaction.transitionState.tunneling = tunneling try: k = reaction.calculateTSTRateCoefficient(T) * factor kappa = k / k0 except (SpeciesError,ZeroDivisionError): k = reaction.getRateCoefficient(T) kappa = 0 logging.info("The species in reaction {} do not have adequate information for TST, using default kinetics values.".format(reaction)) tunneling = reaction.transitionState.tunneling ks.append(k) k0s.append(k0) f.write('# {0:4g} K {1:11.3e} {2:11g} {3:11.3e} {4}\n'.format(T, k0, kappa, k, self.kunits)) f.write('# ======= =========== =========== =========== ===============\n') f.write('\n\n') f.write('# ======= ============ =========== ============ ============= =========\n') f.write('# Temp. Kc (eq) Units krev (TST) krev (TST+T) Units\n') f.write('# ======= ============ =========== ============ ============= =========\n') # Initialize Object for Converting Units if self.Kequnits != ' ': keq_unit_converter = quantity.Units(self.Kequnits).getConversionFactorFromSI() else: keq_unit_converter = 1 for n,T in enumerate(Tlist): k = ks[n] k0 = k0s[n] Keq = keq_unit_converter * reaction.getEquilibriumConstant(T) # getEquilibriumConstant returns SI units k0rev = k0/Keq krev = k/Keq k0revs.append(k0rev) krevs.append(krev) f.write('# {0:4g} K {1:11.3e} {2} {3:11.3e} {4:11.3e} {5}\n'.format(T, Keq, self.Kequnits, k0rev, krev, self.krunits)) f.write('# ======= ============ =========== ============ ============= =========\n') f.write('\n\n') kinetics0rev = Arrhenius().fitToData(Tlist, numpy.array(k0revs), kunits=self.krunits) kineticsrev = Arrhenius().fitToData(Tlist, numpy.array(krevs), kunits=self.krunits) f.write('# krev (TST) = {0} \n'.format(kinetics0rev)) f.write('# krev (TST+T) = {0} \n\n'.format(kineticsrev)) # Reaction path degeneracy is INCLUDED in the kinetics itself! string = 'kinetics(label={0!r}, kinetics={1!r})'.format(reaction.label, reaction.kinetics) f.write('{0}\n\n'.format(prettify(string))) f.close() # Also save the result to chem.inp f = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') reaction = self.reaction kinetics = reaction.kinetics string = '' if reaction.kinetics.comment: for line in reaction.kinetics.comment.split("\n"): string += "! {0}\n".format(line) string += '{0!s:51} {1:9.3e} {2:9.3f} {3:9.3f}\n'.format( reaction, kinetics.A.value_si * factor, kinetics.n.value_si, kinetics.Ea.value_si / 4184., ) f.write('{0}\n'.format(string)) f.close() # We're saving a YAML file for TSs iff structures of the respective reactant/s and product/s are known if all ([spc.molecule is not None and len(spc.molecule) for spc in self.reaction.reactants + self.reaction.products]): self.arkane_species.update_species_attributes(self.reaction.transitionState) self.arkane_species.reaction_label = reaction.label self.arkane_species.reactants = [{'label': spc.label, 'adjacency_list': spc.molecule[0].toAdjacencyList()} for spc in self.reaction.reactants] self.arkane_species.products = [{'label': spc.label, 'adjacency_list': spc.molecule[0].toAdjacencyList()} for spc in self.reaction.products] self.arkane_species.save_yaml(path=os.path.dirname(outputFile))
def save(self, outputFile): logging.info( 'Saving pressure dependence results for network {0}...'.format( self.network.label)) f = open(outputFile, 'a') f_chemkin = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') Nreac = self.network.Nisom + self.network.Nreac Nprod = Nreac + self.network.Nprod Tlist = self.Tlist.value_si Plist = self.Plist.value_si Tcount = Tlist.shape[0] Pcount = Plist.shape[0] count = 0 printed_reactions = [] # list of rxns already printed for prod in range(Nprod): for reac in range(Nreac): if reac == prod: continue reaction = self.network.netReactions[count] count += 1 # make sure we aren't double counting any reactions if not any([reaction.isIsomorphic(other_rxn,checkOnlyLabel=True) \ for other_rxn in printed_reactions]): duplicate = False # add reaction to printed reaction printed_reactions.append(reaction) else: # comment out the extra reverse reaction duplicate = True # write chemkin output. string = writeKineticsEntry(reaction, speciesList=None, verbose=False, commented=duplicate) f_chemkin.write('{0}\n'.format(string)) # write to 'output.py' kdata = self.K[:, :, prod, reac].copy() order = len(reaction.reactants) kdata *= 1e6**(order - 1) kunits = { 1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)' }[order] f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') f.write('# T \ P ') f.write(' '.join(['{0:11.3e}'.format(P * 1e-5) for P in Plist])) f.write('\n') f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') for t in range(Tcount): f.write('# {0:11g}'.format(Tlist[t])) for p in range(Pcount): f.write(' {0:11.3e}'.format(kdata[t, p])) f.write('\n') f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') string = 'pdepreaction(reactants={0!r}, products={1!r}, kinetics={2!r})'.format( [reactant.label for reactant in reaction.reactants], [product.label for product in reaction.products], reaction.kinetics, ) pdep_function = '{0}\n\n'.format(prettify(string)) if duplicate: # add comments to the start of the string pdep_function = '# ' + pdep_function.replace( '\n', '\n# ') f.write(pdep_function) f.close() f_chemkin.close()
def write_output(self, output_directory): """ Save the results of the kinetics job to the `output.py` file located in `output_directory`. """ reaction = self.reaction ks, k0s, k0_revs, k_revs = [], [], [], [] logging.info('Saving kinetics for {0}...'.format(reaction)) order = len(self.reaction.reactants) factor = 1e6**(order - 1) f = open(os.path.join(output_directory, 'output.py'), 'a') if self.usedTST: # If TST is not used, eg. it was given in 'reaction', then this will throw an error. f.write( '# ======= =========== =========== =========== ===============\n' ) f.write('# Temp. k (TST) Tunneling k (TST+T) Units\n') f.write( '# ======= =========== =========== =========== ===============\n' ) if self.Tlist is None: t_list = np.array([300, 400, 500, 600, 800, 1000, 1500, 2000]) else: t_list = self.Tlist.value_si for T in t_list: tunneling = reaction.transition_state.tunneling reaction.transition_state.tunneling = None try: k0 = reaction.calculate_tst_rate_coefficient(T) * factor except SpeciesError: k0 = 0 reaction.transition_state.tunneling = tunneling try: k = reaction.calculate_tst_rate_coefficient(T) * factor kappa = k / k0 except (SpeciesError, ZeroDivisionError): k = reaction.get_rate_coefficient(T) kappa = 0 logging.info( "The species in reaction {0} do not have adequate information for TST, " "using default kinetics values.".format(reaction)) tunneling = reaction.transition_state.tunneling ks.append(k) k0s.append(k0) f.write( '# {0:4g} K {1:11.3e} {2:11g} {3:11.3e} {4}\n'.format( T, k0, kappa, k, self.k_units)) f.write( '# ======= =========== =========== =========== ===============\n' ) f.write('\n\n') f.write( '# ======= ============ =========== ============ ============= =========\n' ) f.write( '# Temp. Kc (eq) Units k_rev (TST) k_rev (TST+T) Units\n' ) f.write( '# ======= ============ =========== ============ ============= =========\n' ) # Initialize Object for Converting Units if self.K_eq_units != ' ': keq_unit_converter = quantity.Units( self.K_eq_units).get_conversion_factor_from_si() else: keq_unit_converter = 1 for n, T in enumerate(t_list): k = ks[n] k0 = k0s[n] K_eq = keq_unit_converter * reaction.get_equilibrium_constant( T) # returns SI units k0_rev = k0 / K_eq k_rev = k / K_eq k0_revs.append(k0_rev) k_revs.append(k_rev) f.write( '# {0:4g} K {1:11.3e} {2} {3:11.3e} {4:11.3e} {5}\n' .format(T, K_eq, self.K_eq_units, k0_rev, k_rev, self.k_r_units)) f.write( '# ======= ============ =========== ============ ============= =========\n' ) f.write('\n\n') kinetics_0_rev = Arrhenius().fit_to_data(t_list, np.array(k0_revs), kunits=self.k_r_units) kinetics_rev = Arrhenius().fit_to_data(t_list, np.array(k_revs), kunits=self.k_r_units) f.write('# k_rev (TST) = {0} \n'.format(kinetics_0_rev)) f.write('# k_rev (TST+T) = {0} \n\n'.format(kinetics_rev)) # Reaction path degeneracy is INCLUDED in the kinetics itself! rxn_str = 'kinetics(label={0!r}, kinetics={1!r})'.format( reaction.label, reaction.kinetics) f.write('{0}\n\n'.format(prettify(rxn_str))) f.close()
def parse(self): """ Parse QChem output file and crate the variables the sampling job needed. """ Log = QChemLog(self.input_file) # Load force constant matrix self.hessian = Log.load_force_constant_matrix() # Load cartesian coordinate coordinates, number, mass = Log.load_geometry() # Create conformer class self.conformer, unscaled_frequencies = Log.load_conformer() # Define the sampling protocol if self.protocol is None: self.protocol = 'UMN' # Extract spin miltiplicity and number of optical isomers if self.spin_multiplicity is None: self.spin_multiplicity = self.conformer.spin_multiplicity # Extract net charge from QChem output file if self.charge is None: self.charge = Log.charge # Determine wheteher `UNRESTRICTED` variable should be used or not in QChem calculation self.unrestricted = Log.is_unrestricted() # Log some information related to QM/MM system self.is_QM_MM_INTERFACE = Log.is_QM_MM_INTERFACE() if self.is_QM_MM_INTERFACE: self.QM_ATOMS = Log.get_QM_ATOMS() self.ISOTOPES = Log.get_ISOTOPES() self.nHcap = len(self.ISOTOPES) self.force_field_params = Log.get_force_field_params() self.opt = Log.get_opt() self.fixed_molecule_string = Log.get_fixed_molecule() self.QM_USER_CONNECT = Log.get_QM_USER_CONNECT() self.QM_mass = Log.QM_mass self.QM_coord = Log.QM_coord self.natom = len(self.QM_ATOMS) + len(self.ISOTOPES) self.symbols = Log.QM_atom self.cart_coords = self.QM_coord.reshape(-1, ) self.conformer.coordinates = (self.QM_coord, "angstroms") self.conformer.number = number[:self.natom] self.conformer.mass = (self.QM_mass, "amu") xyz = '' for i in range(len(self.QM_ATOMS)): if self.QM_USER_CONNECT[i].endswith('0 0 0 0'): xyz += '{}\t{}\t\t{}\t\t{}'.format( self.symbols[i], self.cart_coords[3 * i], self.cart_coords[3 * i + 1], self.cart_coords[3 * i + 2]) if i != self.natom - 1: xyz += '\n' self.xyz = xyz if self.ncpus is None: raise InputError('Lack of defining the number of cpu used.') self.zpe = Log.load_zero_point_energy() if self.addcart is None and self.addtr is None and self.add_interfragment_bonds is None: self.addtr = True else: self.nHcap = 0 self.natom = Log.get_number_of_atoms() self.symbols = [symbol_by_number[i] for i in number] self.cart_coords = coordinates.reshape(-1, ) self.conformer.coordinates = (coordinates, "angstroms") self.conformer.number = number self.conformer.mass = (mass, "amu") self.xyz = getXYZ(self.symbols, self.cart_coords) if self.ncpus is None: raise InputError('Lack of defining the number of cpu used.') self.zpe = Log.load_zero_point_energy() # Determine whether or not the species is linear from its 3D coordinates self.linearity = is_linear(self.conformer.coordinates.value) # Determine hindered rotors information if self.protocol == 'UMVT': if self.rotors is not None: logging.info('Find user defined rotors...') self.rotors_dict = self.rotors else: logging.info('Determing the rotors of {}...'.format( self.label)) self.rotors_dict = self.get_rotors_dict() if self.rotors_dict == {}: logging.info( 'No internal rotations are found for {label}'.format( label=self.label)) else: logging.info('==========================================') logging.info(' Hindered Rotors ') logging.info('==========================================') logging.info(prettify(str(self.rotors_dict))) logging.info('-----------------------------------------\n') self.n_rotors = len(self.rotors_dict) elif self.protocol == 'UMN': self.rotors_dict = [] self.n_rotors = 0 else: raise InputError( 'The protocol of {protocol} is invalid. Please use UMVT or UMN.' .format(protocol=self.protocol)) # Determine whether this system is QM/MM system if self.is_QM_MM_INTERFACE: self.nmode = 3 * len(Log.get_QM_ATOMS()) - (1 if self.is_ts else 0) self.n_vib = 3 * len(Log.get_QM_ATOMS()) - self.n_rotors - ( 1 if self.is_ts else 0) else: self.nmode = 3 * self.natom - (5 if self.linearity else 6) - (1 if self.is_ts else 0) self.n_vib = 3 * self.natom - ( 5 if self.linearity else 6) - self.n_rotors - (1 if self.is_ts else 0) # Create RedundantCoords object if self.is_ts and self.addcart is None and self.addtr is None and self.add_interfragment_bonds is None: self.addcart = True self.internal = get_RedundantCoords( self.label, self.symbols, self.cart_coords / BOHR2ANG, self.bond_factor, nHcap=self.nHcap, add_hrdrogen_bonds=False, addcart=self.addcart, addtr=self.addtr, add_interfragment_bonds=self.add_interfragment_bonds) # Create RedundantCoords object for torsional mode if self.protocol == 'UMVT': self.torsion_internal = get_RedundantCoords( self.label, self.symbols, self.cart_coords / BOHR2ANG, self.bond_factor, self.rotors_dict, self.nHcap, add_hrdrogen_bonds=False, addcart=False, addtr=False, add_interfragment_bonds=True) # Extract imaginary frequency from transition state if self.is_ts: self.imaginary_frequency = Log.load_negative_frequency() # Determine max_loop if self.nnl is not None: self.max_nloop = int(1 / self.step_size_factor) * self.nnl else: self.max_nloop = 200 # The basis used in freq job, which will be used in OptVib job self.freq_basis, self.freq_gen_basis = Log.get_basis()
def save(self, outputFile): logging.info('Saving pressure dependence results for network {0}...'.format(self.network.label)) f = open(outputFile, 'a') f_chemkin = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') Nreac = self.network.Nisom + self.network.Nreac Nprod = Nreac + self.network.Nprod Tlist = self.Tlist.value_si Plist = self.Plist.value_si Tcount = Tlist.shape[0] Pcount = Plist.shape[0] f.write("#Thermo used: \n") spcs = [] for rxn in self.network.pathReactions: spcs.extend(rxn.reactants) spcs.extend(rxn.products) for spc in spcs: if spc.thermo: f.write("#"+spc.label+" SMILES: "+spc.molecule[0].toSMILES()+"\n") f.write("#"+spc.thermo.comment+"\n") f.write("\n#Path Reactions used: \n") for rxn in self.network.pathReactions: if rxn.kinetics: f.write("#"+str(rxn)+"\n") for s in rxn.kinetics.comment.split("\n"): f.write("#"+s+"\n") f.write("\n") count = 0 printed_reactions = [] # list of rxns already printed for prod in range(Nprod): for reac in range(Nreac): if reac == prod: continue reaction = self.network.netReactions[count] count += 1 # make sure we aren't double counting any reactions if not any([reaction.isIsomorphic(other_rxn,checkOnlyLabel=True) \ for other_rxn in printed_reactions]): duplicate = False # add reaction to printed reaction printed_reactions.append(reaction) else: # comment out the extra reverse reaction duplicate = True # write chemkin output. string = writeKineticsEntry(reaction, speciesList=None, verbose=False, commented = duplicate) f_chemkin.write('{0}\n'.format(string)) # write to 'output.py' kdata = self.K[:,:,prod,reac].copy() order = len(reaction.reactants) kdata *= 1e6 ** (order-1) kunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order] f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') f.write('# T \ P ') f.write(' '.join(['{0:11.3e}'.format(P*1e-5) for P in Plist])) f.write('\n') f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') for t in range(Tcount): f.write('# {0:11g}'.format(Tlist[t])) for p in range(Pcount): f.write(' {0:11.3e}'.format(kdata[t,p])) f.write('\n') f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') string = 'pdepreaction(reactants={0!r}, products={1!r}, kinetics={2!r})'.format( [reactant.label for reactant in reaction.reactants], [product.label for product in reaction.products], reaction.kinetics, ) pdep_function = '{0}\n\n'.format(prettify(string)) if duplicate: # add comments to the start of the string pdep_function = '# ' + pdep_function.replace('\n','\n# ') f.write(pdep_function) f.close() f_chemkin.close()