Example #1
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
Example #2
0
def get_default_temp_limits(block_str):
    """ Gets the default temperatures from the header of a thermo block str

    """
    block_str = apf.remove(COMMENTS_PATTERN, block_str)
    line_lst = list(apf.split_lines(block_str))

    # Loop over each line
    for line in line_lst:
        try:
            # Note that this order is different than
            # that in the individual thermo entries
            low_limit = float(line[0:10])
            midpoint = float(line[10:20])
            high_limit = float(line[20:30])
            break
        except ValueError:
            pass
        # Check if the first thermo entry has been reached
        if len(line) >= 80 and line[79] == '1':
            low_limit, midpoint, high_limit = None, None, None

    # Note that this order is different than
    # that in the individual thermo entries
    default_temp_limits = [low_limit, midpoint, high_limit]

    return default_temp_limits
Example #3
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
Example #4
0
def clean_up_whitespace(string):
    """ remove leading spaces, trailing spaces, and empty lines from a string
    """
    empty_line = app.LINE_START + app.maybe(app.LINESPACES) + app.NEWLINE
    trailing_spaces = app.LINESPACES + app.LINE_END
    leading_spaces = app.LINE_START + app.LINESPACES
    pattern = app.one_of_these([empty_line, trailing_spaces, leading_spaces])
    return apf.remove(pattern, string)
Example #5
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
Example #6
0
def remove_empty_lines(string):
    """ Removes empty lines from a input string.

        :param string: string to remove trailing whitespace
        :type string: str
        :rtype: str
    """

    empty_line = app.LINE_START + app.maybe(app.LINESPACES) + app.NEWLINE

    return apf.remove(empty_line, string)
Example #7
0
def remove_comment_lines(string, delim_pattern):
    """ Remove comment lines marked by a delimiter pattern.

        :param string: string to remove comments
        :type string: str
        :param delim_pattern: pattern of delimiter to identify comment lines
        :type delim_pattern: str
        :rtype: str
    """

    pattern = delim_pattern + app.zero_or_more(app.NONNEWLINE)

    return apf.remove(pattern, string)
Example #8
0
def remove_trail_whitespace(string):
    """ Removes trailing spaces and empty lines from a input string.

        :param string: string to remove trailing whitespace
        :type string: str
        :rtype: str
    """

    empty_line = app.LINE_START + app.maybe(app.LINESPACES) + app.NEWLINE
    trailing_spaces = app.LINESPACES + app.LINE_END
    pattern = app.one_of_these([empty_line, trailing_spaces])

    return apf.remove(pattern, string)
Example #9
0
def remove_whitespace_from_string(string):
    """ Removes leading spaces, trailing spaces, and empty lines from a string.

        :param string: string to clean up
        :type string: str
        :rtype: str
    """

    empty_line = app.LINE_START + app.maybe(app.LINESPACES) + app.NEWLINE
    trailing_spaces = app.LINESPACES + app.LINE_END
    leading_spaces = app.LINE_START + app.LINESPACES
    pattern = app.one_of_these([empty_line, trailing_spaces, leading_spaces])

    return apf.remove(pattern, string)
Example #10
0
def create_entry_list(block_str, add_spaces=True):
    """ Creates a list with each line of the thermo block_str as an
        entry in that list
    
        :param block_str: string for thermo block

        :return line_lst: list of strs for each line

    """
    block_str = apf.remove(COMMENTS_PATTERN, block_str)
    #    print('type of block_str\n', type(block_str))
    line_lst = list(apf.split_lines(block_str))
    #line_lst = list(block_str.splitlines)
    #    print(type(line_lst))

    # Get the indices of the entry header lines
    header_idxs = []
    for idx, line in enumerate(line_lst):
        if len(line) >= 80 and line[79] == '1':
            header_idxs.append(idx)
    if not header_idxs:
        raise ImportError(
            'No thermo headers in the file could be read. A "1" in column 80 marks this.'
        )
    header_idxs.append(
        len(line_lst))  # adds an entry to mark the end of the block_str

    # Check that there are at least 4 lines in each entry
    for idx, difference in enumerate(np.diff(header_idxs)):
        assert difference >= 4, (
            f'There are less than 4 lines for this thermo entry: \n{line_lst[header_idxs[idx]]}'
        )

    # Put together the thermo entries into a list of tuples
    entry_lst = []
    for idx in range(len(header_idxs) - 1):  # skips the last entry
        entry = line_lst[header_idxs[idx]:header_idxs[idx + 1]]
        entry_lst.append(entry)

    # Fix the problem of the missing spaces at the beginning of lines without negative signs
    entry_lst = fix_lines(entry_lst)

    return entry_lst
