def _has_scf_convergence_message(output_str): """ Assess whether the output file string contains the message signaling successful convergence of the SCF procedure. :param output_str: string of the program's output file :type output_str: str :rtype: bool """ scf_str1 = ( 'Initial convergence to {} achieved. Increase integral accuracy.' + app.LINE_FILL + app.NEWLINE + app.LINE_FILL + app.escape('SCF Done:') ).format(app.EXPONENTIAL_FLOAT_D) scf_str2 = app.escape('Rotation gradient small -- convergence achieved.') scf_str3 = app.escape('The problem occurs in Multi') scf_str4 = app.escape('The problem occurs in cipro') pattern = app.one_of_these([scf_str1, scf_str2, scf_str3, scf_str4]) return apf.has_match(pattern, output_str, case=False)
def thermo_block(mech_str, remove_comments=True): """ Parses the thermo block out of the mechanism input file. :param mech_str: string of mechanism input file :type mech_str: str :param remove_comments: elect to remove comment liness from string :type remove_comments: bool :return block_str: string containing thermo block :rtype: string """ block_str = _block(string=_clean_up(mech_str, remove_comments=remove_comments), start_pattern=app.one_of_these([ 'THERMO ALL', 'THERM ALL', 'THER ALL', 'THERMO', 'THERM', 'THER' ]), end_pattern='END') return block_str
def colliders(rxn_str): """ Parses the data string for a reaction in the reactions block for the line containing the names of several bath gases and their corresponding collider efficiencies :param rxn_str: raw Chemkin string for a single reaction :type rxn_str: str :return params: collider efficiencies for each bath gas :rtype: dict {spc1: eff1, spc2: ...} """ bad_strings = ('DUP', 'LOW', 'TROE', 'CHEB', 'PLOG', CHEMKIN_ARROW) species_char = app.one_of_these([ app.LETTER, app.DIGIT, app.escape('('), app.escape(')'), app.UNDERSCORE ]) species_name = app.one_or_more(species_char) # Loop over the lines and search for string with collider facts if ('LOW' in rxn_str or 'TROE' in rxn_str or 'M=' in rxn_str or 'M =' in rxn_str): params = {} for line in rxn_str.splitlines(): if not any(apf.has_match(string, line) for string in bad_strings): factor_pattern = ( app.capturing(species_name) + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE) + app.capturing(app.NUMBER) + app.zero_or_more(app.SPACE) + app.escape('/') + app.zero_or_more(app.SPACE)) baths = apf.all_captures(factor_pattern, line) if baths: for bath in baths: params[bath[0]] = float(bath[1]) # If nothing was put into the dictionary, set it to None if not params: params = None else: params = None return params
def matrix_block_pattern(symbol_pattern=SYMBOL_PATTERN, key_pattern=KEY_PATTERN, variable_pattern=VARIABLE_PATTERN): """ captures the whole matrix block of a z-matrix """ entry_pattern = _entry_pattern(variable_pattern) def _patterns(nentries): return [symbol_pattern] + nentries * [key_pattern, entry_pattern] line_patterns = [ _LSTART + app.LINESPACES.join(_patterns(n)) + _LEND for n in range(0, 4) ] pattern = app.one_of_these([ app.NEWLINE.join(line_patterns[:3]) + app.zero_or_more(app.NEWLINE + line_patterns[3]), app.NEWLINE.join(line_patterns[:2]), app.NEWLINE.join(line_patterns[:1]), ]) return app.capturing(pattern)
def _ccsd_t_energy(output_str): """ Reads the CCSD(T)/UCCSD(T) 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 """ ene = ar.energy.read( output_str, app.one_of_these([ app.escape('!CCSD(T) total energy') + app.maybe(':'), app.escape('!RHF-UCCSD(T) energy'), app.LINESPACES.join([ app.escape('!CCSD(T) STATE'), app.FLOAT, app.escape('Energy')]), ])) return ene
def data_strings(block_str): """ Parse all of the NASA polynomials given in the thermo block of the mechanism input file and stores them in a list. :param block_str: string for thermo block :type block_str: str :return thm_strs: strings containing NASA polynomials for all species :rtype: list(str) """ headline_pattern = ( app.LINE_START + app.not_followed_by(app.one_of_these( [app.DIGIT, app.PLUS, app.escape('=')])) + app.one_or_more(app.NONNEWLINE) + app.escape('1') + app.LINE_END ) thm_strs = headlined_sections( string=block_str.strip(), headline_pattern=headline_pattern ) return thm_strs
def hessian(output_str): """ Reads the molecular Hessian (in Cartesian coordinates) from the output file string. Returns the Hessian in atomic units. :param output_str: string of the program's output file :type output_str: str :rtype: tuple(tuple(float)) """ comp_ptt = app.UNSIGNED_INTEGER mat = ar.matrix.read( output_str, val_ptt=app.EXPONENTIAL_FLOAT_D, start_ptt=(app.escape('Force constants in Cartesian coordinates:') + app.lpadded(app.NEWLINE)), block_start_ptt=(app.series(comp_ptt, app.LINESPACES) + app.padded(app.NEWLINE)), line_start_ptt=comp_ptt, tril=True) if mat is not None: mat = [[_cast(apf.replace('d', 'e', dst, case=False)) for dst in row] for row in mat] if mat is None: comp_ptt = app.one_of_these(['X', 'Y', 'Z']) + app.UNSIGNED_INTEGER mat = ar.matrix.read( output_str, start_ptt=(app.escape('The second derivative matrix:') + app.lpadded(app.NEWLINE)), block_start_ptt=(app.series(comp_ptt, app.LINESPACES) + app.padded(app.NEWLINE)), line_start_ptt=comp_ptt, tril=True) if mat is not None: mat = tuple(map(tuple, mat)) return mat
def collider_enhance_factors(rxn_dstr): """ Parses the data string for a reaction in the reactions block for the line containing the names of several bath gases and their corresponding collision enhancement factors. :param rxn_dstr: data string for species in reaction block :type rxn_dstr: str :return factors: Collision enhanncement factors for each bath gas :rtype: dict[bath name: enhancement factors] """ first_str = _first_line_pattern(rct_ptt=SPECIES_NAMES_PATTERN, prd_ptt=SPECIES_NAMES_PATTERN, param_ptt=COEFF_PATTERN) bad_strings = ('DUP', 'LOW', 'TROE', 'CHEB', 'PLOG', first_str) species_char = app.one_of_these([ app.LETTER, app.DIGIT, app.escape('('), app.escape(')'), app.UNDERSCORE ]) species_name = app.one_or_more(species_char) # Loop over the lines and search for string with collider facts factors = {} if apf.has_match('LOW', rxn_dstr) or apf.has_match('TROE', rxn_dstr): for line in rxn_dstr.splitlines(): if not any(apf.has_match(string, line) for string in bad_strings): factor_pattern = (app.capturing(species_name) + app.escape('/') + app.maybe(app.SPACE) + app.capturing(app.NUMBER) + app.escape('/')) baths = apf.all_captures(factor_pattern, line) if baths: factors = {} for bath in baths: factors[bath[0]] = float(bath[1]) return factors
def _lccsd_f12_energy(output_str): """ Reads the LCCSD-F12 energy from the output file string. Currently, the function only reads the energy of the F12b variant. For local, open-shell R/L seem interchangable. I think it works with just PNO variant? (because of search line) I think it is the same for closed- and open-shell systems. Returns the energy in Hartrees. :param output_str: string of the program's output file :type output_str: str :rtype: float """ ptt = app.one_of_these([ app.escape('!PNO-RCCSD-F12b total energy'), app.escape('!PNO-LCCSD-F12b total energy')]) ene = ar.energy.read(output_str, ptt) return ene
def stereo_atoms(ich, iso=True, one_indexed=False): """ Parse the stereo atoms from the stereochemistry layer. :param ich: InChI string :type ich: str :param iso: Include isotope stereochemistry? :type iso: bool :param one_indexed: Return indices in one-indexing? :type one_indexed: bool """ if len(split(ich)) > 1: raise NotImplementedError("Multicomponent InChIs not implemented." "Call inchi.split() first") atm_ptt = (app.capturing(app.UNSIGNED_INTEGER) + app.one_of_these(list(map(app.escape, '+-')))) ste_dct = stereo_sublayers(ich) iso_dct = isotope_sublayers(ich) tlyr = '' if 't' in ste_dct: tlyr += ste_dct['t'] if iso and 't' in iso_dct: tlyr += ',' + iso_dct['t'] atms = () if tlyr: atms = ap_cast(apf.all_captures(atm_ptt, tlyr)) if not one_indexed: atms = tuple(i - 1 for i in atms) atms = atms if atms is not None else () return atms
def test_(): """ test autoread.zmatrix """ string = (' Geometry (in Angstrom), charge = 0, multiplicity = 1:\n' '\n' ' O\n' ' O 1 R1\n' ' H 1 R2 2 A2\n' ' H 2 R2 1 A2 3 D3\n' '\n' ' A2 = 96.7725720000\n' ' D3 = 129.3669950000\n' ' R1 = 1.4470582953\n' ' R2 = 0.9760730000\n') syms, key_mat, name_mat, val_dct = autoread.zmatrix.read( string, start_ptt=( app.padded(app.escape('Geometry (in Angstrom),'), app.NONNEWLINE) + 2 * app.padded(app.NEWLINE))) assert syms == ('O', 'O', 'H', 'H') assert key_mat == ((None, None, None), (1, None, None), (1, 2, None), (2, 1, 3)) assert name_mat == ((None, None, None), ('R1', None, None), ('R2', 'A2', None), ('R2', 'A2', 'D3')) assert val_dct == { 'A2': 96.772572, 'D3': 129.366995, 'R1': 1.4470582953, 'R2': 0.976073 } string = ('C \n' 'O , 1 , R1 \n' 'H , 1 , R2 , 2 , A2 \n' 'H , 1 , R3 , 2 , A3 , 3 , D3 \n' 'H , 1 , R4 , 2 , A4 , 3 , D4 \n' 'H , 2 , R5 , 1 , A5 , 3 , D5 \n' '\n' 'R1 = 2.67535 \n' 'R2 = 2.06501 A2 = 109.528 \n' 'R3 = 2.06501 A3 = 109.528 D3 = 120.808 \n' 'R4 = 2.06458 A4 = 108.982 D4 = 240.404 \n' 'R5 = 1.83748 A5 = 107.091 D5 = 299.596 \n') syms, key_mat, name_mat, val_dct = autoread.zmatrix.read( string, mat_entry_start_ptt=',', mat_entry_sep_ptt=',', setv_sep_ptt=app.padded(app.one_of_these(['', app.NEWLINE]))) assert syms == ('C', 'O', 'H', 'H', 'H', 'H') assert key_mat == ((None, None, None), (1, None, None), (1, 2, None), (1, 2, 3), (1, 2, 3), (2, 1, 3)) assert name_mat == ((None, None, None), ('R1', None, None), ('R2', 'A2', None), ('R3', 'A3', 'D3'), ('R4', 'A4', 'D4'), ('R5', 'A5', 'D5')) assert val_dct == { 'R1': 2.67535, 'R2': 2.06501, 'A2': 109.528, 'R3': 2.06501, 'A3': 109.528, 'D3': 120.808, 'R4': 2.06458, 'A4': 108.982, 'D4': 240.404, 'R5': 1.83748, 'A5': 107.091, 'D5': 299.596 } string = ('C \n' 'X , 1 , R1 \n' 'C , 1 , R2 , 2 , A2 \n' 'H , 1 , R3 , 2 , A3 , 3 , D3 \n' 'C , 3 , R4 , 1 , A4 , 2 , D4 \n' 'H , 3 , R5 , 1 , A5 , 5 , D5 \n' 'C , 5 , R6 , 3 , A6 , 1 , D6 \n' 'H , 5 , R7 , 3 , A7 , 7 , D7 \n' 'C , 7 , R8 , 5 , A8 , 3 , D8 \n' 'H , 7 , R9 , 5 , A9 , 9 , D9 \n' 'O , 9 , R10, 7 , A10, 5 , D10\n' 'H , 9 , R11, 7 , A11, 11, D11\n' '\n' 'R1 = 1 \n' 'R2 = 2.45306 A2 = 90 \n' 'R3 = 2.0156 A3 = 90 D3 = 180 \n' 'R4 = 2.72923 A4 = 125.99 D4 = 0 \n' 'R5 = 2.05621 A5 = 118.134 D5 = 180 \n' 'R6 = 2.53427 A6 = 131.892 D6 = 0.004769 \n' 'R7 = 2.06371 A7 = 112.345 D7 = 180 \n' 'R8 = 2.7902 A8 = 128.119 D8 = 1.62e-05 \n' 'R9 = 2.05471 A9 = 119.045 D9 = 180 \n' 'R10 = 2.31772 A10 = 120.738 D10 = 180 \n' 'R11 = 2.07277 A11 = 117.734 D11 = 180 \n') syms, key_mat, name_mat, val_dct = autoread.zmatrix.read( string, mat_entry_start_ptt=',', mat_entry_sep_ptt=',', setv_sep_ptt=app.padded(app.one_of_these(['', app.NEWLINE])))
def test__setval(): """ test autoread.zmatrix.setval """ string = (' A2 = 96.7725720000\n' ' D3 = 129.3669950000\n' ' R1 = 1.4470582953\n' ' R2 = 0.9760730000\n') val_dct = autoread.zmatrix.setval.read(string) assert val_dct == { 'A2': 96.772572, 'D3': 129.366995, 'R1': 1.4470582953, 'R2': 0.976073 } string = (' ----------------------------\n' ' ! Optimized Parameters !\n' ' ! (Angstroms and Degrees) !\n' ' ------------- -----\n' ' ! Name Value Derivative information !\n' ' ----------------------------------------------\n' ' ! R1 1.4057 -DE/DX = 0.0 !\n' ' ! R2 0.9761 -DE/DX = 0.0628 !\n' ' ! A2 96.7726 -DE/DX = 0.0552 !\n' ' ! D3 129.367 -DE/DX = 0.0019 !\n' ' ----------------------------------------------\n' ' GradGradGradGradGradGradGradGradGradGradGradGrad\n') start_ptt = app.padded(app.NEWLINE).join([ app.escape('! Optimized Parameters !'), app.LINE, app.LINE, app.LINE, app.LINE, '' ]) val_dct = autoread.zmatrix.setval.read( string, start_ptt=start_ptt, entry_sep_ptt='', entry_start_ptt=app.escape('!'), sep_ptt=app.maybe(app.LINESPACES).join( [app.escape('-DE/DX ='), app.FLOAT, app.escape('!'), app.NEWLINE])) assert val_dct == { 'R1': 1.4057, 'R2': 0.9761, 'A2': 96.7726, 'D3': 129.367 } string = ('R1 = 2.73454 \n' 'R2 = 1.84451 A2 = 96.7726 \n' 'R3 = 1.84451 A3 = 96.7726 D3 = 129.367 \n') val_dct = autoread.zmatrix.setval.read(string, sep_ptt=app.one_of_these( ['', app.NEWLINE])) assert val_dct == { 'R1': 2.73454, 'R2': 1.84451, 'A2': 96.7726, 'R3': 1.84451, 'A3': 96.7726, 'D3': 129.367 } string = (' SETTING R1 = 1.37586100\n' ' SETTING R2 = 1.05835400\n' ' SETTING A2 = 108.86198100\n' ' SETTING R3 = 1.05835400\n' ' SETTING A3 = 108.86198100\n' ' SETTING D3 = 120.32113700\n' ' SETTING R4 = 1.05835400\n' ' SETTING A4 = 108.86198100\n' ' SETTING D4 = 234.91269600\n' ' SETTING R5 = 0.95251900\n' ' SETTING A5 = 103.13240300\n' ' SETTING D5 = 297.93805300\n' ' SETTING SPIN = 0.00000000D+00\n' ' SETTING CHARGE = 0.00000000D+00\n') val_dct = autoread.zmatrix.setval.read( string, entry_start_ptt='SETTING', val_ptt=app.one_of_these([app.EXPONENTIAL_FLOAT_D, app.NUMBER]), last=False, case=False) assert val_dct == { 'R1': 1.375861, 'R2': 1.058354, 'A2': 108.861981, 'R3': 1.058354, 'A3': 108.861981, 'D3': 120.321137, 'R4': 1.058354, 'A4': 108.861981, 'D4': 234.912696, 'R5': 0.952519, 'A5': 103.132403, 'D5': 297.938053, 'SPIN': '0.00000000D+00', 'CHARGE': '0.00000000D+00' } string = (' Optimized variables\n' ' R1= 1.43218364 ANGSTROM\n' ' R2= 1.09538054 ANGSTROM\n' ' A2= 112.03775543 DEGREE\n' ' R3= 1.09538307 ANGSTROM\n' ' A3= 112.04463832 DEGREE\n' ' R4= 1.09084803 ANGSTROM\n' ' A4= 108.31761858 DEGREE\n' ' D4= 240.16203078 DEGREE\n' ' D5= 299.84441753 DEGREE\n') val_dct = autoread.zmatrix.setval.read( string, start_ptt=app.padded('Optimized variables') + app.NEWLINE, entry_end_ptt=app.one_of_these(['ANGSTROM', 'DEGREE']), last=True, case=False) assert val_dct == { 'R1': 1.43218364, 'R2': 1.09538054, 'A2': 112.03775543, 'R3': 1.09538307, 'A3': 112.04463832, 'R4': 1.09084803, 'A4': 108.31761858, 'D4': 240.16203078, 'D5': 299.84441753 }
def opt_zmatrix(output_string): """ get optimized z-matrix geometry from output """ # read the matrix from the beginning of the output syms, key_mat, name_mat = ar.zmatrix.matrix.read( output_string, start_ptt=app.maybe(app.SPACES).join( ['geometry', app.escape('='), app.escape('{'), '']), entry_start_ptt=app.maybe(','), entry_sep_ptt=',', last=False, case=False) # read the initial z-matrix values from the beginning out the output if len(syms) == 1: val_dct = {} else: val_dct = ar.zmatrix.setval.read( output_string, # entry_start_ptt=MOLPRO_ENTRY_START_PATTERN, entry_start_ptt='SETTING', name_ptt=(app.one_of_these(['R', 'A', 'D']) + app.one_or_more(app.INTEGER)), val_ptt=(app.one_of_these([app.EXPONENTIAL_FLOAT_D, app.NUMBER])), last=True, case=False) names = sorted(set(numpy.ravel(name_mat)) - {None}) caps_names = list(map(str.upper, names)) name_dct = dict(zip(caps_names, names)) assert set(caps_names) <= set(val_dct) val_dct = { name_dct[caps_name]: val_dct[caps_name] for caps_name in caps_names } # read optimized z-matrix values from the end of the output var_string = app.one_of_these( [app.padded('Optimized variables'), app.padded('Current variables')]) opt_val_dct = ar.zmatrix.setval.read(output_string, start_ptt=var_string + app.NEWLINE, entry_end_ptt=app.one_of_these( ['ANGSTROM', 'DEGREE']), last=True, case=False) opt_val_dct = { name_dct[caps_name]: opt_val_dct[caps_name] for caps_name in opt_val_dct.keys() } assert set(opt_val_dct) <= set(val_dct) val_dct.update(opt_val_dct) # call the automol constructor zma = automol.zmatrix.from_data(syms, key_mat, name_mat, val_dct, one_indexed=True, angstrom=True, degree=True) return zma
""" molecular geometry and structure readers """ import numpy import autoread as ar import autoparse.pattern as app import automol MOLPRO_ENTRY_START_PATTERN = ('SETTING' + app.SPACES + app.one_of_these(['R', 'A', 'D']) + app.one_or_more(app.INTEGER)) # 'SETTING' + app.not_followed_by(app.padded('MOLPRO_ENERGY')), # 'SETTING' + app.not_followed_by('MOLPRO_ENERGY'), # 'SETTING' + app.not_followed_by(app.padded('SPIN')), # 'SETTING' + app.not_followed_by(app.padded('CHARGE')) def opt_geometry(output_string): """ get optimized geometry from output """ ptt = app.padded(app.NEWLINE).join([ app.escape('Current geometry (xyz format, in Angstrom)'), '', app.UNSIGNED_INTEGER, (app.one_or_more(app.NONNEWLINE) + app.SPACES + 'ENERGY=' + app.FLOAT), '' ]) # app.padded(app.NEWLINE).join([ # app.escape('ATOMIC COORDINATES'), # app.LINE, app.LINE, app.LINE, '']), syms, xyzs = ar.geom.read(output_string, start_ptt=ptt) # line_start_ptt=(app.LETTER + app.maybe(app.LETTER)))
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
def _charge_layer_pattern(): q_slyr_ptt = _sublayer_pattern(key_ptt='q') p_slyr_ptt = _sublayer_pattern(key_ptt='p') ptt = (app.one_of_these([q_slyr_ptt, p_slyr_ptt]) + app.maybe(SLASH + p_slyr_ptt)) return ptt
from phydat import phycon from autoreact.params import RxnParams # Various strings needed to parse the data sections of the Reaction block CHEMKIN_ARROW = (app.maybe(app.escape('<')) + app.escape('=') + app.maybe(app.escape('>'))) CHEMKIN_PLUS_EM = app.PLUS + 'M' CHEMKIN_PAREN_PLUS_EM = app.escape('(') + app.PLUS + 'M' + app.escape(')') CHEMKIN_PAREN_PLUS = app.escape('(') + app.PLUS CHEMKIN_PAREN_CLOSE = app.escape(')') SPECIES_NAME_PATTERN = (r'[^\s=+\-]' + app.zero_or_more( app.one_of_these([ app.LETTER, app.DIGIT, r'[#,()\-_]', app.escape('*'), app.escape('(+)'), app.escape('['), app.escape(']') ])) + app.zero_or_more(app.PLUS)) SPECIES_NAMES_PATTERN = app.series(app.padded(SPECIES_NAME_PATTERN), app.padded(app.PLUS)) REACTION_PATTERN = (SPECIES_NAMES_PATTERN + app.padded(CHEMKIN_ARROW) + SPECIES_NAMES_PATTERN) COEFF_PATTERN = (app.NUMBER + app.LINESPACES + app.NUMBER + app.LINESPACES + app.NUMBER) COMMENTS_PATTERN = app.escape('!') + app.capturing( app.one_or_more(app.WILDCARD2)) BAD_STRS = ['inf', 'INF', 'nan']
""" energy parsers """ from autoparse import cast as _cast import autoparse.find as apf import autoparse.pattern as app # VALUE_PATTERN = app.one_of_these([app.FLOAT]) VALUE_PATTERN = app.one_of_these([app.EXPONENTIAL_FLOAT_D, app.FLOAT]) SEP_PATTERN = app.LINESPACES def read(string, start_ptt, val_ptt=VALUE_PATTERN, last=True, case=False): """ read energy from a string """ ptt_ = pattern(start_ptt=start_ptt, val_ptt=app.capturing(val_ptt)) ene_str = (apf.last_capture(ptt_, string, case=case) if last else apf.first_capture(ptt_, string, case=case)) ene = _cast(ene_str.replace('D', 'E')) return ene def pattern(start_ptt, val_ptt=VALUE_PATTERN): """ energy pattern """ return start_ptt + app.lpadded(val_ptt)
def opt_zmatrix(output_str): """ Reads the optimized Z-Matrix 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 """ # Reads the matrix from the beginning of the output symbs, key_mat, name_mat = ar.vmat.read( output_str, start_ptt=app.padded(app.NEWLINE).join( [app.escape('Symbolic Z-matrix:'), app.LINE, '']), symb_ptt=ar.par.Pattern.ATOM_SYMBOL + 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 end of the output if all(x is not None for x in (symbs, key_mat, name_mat)): grad_val = app.one_of_these([app.FLOAT, 'nan', '-nan']) if len(symbs) == 1: val_mat = ((None, None, None), ) else: val_dct = ar.setval.read(output_str, start_ptt=app.padded(app.NEWLINE).join([ app.padded('Optimized Parameters', app.NONNEWLINE), app.LINE, app.LINE, app.LINE, app.LINE, '' ]), entry_sep_ptt='', entry_start_ptt=app.escape('!'), sep_ptt=app.maybe(app.LINESPACES).join([ app.escape('-DE/DX ='), grad_val, app.escape('!'), app.NEWLINE ]), last=True) val_mat = ar.setval.convert_dct_to_matrix(val_dct, name_mat) # Check for the pattern err_ptt = app.LINESPACES.join( [app.escape('-DE/DX ='), app.one_of_these(['nan', '-nan'])]) if 'Optimized Parameters' in output_str: test_str = output_str.split('Optimized Parameters')[1] if apf.has_match(err_ptt, test_str): print('Warning: Bad gradient value (nan)', 'in "Optimized Parameters" list.') # 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 test__matrix(): """ test autoread.matrix """ # Gradients start_ptt = (app.padded(app.NEWLINE).join([ app.padded(app.escape('Forces (Hartrees/Bohr)'), app.NONNEWLINE), app.LINE, app.LINE, '' ])) mat = autoread.matrix.read(GRAD1_STR, start_ptt=start_ptt, line_start_ptt=app.LINESPACES.join( [app.UNSIGNED_INTEGER] * 2)) assert numpy.allclose(mat, ((0.0, -0.0, -0.061240635), (0.0, -0.021691602, 0.030622057), (-0.0, 0.021691602, 0.030622057))) start_ptt = (app.padded(app.NEWLINE).join([ app.escape('## Gradient (Symmetry 0) ##'), app.LINE, '', app.LINE, '', '' ])) mat = autoread.matrix.read(GRAD2_STR, start_ptt=start_ptt, line_start_ptt=app.UNSIGNED_INTEGER) assert numpy.allclose(mat, ((0.0, 0.0, 0.997), (0.0, -0.749, -0.488), (-0.0, 0.749, -0.488))) # Hessians start_ptt = (app.escape('The second derivative matrix:') + app.lpadded(app.NEWLINE)) comp_ptt = app.one_of_these(['X', 'Y', 'Z']) + app.UNSIGNED_INTEGER block_start_ptt = (app.series(comp_ptt, app.LINESPACES) + app.padded(app.NEWLINE)) mat = autoread.matrix.read(HESS1_STR, start_ptt=start_ptt, block_start_ptt=block_start_ptt, line_start_ptt=comp_ptt, tril=True) assert numpy.allclose( mat, ((-0.21406, 0., 0., -0.06169, 0., 0., 0.27574, 0., 0.), (0., 2.05336, 0.12105, 0., -0.09598, 0.08316, 0., -1.95737, -0.20421), (0., 0.12105, 0.19177, 0., -0.05579, -0.38831, 0., -0.06525, 0.19654), (-0.06169, 0., 0., 0.0316, 0., 0., 0.03009, 0., 0.), (0., -0.09598, -0.05579, 0., 0.12501, -0.06487, 0., -0.02902, 0.12066), (0., 0.08316, -0.38831, 0., -0.06487, 0.44623, 0., -0.01829, -0.05792), (0.27574, 0., 0., 0.03009, 0., 0., -0.30583, 0., 0.), (0., -1.95737, -0.06525, 0., -0.02902, -0.01829, 0., 1.9864, 0.08354), (0., -0.20421, 0.19654, 0., 0.12066, -0.05792, 0., 0.08354, -0.13862))) start_ptt = (app.padded(app.NEWLINE).join( [app.escape('## Hessian (Symmetry 0) ##'), app.LINE, ''])) block_start_ptt = (app.padded(app.NEWLINE).join( ['', app.series(app.UNSIGNED_INTEGER, app.LINESPACES), '', ''])) mat = autoread.matrix.read(HESS2_STR, start_ptt=start_ptt, block_start_ptt=block_start_ptt, line_start_ptt=app.UNSIGNED_INTEGER) assert numpy.allclose( mat, ((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.0, 0.959, 0.0, 0.0, -0.452, 0.519, 0.0, -0.477, -0.23), (0.0, 0.0, 0.371, 0.0, 0.222, -0.555, 0.0, -0.279, -0.128), (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.0, -0.479, 0.279, 0.0, 0.455, -0.256, 0.0, -0.017, 0.051), (0.0, 0.251, -0.185, 0.0, -0.247, 0.607, 0.0, -0.012, 0.09), (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.0, -0.479, -0.279, 0.0, -0.003, -0.263, 0.0, 0.494, 0.279), (0.0, -0.251, -0.185, 0.0, 0.025, 0.947, 0.0, 0.292, 0.137))) # Test finding nothing mat = autoread.matrix.read('', start_ptt=start_ptt, block_start_ptt=block_start_ptt, line_start_ptt=app.UNSIGNED_INTEGER) assert mat is None
def opt_zmatrix(output_str): """ Reads the optimized Z-Matrix 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 """ # Reads the matrix from the beginning of the output symbs, key_mat, name_mat = ar.vmat.read( output_str, start_ptt=app.maybe(app.SPACES).join([ 'geometry', app.escape('='), app.escape('{'), '']), entry_start_ptt=app.maybe(','), entry_sep_ptt=',', last=False, case=False) # Read the initial z-matrix values from the beginning out the output if all(x is not None for x in (symbs, key_mat, name_mat)): if len(symbs) == 1: val_dct = {} else: val_dct = ar.setval.read( output_str, # entry_start_ptt=MOLPRO_ENTRY_START_PATTERN, entry_start_ptt='SETTING', name_ptt=( app.one_of_these(['R', 'A', 'D']) + app.one_or_more(app.INTEGER)), val_ptt=( app.one_of_these([app.EXPONENTIAL_FLOAT_D, app.NUMBER])), last=True, case=False) names = sorted(set(numpy.ravel(name_mat)) - {None}) caps_names = list(map(str.upper, names)) name_dct = dict(zip(caps_names, names)) assert set(caps_names) <= set(val_dct) val_dct = {name_dct[caps_name]: val_dct[caps_name] for caps_name in caps_names} # Read optimized z-matrix values from the end of the output var_string = app.one_of_these([ app.padded('Optimized variables'), app.padded('Current variables') ]) opt_val_dct = ar.setval.read( output_str, start_ptt=var_string + app.NEWLINE, entry_end_ptt=app.one_of_these(['ANGSTROM', 'DEGREE']), last=True, case=False) opt_val_dct = {name_dct[caps_name]: opt_val_dct[caps_name] for caps_name in opt_val_dct.keys()} assert set(opt_val_dct) <= set(val_dct) val_dct.update(opt_val_dct) val_mat = ar.setval.convert_dct_to_matrix(val_dct, name_mat) # 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 test__setval(): """ test autoread.zmat.setval """ val_dct = autoread.setval.read(ZMA_VAL1_STR) assert val_dct == { 'A2': 96.772572, 'D3': 129.366995, 'R1': 1.4470582953, 'R2': 0.976073 } start_ptt = app.padded(app.NEWLINE).join([ app.escape('! Optimized Parameters !'), app.LINE, app.LINE, app.LINE, app.LINE, '' ]) val_dct = autoread.setval.read(ZMA_VAL2_STR, start_ptt=start_ptt, entry_sep_ptt='', entry_start_ptt=app.escape('!'), sep_ptt=app.maybe(app.LINESPACES).join([ app.escape('-DE/DX ='), app.FLOAT, app.escape('!'), app.NEWLINE ])) assert val_dct == { 'R1': 1.4057, 'R2': 0.9761, 'A2': 96.7726, 'D3': 129.367 } val_dct = autoread.setval.read(ZMA_VAL3_STR, sep_ptt=app.one_of_these(['', app.NEWLINE])) assert val_dct == { 'R1': 2.73454, 'R2': 1.84451, 'A2': 96.7726, 'R3': 1.84451, 'A3': 96.7726, 'D3': 129.367 } val_dct = autoread.setval.read(ZMA_VAL4_STR, entry_start_ptt='SETTING', val_ptt=app.one_of_these( [app.EXPONENTIAL_FLOAT_D, app.NUMBER]), last=False, case=False) assert val_dct == { 'R1': 1.375861, 'R2': 1.058354, 'A2': 108.861981, 'R3': 1.058354, 'A3': 108.861981, 'D3': 120.321137, 'R4': 1.058354, 'A4': 108.861981, 'D4': 234.912696, 'R5': 0.952519, 'A5': 103.132403, 'D5': 297.938053, 'SPIN': '0.00000000D+00', 'CHARGE': '0.00000000D+00' } val_dct = autoread.setval.read( ZMA_VAL5_STR, start_ptt=app.padded('Optimized variables') + app.NEWLINE, entry_end_ptt=app.one_of_these(['ANGSTROM', 'DEGREE']), last=True, case=False) assert val_dct == { 'R1': 1.43218364, 'R2': 1.09538054, 'A2': 112.03775543, 'R3': 1.09538307, 'A3': 112.04463832, 'R4': 1.09084803, 'A4': 108.31761858, 'D4': 240.16203078, 'D5': 299.84441753 }
def test_zmat(): """ test autoread.zmat """ def _val_mats_similar(val_mat, ref_val_mat): """ Check if two value matrices are the same """ for i, row in enumerate(val_mat): for j, val in enumerate(row): ref_val = ref_val_mat[i][j] if val is None: assert ref_val is None else: assert numpy.isclose(val, ref_val) # Simple ZMA reads start_ptt = ( app.padded(app.escape('Geometry (in Angstrom),'), app.NONNEWLINE) + 2 * app.padded(app.NEWLINE)) symbs, key_mat, name_mat, val_mat = autoread.zmat.read(ZMA1_STR, start_ptt=start_ptt) assert symbs == ('O', 'O', 'H', 'H') assert key_mat == ((None, None, None), (1, None, None), (1, 2, None), (2, 1, 3)) assert name_mat == ((None, None, None), ('R1', None, None), ('R2', 'A2', None), ('R2', 'A2', 'D3')) ref_val_mat = ((None, None, None), (1.4470582953, None, None), (0.976073, 96.772572, None), (0.976073, 96.772572, 129.36699)) _val_mats_similar(val_mat, ref_val_mat) symbs, key_mat, name_mat, val_mat = autoread.zmat.read( ZMA2_STR, mat_entry_start_ptt=',', mat_entry_sep_ptt=',', setv_sep_ptt=app.padded(app.one_of_these(['', app.NEWLINE]))) assert symbs == ('C', 'O', 'H', 'H', 'H', 'H') assert key_mat == ((None, None, None), (1, None, None), (1, 2, None), (1, 2, 3), (1, 2, 3), (2, 1, 3)) assert name_mat == ((None, None, None), ('R1', None, None), ('R2', 'A2', None), ('R3', 'A3', 'D3'), ('R4', 'A4', 'D4'), ('R5', 'A5', 'D5')) ref_val_mat = ((None, None, None), (2.67535, None, None), (2.06501, 109.528, None), (2.06501, 109.528, 120.808), (2.06458, 108.982, 240.404), (1.83748, 107.091, 299.596)) _val_mats_similar(val_mat, ref_val_mat) # assert val_dct == { # 'R1': 2.67535, 'R2': 2.06501, 'A2': 109.528, 'R3': 2.06501, # 'A3': 109.528, 'D3': 120.808, 'R4': 2.06458, 'A4': 108.982, # 'D4': 240.404, 'R5': 1.83748, 'A5': 107.091, 'D5': 299.596} symbs, key_mat, name_mat, val_mat = autoread.zmat.read( ZMA4_STR, mat_entry_start_ptt=',', mat_entry_sep_ptt=',', setv_sep_ptt=app.padded(app.one_of_these(['', app.NEWLINE])), last=False) assert symbs == ('C', ) assert key_mat == ((None, None, None), ) assert name_mat == ((None, None, None), ) assert val_mat == ((None, None, None), ) # Check last functionality symbs, key_mat, name_mat, val_mat = autoread.zmat.read( ZMA2_STR + '\n\n' + ZMA3_STR, mat_entry_start_ptt=',', mat_entry_sep_ptt=',', setv_sep_ptt=app.padded(app.one_of_these(['', app.NEWLINE])), last=False) assert symbs == ('C', 'O', 'H', 'H', 'H', 'H') assert key_mat == ((None, None, None), (1, None, None), (1, 2, None), (1, 2, 3), (1, 2, 3), (2, 1, 3)) assert name_mat == ((None, None, None), ('R1', None, None), ('R2', 'A2', None), ('R3', 'A3', 'D3'), ('R4', 'A4', 'D4'), ('R5', 'A5', 'D5')) ref_val_mat = ((None, None, None), (2.67535, None, None), (2.06501, 109.528, None), (2.06501, 109.528, 120.808), (2.06458, 108.982, 240.404), (1.83748, 107.091, 299.596)) _val_mats_similar(val_mat, ref_val_mat)
def _main_layer_pattern(): c_slyr_ptt = _sublayer_pattern(key_ptt='c') h_slyr_ptt = _sublayer_pattern(key_ptt='h') ptt = (app.one_of_these([c_slyr_ptt, h_slyr_ptt]) + app.maybe(SLASH + h_slyr_ptt)) return ptt
def _has_scf_convergence_message(output_string): """ does this output string have a convergence success message? """ scf_str1 = 'Energy and wave function converged' pattern = app.one_of_these([scf_str1]) return apf.has_match(pattern, output_string, case=True)
def options_matrix_optimization(script_str, prefix, geom, chg, mul, method, basis, prog, errors=(), options_mat=(), feedback=False, frozen_coordinates=(), freeze_dummy_atoms=True, **kwargs): """ try several sets of options to generate an output file :returns: the input string and the output string :rtype: (str, str) """ assert len(errors) == len(options_mat) subrun_fs = autofile.fs.subrun(prefix) max_macro_idx, _ = max(subrun_fs[-1].existing(), default=(-1, -1)) macro_idx = max_macro_idx + 1 micro_idx = 0 read_geom_ = (elstruct.reader.opt_zmatrix_(prog) if automol.zmatrix.is_valid(geom) else elstruct.reader.opt_geometry_(prog)) if freeze_dummy_atoms and automol.zmatrix.is_valid(geom): frozen_coordinates = (tuple(frozen_coordinates) + automol.zmatrix.dummy_coordinate_names(geom)) kwargs_ = dict(kwargs) while True: subrun_fs[-1].create([macro_idx, micro_idx]) path = subrun_fs[-1].path([macro_idx, micro_idx]) with warnings.catch_warnings(): warnings.simplefilter('ignore') inp_str, out_str = elstruct.run.direct( elstruct.writer.optimization, script_str, path, geom=geom, charge=chg, mult=mul, method=method, basis=basis, prog=prog, frozen_coordinates=frozen_coordinates, **kwargs_) error_vals = [ elstruct.reader.has_error_message(prog, error, out_str) for error in errors ] # Kill the while loop if we Molpro error signaling a hopeless point # When an MCSCF WF calculation fails to converge at some step in opt # it is not clear how to save the optimization, so we give up on opt fail_pattern = app.one_of_these([ app.escape('The problem occurs in Multi'), app.escape('The problem occurs in cipro') ]) if apf.has_match(fail_pattern, out_str, case=False):
def opt_zmatrix(output_str): """ Reads the optimized Z-Matrix 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 """ # complicated string patterns for the initial matrix read mat_ptt = app.padded(app.NEWLINE).join([ app.LINESPACES.join( [app.escape('Input from ZMAT file'), app.escape('*')]), app.LINE, app.LINE, '' ]) nam_ptt = (app.LETTER + app.one_or_more( app.one_of_these([app.LETTER, app.UNDERSCORE, app.DIGIT])) + app.maybe(app.escape('*'))) # read the matrix from the beginning of the output symbs, key_mat, name_mat = ar.vmat.read( output_str, start_ptt=mat_ptt, symb_ptt=ar.par.Pattern.ATOM_SYMBOL + app.maybe(app.UNSIGNED_INTEGER), key_ptt=app.one_of_these([app.UNSIGNED_INTEGER, app.VARIABLE_NAME]), name_ptt=nam_ptt, last=False) # Remove any asterisks(*) from the entries in the name matrix if all(x is not None for x in (symbs, key_mat, name_mat)): name_mat = tuple([[ name.replace('*', '') if name is not None else None for name in name_row ] for name_row in name_mat]) # complicated string patterns for the value dictionary read start_ptt = app.padded(app.NEWLINE).join( [app.padded('Final ZMATnew file', app.NONNEWLINE)] + [app.LINE for i in range(len(symbs) + 3)] + ['']) # read the values from the end of the output if len(symbs) == 1: # val_dct = {} val_mat = ((None, None, None), ) else: val_dct = ar.setval.read(output_str, start_ptt=start_ptt, entry_sep_ptt='=', last=True) val_mat = ar.setval.convert_dct_to_matrix(val_dct, name_mat) # 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 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
def test__matrix(): """ test autoread.matrix """ # gaussian gradient string = (' ***** Axes restored to original set *****\n' ' ------------------------------------------------------------\n' ' Center Atomic Forces (Hartrees/Bohr)\n' ' Number Number X Y Z\n' ' ------------------------------------------------------------\n' ' 1 8 0.000000000 -0.000000000 -0.061240635\n' ' 2 1 0.000000000 -0.021691602 0.030622057\n' ' 3 1 -0.000000000 0.021691602 0.030622057\n' ' ------------------------------------------------------------\n' ' Cartesian Forces: Max 0.061240635 RMS 0.027012111\n') mat = autoread.matrix.read( string, start_ptt=app.padded(app.NEWLINE).join([ app.padded(app.escape('Forces (Hartrees/Bohr)'), app.NONNEWLINE), app.LINE, app.LINE, '' ]), line_start_ptt=app.LINESPACES.join([app.UNSIGNED_INTEGER] * 2)) assert numpy.allclose(mat, ((0.0, -0.0, -0.061240635), (0.0, -0.021691602, 0.030622057), (-0.0, 0.021691602, 0.030622057))) # gaussian hessian string = (' The second derivative matrix:\n' ' X1 Y1 Z1 X2 Y2\n' ' X1 -0.21406\n' ' Y1 -0.00000 2.05336\n' ' Z1 -0.00000 0.12105 0.19177\n' ' X2 -0.06169 -0.00000 0.00000 0.03160\n' ' Y2 0.00000 -0.09598 -0.05579 -0.00000 0.12501\n' ' Z2 0.00000 0.08316 -0.38831 -0.00000 -0.06487\n' ' X3 0.27574 0.00000 0.00000 0.03009 -0.00000\n' ' Y3 0.00000 -1.95737 -0.06525 0.00000 -0.02902\n' ' Z3 0.00000 -0.20421 0.19654 -0.00000 0.12066\n' ' Z2 X3 Y3 Z3\n' ' Z2 0.44623\n' ' X3 0.00000 -0.30583\n' ' Y3 -0.01829 -0.00000 1.98640\n' ' Z3 -0.05792 -0.00000 0.08354 -0.13862\n' ' ITU= 0\n' ' Eigenvalues --- 0.06664 0.66895 3.25121\n') comp_ptt = app.one_of_these(['X', 'Y', 'Z']) + app.UNSIGNED_INTEGER mat = autoread.matrix.read( string, start_ptt=(app.escape('The second derivative matrix:') + app.lpadded(app.NEWLINE)), block_start_ptt=(app.series(comp_ptt, app.LINESPACES) + app.padded(app.NEWLINE)), line_start_ptt=comp_ptt, tril=True) assert numpy.allclose( mat, ((-0.21406, 0., 0., -0.06169, 0., 0., 0.27574, 0., 0.), (0., 2.05336, 0.12105, 0., -0.09598, 0.08316, 0., -1.95737, -0.20421), (0., 0.12105, 0.19177, 0., -0.05579, -0.38831, 0., -0.06525, 0.19654), (-0.06169, 0., 0., 0.0316, 0., 0., 0.03009, 0., 0.), (0., -0.09598, -0.05579, 0., 0.12501, -0.06487, 0., -0.02902, 0.12066), (0., 0.08316, -0.38831, 0., -0.06487, 0.44623, 0., -0.01829, -0.05792), (0.27574, 0., 0., 0.03009, 0., 0., -0.30583, 0., 0.), (0., -1.95737, -0.06525, 0., -0.02902, -0.01829, 0., 1.9864, 0.08354), (0., -0.20421, 0.19654, 0., 0.12066, -0.05792, 0., 0.08354, -0.13862))) # psi4 gradient string = (' ## Gradient (Symmetry 0) ##\n' ' Irrep: 1 Size: 3 x 3\n' '\n' ' 1 2 3\n' '\n' ' 1 0.000 0.000 0.997\n' ' 2 0.000 -0.749 -0.488\n' ' 3 -0.000 0.749 -0.488\n') mat = autoread.matrix.read(string, start_ptt=app.padded(app.NEWLINE).join([ app.escape('## Gradient (Symmetry 0) ##'), app.LINE, '', app.LINE, '', '' ]), line_start_ptt=app.UNSIGNED_INTEGER) assert numpy.allclose(mat, ((0.0, 0.0, 0.997), (0.0, -0.749, -0.488), (-0.0, 0.749, -0.488))) # psi4 hessian string = ('-------------------------------------------\n' ' ## Hessian (Symmetry 0) ##\n' ' Irrep: 1 Size: 9 x 9\n' '\n' ' 1 2 3 4 5 \n' '\n' ' 1 0.000 0.000 0.000 0.000 0.000\n' ' 2 0.000 0.959 0.000 0.000 -0.452\n' ' 3 0.000 0.000 0.371 0.000 0.222\n' ' 4 0.000 0.000 0.000 0.000 0.000\n' ' 5 0.000 -0.479 0.279 0.000 0.455\n' ' 6 0.000 0.251 -0.185 0.000 -0.247\n' ' 7 0.000 0.000 0.000 0.000 0.000\n' ' 8 0.000 -0.479 -0.279 0.000 -0.003\n' ' 9 0.000 -0.251 -0.185 0.000 0.025\n' '\n' ' 6 7 8 9\n' '\n' ' 1 0.000 0.000 0.000 0.000\n' ' 2 0.519 0.000 -0.477 -0.230\n' ' 3 -0.555 0.000 -0.279 -0.128\n' ' 4 0.000 0.000 0.000 0.000\n' ' 5 -0.256 0.000 -0.017 0.051\n' ' 6 0.607 0.000 -0.012 0.090\n' ' 7 0.000 0.000 0.000 0.000\n' ' 8 -0.263 0.000 0.494 0.279\n' ' 9 0.947 0.000 0.292 0.137\n') mat = autoread.matrix.read(string, start_ptt=app.padded(app.NEWLINE).join([ app.escape('## Hessian (Symmetry 0) ##'), app.LINE, '' ]), block_start_ptt=app.padded(app.NEWLINE).join([ '', app.series(app.UNSIGNED_INTEGER, app.LINESPACES), '', '' ]), line_start_ptt=app.UNSIGNED_INTEGER) assert numpy.allclose( mat, ((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.0, 0.959, 0.0, 0.0, -0.452, 0.519, 0.0, -0.477, -0.23), (0.0, 0.0, 0.371, 0.0, 0.222, -0.555, 0.0, -0.279, -0.128), (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.0, -0.479, 0.279, 0.0, 0.455, -0.256, 0.0, -0.017, 0.051), (0.0, 0.251, -0.185, 0.0, -0.247, 0.607, 0.0, -0.012, 0.09), (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.0, -0.479, -0.279, 0.0, -0.003, -0.263, 0.0, 0.494, 0.279), (0.0, -0.251, -0.185, 0.0, 0.025, 0.947, 0.0, 0.292, 0.137)))
def options_matrix_optimization(script_str, prefix, geo, chg, mul, method, basis, prog, errors=(), options_mat=(), feedback=False, frozen_coordinates=(), freeze_dummy_atoms=True, **kwargs): """ try several sets of options to generate an output file :param script_str: BASH submission script for electronic structure job :type script_str: str :param prefix: :type prefix: :param geo: molecular geometry or Z-Matrix :type geo: :param chg: electric charge :type chg: int :param mul: spin-multiplicity :type mul: int :param method: name of the electronic structure method :type method: str :param basis: name of the basis set :type basis: str :param prog: name of the electronic structure program :type prog: str :param errors: list of error message types to search output for :type errors: tuple(str) :param options_mat: varopis options to run job with :type options_mat: tuple(dict[str: str]) :param feedback: update geom with job from previous sequence :type feedback: bool :param frozen_coordinates: Z-matrix coordinate names to freeze in opts :type frozen_coordinates: tuple(str) :param freeze_dummy_atoms: freeze any coords defined by dummy atoms :type freeze_dummy_atoms: bool :param kwargs: :type: :returns: the input string and the output string :rtype: (str, str) """ assert len(errors) == len(options_mat) subrun_fs = autofile.fs.subrun(prefix) max_macro_idx, _ = max(subrun_fs[-1].existing(), default=(-1, -1)) macro_idx = max_macro_idx + 1 if macro_idx == 26: macro_idx = 0 micro_idx = 0 if freeze_dummy_atoms and automol.zmat.is_valid(geo): frozen_coordinates = (tuple(frozen_coordinates) + automol.zmat.dummy_coordinate_names(geo)) kwargs_ = dict(kwargs) # Initialize loop geo step_geo = geo while True: subrun_fs[-1].create([macro_idx, micro_idx]) path = subrun_fs[-1].path([macro_idx, micro_idx]) with warnings.catch_warnings(): warnings.simplefilter('ignore') inp_str, out_str = elstruct.run.direct( elstruct.writer.optimization, script_str, path, geo=step_geo, charge=chg, mult=mul, method=method, basis=basis, prog=prog, frozen_coordinates=frozen_coordinates, **kwargs_) error_vals = [elstruct.reader.has_error_message(prog, error, out_str) for error in errors] # Kill the while loop if we Molpro error signaling a hopeless point # When an MCSCF WF calculation fails to converge at some step in opt # it is not clear how to save the optimization, so we give up on opt fail_pattern = app.one_of_these([ app.escape('The problem occurs in Multi'), app.escape('The problem occurs in cipro') ]) if apf.has_match(fail_pattern, out_str, case=False):