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 plog_parameters(rxn_dstr): """ gets parameters associated with plog strings """ pattern = ('PLOG' + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.zero_or_more(app.SPACE) + app.escape('/')) params_lst = apf.all_captures(pattern, rxn_dstr) # Build dictionary of parameters, indexed by parameter if params_lst: params_dct = {} for params in params_lst: pressure = float(params[0]) vals = list(map(float, params[1:])) params_dct[pressure] = vals # if pressure not in params_dct: # params_dct[pressure] = [vals] # else: # params_dct[pressure].append(vals) else: params_dct = None return params_dct
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 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 zpves(output_string): """ Reads the zero-point energies for each of the hindered rotors from MESS output file string. :param output_string: string of lines of MESS output file :type output_string: str :return zpves: zero-point energy for each of the rotors :rtype: list(float) """ # Patterns for the ZPVE of a rotor num_patterns = (app.EXPONENTIAL_FLOAT, app.FLOAT) pattern1 = (app.escape('minimum energy[kcal/mol]') + app.one_or_more(app.SPACE) + '=' + app.one_or_more(app.SPACE) + app.capturing(app.one_of_these(num_patterns))) pattern2 = (app.escape('ground energy [kcal/mol]') + app.one_or_more(app.SPACE) + '=' + app.one_or_more(app.SPACE) + app.capturing(app.one_of_these(num_patterns))) # Obtain each ZPVE from the output string tmp1 = [-float(val) for val in apf.all_captures(pattern1, output_string)] tmp2 = [float(val) for val in apf.all_captures(pattern2, output_string)] tors_zpes = [sum(tmp) for tmp in zip(tmp1, tmp2)] # print('tors_zpes calc test:', tmp1, tmp2, tors_zpes) return tors_zpes
def troe(rxn_str): """ Parses the data string for a reaction in the reactions block for a line containing the Troe fitting parameters, then reads the parameters from this line. Only gets the 4 Troe-specific parameters: alpha, T***, T*, and T** :param rxn_str: raw Chemkin string for a single reaction :type rxn_str: str :return params: Troe fitting parameters :rtype: list(float) """ pattern = ( 'TROE' + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.maybe(app.one_or_more(app.SPACE) + app.capturing(app.NUMBER)) + app.zero_or_more(app.SPACE) + app.escape('/')) cap1 = apf.first_capture(pattern, rxn_str) if cap1 is not None: params = [] for val in cap1: if val is not None: params.append(float(val)) else: params.append(None) else: params = None return params
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 plog_parameters(rxn_dstr): """ Parses the data string for a reaction in the reactions block for the lines containing the PLog fitting parameters, then reads the parameters from these lines. :param rxn_dstr: data string for species in reaction block :type rxn_dstr: str :return params: PLog fitting parameters :rtype: dict[pressure: params] """ pattern = ('PLOG' + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.zero_or_more(app.SPACE) + app.escape('/')) params_lst = apf.all_captures(pattern, rxn_dstr) # Build dictionary of parameters, indexed by parameter if params_lst: params_dct = {} for params in params_lst: pressure = float(params[0]) vals = list(map(float, params[1:])) if pressure not in params_dct: params_dct[pressure] = [vals] else: params_dct[pressure].append(vals) else: params_dct = None return params_dct
def low_p(rxn_str, ea_units, a_units): """ Parses the data string for a reaction in the reactions block for a line containing the low-pressure fitting parameters, then reads the parameters from this line. :param rxn_str: raw Chemkin string for a single reaction :type rxn_str: str :param ea_units: units of activation energies :type ea_units: string :param a_units: units of rate constants; either 'moles' or 'molecules' :type a_units: str :return params: Arrhenius fitting parameters for low-P rates :rtype: list(list(float)) """ pattern = ('LOW' + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.zero_or_more(app.SPACE) + app.escape('/')) cap1 = apf.first_capture(pattern, rxn_str) if cap1 is not None: params = [float(val) for val in cap1] # Convert the units of Ea and A ea_conv_factor = get_ea_conv_factor(ea_units) a_conv_factor = get_a_conv_factor(rxn_str, a_units) params[2] = params[2] * ea_conv_factor params[0] = params[0] * a_conv_factor params = [params] # convert to list inside a list else: params = None return params
def low_p_parameters(rxn_dstr, ea_units, a_units): """ Parses the data string for a reaction in the reactions block for a line containing the low-pressure fitting parameters, then reads the parameters from this line. :param rxn_dstr: data string for species in reaction block :type rxn_dstr: str :return params: Arrhenius fitting parameters for low-P rates :rtype: list(float) """ pattern = ('LOW' + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.zero_or_more(app.SPACE) + app.escape('/')) cap1 = apf.first_capture(pattern, rxn_dstr) if cap1 is not None: params = [float(val) for val in cap1] # Convert the units of Ea and A ea_conv_factor = get_ea_conv_factor(rxn_dstr, ea_units) a_conv_factor = get_a_conv_factor(rxn_dstr, a_units) params[2] = params[2] * ea_conv_factor params[0] = params[0] * a_conv_factor else: params = None return params
def troe_parameters(rxn_dstr): """ Parses the data string for a reaction in the reactions block for a line containing the Troe fitting parameters, then reads the parameters from this line. :param rxn_dstr: data string for species in reaction block :type rxn_dstr: str :return params: Troe fitting parameters :rtype: list(float) """ pattern = ( 'TROE' + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.maybe(app.one_or_more(app.SPACE) + app.capturing(app.NUMBER)) + app.zero_or_more(app.SPACE) + app.escape('/')) cap1 = apf.first_capture(pattern, rxn_dstr) if cap1 is not None: params = [] for val in cap1: if val is not None: params.append(float(val)) else: params.append(None) else: params = None return params
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 zero_point_vibrational_energies(output_str): """ Reads the zero-point energies for each of the hindered rotors from MESS output file string. :param output_str: string of lines of MESS output file :type output_str: str :return zpves: zero-point energy for each of the rotors :rtype: list(float) """ # Patterns for the ZPVE of a rotor num_patterns = (app.EXPONENTIAL_FLOAT, app.FLOAT, app.INTEGER) pattern1 = (app.escape('minimum energy[kcal/mol]') + app.one_or_more(app.SPACE) + '=' + app.one_or_more(app.SPACE) + app.capturing(app.one_of_these(num_patterns))) pattern2 = (app.escape('ground energy [kcal/mol]') + app.one_or_more(app.SPACE) + '=' + app.one_or_more(app.SPACE) + app.capturing(app.one_of_these(num_patterns))) # Obtain each ZPVE from the output string tmp1 = tuple(-float(val) for val in apf.all_captures(pattern1, output_str)) tmp2 = tuple(float(val) for val in apf.all_captures(pattern2, output_str)) tors_zpves = [sum(tmp) for tmp in zip(tmp1, tmp2)] # Convert to Hartrees for i, _ in enumerate(tors_zpves): tors_zpves[i] *= phycon.KCAL2EH return tuple(tors_zpves)
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 grid_min_freqs(output_string): """ Reads the analytic frequencies for each of the hindered rotors from MESS output file string. Frequency corresponds to the minimum from the minimum on the grid of the user supplied hindered rotor potential in the input. :param output_string: string of lines of MESS output file :type output_string: str :return freqs: frequency for each of the rotors :rtype: list(float) """ # Pattern for the frequency of a rotor pattern = (app.escape('first point frequency estimate =') + app.one_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.one_or_more(app.SPACE) + app.escape('1/cm')) # Obtain each frequency from the output string tors_freqs = [ float(val) for val in apf.all_captures(pattern, output_string) ] print('tors freqs test in grid_min_freq:', tors_freqs) return tors_freqs
def get_defined_species(inp_str): """ gets a list which specifies what species have been defined """ species_def_pattern = ('species' + one_or_more(SPACE) + capturing(one_or_more(NONSPACE))) defined_species = all_captures(species_def_pattern, inp_str) return defined_species
def _get_level_section(input_string, level): """ species input """ pattern = ('level' + one_or_more(SPACE) + level + capturing(one_or_more(WILDCARD, greedy=False)) + 'end') section = first_capture(pattern, input_string) return section
def get_defined_lvls(inp_str): """ gets a list which specifies what levels have been defined """ levels_def_pattern = ('level' + one_or_more(SPACE) + capturing(one_or_more(NONSPACE))) defined_levels = all_captures(levels_def_pattern, inp_str) return defined_levels
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 get_task_str(inp_str, task): """ species input """ # Set the species string pattern task_pattern = ('task' + one_or_more(SPACE) + task + capturing(one_or_more(WILDCARD, greedy=False)) + 'end') # Obtain the species string task_str = first_capture(task_pattern, inp_str) return task_str
def _get_prog_string(output_string): """ obtains the string containing the version name and number """ pattern = app.capturing( ('Gaussian ' + app.one_or_more(app.INTEGER) + ':' + app.SPACES + app.one_or_more(app.NONNEWLINE))) prog_string = apf.first_capture(pattern, output_string) return prog_string
def get_lvl_str(inp_str, lvl): """ species input """ # Set the species string pattern lvl_pattern = ('level' + one_or_more(SPACE) + lvl + capturing(one_or_more(WILDCARD, greedy=False)) + 'end') # Obtain the species string lvl_str = first_capture(lvl_pattern, inp_str) return lvl_str
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 _get_prog_string(output_str): """ Parses out the program information from the output file string. :param output_str: string of the program's output file :type output_str: str :rtype: str """ pattern = app.capturing(('Gaussian ' + app.one_or_more(app.INTEGER) + ':' + app.SPACES + app.one_or_more(app.NONNEWLINE))) prog_string = apf.first_capture(pattern, output_str) return prog_string
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 inp_zmatrix(output_str): """ Reads the Z-Matrix specified in the input from the output file string. Returns the Z-Matrix in Bohr and Radians. :param output_str: string of the program's output file :type output_str: str :rtype: automol molecular geometry data structure """ # Block with init geom block_ptt = ('molecule' + app.SPACES + app.escape('{') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape('}')) block = apf.first_capture(block_ptt, output_str) # Read the matrix and the values from the output start_ptt = app.LINE_FILL + app.NEWLINE + app.LINE_FILL + app.NEWLINE symbs, key_mat, name_mat, val_mat = ar.zmat.read(block, start_ptt=start_ptt) # Call the automol constructor if all(x is not None for x in (symbs, key_mat, name_mat, val_mat)): zma = automol.zmat.from_data(symbs, key_mat, val_mat, name_mat, one_indexed=True, angstrom=True, degree=True) else: zma = None return zma
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 paren_section(string): """ Read the string that has the global model information """ return (string + app.SPACE + app.escape('=') + app.SPACE + app.escape('(') + app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) + app.escape(')'))
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 keyword_pattern(string): """ Generates the key pattern string """ value = (string + app.zero_or_more(app.SPACE) + '=' + app.zero_or_more(app.SPACE) + app.capturing(app.one_or_more(app.NONSPACE))) return _set_value_type(value)