Example #11
0
def cheb(rxn_str):
    """ Parses the data string for a reaction in the reactions block
        for the lines containing the Chebyshevs fitting parameters,
        then reads the parameters from these lines.

        :param rxn_str: raw Chemkin string for a single reaction
        :type rxn_str: str
        :return params: Chebyshev fitting parameters
        :rtype: dict[param: value]
    """

    original_rxn_str = rxn_str
    rxn_str = apf.remove(COMMENTS_PATTERN, rxn_str)

    tcheb_pattern = ('TCHEB' + 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.zero_or_more(app.SPACE) + app.escape('/'))
    pcheb_pattern = ('PCHEB' + 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.zero_or_more(app.SPACE) + app.escape('/'))
    cheb_pattern = (app.not_preceded_by(app.one_of_these(['T', 'P'])) +
                    'CHEB' + app.zero_or_more(app.SPACE) + app.escape('/') +
                    app.capturing(app.one_or_more(app.WILDCARD2)) +
                    app.escape('/'))

    cheb_params_raw = apf.all_captures(cheb_pattern, rxn_str)

    if cheb_params_raw:
        params = {}
        # Get temp and pressure limits or use Chemkin defaults if non-existent
        cheb_temps = apf.first_capture(tcheb_pattern, rxn_str)
        cheb_pressures = apf.first_capture(pcheb_pattern, rxn_str)
        if cheb_temps is None:
            cheb_temps = ('300.00', '2500.00')
            print('No Chebyshev temperature limits specified' +
                  ' for the below reaction.' +
                  f' Assuming 300 and 2500 K. \n \n {original_rxn_str}\n')
        if cheb_pressures is None:
            cheb_pressures = ('0.001', '100.00')
            print('No Chebyshev pressure limits specified' +
                  ' for the below reaction.' +
                  f' Assuming 0.001 and 100 atm. \n \n {original_rxn_str}\n')

        # Get all the numbers from the CHEB parameters
        cheb_params = []
        for cheb_line in cheb_params_raw:
            cheb_params.extend(cheb_line.split())

        # Get alpha dimensions N and M, which are the first two CHEB entries
        cheb_n = int(float(cheb_params[0]))
        cheb_m = int(float(cheb_params[1]))

        # Start on third value (after N and M) and get all polynomial coeffs
        coeffs = []
        for idx, coeff in enumerate(cheb_params[2:]):
            # extra coefficients are allowed but ignored
            if idx + 1 > (cheb_n * cheb_m):
                break
            coeffs.append(coeff)
        assert len(coeffs) == (cheb_n * cheb_m), (
            f'For the below reaction, there should be {cheb_n*cheb_m}' +
            ' Chebyshev polynomial' +
            f' coefficients, but there are only {len(coeffs)}.' +
            f' \n \n {original_rxn_str}\n')
        alpha = np.array(list(map(float, coeffs)))

        params['tlim'] = tuple(float(val) for val in cheb_temps)
        params['plim'] = tuple(float(val) for val in cheb_pressures)
        params['alpha'] = alpha.reshape([cheb_n, cheb_m])

    else:
        params = None

    return params
Example #12
0
def chebyshev_parameters(rxn_dstr, a_units='moles'):
    """ Parses the data string for a reaction in the reactions block
        for the lines containing the Chebyshevs 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: Chebyshev fitting parameters
        :rtype: dict[param: value]
    """
    original_rxn_dstr = rxn_dstr
    rxn_dstr = apf.remove(COMMENTS_PATTERN, rxn_dstr)

    tcheb_pattern = ('TCHEB' + 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.zero_or_more(app.SPACE) + app.escape('/'))
    pcheb_pattern = ('PCHEB' + 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.zero_or_more(app.SPACE) + app.escape('/'))
    cheb_pattern = (app.not_preceded_by(app.one_of_these(['T', 'P'])) +
                    'CHEB' + app.zero_or_more(app.SPACE) + app.escape('/') +
                    app.capturing(app.one_or_more(app.WILDCARD2)) +
                    app.escape('/'))

    cheb_params_raw = apf.all_captures(cheb_pattern, rxn_dstr)

    if cheb_params_raw:
        params = {}
        # Get the temp and pressure limits; add the Chemkin default values if they don't exist
        cheb_temps = apf.first_capture(tcheb_pattern, rxn_dstr)
        cheb_pressures = apf.first_capture(pcheb_pattern, rxn_dstr)
        if cheb_temps is None:
            cheb_temps = ('300.00', '2500.00')
            print(
                f'No Chebyshev temperature limits specified for the below reaction. Assuming 300 and 2500 K. \n \n {original_rxn_dstr}\n'
            )
        if cheb_pressures is None:
            cheb_pressures = ('0.001', '100.00')
            print(
                f'No Chebyshev pressure limits specified for the below reaction. Assuming 0.001 and 100 atm. \n \n {original_rxn_dstr}\n'
            )

        # Get all the numbers from the CHEB parameters
        cheb_params = []
        for cheb_line in cheb_params_raw:
            cheb_params.extend(cheb_line.split())

        # Get the cheb array dimensions N and M, which are the first two entries of the CHEB params
        cheb_n = int(
            math.floor(float(cheb_params[0]))
        )  # rounds down to match the Chemkin parser, although it should be an integer already
        cheb_m = int(math.floor(float(cheb_params[1])))

        # Start on the third value (after N and M) and get all the polynomial coefficients
        coeffs = []
        for idx, coeff in enumerate(cheb_params[2:]):
            if idx + 1 > (
                    cheb_n * cheb_m
            ):  # there are allowed to be extra coefficients, but just ignore them
                break
            coeffs.append(coeff)
        assert len(coeffs) == (cheb_n * cheb_m), (
            f'For the below reaction, there should be {cheb_n*cheb_m} Chebyshev polynomial coefficients, but there are only {len(coeffs)}. \n \n {original_rxn_dstr}\n'
        )
        alpha = numpy.array(list(map(float, coeffs)))

        params['t_limits'] = [float(val) for val in cheb_temps]
        params['p_limits'] = [float(val) for val in cheb_pressures]
        params['alpha_elm'] = alpha.reshape([cheb_n, cheb_m])
        params['a_units'] = a_units

    else:
        params = None

    return params
Example #13
0
def remove_line_comments(string, delim_pattern):
    """ remove line comments marked by a delimiter pattern
    """
    pattern = delim_pattern + app.zero_or_more(app.NONNEWLINE)
    return apf.remove(pattern, string)