def third_body(rxn_str): """ Parses the data string for a reaction in the reactions block for the line containing the chemical equation in order to read the names of the third body collider if present :param rxn_str: raw Chemkin string for a single reaction :type rxn_str: str :return trd_body: names of the colliders and corresponding fraction :rtype: tuple(str) """ pattern = _first_line_pattern(rct_ptt=app.capturing(SPECIES_NAMES_PATTERN), prd_ptt=SPECIES_NAMES_PATTERN, param_ptt=app.maybe(COEFF_PATTERN)) rgt_str = apf.first_capture(pattern, rxn_str) rgt_str = apf.remove(app.LINESPACES, rgt_str) rgt_split_paren = apf.split(CHEMKIN_PAREN_PLUS, rgt_str) rgt_split_plus = apf.split(app.PLUS, rgt_str) if len(rgt_split_paren) > 1: trd_body = '(+' + apf.split(CHEMKIN_PAREN_CLOSE, rgt_split_paren[1])[0] + ')' elif 'M' in rgt_split_plus: trd_body = '+M' else: trd_body = None trd_body = (trd_body, ) return trd_body
def _split_reagent_string(rgt_str): """ Parses out the names of all the species given in a string with the chemical equation within the reactions block. :param rgt_str: string with the reaction chemical equation :type rgt_str: str :return rgts: names of the species in the reaction :type rgts: list(str) """ def _interpret_reagent_count(rgt_cnt_str): """ Count the species in a string containing one side of a chemical equation. :param rgt_cnt_str: string of one side of chemcial equation :type rgt_cnt_str: str :return: rgts: names of species from string :rtype: list(str) """ _pattern = (app.STRING_START + app.capturing(app.maybe(app.DIGIT)) + app.capturing(app.one_or_more(app.NONSPACE))) cnt, rgt = apf.first_capture(_pattern, rgt_cnt_str) cnt = int(cnt) if cnt else 1 rgts = (rgt, ) * cnt return rgts rgt_str = apf.remove(app.LINESPACES, rgt_str) rgt_str = apf.remove(CHEMKIN_PAREN_PLUS_EM, rgt_str) rgt_str = apf.remove(CHEMKIN_PLUS_EM, rgt_str) pattern = app.PLUS + app.not_followed_by(app.PLUS) rgt_cnt_strs = apf.split(pattern, rgt_str) rgts = tuple(itertools.chain(*map(_interpret_reagent_count, rgt_cnt_strs))) return rgts
def normal_coordinates(output_str): """ Parse the normal coordinates of the vibrational modes out of the ProjRot displacement output files: *_cd.dat Works for the output of both (1) rotation-translation projections and (2) rotation-translation/hindered-rotor projections. Since ProjRot outputs the displacements in Gaussian frequency format, this function is similar to the Gaussian parser. Currently, does NOT follow the order of the frequency reader. Need to fix. :param output_str: string of lines of ProjRot output file :type output_str: str :rtype: tuple(numpy.ndarray) """ # Set the patterns to read the normal coordinates comp_ptt = app.UNSIGNED_INTEGER + app.SPACES + app.UNSIGNED_INTEGER # Gaussian prints freqs/norm coords as columns. Up to 3 columns printed # Three patterns used to handle cases of when 1, 2, or 3 columns printed start_ptt = 'Atom AN X Y Z' start_ptt2 = ' X Y Z' start_ptt_lst = ( (start_ptt + start_ptt2 + start_ptt2), # 3 freq column(s) (start_ptt + start_ptt2), # 2 freq column(s) (start_ptt), # 1 freq column(s) ) # Read the normal coordinate modes nmodes = () for mode in apf.split('Frequencies', output_str)[1:]: mat = None # Parse out coords by trying all possibilities of nfreq cols printed for start in start_ptt_lst: _ptt = app.padded(app.NEWLINE).join([app.escape(start), '']) mat = ar.matrix.read(mode, start_ptt=_ptt, line_start_ptt=comp_ptt) if mat is not None: # If pattern found, slice 3xN mat into N 3x3 mats # where N/3 corresponds to number of freq columns parsed nmat = numpy.array(mat) * phycon.ANG2BOHR _, ncols = numpy.shape(nmat) for i in range(int(ncols / 3)): nmodes += (nmat[:, i * 3:(i + 1) * 3], ) break # Set nmodes to None if nothing found from apf.split command if not nmodes: nmodes = None return nmodes
def normal_coords(output_string): """ read normal modes from the output string """ comp_ptt = app.UNSIGNED_INTEGER + app.SPACES + app.UNSIGNED_INTEGER nmodes = [] start = 'Atom AN X Y Z ' start += 'X Y Z X Y Z' for mode in apf.split('Frequencies', output_string)[1:]: mat = ar.matrix.read(mode, start_ptt=app.padded(app.NEWLINE).join( [app.escape(start), '']), line_start_ptt=comp_ptt) nmat = numpy.array(mat) for i in range(int(len(nmat) / 3)): nmodes.append(nmat[:, i * 3:(i + 1) * 3]) return nmodes
def _split_sublayer_string(slyr, count_sep_ptt=app.escape('*'), sep_ptt=app.escape(';')): count_ptt = app.UNSIGNED_INTEGER group_ptt = (app.STRING_START + app.capturing(count_ptt) + count_sep_ptt + app.capturing(app.zero_or_more(app.WILDCARD))) def _expand_group(group_str): if apf.has_match(group_ptt, group_str): count, part = ap_cast(apf.first_capture(group_ptt, group_str)) parts = [part] * count else: parts = [group_str] return parts parts = tuple( itertools.chain(*map(_expand_group, apf.split(sep_ptt, slyr)))) return parts
def _split_reagent_string(rgt_str): def _interpret_reagent_count(rgt_cnt_str): _pattern = (app.STRING_START + app.capturing(app.maybe(app.DIGIT)) + app.capturing(app.one_or_more(app.NONSPACE))) cnt, rgt = apf.first_capture(_pattern, rgt_cnt_str) cnt = int(cnt) if cnt else 1 rgts = (rgt, ) * cnt return rgts rgt_str = apf.remove(app.LINESPACES, rgt_str) rgt_str = apf.remove(CHEMKIN_PAREN_PLUS_EM, rgt_str) rgt_str = apf.remove(CHEMKIN_PLUS_EM, rgt_str) pattern = app.PLUS + app.not_followed_by(app.PLUS) rgt_cnt_strs = apf.split(pattern, rgt_str) rgts = tuple(itertools.chain(*map(_interpret_reagent_count, rgt_cnt_strs))) return rgts
def normal_coordinates(output_str): """ Reads the displacement along the normal modes (in Cartesian coordinates) from the output string. Returns the coordinates in Bohr. :param output_str: string of the program's output file :type output_str: str :rtype: tuple(tuple(float)) """ # Set the patterns to read the normal coordinates comp_ptt = app.UNSIGNED_INTEGER + app.SPACES + app.UNSIGNED_INTEGER # Gaussian prints freqs/norm coords as columns. Up to 3 columns printed # Three patterns used to handle cases of when 1, 2, or 3 columns printed start_ptt = 'Atom AN X Y Z' start_ptt2 = ' X Y Z' start_ptt_lst = ( (start_ptt + start_ptt2 + start_ptt2), # 3 freq column(s) (start_ptt + start_ptt2), # 2 freq column(s) (start_ptt), # 1 freq column(s) ) # Read the normal coordinate modes nmodes = () for mode in apf.split('Frequencies', output_str)[1:]: mat = None # Parse out coords by trying all possibilities of nfreq cols printed for start in start_ptt_lst: _ptt = app.padded(app.NEWLINE).join([app.escape(start), '']) mat = ar.matrix.read(mode, start_ptt=_ptt, line_start_ptt=comp_ptt) if mat is not None: # If pattern found, slice 3xN mat into N 3x3 mats # where N/3 corresponds to number of freq columns parsed nmat = numpy.array(mat) * phycon.ANG2BOHR _, ncols = numpy.shape(nmat) for i in range(int(ncols / 3)): nmodes += (nmat[:, i * 3:(i + 1) * 3], ) break # Set nmodes to None if nothing found from apf.split command if not nmodes: nmodes = None return nmodes
def normal_coordinates(output_str): """ Reads the displacement along the normal modes (in Cartesian coordinates) from the output string. Returns the coordinates in Bohr. :param output_str: string of the program's output file :type output_str: str :rtype: tuple(tuple(float)) """ comp_ptt = app.UNSIGNED_INTEGER + app.SPACES + app.UNSIGNED_INTEGER nmodes = [] start = 'Atom AN X Y Z ' start += 'X Y Z X Y Z' for mode in apf.split('Frequencies', output_str)[1:]: mat = ar.matrix.read(mode, start_ptt=app.padded(app.NEWLINE).join( [app.escape(start), '']), line_start_ptt=comp_ptt) nmat = numpy.array(mat) for i in range(int(len(nmat) / 3)): nmodes.append(nmat[:, i * 3:(i + 1) * 3]) return nmodes