def cent_dist_const_reader(output_string): """ Get the quartic centrifugal distortion constants """ # block block = apf.last_capture( ('Quartic Centrifugal Distortion Constants Tau Prime' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Asymmetric Top Reduction'), output_string) if not block: block = apf.last_capture( ('Quartic Centrifugal Distortion Constants Tau Prime' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Constants in the Symmetrically Reduced Hamiltonian'), output_string) if not block: block = apf.last_capture( ('Quartic Centrifugal Distortion Constants Tau Prime' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Rotational l-type doubling constants'), output_string) # pattern pattern = ('TauP' + app.SPACE + app.capturing(app.one_or_more(app.LOWERCASE_LETTER)) + app.SPACES + app.capturing(app.EXPONENTIAL_FLOAT_D) + app.SPACES + app.EXPONENTIAL_FLOAT_D) # Get list of values cent_dist_const = [[lbl, float(val.replace('D', 'E'))] for (lbl, val) in apf.all_captures(pattern, block)] return cent_dist_const
def centrifugal_distortion_constants(output_str): """ Reads the VPT2-computed quartic centrifugal distortion constants from the output file string. Returns the constants in _. :param output_str: string of the program's output file :type output_str: str :rtype: tuple(tuple(float)) """ # Set patterns for all molecule types and symmetries block = apf.last_capture( ('Quartic Centrifugal Distortion Constants Tau Prime' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Asymmetric Top Reduction'), output_str) if not block: block = apf.last_capture( ('Quartic Centrifugal Distortion Constants Tau Prime' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Constants in the Symmetrically Reduced Hamiltonian'), output_str) if not block: block = apf.last_capture( ('Quartic Centrifugal Distortion Constants Tau Prime' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Rotational l-type doubling constants'), output_str) # Read values pattern = ('TauP' + app.SPACE + app.capturing(app.one_or_more(app.LOWERCASE_LETTER)) + app.SPACES + app.capturing(app.EXPONENTIAL_FLOAT_D) + app.SPACES + app.EXPONENTIAL_FLOAT_D) cent_dist_const = [[lbl, float(val.replace('D', 'E'))] for (lbl, val) in apf.all_captures(pattern, block)] return cent_dist_const
def quartic_force_constants(output_str): """ Reads the quartic force constants from the output file string. Returns the constants in _. Hartree*amu(2)*Bohr(-4) :param output_str: string of the program's output file :type output_str: str :rtype: tuple(tuple(float)) """ block = apf.last_capture( ('QUARTIC FORCE CONSTANTS IN NORMAL MODES' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Input to Restart Anharmonic Calculations'), output_str) if block is None: block = apf.last_capture( ('QUARTIC FORCE CONSTANTS IN NORMAL MODES' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Input for POLYMODE'), output_str) pattern = (app.capturing(app.INTEGER) + app.SPACES + app.capturing(app.INTEGER) + app.SPACES + app.capturing(app.INTEGER) + app.SPACES + app.capturing(app.INTEGER) + app.SPACES + app.FLOAT + app.SPACES + app.FLOAT + app.SPACES + app.capturing(app.FLOAT)) caps = apf.all_captures(pattern, block) if caps: qfc_mat = _fc_mat(caps) else: qfc_mat = None return qfc_mat
def irc_path(output_str): """ Reads the coordinates and electronic energies (relative to saddple point) of the Intrinsic Reaction Coordinate. :param output_str: string of the program's output file :type output_str: str :rtype: tuple(automol geom data structure) """ # coordinates block = apf.last_capture( (app.escape('@IRC **** IRC Steps ****') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('---Fragment 1 Intrafragment Coordinates---')), output_str) pattern = ( app.escape('@IRC') + app.SPACES + app.INTEGER + app.SPACES + app.FLOAT + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.FLOAT + app.SPACES + app.LINE_FILL ) captures = apf.all_captures(pattern, block) if captures is not None: # Remove duplicates that may appear because of Psi4 output printing unique_coords = [] for coord in captures: if coord not in unique_coords: unique_coords.append(coord) coords = [float(coord) for coord in unique_coords] else: coords = None # energies block = apf.last_capture( (app.escape('@IRC **** IRC Report ****') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('@IRC **** IRC Steps ****')), output_str) pattern = ( app.escape('@IRC') + app.SPACES + app.INTEGER + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.FLOAT ) captures = apf.all_captures(pattern, block) if captures is not None: energies = [float(capture) for capture in captures] else: energies = None return (coords, energies)
def irc_path(output_string): """ get the coordinates and energies relative to the saddle point """ # coordinates block = apf.last_capture( (app.escape('@IRC **** IRC Steps ****') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('---Fragment 1 Intrafragment Coordinates---')), output_string) pattern = ( app.escape('@IRC') + app.SPACES + app.INTEGER + app.SPACES + app.FLOAT + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.FLOAT + app.SPACES + app.LINE_FILL ) captures = apf.all_captures(pattern, block) if captures is not None: # Remove duplicates that may appear because of Psi4 output printing unique_coords = [] for coord in captures: if coord not in unique_coords: unique_coords.append(coord) coords = [float(coord) for coord in unique_coords] else: coords = None # energies block = apf.last_capture( (app.escape('@IRC **** IRC Report ****') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('@IRC **** IRC Steps ****')), output_string) pattern = ( app.escape('@IRC') + app.SPACES + app.INTEGER + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.FLOAT ) captures = apf.all_captures(pattern, block) if captures is not None: energies = [float(capture) for capture in captures] else: energies = None return (coords, energies)
def opt_geometry(output_str): """ Reads the optimized molecular geometry (in Cartesian coordinates) from the output file string. Returns the geometry in Bohr. :param output_str: string of the program's output file :type output_str: str :rtype: automol molecular geometry data structure """ geo = None # Read the block of text with the geometry opt_block_ptt = ( app.escape('** OPTIMIZATION CONVERGED **') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Z-matrix Print:') opt_block = apf.last_capture(opt_block_ptt, output_str) # Read the geometry info if opt_block is not None: nums, xyzs = ar.geom.read(output_str, start_ptt=app.padded(app.NEWLINE).join([ app.escape('Coordinates (Angstroms)'), app.LINE, '' ]), line_start_ptt=app.UNSIGNED_INTEGER) if all(x is not None for x in (nums, xyzs)): symbs = tuple(map(ptab.to_symbol, nums)) geo = automol.geom.from_data(symbs, xyzs, angstrom=True) return geo
def _read_irc_reaction_path_summary(output_string, read_val): """ get the desired values from the reaction path summary block """ assert read_val in ('energy', 'coord') block = apf.last_capture( (app.escape('Summary of reaction path following') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('Total number of points:') + app.SPACES + app.INTEGER), output_string) if read_val == 'energy': pattern = (app.INTEGER + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.FLOAT) elif read_val == 'coord': pattern = (app.INTEGER + app.SPACES + app.FLOAT + app.SPACES + app.capturing(app.FLOAT)) captures = apf.all_captures(pattern, block) if captures is not None: values = [float(capture) for capture in captures] else: values = None return values
def _read_irc_reaction_path_summary(output_str, read_val): """ Reads the values for the Intrinsic Reaction Path from the table. :param output_str: string of the program's output file :type output_str: str :param read_val: value to read from table :type read_val: str :rtype: tuple(automol geom data structure) """ assert read_val in ('energy', 'coord') block = apf.last_capture( (app.escape('Summary of reaction path following') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('Total number of points:') + app.SPACES + app.INTEGER), output_str) if read_val == 'energy': pattern = (app.INTEGER + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.FLOAT) elif read_val == 'coord': pattern = (app.INTEGER + app.SPACES + app.FLOAT + app.SPACES + app.capturing(app.FLOAT)) captures = apf.all_captures(pattern, block) if captures is not None: values = [float(capture) for capture in captures] else: values = None return values
def anharmonic_frequencies_reader(output_string): """ Get the anharmonic vibrational frequencies """ # block block = apf.last_capture( (app.escape('Fundamental Bands (DE w.r.t. Ground State)') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('Overtones (DE w.r.t. Ground State)')), output_string) pattern = (app.INTEGER + app.escape('(1)') + app.SPACE + app.maybe(app.one_or_more(app.LOWERCASE_LETTER)) + app.one_or_more(app.SPACE) + app.FLOAT + app.one_or_more(app.SPACE) + app.capturing(app.FLOAT)) # pattern2 = ( # app.INTEGER + # app.escape('(1)') + # app.SPACE + # app.maybe(app.one_or_more(app.LOWERCASE_LETTER)) + # app.one_or_more(app.SPACE) + # app.FLOAT + # app.one_or_more(app.SPACE) + # app.capturing(app.FLOAT) + # app.one_or_more(app.SPACE) + # app.one_or_more(app.escape('*')) + # app.one_or_more(app.SPACE) + # app.one_or_more(app.escape('*')) + # app.one_or_more(app.SPACE) + # app.FLOAT # ) # Get list of values anharm_freq = [float(val) for val in apf.all_captures(pattern, block)] return sorted(anharm_freq)
def polarizability(output_str): """ Reads the xyz-components of an SCF-computed polarizability tensor from the output file string. Returns the polarizability in _. :param output_str: string of the program's output file :type output_str: str :rtype: float """ pattern = ('Exact polarizability:' + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT)) captures = apf.last_capture(pattern, output_str) vals = captures if captures is not None else [] if vals: vals = [float(val) for val in vals] tensor = np.array([[vals[0], vals[1], vals[3]], [vals[1], vals[2], vals[4]], [vals[3], vals[4], vals[5]]]) else: tensor = None return tensor
def anharm_zpve_reader(output_string): """ Get the anharmonic ZPVE """ anharm_zpve_pattern = ('Total Anharm' + app.one_or_more(app.SPACE) + ':' + app.SPACE + 'cm-1' + app.SPACE + '=' + app.one_or_more(app.SPACE) + app.FLOAT + app.SPACE + ';' + app.SPACE + 'Kcal/mol' + app.SPACE + '=' + app.one_or_more(app.SPACE) + app.FLOAT + app.SPACE + ';' + app.SPACE + 'KJ/mol' + app.SPACE + '=' + app.one_or_more(app.SPACE) + app.capturing(app.FLOAT)) # Set the string pattern containing the anharm ZPVE # anharm_zpve_pattern = ( # app.escape('ZPE(harm) = ') + # app.EXPONENTIAL_FLOAT_D + # app.one_or_more(app.SPACE) + # 'kJ/mol' + # app.one_or_more(app.SPACE) + # app.escape('ZPE(anh)=') + # app.one_or_more(app.SPACE) + # app.capturing(app.EXPONENTIAL_FLOAT_D) + # app.one_or_more(app.SPACE) + # 'kJ/mol' # ) # Retrieve the anharm ZPVE anh_zpve = apf.last_capture(anharm_zpve_pattern, output_string) # Format the ZPVE anh_zpve = float(anh_zpve.replace('D', 'E')) anh_zpve *= KJ2EH return anh_zpve
def cubic_force_constants(output_str): """ Reads the cubic force constants from the output file string. Returns the constants in _. Hartree*amu(-3/2)*Bohr(-3) :param output_str: string of the program's output file :type output_str: str :rtype: tuple(tuple(float)) """ block = apf.last_capture( ('CUBIC FORCE CONSTANTS IN NORMAL MODES' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'QUARTIC FORCE CONSTANTS IN NORMAL MODES'), output_str) pattern = (app.capturing(app.INTEGER) + app.SPACES + app.capturing(app.INTEGER) + app.SPACES + app.capturing(app.INTEGER) + app.SPACES + app.FLOAT + app.SPACES + app.FLOAT + app.SPACES + app.capturing(app.FLOAT)) caps = apf.all_captures(pattern, block) if caps: cfc_mat = _fc_mat(caps) else: cfc_mat = None return cfc_mat
def anharmonic_zpve(output_str): """ Reads the VPT2-computed anharmonic zero-point vibrational energy from the output file string. Returns the energy in Hartrees. :param output_str: string of the program's output file :type output_str: str :rtype: float """ anharm_zpve_pattern = ('Total Anharm' + app.one_or_more(app.SPACE) + ':' + app.SPACE + 'cm-1' + app.SPACE + '=' + app.one_or_more(app.SPACE) + app.FLOAT + app.SPACE + ';' + app.SPACE + 'Kcal/mol' + app.SPACE + '=' + app.one_or_more(app.SPACE) + app.FLOAT + app.SPACE + ';' + app.SPACE + 'KJ/mol' + app.SPACE + '=' + app.one_or_more(app.SPACE) + app.capturing(app.FLOAT)) # Retrieve the anharm ZPVE anh_zpve = apf.last_capture(anharm_zpve_pattern, output_str) # Convert the ZPVE units anh_zpve = float(anh_zpve.replace('D', 'E')) anh_zpve *= phycon.KJ2EH return anh_zpve
def irc_path(output_str): """ Reads the coordinates and electronic energies (relative to saddple point) of the Intrinsic Reaction Coordinate summarized at the end of the output file. oint. Returns the energy in Hartress. :param output_str: string of the program's output file :type output_str: str :rtype: tuple(automol geom data structure) """ # Reads the coordiantes coordinates = _read_irc_reaction_path_summary(output_str, 'coord') # Reads the energies (the ts/sadpt) ptt = ('Energies reported relative to the TS energy of' + app.SPACES + app.capturing(app.FLOAT)) ts_energy = apf.last_capture(ptt, output_str) pt_energies = _read_irc_reaction_path_summary(output_str, 'energy') if ts_energy and pt_energies: energies = [float(ts_energy) + ene for ene in pt_energies] # See if the enes need to be flipped so the ts ene is first if pt_energies[0] != 0.0: coordinates = coordinates[::-1] energies = energies[::-1] return (coordinates, energies)
def irc_points(output_string): """ obtain the geometry, gradient, and hessian at each point along the irc """ # Set pattern to find the end of each IRC optimization pattern = app.escape('@IRC **** Point ' + app.INTEGER + ' on IRC path is optimized ****') block = apf.last_capture( (pattern + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape(' Back-transformation to cartesian coordinates...')), output_string) # Set pattern for grabbing the geometry from the block geo_head_ptt = (app.escape('@IRC Cartesian Geometry (in Angstrom)') + app.LINE_FILL + '\n') # Grab all of the optimized geometries captures = apf.all_captures(pattern, block) if captures is not None: geoms = [] for string in captures: syms, xyzs = ar.geom.read(string, start_ptt=geo_head_ptt, line_start_ptt=app.escape('@IRC')) geoms.append(automol.geom.from_data(syms, xyzs, angstrom=True)) else: geoms = [] # Set the gradients and hessians to empty lists since they MAY not be run grads, hessians = [], [] return geoms, grads, hessians
def gradient(output_string): """ read gradient from the output string """ # Grab a block of text containing the gradient block_ptt = ('Molecular gradient' + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + 'Molecular gradient norm') block = apf.last_capture(block_ptt, output_string) # Trim the block to start it at the gradient lines blank_count = 0 for i, line in enumerate(block.splitlines()): if line.strip() == '': blank_count += 1 if blank_count == 3: grad_start = i break trim_block = '\n'.join(block.splitlines()[grad_start:]) # Grab the gradient from the trimmed block string grad = ar.matrix.read( trim_block, line_start_ptt=app.LINESPACES.join([ app.LETTER, app.escape('#') + app.UNSIGNED_INTEGER, app.maybe(app.UNSIGNED_INTEGER)])) print(grad) assert numpy.shape(grad)[1] == 3 return grad
def program_version(output_string): """ Read the version """ pattern = ('OneDMin' + app.SPACES + 'version' + app.SPACES + app.capturing(app.FLOAT)) capture = apf.last_capture(pattern, output_string) return capture
def dipole_moment(output_string): """ Reads the dipole moment """ pattern = (app.escape('Dipole moment (field-independent basis, Debye):') + app.NEWLINE + app.padded('X=') + app.capturing(app.FLOAT) + app.padded('Y=') + app.capturing(app.FLOAT) + app.padded('Z=') + app.capturing(app.FLOAT)) vals = [float(val) for val in apf.last_capture(pattern, output_string)] return vals
def get_hform_298k_thermp(output_string): """ Obtains deltaHf from thermp output """ # Line pattern containing the DeltaHf value at 298 K dhf298_pattern = ('h298 final' + app.one_or_more(app.SPACE) + app.capturing(app.FLOAT)) dhf298 = float(apf.last_capture(dhf298_pattern, output_string)) return dhf298
def dipole_moment(output_string): """ Reads the dipole moment """ pattern = app.padded((app.LINESPACES.join( [app.escape('Dipole moment [Debye]:'), app.FLOAT])) + app.NEWLINE + app.padded('x=') + app.capturing(app.FLOAT) + app.padded('y=') + app.capturing(app.FLOAT) + app.padded('z=') + app.capturing(app.FLOAT)) vals = [float(val) for val in apf.last_capture(pattern, output_string)] return vals
def diagonal_born_oppenheimer_correction(output_str): """ DBOC """ ptt = ('The total diagonal Born-Oppenheimer correction (DBOC) is:' + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + 'a.u.') cap = apf.last_capture(ptt, output_str) val = float(cap) if cap is not None else None return val
def dipole_moment(output_string): """ Reads the dipole moment """ pattern = app.LINESPACES.join([ 'Total Dipole Moment', ':', app.capturing(app.FLOAT), app.capturing(app.FLOAT), app.capturing(app.FLOAT) ]) vals = [float(val) for val in apf.last_capture(pattern, output_string)] return vals
def _end_file_energy(output_string): # end_file_ptt = ( # method + app.escape('/') + BASIS_PATTERN + # app.escape('//') + # app.one_or_more(app.NONNEWLINE) + # 'energy=') end_file_ptt = ('MOLPRO_ENERGY' + app.SPACES + app.escape('=') + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + 'AU') ene = apf.last_capture(end_file_ptt, output_string) ene = float(ene) if ene is not None else ene return ene
def relativistic_energy(output_str): """ Read a relativistic energy """ # 'relativistic' for MVD1 methods = app.one_of_these(['DPT', 'MVD2', 'relativistic']) ptt = ('Total energy with' + app.SPACE + methods + app.SPACE + 'correction:' + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + 'Hartree') cap = apf.last_capture(ptt, output_str) val = float(cap) if cap is not None else None return val
def irc_energies(output_string): """ get the energies relative to the saddle point """ # Read the reference energy (the ts/sadpt) ptt = ('Energies reported relative to the TS energy of' + app.SPACES + app.capturing(app.FLOAT)) ts_energy = apf.last_capture(ptt, output_string) pt_energies = _read_irc_reacion_path_summary(output_string, 'energy') if ts_energy and pt_energies: energies = [float(ts_energy) + ene for ene in pt_energies] # See if the enes need to be flipped so the ts ene is first if pt_energies[0] != 0.0: energies = energies[::-1] return energies
def _end_file_energy(output_str): """ Reads a user-defined electronic energy in the output string that has be given the variable name is MOLPRO_ENERGY. Returns the energy in Hartrees. """ end_file_ptt = ( 'MOLPRO_ENERGY' + app.SPACES + app.escape('=') + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + 'AU' ) ene = apf.last_capture(end_file_ptt, output_str) ene = float(ene) if ene is not None else ene return ene
def dipole_moment(output_string): """ Reads the dipole moment """ pattern = (app.escape('Dipole moment (field-independent basis, Debye):') + app.LINE_FILL + app.NEWLINE + app.padded('X=') + app.capturing(app.FLOAT) + app.padded('Y=') + app.capturing(app.FLOAT) + app.padded('Z=') + app.capturing(app.FLOAT)) captures = apf.last_capture(pattern, output_string) vals = captures if captures is not None else [] if vals: vals = [float(val) for val in vals] else: vals = None return vals
def dipole_moment(output_string): """ Reads the dipole moment """ pattern = app.LINESPACES.join([ 'Total Dipole Moment', ':', app.capturing(app.FLOAT), app.capturing(app.FLOAT), app.capturing(app.FLOAT) ]) captures = apf.last_capture(pattern, output_string) vals = captures if captures is not None else [] if vals: vals = [float(val) for val in vals] else: vals = None return vals
def polarizability(output_string): """ Reads the static polarizability """ pattern = ('Exact polarizability:' + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT)) vals = [float(val) for val in apf.last_capture(pattern, output_string)] tensor = np.array([[vals[0], vals[1], vals[3]], [vals[1], vals[2], vals[4]], [vals[3], vals[4], vals[5]]]) return tensor
def irc_energies(output_string): """ get the energies relative to the saddle point """ block = apf.last_capture( (app.escape('@IRC **** IRC Report ****') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('@IRC **** IRC Steps ****')), output_string) pattern = (app.escape('@IRC') + app.SPACES + app.INTEGER + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.FLOAT) captures = apf.all_captures(pattern, block) if captures is not None: energies = [float(capture) for capture in captures] else: energies = None return energies