def __init__(self, filename): self.filename = filename self.prefix = filename[:-5] fchk = FCHKFile(filename, field_labels=[ "Charge", "Number of basis functions", "Dipole Moment", "Number of electrons", "Number of alpha electrons", "Number of beta electrons", "Alpha Orbital Energies", "Beta Orbital Energies", ]) # for usage by the rest of the program self.charge = fchk.fields["Charge"] self.num_orbitals = fchk.fields["Number of basis functions"] self.dipole = fchk.fields["Dipole Moment"] self.num_electrons = fchk.fields["Number of electrons"] self.num_alpha = fchk.fields["Number of alpha electrons"] self.num_beta = fchk.fields["Number of beta electrons"] self.restricted = "Beta Orbital Energies" not in fchk.fields self.molecule = fchk.molecule # for internal usage self._hack_fchk = self.restricted and (self.num_alpha != self.num_beta) if "mp2" in fchk.lot.lower(): self._density_type = "mp2" elif "mp3" in fchk.lot.lower(): self._density_type = "mp3" elif "mp4" in fchk.lot.lower(): self._density_type = "mp4" else: self._density_type = "scf"
def test_o2_cc_pvtz_cart_num(): tmpdir, fn_fchk = setup_gaussian("o2_cc_pvtz_cart") fchk = FCHKFile(fn_fchk) basis = GaussianBasis.from_fchk(fchk) assert (basis.num_shells == 20) print basis.num_dof assert (basis.num_dof == 70)
def test_orb0_hf_sto3g(): tmpdir, fn_fchk = setup_gaussian("hf_sto3g") fchk = FCHKFile(fn_fchk) shutil.rmtree(tmpdir) basis = GaussianBasis.from_fchk(fchk) weights = fchk.fields["Alpha MO coefficients"][:basis.num_dof] points = ref_data_hf_sto3g_orb0[:, :3] fns = basis.call_gint_grid(gint1_fns_basis, weights.reshape((1, -1)), points * angstrom, 1)[0] assert (abs(fns - ref_data_hf_sto3g_orb0[:, 3]).max() < 1e-10)
def load_molecule_g98fchk(fn_freq, fn_ener=None, energy=None): """Load a molecule from Gaussian98 formatted checkpoint files. Arguments: | ``fn_freq`` -- The formatted checkpoint file of the frequency job. Optional arguments: | ``fn_ener`` -- The formatted checkpoint file of a single point computation for the energy. When not given, the energy is taken from the frequency job. | ``energy`` -- Override the energy from the formatted checkpoint file with the given value. """ fchk_freq = FCHKFile(fn_freq, ignore_errors=True, field_labels=[ "Cartesian Force Constants", "Total Energy", "Multiplicity", "Cartesian Gradient" ]) if fn_ener is None: fchk_ener = fchk_freq else: fchk_ener = FCHKFile(fn_ener, ignore_errors=True, field_labels=["Total Energy"]) masses = np.array([g98_masses[n - 1] for n in fchk_freq.molecule.numbers]) if energy is None: energy = fchk_ener.fields["Total Energy"] return Molecule( fchk_freq.molecule.numbers, fchk_freq.molecule.coordinates, masses, energy, np.reshape(np.array(fchk_freq.fields["Cartesian Gradient"]), (len(fchk_freq.molecule.numbers), 3)), fchk_freq.get_hessian(), fchk_freq.fields["Multiplicity"], None, # gaussian is very poor at computing the rotational symmetry number False, )
def test_orb0_o2_cc_pvtz_pure(): tmpdir, fn_fchk = setup_gaussian("o2_cc_pvtz_pure") fchk = FCHKFile(fn_fchk) shutil.rmtree(tmpdir) basis = GaussianBasis.from_fchk(fchk) weights = fchk.fields["Alpha MO coefficients"][:basis.num_dof] weights = weights[basis.g03_permutation] points = ref_data_o2_cc_pvtz_pure_orb0[:, :3] fns = basis.call_gint_grid(gint1_fns_basis, weights.reshape((1, -1)), points * angstrom, 1)[0] assert (abs(fns - ref_data_o2_cc_pvtz_pure_orb0[:, 3]).max() < 1e-10)
def get_mol(self, state, root): if self.name == "opt": # load the initial geometry mol = Molecule.from_file("init/%s.xyz" % state.name) else: # load the optimized geometry fn_fchk = "%s/%s__opt/gaussian.fchk" % (root, state.name) mol = FCHKFile(fn_fchk, field_labels=[]).molecule with open("init/%s.fragments" % state.name) as f: mol.charge_mult = f.readline().split() mol.tags = f.readline().split() return mol
def test_orb0_h_sto3g(): tmpdir, fn_fchk = setup_gaussian("h_sto3g") fchk = FCHKFile(fn_fchk) shutil.rmtree(tmpdir) basis = GaussianBasis.from_fchk(fchk) # real test for the output weights = fchk.fields["Alpha MO coefficients"][:basis.num_dof] points = ref_data_h_sto3g_orb0[:, :3] fns = basis.call_gint_grid(gint1_fns_basis, weights.reshape((1, -1)), points * angstrom, 1)[0] assert (abs(fns - ref_data_h_sto3g_orb0[:, 3]).max() < 1e-10) # test error mechanism basis.shell_types[0] = 102 assert_raises(ValueError, basis.call_gint_grid, gint1_fns_basis, weights.reshape((1, -1)), points * angstrom, 1) basis.shell_types[0] = -763 assert_raises(ValueError, basis.call_gint_grid, gint1_fns_basis, weights.reshape((1, -1)), points * angstrom, 1)
def test_pot_o2_cc_pvtz_pure(): tmpdir, fn_fchk = setup_gaussian("o2_cc_pvtz_pure") fchk = FCHKFile(fn_fchk) shutil.rmtree(tmpdir) basis = GaussianBasis.from_fchk(fchk) dmat = fchk.fields["Total SCF Density"] reorder_dmat(dmat, basis.g03_permutation) points = ref_data_o2_cc_pvtz_pure_pot[:, :3] * angstrom ref_potential = ref_data_o2_cc_pvtz_pure_pot[:, 3] nuc_potential = 0.0 for i in xrange(fchk.molecule.size): center = fchk.molecule.coordinates[i] Z = fchk.molecule.numbers[i] radius = numpy.sqrt(((points - center)**2).sum(axis=1)) nuc_potential += Z / radius ref_potential -= nuc_potential potential = -basis.call_gint_grid(gint2_nai_dmat, dmat, points) assert (abs(potential - ref_potential).max() < 1e-6)
def test_pot_h_sto3g(): tmpdir, fn_fchk = setup_gaussian("h_sto3g") fchk = FCHKFile(fn_fchk) shutil.rmtree(tmpdir) basis = GaussianBasis.from_fchk(fchk) # real test for the output dmat = fchk.fields["Total SCF Density"] points = ref_data_h_sto3g_pot[:, :3] * angstrom radius = numpy.sqrt((points**2).sum(axis=1)) ref_data_h_sto3g_pot[:, 3] -= 1 / radius potential = -basis.call_gint_grid(gint2_nai_dmat, dmat, points) assert (abs(potential - ref_data_h_sto3g_pot[:, 3]).max() < 1e-8) # test error mechanism basis.shell_types[0] = 102 assert_raises(ValueError, basis.call_gint_grid, gint2_nai_dmat, dmat, points * angstrom) basis.shell_types[0] = -763 assert_raises(ValueError, basis.call_gint_grid, gint2_nai_dmat, dmat, points * angstrom)
def from_file(cls, filename): """Construct a molecule object read from the given file. The file format is inferred from the extensions. Currently supported formats are: ``*.cml``, ``*.fchk``, ``*.pdb``, ``*.sdf``, ``*.xyz`` If a file contains more than one molecule, only the first one is read. Argument: | ``filename`` -- the name of the file containing the molecule Example usage:: >>> mol = Molecule.from_file("foo.xyz") """ # TODO: many different API's to load files. brrr... if filename.endswith(".cml"): from molmod.io import load_cml return load_cml(filename)[0] elif filename.endswith(".fchk"): from molmod.io import FCHKFile fchk = FCHKFile(filename, field_labels=[]) return fchk.molecule elif filename.endswith(".pdb"): from molmod.io import load_pdb return load_pdb(filename) elif filename.endswith(".sdf"): from molmod.io import SDFReader return next(SDFReader(filename)) elif filename.endswith(".xyz"): from molmod.io import XYZReader xyz_reader = XYZReader(filename) title, coordinates = next(xyz_reader) return Molecule(xyz_reader.numbers, coordinates, title, symbols=xyz_reader.symbols) else: raise ValueError("Could not determine file format for %s." % filename)
def test_dens_h_sto3g(): tmpdir, fn_fchk = setup_gaussian("h_sto3g") fchk = FCHKFile(fn_fchk) shutil.rmtree(tmpdir) basis = GaussianBasis.from_fchk(fchk) weights = fchk.fields["Alpha MO coefficients"][:basis.num_dof] weights = weights[basis.g03_permutation] points = ref_data_h_sto3g_orb0[:, :3] orb0 = basis.call_gint_grid(gint1_fns_basis, weights.reshape((1, -1)), points * angstrom, 1)[0] num_dmat = (basis.num_dof * (basis.num_dof + 1)) / 2 dmat = fchk.fields["Total SCF Density"][:num_dmat] density = basis.call_gint_grid(gint1_fn_dmat, dmat, points * angstrom) assert (abs(orb0**2 - density).max() < 1e-10) # test error mechanism basis.shell_types[0] = 102 assert_raises(ValueError, basis.call_gint_grid, gint1_fn_dmat, dmat, points * angstrom, 1) basis.shell_types[0] = -763 assert_raises(ValueError, basis.call_gint_grid, gint1_fn_dmat, dmat, points * angstrom, 1)
def test_dens_o2_cc_pvtz_pure(): tmpdir, fn_fchk = setup_gaussian("o2_cc_pvtz_pure") fchk = FCHKFile(fn_fchk) shutil.rmtree(tmpdir) basis = GaussianBasis.from_fchk(fchk) num_dmat = (basis.num_dof * (basis.num_dof + 1)) / 2 points = ref_data_o2_cc_pvtz_pure_orb0[:, :3] dmat = fchk.fields["Total SCF Density"][:num_dmat] reorder_dmat(dmat, basis.g03_permutation) density = basis.call_gint_grid(gint1_fn_dmat, dmat, points * angstrom) num_alpha = fchk.fields["Number of alpha electrons"] weights = fchk.fields["Alpha MO coefficients"][:num_alpha * basis.num_dof] weights = weights.reshape((num_alpha, basis.num_dof)) weights = weights[:, basis.g03_permutation] orbitals = basis.call_gint_grid(gint1_fns_basis, weights, points * angstrom, num_alpha) assert (orbitals.shape == (num_alpha, len(points))) expected_density = 2 * (orbitals**2).sum(axis=0) assert (abs(density - expected_density).max() < 1e-6)
N3 = coordinates.size jacobian = numpy.zeros((N3, len(ics)), float) for j, ic in enumerate(ics): # Let the ic object fill in each column of the Jacobian. ic.fill_jacobian_column(jacobian[:, j], coordinates) return jacobian # This if block is only executed when this file is ran as a program, and not # when it is loaded as a module. if __name__ == "__main__": # Load the formatted checkpoint file with the frequency computation. This # file also contains the atomic numbers and the coordinates of the atoms, # and therefore one can access the dopamine molecule object through # fchk.molecule. fchk = FCHKFile("dopamine.fchk") # Set the default graph for the construction of the internal coordinates: fchk.molecule.set_default_graph() # Setup a list of internal coordinates ics = setup_ics(fchk.molecule.graph) # Compute the Jacobian. J = compute_jacobian(ics, fchk.molecule.coordinates) # Compute the pseudo-inverse, using a loose threshold for the singular # values to filter out equivalent internal coordinates. Jinv = numpy.linalg.pinv(J, 1e-5) # Get the Hessian in Cartesian coordinates. H = fchk.get_hessian() # Transform to internal coordinates. K = numpy.dot(Jinv, numpy.dot(H, Jinv.transpose())) # Make a nice printout of K. print("The Hessian in internal coordinates in kcal/mol/angstrom**2")
def load_ener(fn_fchk): fchk = FCHKFile(fn_fchk, field_labels=["Total Energy"]) return fchk.fields["Total Energy"]
def load_molecule_g03fchk(fn_freq, fn_ener=None, fn_vdw=None, energy=None, fn_punch=None): """Load a molecule from Gaussian03 formatted checkpoint files. Arguments: | ``fn_freq`` -- the formatted checkpoint file of the frequency job Optional arguments: | ``fn_ener`` -- the formatted checkpoint file of a single point computation for the energy. When not given, the energy is taken from the frequency job. | ``fn_vdw`` -- An orca output file containing a Van der Waals correction for the energy. | ``energy`` -- Override the energy from the formatted checkpoint file with the given value. | ``punch`` -- A Gaussian derivatives punch file. When given, the gradient and the Hessian are read from this file instead. """ fchk_freq = FCHKFile(fn_freq, ignore_errors=True, field_labels=[ "Cartesian Force Constants", "Real atomic weights", "Total Energy", "Multiplicity", "Cartesian Gradient", "MicOpt", ]) if fn_ener is None: fchk_ener = fchk_freq else: fchk_ener = FCHKFile(fn_ener, ignore_errors=True, field_labels=[ "Total Energy" ]) if energy is None: energy = fchk_ener.fields["Total Energy"] vdw = 0 if fn_vdw is not None: from tamkin.io.dispersion import load_dftd_orca vdw = load_dftd_orca(fn_vdw) natom = fchk_freq.molecule.size if fchk_freq.molecule.size == 1 and \ "Cartesian Force Constants" not in fchk_freq.fields: gradient = np.zeros((1,3), float) hessian = np.zeros((3,3), float) elif fn_punch is None: gradient = fchk_freq.fields["Cartesian Gradient"].copy() gradient.shape = (natom, 3) hessian = fchk_freq.get_hessian() else: gradient = np.zeros((natom, 3), float) hessian = np.zeros((3*natom, 3*natom), float) iterator = iter_floats_file(fn_punch) for i in xrange(natom): for j in xrange(3): gradient[i,j] = iterator.next() for i in xrange(3*natom): for j in xrange(i+1): v = iterator.next() hessian[i,j] = v hessian[j,i] = v if "MicOpt" in fchk_freq.fields: fixed = (fchk_freq.fields["MicOpt"] == -2).nonzero()[0] if len(fixed) == 0: fixed = None else: fixed = None return Molecule( fchk_freq.molecule.numbers, fchk_freq.molecule.coordinates, fchk_freq.fields["Real atomic weights"]*amu, energy+vdw, gradient, hessian, fchk_freq.fields["Multiplicity"], None, # gaussian is very poor at computing the rotational symmetry number False, title=fchk_freq.title, fixed=fixed, )
def test_h_sto3g_num(): tmpdir, fn_fchk = setup_gaussian("h_sto3g") fchk = FCHKFile(fn_fchk) basis = GaussianBasis.from_fchk(fchk) assert (basis.num_shells == 1) assert (basis.num_dof == 1)
def get_pf(dn, temps): '''Construct a partition function from a molecule directory. **Arguments:** dn A molecule directory name temps A list of temperatures at which the properties of the molecule must be evaluated. ''' print ' Loading partition function from', dn # A1) load the molecule molecule = load_molecule_g03fchk('%s/freq/gaussian.fchk' % dn) # A2) if present, load a more accurate energy fn_sp = '%s/sp/gaussian.fchk' % dn if os.path.isfile(fn_sp): from molmod.io import FCHKFile sp_energy = FCHKFile(fn_sp).fields['Total Energy'] molecule = molecule.copy_with(energy=sp_energy) # A3) if present add a grimme correction fn_dftd3 = '%s/dftd3/dftd3.out' % dn if os.path.isfile(fn_dftd3): print ' Loading DFT-D3 corrections' disp_energy = load_dftd3(fn_dftd3) molecule = molecule.copy_with(energy=molecule.energy + disp_energy) # B) Load all rotors and keep directories of each rotor (dns_rotor). rotors = [] dns_rotor = [] # B1) load all rotors computed with Gaussian for dn_rotor in glob('%s/rotor_g_*' % dn): print ' Loading rotor', dn_rotor dns_rotor.append(dn_rotor) fn_log = '%s/gaussian.log' % dn_rotor # Load the config file rotor_cfg = load_cfg(os.path.join(dn_rotor, 'rotor.cfg')) # Load the rotational scan data from the Gaussian log file. rotor_scan = load_rotscan_g03log(fn_log, get_atom_indexes(rotor_cfg, 'top')) # Construct a Rotor object (solves Schrodinger equation etc.) rotor = Rotor(rotor_scan, molecule, suffix=os.path.basename(dn_rotor)[6:], rotsym=rotor_cfg.get('rotsym', 1), even=rotor_cfg.get('even', False), num_levels=rotor_cfg.get('num_levels', 50), dofmax=rotor_cfg.get('dofmax', 5), v_threshold=v_threshold) rotors.append(rotor) # B2) load all free rotors for dn_rotor in glob('%s/rotor_f_*' % dn): print ' Loading rotor', dn_rotor dns_rotor.append(dn_rotor) fn_cfg = '%s/rotor.cfg' % dn_rotor # Load the config file rotor_cfg = load_cfg(fn_cfg) # Construct a Rotor object (solves Schrodinger equation etc.) rotor_scan = RotScan(get_atom_indexes(rotor_cfg, 'dihed'), molecule, get_atom_indexes(rotor_cfg, 'top')) rotor = Rotor(rotor_scan, molecule, suffix=os.path.basename(dn_rotor)[6:], rotsym=rotor_cfg.get('rotsym', 1), num_levels=rotor_cfg.get('num_levels', 50), dofmax=rotor_cfg.get('dofmax', 5), v_threshold=v_threshold) rotors.append(rotor) # B3) load all custom rotors for dn_rotor in glob('%s/rotor_c_*' % dn): print ' Loading rotor', dn_rotor dns_rotor.append(dn_rotor) fn_dat = '%s/rotor.dat' % dn_rotor # Load the potential data potential = np.loadtxt(fn_dat).T # Load the config file rotor_cfg = load_cfg(os.path.join(dn_rotor, 'rotor.cfg')) # Construct a Rotor object (solves Schrodinger equation etc.) rotor_scan = RotScan(get_atom_indexes(rotor_cfg, 'dihed'), molecule, get_atom_indexes(rotor_cfg, 'top'), potential) rotor = Rotor(rotor_scan, molecule, suffix=os.path.basename(dn_rotor)[6:], rotsym=rotor_cfg.get('rotsym', 1), even=rotor_cfg.get('even', False), num_levels=rotor_cfg.get('num_levels', 50), dofmax=rotor_cfg.get('dofmax', 5), v_threshold=v_threshold) rotors.append(rotor) # C) Perform a normal mode analysis if molecule.fixed is None: print ' Performing NMA with fixed external degrees of freedom' nma = NMA(molecule, ConstrainExt(gradient_threshold=gradient_threshold)) else: print ' Performing NMA with fixed atoms: %s' % molecule.fixed nma = NMA(molecule, PHVA(molecule.fixed)) # D) Define the partition function mol_cfg = load_cfg('%s/molecule.cfg' % dn) pf_contributions = [ Vibrations(freq_scaling=mol_cfg.get('freq_scaling', 1.0), zp_scaling=mol_cfg.get('zp_scaling', 1.0)) ] if molecule.fixed is None: pf_contributions.append(ExtTrans()) pf_contributions.append(ExtRot(mol_cfg.get('symnum', None))) pf_contributions.extend(rotors) pf = PartFun(nma, pf_contributions) # Store the atomic numbers as an attribute of the partition function (used # to check that no atoms get lost in a reaction. pf.numbers = molecule.numbers # E) Make plots of the rotor for dn_rotor, rotor in zip(dns_rotor, rotors): rotor.plot_levels('%s/levels.png' % dn_rotor, 300) # F) Write a partf.txt file pf.write_to_file('%s/partf.txt' % dn) # G) Write a thermo analysis if temperatures are provided if len(temps) > 0: ta = ThermoAnalysis(pf, temps) ta.write_to_file('%s/thermo.csv' % dn) return pf
def __init__(self, filename, options): if len(options) == 1: density_type = options[0] elif len(options) == 0: density_type = None else: raise ValueError( "Only one option is supported for the FCHKWaveFunction") self.filename = filename self.options = options self.prefix = filename[:-5] fchk = FCHKFile(filename) # for use by the rest of the program self.charge = fchk.fields["Charge"] self.num_orbitals = fchk.fields["Number of basis functions"] self.dipole = fchk.fields["Dipole Moment"] self.num_electrons = fchk.fields["Number of electrons"] self.num_alpha = fchk.fields["Number of alpha electrons"] self.num_beta = fchk.fields["Number of beta electrons"] self.restricted = "Beta Orbital Energies" not in fchk.fields self.molecule = fchk.molecule self.nuclear_charges = fchk.fields["Nuclear charges"] # for internal usage if density_type is None: if "mp2" in fchk.lot.lower(): density_type = "mp2" elif "mp3" in fchk.lot.lower(): density_type = "mp3" elif "mp4" in fchk.lot.lower(): density_type = "mp4" else: density_type = "scf" # electronic structure data self.basis = GaussianBasis.from_fchk(fchk) # orbitals self.alpha_orbital_energies = None self.beta_orbital_energies = None self.natural_orbitals = None self.alpha_orbitals = None self.beta_orbitals = None self.alpha_occupations = None self.beta_occupations = None self.natural_occupations = None if density_type == "scf": # Load orbital stuff only for scf computations. self.alpha_orbital_energies = fchk.fields["Alpha Orbital Energies"] self.beta_orbital_energies = fchk.fields.get( "Beta Orbital Energies", self.alpha_orbital_energies) self.alpha_orbitals = fchk.fields["Alpha MO coefficients"].reshape( (-1, self.basis.num_dof)) self.alpha_orbitals = self.alpha_orbitals[:, self.basis. g03_permutation] self.beta_orbitals = fchk.fields.get("Beta MO coefficients") if self.beta_orbitals is None: self.beta_orbitals = self.alpha_orbitals else: self.beta_orbitals = self.beta_orbitals.reshape( (-1, self.basis.num_dof))[:, self.basis.g03_permutation] self.alpha_occupations = numpy.zeros(self.num_orbitals, float) self.alpha_occupations[:self.num_alpha] = 1.0 if self.beta_orbitals is None: self.beta_occupations = self.alpha_occupations else: self.beta_occupations = numpy.zeros(self.num_orbitals, float) self.beta_occupations[:self.num_beta] = 1.0 if self.restricted: self.natural_orbitals = self.alpha_orbitals self.natural_occupations = self.alpha_occupations + self.beta_occupations self.num_natural = max(self.num_alpha, self.num_beta) # density matrices hack_fchk = self.restricted and ( self.num_alpha != self.num_beta) and density_type == "scf" if hack_fchk: # construct density matrices manually because the fchk file # contains the wrong one. we only do this for scf computations. n = self.basis.num_dof size = (n * (n + 1)) / 2 self.density_matrix = numpy.zeros(size, float) add_orbitals_to_dmat(self.alpha_orbitals[:self.num_alpha], self.density_matrix) add_orbitals_to_dmat(self.beta_orbitals[:self.num_beta], self.density_matrix) self.spin_density_matrix = numpy.zeros(size, float) num_min = min(self.num_alpha, self.num_beta) num_max = max(self.num_alpha, self.num_beta) add_orbitals_to_dmat(self.alpha_orbitals[num_min:num_max], self.spin_density_matrix) else: self.density_matrix = None self.spin_density_matrix = None # load the density matrices for key in fchk.fields: if key.startswith("Total") and key.endswith("Density"): if key[6:-8].lower() != density_type: continue assert self.density_matrix is None dmat = fchk.fields[key] reorder_dmat(dmat, self.basis.g03_permutation) self.density_matrix = dmat elif key.startswith("Spin") and key.endswith("Density"): if key[5:-8].lower() != density_type: continue assert self.spin_density_matrix is None dmat = fchk.fields[key] reorder_dmat(dmat, self.basis.g03_permutation) self.spin_density_matrix = dmat if self.density_matrix is None: raise ValueError( "Could not find the '%s' density matrix in the fchk file." % self._density_type)