def format_rotor_potential(potential): """ Formats the potential energy surface along a rotor into a string used to define hindered rotors and internal rotors in MESS input files. :param potential: value of the potential along torsion (kcal.mol-1) :type potential: list(float) :return npotential: number of values in the potential :rtype int :return potential_str: values of potential in a MESS-format string :rtype str """ # Get the number of the terms in the potential npot = len(potential) # Build potentials string coord_str, ene_str = '', '' for i, (coord, energy) in enumerate(potential.items()): if ((i + 1) % 6) == 0 and (i + 1) != npot: coord_str += f'{coord[0]:<8.2f}\n' ene_str += f'{energy:<8.2f}\n' else: coord_str += f'{coord[0]:<8.2f}' ene_str += f'{energy:<8.2f}' # Indent the lines coord_str = indent(coord_str, 4) ene_str = indent(ene_str, 4) return npot, coord_str, ene_str
def core_phasespace(geom1, geom2, sym_factor, stoich, pot_prefactor=10.0, pot_exp=6.0, tstlvl='e'): """ Writes the string that defines the `Core` section for a phase space theory model of a transition state for a MESS input file by formatting input information into strings a filling Mako template. :param geom1: geometry of the dissociation species 1 :type geom1: list :param geom2: geometry of the dissociation species 2 :type geom2: list :param sym_factor: symmetry factor of transition state :type sym_factor: float :param stoich: combined stoichiometry of dissociation species 1 and 2 :type stoich: str :param pot_prefator: factor C0 in potential expression V = -C0/R^n (au) :type pot_prefactor: float :param pot_exp: power n in potential expression V = -C0/R^n (au) :type pot_exp: float :param tstlvl: level to resolve the rate constant :type tstlvl: str :rtype: str """ assert tstlvl in ('e', 'ej', 't') # Format the geometry section of each fragment natom1, geom1 = util.geom_format(geom1) natom2, geom2 = util.geom_format(geom2) # Indent the geometry strings geom1 = indent(geom1, 2) geom2 = indent(geom2, 2) # Format the tstlvl string assert tstlvl in ('e', 'ej', 't') tstlvl = tstlvl.upper() # Create dictionary to fill template core_keys = { 'sym_factor': sym_factor, 'natom1': natom1, 'geom1': geom1, 'natom2': natom2, 'geom2': geom2, 'stoich': stoich, 'pot_prefactor': pot_prefactor, 'pot_exp': pot_exp, 'tstlvl': tstlvl } return build_mako_str(template_file_name='core_phasespace.mako', template_src_path=SPEC_INFO_PATH, template_keys=core_keys)
def intensities_format(intens): """ Formats the vibrational intenuencies of a species into a string that is appropriate for a MESS input file. :param intens: harmonic infrared intensities of species :type intens: list(float) :return nintens: number of harmonic infrared intensities for species :rtype int :return inten_str: MESS-format string containing infrared intensities :rtype string """ # Get the number of intens nintens = len(intens) # Build intens string inten_str = '' for i, inten in enumerate(intens): if ((i + 1) % 6) == 0 and (i + 1) != len(intens): inten_str += '{0:<8.1f}\n'.format(int(inten)) else: inten_str += '{0:<8.1f}'.format(inten) # Indent the lines inten_str = indent(inten_str, 4) return nintens, inten_str
def format_rotor_potential(potential): """ Formats the potential energy surface along a rotor into a string used to define hindered rotors and internal rotors in MESS input files. :param potential: value of the potential along torsion (kcal.mol-1) :type potential: list(float) :return npotential: number of values in the potential :rtype int :return potential_str: values of potential in a MESS-format string :rtype str """ # Get the number of the terms in the potential npotential = len(potential) # Build potentials string potential_str = '' for i, energy in enumerate(potential.values()): if ((i + 1) % 6) == 0 and (i + 1) != npotential: potential_str += '{0:<8.2f}\n'.format(energy) else: potential_str += '{0:<8.2f}'.format(energy) # Indent the lines potential_str = indent(potential_str, 4) return npotential, potential_str
def freqs_format(freqs): """ Formats the vibrational frequencies of a species into a string that is appropriate for a MESS input file. :param freqs: vibrational frequencies of species :type freqs: list(float) :return nfreqs: number of frequences for the species :rtype int :return freq_str: MESS-format string containing frequencies :rtype string """ # Get the number of freqs nfreqs = len(freqs) # Build freqs string freq_str = '' for i, freq in enumerate(freqs): if ((i + 1) % 6) == 0 and (i + 1) != len(freqs): freq_str += '{0:<8.0f}\n'.format(int(freq)) else: freq_str += '{0:<8.0f}'.format(freq) # Indent the lines freq_str = indent(freq_str, 4) return nfreqs, freq_str
def geometry_format(geo, indent_lines=True): """ Formats the geometry of a species into a string that is appropriate for a MESS input file. :param geo: geometry of a species :param indent_lines: indent the lines of the geometry :return natoms: number of atoms in the geometry :rtype int :return geo_str: MESS-format string containing geometry :rtype string """ # Get the number of atoms natoms = len(geo) # Build geom string; converting the coordinates to angstrom gstr = '' for (symb, xyz) in geo: xyzc = tuple(val * 0.529177 for val in xyz) gstr += f'{symb:<4s}{xyzc[0]:>14.5f}{xyzc[1]:>14.5f}{xyzc[2]:>14.5f}\n' # Remove final newline character and indent the lines if indent_lines: gstr = indent(gstr.rstrip(), 4) else: gstr = gstr.rstrip() return natoms, gstr
def _format_well_extension_inp(inp_str, well_enes_dct, well_lump_str): """ handles building new input will well lumping/extension info """ # Reinitialize string new_inp_str = inp_str # Write string for each of the well enes for well, ene in well_enes_dct.items(): if ene is not None: # Find line for where well start, for-loop handle weird format for line in inp_str.splitlines(): if 'Well' in line and well in line: _search = line break _add = f' WellExtensionCap[kcal/mol] {ene*phycon.EH2KCAL:.2f}' new_inp_str = ioformat.add_line(string=new_inp_str, addline=_add, searchline=_search, position='after') # Write new strings with the lumped input well_extend_line = 'WellExtension\nExtensionCorrection 0.2' well_lump_line = ioformat.indent(well_lump_str, 2) new_inp_str = ioformat.add_line(string=new_inp_str, addline=well_extend_line, searchline='Model', position='before') new_inp_str = ioformat.add_line(string=new_inp_str, addline=well_lump_line, searchline='Model', position='after') return new_inp_str
def format_xmat(xmat): """ Formats the anharmonicity (X) matrix for a species into a string appropriate for a MESS input file. :param xmat: anharmonicity matrix (cm-1) :type xmat: list(list(float)) :return xmat_str: anharmonicity matrix in a MESS-format string :rtype string """ xmat = numpy.array(xmat) # Loop over the rows of the anharm numpy array xmat_str = '' for i in range(xmat.shape[0]): xmat_str += ' '.join([ '{0:>12.5f}'.format(val) for val in list(xmat[i, :i + 1]) if val != 0.0 ]) if (i + 1) != xmat.shape[0]: xmat_str += '\n' # Indent the lines xmat_str = indent(xmat_str, 2) return xmat_str
def rotor_hindered(group, axis, symmetry, potential, remdummy=None, geom=None, use_quantum_weight=False, rotor_id=''): """ Writes the string that defines the `Rotor` section for a single hindered rotor of a species for a MESS input file by formatting input information into strings a filling Mako template. :param group: idxs for the atoms of one of the rotational groups :type group: list(int) :param axis: idxs for the atoms that make up the rotational axis :type axis: list(int) :param symmetry: overall symmetry of the torsional motion (potential) :type symmetry: int :param potential: value of the potential along torsion (kcal.mol-1) :type potential: list(float) :param remdummy: list of idxs of dummy atoms for shifting values :type remdummy: list(int) :param geom: geometry of the species the rotor exists for :type geom: list :param use_quantum_weight: toggle weigthing of quantum effects :type use_quantum_weight: bool :param rotor_id: name associated with the rotor :type rotor_id: str :rtype: str """ # Format the rotor sections rotor_group = util.format_rotor_key_defs(group, remdummy) rotor_axis = util.format_rotor_key_defs(axis, remdummy) rotor_npotential, rotor_potential = util.format_rotor_potential(potential) # Format the geom natom = 1 if geom is not None: natom, geom = util.geom_format(geom) geom = indent(geom, 4) # Create dictionary to fill template rotor_keys = { 'group': rotor_group, 'axis': rotor_axis, 'symmetry': symmetry, 'npotential': rotor_npotential, 'potential': rotor_potential, 'natom': natom, 'geom': geom, 'use_quantum_weight': use_quantum_weight, 'rotor_id': rotor_id } return build_mako_str(template_file_name='rotor_hindered.mako', template_src_path=SPEC_INFO_PATH, template_keys=rotor_keys)
def symbols_format(geo): """ Format the symbols """ symbs = automol.geom.symbols(geo) symb_str = automol.util.vec.string(symbs, num_per_row=6, val_format='{0:>6s}') symb_str = indent(symb_str, 6) return symb_str
def geometry_format(geo): """ Format the geometry string """ # Build geom str geo_str = '' for (_, xyz) in geo: geo_str += '{:>14.5f}{:>14.5f}{:>14.5f}\n'.format(*xyz) # Remove final newline character and indent the lines geo_str = indent(geo_str.rstrip(), 4) return geo_str
def geometry_format(geo): """ Format the geometry string """ # Build geom str geo_str = '' for (_, xyz) in geo: geo_str += f'{xyz[0]:>14.5f}{xyz[1]:>14.5f}{xyz[2]:>14.5f}\n' # Indent the lines and remove final newline character geo_str = indent(geo_str, 4) geo_str = geo_str.rstrip() return geo_str
def global_energy_transfer_input(edown_str, collid_freq_str): """ Writes the global energy transfer section of the MESS input file by formatting input information into strings a filling Mako template. :param edown_str: String for the energy down parameters :type edown_str: str :param collid_freq_str: String for the collisional freq parameters :type collid_freq_str: str :rtype: str """ edown_str = indent(edown_str, 2) collid_freq_str = indent(collid_freq_str, 2) # Create dictionary to fill template glob_etrans_keys = { 'edown_str': edown_str, 'collid_freq_str': collid_freq_str } return build_mako_str(template_file_name='global_etrans.mako', template_src_path=SECTION_PATH, template_keys=glob_etrans_keys)
def format_rovib_coups(rovib_coups): """ Formats the matrix of rovibrational coupling terms for a species into a string appropriate for a MESS input file. :param rovib_coups: rovibrational coupling matrix :type rovib_coups: numpy.ndarray :return rovib_coups_str: values of potential in a MESS-format string :rtype str """ # Join the values into a string rovib_coups_str = ' '.join(str(val) for val in rovib_coups) # Indent the lines rovib_coups_str = indent(rovib_coups_str, 4) return rovib_coups_str
def core_multirotor(geom, sym_factor, pot_surf_file, int_rot_str, interp_emax=100, quant_lvl_emax=9): """ Writes the string that defines the `Core` section for a multidimensional rotor model of a species for a MESS input file by formatting input information into strings a filling Mako template. :param geom: geometry of species :type geom: list :param sym_factor: symmetry factor of species :type sym_factor: float :param pot_surf_file: name of file with PES along rotor (kcal.mol-1) :type pot_sur_file: str :param int_rot_str: MESS-format strings that define internal rotors :type int_rot_str: str :param interp_emax: max energy to calculate density/number of states :type interp_emax: float :param quant_lvl_emax: max energy to calculate quantum energy levels :type quant_lvl_emax: float :rtype: str """ # Format the geometry section natom, geom = util.geom_format(geom) # Indent the internal rotor string int_rot_str = indent(int_rot_str, 2) # Create dictionary to fill template core_keys = { 'sym_factor': sym_factor, 'natom': natom, 'geom': geom, 'pot_surf_file': pot_surf_file, 'int_rot': int_rot_str, 'interp_emax': interp_emax, 'quant_lvl_emax': quant_lvl_emax } return build_mako_str(template_file_name='core_multirotor.mako', template_src_path=SPEC_INFO_PATH, template_keys=core_keys)
def test__string_build(): """ test ioformat.build_mako_str test ioformat.indent test ioformat.addchar """ mako_keys = {'param1': 'molecule', 'param2': 'atom', 'param3': 3} mako_str = ioformat.build_mako_str('test.mako', MAKO_PATH, mako_keys) assert mako_str == ('param1 is molecule\n' 'param2 is atom\n' 'param3 is 3\n' 'param3 is 3\n' 'param3 is 3\n') ini_string = 'molecule' assert ioformat.indent(ini_string, 4) == ' molecule' assert ioformat.addchar(ini_string, '- ', side='pre') == '- molecule' assert ioformat.addchar(ini_string, ' +++', side='post') == 'molecule +++'
def umbrella_mode(group, plane, ref_atom, potential, geo=None): """ Writes the string that defines the `Umbrella` section for a single umbrella mode of a species for a MESS input file by formatting input information into strings a filling Mako template. :param group: idxs for the atoms of ? :type group: list(int) :param axis: idxs for the atoms that ? :type axis: list(int) :param geo: geometry of the species the umbrella mode exists for :type geo: list :rtype: str """ # Format the sections umbr_group = messformat.format_rotor_key_defs(group) umbr_plane = messformat.format_rotor_key_defs(plane) umbr_npotential, _, umbr_potential = messformat.format_rotor_potential( potential) ref_atom += 1 # Format the geom if geo is not None: natom, geo = messformat.geometry_format(geo) geo = indent(geo, 4) else: natom = None # Create dictionary to fill template umbr_keys = { 'group': umbr_group, 'axis': umbr_plane, 'ref_atom': ref_atom, 'npotential': umbr_npotential, 'potential': umbr_potential, 'natom': natom, 'geo': geo, } return build_mako_str( template_file_name='umbrella_mode.mako', template_src_path=SPEC_INFO_PATH, template_keys=umbr_keys)
def symbols_format(geo): """ Format the symbols """ symbs = automol.geom.symbols(geo) # nsymbs = len(symbs) symb_str = automol.util.vec.string(symbs, num_per_row=6, val_format='{0:>6s}') # for i, symb in enumerate(symbs): # if ((i+1) % 6) == 0 and (i+1) != nsymbs: # symb_str += '{0:>6s}\n'.format(symb) # else: # symb_str += '{0:>6s}'.format(symb) symb_str = ioformat.indent(symb_str, 6) return symb_str
def format_rot_dist_consts(rot_dists): """ Formats the list of rotational distortion constants into a string appropriate for a MESS input file. :param rot_dists: rotational distortion constants: [['aaa'], [val]] :type rot_dists: list(list(str), list(float)) :return rot_dists_str: values of potential in a MESS-format string :rtype string """ # Build rotational dists string rot_dists_str = '' for i, const in enumerate(rot_dists): rot_dists_str += ' '.join(map(str, const)) if (i + 1) != len(rot_dists): rot_dists_str += '\n' # Indent the lines rot_dists_str = indent(rot_dists_str, 4) return rot_dists_str
def molec_spec_format(geo): """ Parses out the atom labels of a Cartesian geometry and formats them into a string appropriate for definining molecular species for Monte Carlo calculations in MESS. :param geo: geometry :type geo: list :return atom_lst_str :rtype: string """ # Build geom string; converting the coordinates to angstrom atom_lst_str = '' for (asymb, _) in geo: atom_lst_str += '{:s} '.format(asymb) # Remove final newline character atom_lst_str = atom_lst_str.rstrip() # Indent the lines atom_lst_str = indent(atom_lst_str, 6) return atom_lst_str
def elec_levels_format(elec_levels): """ Formats the list of electronic energy levels into a string that is appropriate for a MESS input file. :param elec_levels: levels, given as [[energy, degeneracy], ...] :type elec_levels: list(list(float)) :return elec_levels_str: MESS-format string containing levels :rtype string """ # Get the number of elec levles nlevels = len(elec_levels) # Build elec levels string elec_levels_str = '' for i, level in enumerate(elec_levels): elec_levels_str += ' '.join(map(str, level)) if (i + 1) != len(elec_levels): elec_levels_str += '\n' # Indent the lines elec_levels_str = indent(elec_levels_str, 4) return nlevels, elec_levels_str
def pt_format(header, hess, vlabel, vval, slabel=None, sval=None, geo=None, grad=None): """ write a point string """ # Intialize with header pt_str = f'*{header}' pt_str += '\n\n' # Write the energy and coordinate along reaction coordinate pt_str += energy_format(vlabel, vval) pt_str += '\n' if sval is not None: pt_str += energy_format(slabel, sval) pt_str += '\n' pt_str += '\n' # Write the structurea information if geo is not None: pt_str += geometry_format(geo) pt_str += '\n\n' if grad is not None: pt_str += gradient_format(grad) pt_str += '\n\n' pt_str += hessian_format(hess) pt_str += '\n' pt_str = indent(pt_str, 2) return pt_str
def geometry_format(geo): """ Formats the geometry of a species into a string that is appropriate for a MESS input file. :param geo: geometry of a species :return natoms: number of atoms in the geometry :rtype int :return geo_str: MESS-format string containing geometry :rtype string """ # Get the number of atoms natoms = len(geo) # Build geom string; converting the coordinates to angstrom geo_str = '' for (asymb, xyz) in geo: geo_str += '{:<4s}{:>14.5f}{:>14.5f}{:>14.5f}\n'.format( asymb, *tuple((val * 0.529177 for val in xyz))) # Remove final newline character and indent the lines geo_str = indent(geo_str.rstrip(), 4) return natoms, geo_str
def rotor_internal(group, axis, symmetry, grid_size, mass_exp_size, pot_exp_size=5, hmin=13, hmax=101, geo=None, rotor_id=''): """ Writes the string that defines the `Rotor` section for a single internal rotor of a species for a MESS input file by formatting input information into strings a filling Mako template. :param group: idxs for the atoms of one of the rotational groups :type group: list(int) :param axis: idxs for the atoms that make up the rotational axis :type axis: list(int) :param symmetry: overall symmetry of the torsional motion (potential) :type symmetry: int :param grid_size: grid_size for statistical weight calculation :type grid_size: int :param mass_exp_size: num. mass expansion Fourier harmonics :type mass_exp_size: int :param pot_exp_size: num. potential expansion Fourier harmonics :type pot_exp_size: int :param hmin: minimum value for quantum phase space dimension :type hmin: int :param hmax: maximum value for quantum phase space dimension :type hmax: int :param geo: geometry of the species the rotor exists for :type geo: list :param rotor_id: name associated with the rotor :type rotor_id: str :rtype: str """ assert mass_exp_size > 0 and mass_exp_size % 2 == 1, ( f'Mass exponent size: {mass_exp_size} is not an odd number' ) assert pot_exp_size > 0 and pot_exp_size % 2 == 1, ( f'Potential exponent size: {pot_exp_size} is not an odd number' ) # Format the sections rotor_group = messformat.format_rotor_key_defs(group) rotor_axis = messformat.format_rotor_key_defs(axis) # Format the geom if geo is not None: natom, geo = messformat.geometry_format(geo) geo = indent(geo, 4) else: natom = None # Create dictionary to fill template rotor_keys = { 'group': rotor_group, 'axis': rotor_axis, 'symmetry': symmetry, 'mass_exp_size': mass_exp_size, 'pot_exp_size': pot_exp_size, 'hmin': hmin, 'hmax': hmax, 'grid_size': grid_size, 'natom': natom, 'geo': geo, 'rotor_id': rotor_id } return build_mako_str( template_file_name='rotor_internal.mako', template_src_path=SPEC_INFO_PATH, template_keys=rotor_keys)
def mc_species(geo, sym_factor, elec_levels, flux_mode_str, data_file_name, ref_config_file_name='', ground_ene=None, reference_ene=None, freqs=(), use_cm_shift=False): """ Writes a monte carlo species section :param geo: geometry of species :type geo: list :param sym_factor: symmetry factor of species :type sym_factor: float :param elec_levels: energy and degeneracy of atom's electronic states :type elec_levels: list(float) :param flux_mode_str: MESS-format `FluxionalMode` sections for rotors :type flux_mode_str: str :param data_file_name: Name of data file with molecular info :type data_file_name: str :param ground_ene: energy relative to reference n PES (kcal.mol-1) :type ground_ene: float :param reference_ene: harmonic ZPVE used for MC PF (kcal.mol-1) :type reference_ene: float :param freqs: vibrational frequencies (cm-1) :type freqs: list(float) :param use_cm_chift: signal to include a CM shift :type use_cm_shift: bool :rtype: str """ # Format the molecule specification section atom_list = messformat.molec_spec_format(geo) # Build a formatted frequencies and elec levels string nlevels, levels = messformat.elec_levels_format(elec_levels) levels = indent(levels, 2) if freqs: nfreqs, freqs = messformat.freqs_format(freqs) else: nfreqs = 0 # Check if reference config name is present if nfreqs > 0: assert ref_config_file_name, ( 'Must provide a reference configuration file if no Hessians given') # Indent various strings string if needed flux_mode_str = messformat.indent(flux_mode_str, 4) # Create dictionary to fill template monte_carlo_keys = { 'atom_list': atom_list, 'sym_factor': sym_factor, 'flux_mode_str': flux_mode_str, 'data_file_name': data_file_name, 'ref_config_file_name': ref_config_file_name, 'reference_ene': reference_ene, 'ground_ene': ground_ene, 'nlevels': nlevels, 'levels': levels, 'nfreqs': nfreqs, 'freqs': freqs, 'use_cm_shift': use_cm_shift } return build_mako_str(template_file_name='monte_carlo.mako', template_src_path=MONTE_CARLO_PATH, template_keys=monte_carlo_keys)
def rotor_hindered(group, axis, symmetry, potential, hmin=None, hmax=None, lvl_ene_max=None, therm_pow_max=None, geo=None, rotor_id='', potential_form='spline'): """ Writes the string that defines the `Rotor` section for a single hindered rotor of a species for a MESS input file by formatting input information into strings a filling Mako template. :param group: idxs for the atoms of one of the rotational groups :type group: list(int) :param axis: idxs for the atoms that make up the rotational axis :type axis: list(int) :param symmetry: overall symmetry of the torsional motion (potential) :type symmetry: int :param hmin: minimum value for quantum phase space dimension :type hmin: int :param hmax: maximum value for quantum phase space dimension :type hmax: int :param potential: value of the potential along torsion (kcal.mol-1) :type potential: list(float) :param therm_pow_max: max exp't power in Boltzmann weight :type therm_pow_max: int :param geo: geometry of the species the rotor exists for :type geo: list :param rotor_id: name associated with the rotor :type rotor_id: str :param potential_form: expression the potential should be fit to :type potential_form: str :rtype: str """ # Format the rotor sections fmtd_group = messformat.format_rotor_key_defs(group) fmtd_axis = messformat.format_rotor_key_defs(axis) npot, fmtd_coords, fmtd_enes = messformat.format_rotor_potential( potential) # Format the geom natom = 1 if geo is not None: natom, geo = messformat.geometry_format(geo) geo = indent(geo, 4) # Create dictionary to fill template rotor_keys = { 'group': fmtd_group, 'axis': fmtd_axis, 'symmetry': symmetry, 'npotential': npot, 'pot_coords': fmtd_coords, 'pot_enes': fmtd_enes, 'potential_form': potential_form, 'hmin': hmin, 'hmax': hmax, 'lvl_ene_max': lvl_ene_max, 'therm_pow_max': therm_pow_max, 'natom': natom, 'geo': geo, 'rotor_id': rotor_id } return build_mako_str( template_file_name='rotor_hindered.mako', template_src_path=SPEC_INFO_PATH, template_keys=rotor_keys)