def objects_dct(job_path): """ Get the sections for the run block """ # Read the obj section run_str = ptt.read_inp_str(job_path, RUN_INP, remove_comments='#') obj_str = object_block(run_str) # Read the sections of the obj section pes_block_str = apf.first_capture(ptt.paren_section('pes'), obj_str) spc_block_str = apf.first_capture(ptt.paren_section('spc'), obj_str) # Check if the obj section has been specified check_obj_spec(obj_str, pes_block_str, spc_block_str) # Build the run dictionary run_dct = {} if pes_block_str is not None: run_dct['pes'] = get_pes_idxs( ioformat.remove_whitespace(pes_block_str)) else: run_dct['pes'] = [] if spc_block_str is not None: run_dct['spc'] = get_spc_idxs( ioformat.remove_whitespace(spc_block_str)) else: run_dct['spc'] = [] return run_dct
def build_model_keyword_dct(model_str): """ Build a dictionary for all the models keywords """ # Grab the various sections required for each model pf_str = apf.first_capture(ptt.paren_section('pf'), model_str) es_str = apf.first_capture(ptt.paren_section('es'), model_str) etrans_str = apf.first_capture(ptt.paren_section('etransfer'), model_str) options_str = apf.first_capture(ptt.paren_section('options'), model_str) assert pf_str is not None assert es_str is not None assert options_str is not None # Get the dictionary for each section and check them pf_dct = ptt.build_keyword_dct(pf_str) es_dct = ptt.build_keyword_dct(es_str) etransfer_dct = ptt.build_keyword_dct(etrans_str) options_dct = ptt.build_keyword_dct(options_str) # assert check_model_dct(keyword_dct) # Combine dcts into single model dct model_dct = {} model_dct['pf'] = pf_dct model_dct['es'] = es_dct model_dct['etransfer'] = etransfer_dct model_dct['options'] = options_dct return model_dct
def chebyshev_parameters(rxn_dstr): """ 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] """ temp_pattern = ('TCHEB' + app.zero_or_more(app.SPACE) + app.escape('/') + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.zero_or_more(app.SPACE) + app.escape('/')) pressure_pattern = ('PCHEB' + app.zero_or_more(app.SPACE) + app.escape('/') + app.SPACES + app.capturing(app.FLOAT) + app.SPACES + app.capturing(app.FLOAT) + app.zero_or_more(app.SPACE) + app.escape('/')) alpha_dimension_pattern = ('CHEB' + app.zero_or_more(app.SPACE) + app.escape('/') + app.SPACES + app.capturing(app.INTEGER) + app.SPACES + app.capturing(app.INTEGER) + app.zero_or_more(app.SPACE) + app.escape('/')) alpha_elements_pattern = ( 'CHEB' + app.zero_or_more(app.SPACE) + app.escape('/') + app.series( app.capturing(app.SPACES + app.capturing(app.EXPONENTIAL_FLOAT)), app.SPACES) + app.zero_or_more(app.SPACE) + app.escape('/')) cheb_temps = apf.first_capture(temp_pattern, rxn_dstr) cheb_pressures = apf.first_capture(pressure_pattern, rxn_dstr) alpha_dims = apf.first_capture(alpha_dimension_pattern, rxn_dstr) alpha_elm = apf.all_captures(alpha_elements_pattern, rxn_dstr) if not alpha_elm: alpha_elm = None params_dct = {} if all(vals is not None for vals in (cheb_temps, cheb_pressures, alpha_dims, alpha_elm)): params_dct['t_limits'] = [float(val) for val in cheb_temps] params_dct['p_limits'] = [float(val) for val in cheb_pressures] params_dct['alpha_dim'] = [int(val) for val in alpha_dims] params_dct['alpha_elm'] = [list(map(float, row)) for row in alpha_elm] else: params_dct = None return params_dct
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 reaction_units(string, start_pattern, units_pattern): """ return a block delimited by start and end patterns """ rxn_line_pattern = start_pattern + app.capturing(app.LINE_FILL) units_string = apf.first_capture(rxn_line_pattern, string) units_lst = apf.all_captures(units_pattern, units_string) ckin_ea_units = [ 'CAL/MOLE', 'KCAL/MOLE', 'JOULES/MOLE', 'KJOULES/MOLE', 'KELVINS' ] ckin_a_units = ['MOLES', 'MOLECULES'] if units_lst: if any(unit in ckin_ea_units for unit in units_lst): for unit in ckin_ea_units: if unit in units_lst: ea_unit = unit.lower() else: ea_unit = 'cal/mole' if any(unit in ckin_a_units for unit in units_lst): for unit in ckin_a_units: if unit in units_lst: a_unit = unit.lower() else: a_unit = 'moles' units = (ea_unit, a_unit) else: units = ('cal/mole', 'moles') return units
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 _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
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 _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
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 formula_sublayer(ich): """ formula sublayer """ ptt = (_version_pattern() + SLASH + app.capturing(_formula_sublayer_pattern())) lyr = apf.first_capture(ptt, ich) return lyr
def pressure_region_specification(rxn_dstr): """ Parses the data string for a reaction in the reactions block for the line containing the chemical equation in order to check if a body M is given, indicating pressure dependence. :param rxn_dstr: data string for species in reaction block :type rxn_dstr: str :return pressure_region: type of pressure indicated :rtype: str """ pattern = app.capturing( _first_line_pattern(rct_ptt=SPECIES_NAMES_PATTERN, prd_ptt=SPECIES_NAMES_PATTERN, param_ptt=app.maybe(COEFF_PATTERN))) string = apf.first_capture(pattern, rxn_dstr) if string is not None: string = string.strip() if 'M' in string: # Presence of M denotes specific region assumptions if '(+M)' in string: pressure_region = 'falloff' else: pressure_region = 'lowp' else: # No M can be independent or not, depending on subsequent info if 'PLOG' in rxn_dstr or 'CHEB' in rxn_dstr: pressure_region = 'all' else: pressure_region = 'indep' else: pressure_region = None return pressure_region
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 buffer_enhance_factors(rxn_dstr): """ get the factors of speed-up from bath gas """ species_char = app.one_of_these([ app.LETTER, app.DIGIT, app.escape('('), app.escape(')'), app.UNDERSCORE ]) species_name = app.one_or_more(species_char) # Get the line that could have the bath gas buffer enhancements bath_line_pattern = (_first_line_pattern(rct_ptt=SPECIES_NAMES_PATTERN, prd_ptt=SPECIES_NAMES_PATTERN, coeff_ptt=COEFF_PATTERN) + '\n' + app.capturing(app.LINE)) bath_string = apf.first_capture(bath_line_pattern, rxn_dstr) # Check if this line has bath gas factors or is for something else # If factors in string, get factors bad_strings = ('DUPLICATE', 'LOW', 'TROE', 'CHEB', 'PLOG') if (any(string in bath_string for string in bad_strings) and bath_string.strip() != ''): factors = None else: bath_string = '\n'.join(bath_string.strip().split()) factor_pattern = (app.capturing(species_name) + app.escape('/') + app.capturing(app.NUMBER) + app.escape('/')) baths = apf.all_captures(factor_pattern, bath_string) factors = {} for bath in baths: factors[bath[0]] = float(bath[1]) return factors
def em_parameters(rxn_dstr): """ Parses the data string for a reaction in the reactions block for the line containing the chemical equation in order to check if a body M is given, indicating pressure dependence. :param rxn_dstr: data string for species in reaction block :type rxn_dstr: str :return pressure_region: type of pressure indicated :rtype: str """ pattern = app.capturing( _first_line_pattern(rct_ptt=SPECIES_NAMES_PATTERN, prd_ptt=SPECIES_NAMES_PATTERN, param_ptt=COEFF_PATTERN)) string = apf.first_capture(pattern, rxn_dstr) if string is not None: string = string.strip() if '(+M)' in string: params = '(+M)' elif 'M' in string: params = '+M' else: params = None return params
def get_mc_nsamp(inp_str, species): """ Get the number of samples for the Monte Carlo sampling """ # Set the nsamp pattern mc_nsamp_pattern = ('mc_nsamp' + zero_or_more(SPACE) + '=' + zero_or_more(SPACE) + capturing(one_or_more(NONNEWLINE))) # Obtain the appropriate species string species_str = get_species_str(inp_str, species) # Obtain the charge string mc_nsamp_str = first_capture(mc_nsamp_pattern, species_str) # Set the nsamp (maybe check the ntau variable) if mc_nsamp_str is not None: mc_nsamp_str = mc_nsamp_str.split() if len(mc_nsamp_str) < 4: mc_nsamp = [False, 0, 0, 0, 0, int(mc_nsamp_str[0])] else: mc_nsamp = [True] for n in mc_nsamp_str: mc_nsamp.append(int(n)) mc_nsamp.append(12) else: mc_nsamp = 0 return mc_nsamp
def get_mc_tau(inp_str, species): """ Get the electric charge of the species """ # Set the charge pattern mc_tau_pattern = ('mc_tau' + zero_or_more(SPACE) + '=' + zero_or_more(SPACE) + '"' + capturing(one_or_more(WILDCARD, greedy=False)) + '"') # Obtain the appropriate species string species_str = get_species_str(inp_str, species) # Obtain the geom string mc_tau_str = first_capture(mc_tau_pattern, species_str) # Set the geom as an integer if mc_tau_str is not None: if mc_tau_str == 'auto': mc_tau_dict = "auto" else: mc_tau_dict = literal_eval(mc_tau_str) else: mc_tau_dict = {} return mc_tau_dict
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 _charge_layer(ich): """ charge layer """ ptt = (_version_pattern() + SLASH + _formula_sublayer_pattern() + app.maybe(SLASH + _main_layer_pattern()) + SLASH + app.capturing(_charge_layer_pattern())) lyr = apf.first_capture(ptt, ich) return lyr
def _block(string, start_pattern, end_pattern): """ return a block delimited by start and end patterns """ contents_pattern = app.capturing( app.one_or_more(app.WILDCARD, greedy=False)) pattern = start_pattern + contents_pattern + end_pattern contents = apf.first_capture(pattern, string) return contents
def inp_zmatrix(inp_str): """ Reads the input z-matrix from the input 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 """ # Reads the matrix from the beginning of the input symbs, key_mat, name_mat = ar.vmat.read( inp_str, start_ptt=app.padded(app.NEWLINE).join([ app.escape('comment:'), app.LINE, app.LINE, '']), symb_ptt=(ar.par.Pattern.ATOM_SYMBOL + app.not_followed_by(app.SPACES + app.FLOAT) + app.maybe(app.UNSIGNED_INTEGER)), key_ptt=app.one_of_these([app.UNSIGNED_INTEGER, app.VARIABLE_NAME]), line_end_ptt=app.maybe(app.UNSIGNED_INTEGER), last=False) # Reads the values from the input if all(x is not None for x in (symbs, key_mat, name_mat)): if len(symbs) == 1: # val_dct = {} val_mat = ((None, None, None),) else: val_dct = ar.setval.read( inp_str, start_ptt=app.padded(app.NEWLINE).join([ app.padded('Variables:', app.NONNEWLINE), '']), entry_sep_ptt='', entry_start_ptt='', sep_ptt=app.maybe(app.LINESPACES).join([ app.NEWLINE]), last=True) val_mat = ar.setval.convert_dct_to_matrix(val_dct, name_mat) # Check for the pattern # For the case when variable names are used instead of integer keys: # (otherwise, does nothing) key_dct = dict(map(reversed, enumerate(symbs))) key_dct[None] = 0 key_mat = [ [key_dct[val]+1 if not isinstance(val, numbers.Real) else val for val in row] for row in key_mat] symb_ptt = app.STRING_START + app.capturing(ar.par.Pattern.ATOM_SYMBOL) symbs = [apf.first_capture(symb_ptt, symb) for symb in symbs] # Call the automol constructor 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 _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 product_names(rxn_dstr): """ product species names """ pattern = _first_line_pattern(rct_ptt=SPECIES_NAMES_PATTERN, prd_ptt=app.capturing(SPECIES_NAMES_PATTERN), coeff_ptt=COEFF_PATTERN) string = apf.first_capture(pattern, rxn_dstr) names = _split_reagent_string(string) return names
def end_block(string, header, name=None, footer=None): """ A pattern for a certain block rtype: str """ _ptt = end_block_ptt(header, name=name, footer=footer) cap = apf.first_capture(_ptt, string) return cap if cap is not None else None
def _get_version_string(output_str): """ obtains the string containing the version number """ pattern = ('Version ' + app.capturing(app.one_or_more(app.NONNEWLINE))) version_string = apf.first_capture(pattern, output_str) return version_string
def prefix(chi): """ Determine the chemical identifier prefix (InChI or AMChI). :param chi: ChI string :type chi: str :rtype: str """ ptt = app.capturing(NONSLASHES) + app.followed_by('=') std = apf.first_capture(ptt, chi) return std
def temp_common_default(block_str): """ temperature defaults from the thermo block """ pattern = (app.STRING_START + app.UNSIGNED_FLOAT + app.LINESPACES + app.capturing(app.UNSIGNED_FLOAT) + app.LINESPACES + app.UNSIGNED_FLOAT) capture = apf.first_capture(pattern, block_str) assert capture tmp_com_def = float(capture) return tmp_com_def
def get_key_int(inp_str, lvl, key): # Find the value for a given key, make int pattern = (key + zero_or_more(SPACE) + '=' + zero_or_more(SPACE) + capturing(one_or_more(NONSPACE))) # Obtain the appropriate species string patt_str = get_lvl_str(inp_str, lvl) # Obtain the charge string patt_str = first_capture(pattern, patt_str) assert patt_str is not None return int(patt_str)
def _get_prog_string(output_string): """ obtains the string containing the version name and number """ pattern = app.capturing(('NAME' + app.SPACES + ':' + app.SPACES + app.one_or_more(app.NONNEWLINE))) prog_string = apf.first_capture(pattern, output_string) return prog_string
def version(chi): """ Determine version number of the ChI string. :param chi: ChI string :type chi: str :rtype: str """ ptt = app.capturing(_version_pattern()) ver = apf.first_capture(ptt, chi) return ver