Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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