def run(self) -> QMolecule: psi4d_directory = os.path.dirname(os.path.realpath(__file__)) template_file = psi4d_directory + '/_template.txt' qiskit_chemistry_directory = os.path.abspath( os.path.join(psi4d_directory, '../..')) molecule = QMolecule() input_text = self._config + '\n' input_text += 'import sys\n' syspath = '[\'' + qiskit_chemistry_directory + '\',\'' + '\',\''.join( sys.path) + '\']' input_text += 'sys.path = ' + syspath + ' + sys.path\n' input_text += 'from qmolecule import QMolecule\n' input_text += '_q_molecule = QMolecule("{0}")\n'.format( molecule.filename) with open(template_file, 'r') as file: input_text += file.read() file_fd, input_file = tempfile.mkstemp(suffix='.inp') os.close(file_fd) with open(input_file, 'w') as stream: stream.write(input_text) file_fd, output_file = tempfile.mkstemp(suffix='.out') os.close(file_fd) try: PSI4Driver._run_psi4(input_file, output_file) if logger.isEnabledFor(logging.DEBUG): with open(output_file, 'r') as file: logger.debug('PSI4 output file:\n%s', file.read()) finally: run_directory = os.getcwd() for local_file in os.listdir(run_directory): if local_file.endswith('.clean'): os.remove(run_directory + '/' + local_file) try: os.remove('timer.dat') except Exception: # pylint: disable=broad-except pass try: os.remove(input_file) except Exception: # pylint: disable=broad-except pass try: os.remove(output_file) except Exception: # pylint: disable=broad-except pass _q_molecule = QMolecule(molecule.filename) _q_molecule.load() # remove internal file _q_molecule.remove_file() _q_molecule.origin_driver_name = 'PSI4' _q_molecule.origin_driver_config = self._config return _q_molecule
def run(self) -> QMolecule: """Constructs a QMolecule instance out of a FCIDump file. Returns: A QMolecule instance populated with a minimal set of required data. """ fcidump_data = parse(self._fcidump_input) q_mol = QMolecule() q_mol.nuclear_repulsion_energy = fcidump_data.get('ecore', None) q_mol.num_orbitals = fcidump_data.get('NORB') q_mol.multiplicity = fcidump_data.get('MS2', 0) + 1 q_mol.charge = 0 # ensures QMolecule.log() works q_mol.num_beta = (fcidump_data.get('NELEC') - (q_mol.multiplicity - 1)) // 2 q_mol.num_alpha = fcidump_data.get('NELEC') - q_mol.num_beta if self.atoms is not None: q_mol.num_atoms = len(self.atoms) q_mol.atom_symbol = self.atoms q_mol.atom_xyz = [[float('NaN')] * 3] * len( self.atoms) # ensures QMolecule.log() works q_mol.mo_onee_ints = fcidump_data.get('hij', None) q_mol.mo_onee_ints_b = fcidump_data.get('hij_b', None) q_mol.mo_eri_ints = fcidump_data.get('hijkl', None) q_mol.mo_eri_ints_bb = fcidump_data.get('hijkl_bb', None) q_mol.mo_eri_ints_ba = fcidump_data.get('hijkl_ba', None) return q_mol
def run(self) -> QMolecule: hdf5_file = self._hdf5_input if self.work_path is not None and not os.path.isabs(hdf5_file): hdf5_file = os.path.abspath(os.path.join(self.work_path, hdf5_file)) if not os.path.isfile(hdf5_file): raise LookupError('HDF5 file not found: {}'.format(hdf5_file)) molecule = QMolecule(hdf5_file) molecule.load() return molecule
def load_molecule(filename): if os.path.exists(filename): print(f"Found {filename}. Loading...") molecule = QMolecule(filename) molecule.load() else: # Regenerate print(f"Couldn't find {filename}. Regenerating...") molecule = self.driver.run() molecule.save(filename) return molecule
def compute_integrals(atoms, units, charge, multiplicity, basis, calc_type='rhf'): # Get config from input parameters # Molecule is in this format xyz as below or in Z-matrix e.g "H; O 1 1.08; H 2 1.08 1 107.5": # atoms=H .0 .0 .0; H .0 .0 0.2 # units=Angstrom # charge=0 # multiplicity=1 # where we support symbol for atom as well as number units = _check_units(units) mol = _parse_molecule(atoms, units, charge, multiplicity) calc_type = calc_type.lower() try: ehf, enuke, norbs, mohij, mohijkl, orbs, orbs_energy = _calculate_integrals( mol, basis, calc_type) except Exception as exc: raise QiskitChemistryError( 'Failed electronic structure computation') from exc # Create driver level molecule object and populate _q_ = QMolecule() # Energies and orbits _q_.hf_energy = ehf _q_.nuclear_repulsion_energy = enuke _q_.num_orbitals = norbs _q_.num_alpha = mol.nup() _q_.num_beta = mol.ndown() _q_.mo_coeff = orbs _q_.orbital_energies = orbs_energy # Molecule geometry _q_.molecular_charge = mol.charge _q_.multiplicity = mol.multiplicity _q_.num_atoms = len(mol) _q_.atom_symbol = [] _q_.atom_xyz = np.empty([len(mol), 3]) atoms = mol.atoms for _n in range(0, _q_.num_atoms): atuple = atoms[_n].atuple() _q_.atom_symbol.append(QMolecule.symbols[atuple[0]]) _q_.atom_xyz[_n][0] = atuple[1] _q_.atom_xyz[_n][1] = atuple[2] _q_.atom_xyz[_n][2] = atuple[3] # 1 and 2 electron integrals _q_.mo_onee_ints = mohij _q_.mo_eri_ints = mohijkl return _q_
def qmol_func(mol, calc_type='rhf', atomic=False): ehf, enuke, norbs, mohij, mohijkl, mo_coeff, orbs_energy, x_dip, y_dip, z_dip, nucl_dip = _calculate_integrals( mol, calc_type, atomic) # Create driver level molecule object and populate _q_ = QMolecule() # Energies and orbits _q_.hf_energy = ehf _q_.nuclear_repulsion_energy = enuke _q_.num_orbitals = norbs _q_.num_alpha = mol.nelec[0] _q_.num_beta = mol.nelec[1] _q_.mo_coeff = mo_coeff _q_.orbital_energies = orbs_energy # Molecule geometry _q_.molecular_charge = mol.charge _q_.multiplicity = mol.spin + 1 _q_.num_atoms = mol.natm _q_.atom_symbol = [] _q_.atom_xyz = np.empty([mol.natm, 3]) atoms = mol.atom_coords() for _n in range(0, _q_.num_atoms): xyz = mol.atom_coord(_n) _q_.atom_symbol.append(mol.atom_pure_symbol(_n)) _q_.atom_xyz[_n][0] = xyz[0] _q_.atom_xyz[_n][1] = xyz[1] _q_.atom_xyz[_n][2] = xyz[2] # 1 and 2 electron integrals. h1 & h2 are ready to pass to FermionicOperator _q_.mo_onee_ints = mohij _q_.mo_eri_ints = mohijkl # dipole integrals _q_.x_dip_mo_ints = x_dip _q_.y_dip_mo_ints = y_dip _q_.z_dip_mo_ints = z_dip # dipole moment _q_.nuclear_dipole_moment = nucl_dip _q_.reverse_dipole_sign = True return _q_
def run(self): return QMolecule()
def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init_guess='minao'): """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in the given basis. Args: mol (gto.Mole) : A PySCF gto.Mole object. hf_method (str): rhf, uhf, rohf conv_tol (float): Convergence tolerance max_cycle (int): Max convergence cycles init_guess (str): Initial guess for SCF Returns: QMolecule: QMolecule populated with driver integrals etc """ enuke = gto.mole.energy_nuc(mol) if hf_method == 'rhf': mf = scf.RHF(mol) elif hf_method == 'rohf': mf = scf.ROHF(mol) elif hf_method == 'uhf': mf = scf.UHF(mol) else: raise QiskitChemistryError( 'Invalid hf_method type: {}'.format(hf_method)) mf.conv_tol = conv_tol mf.max_cycle = max_cycle mf.init_guess = init_guess ehf = mf.kernel() logger.info('PySCF kernel() converged: {}, e(hf): {}'.format( mf.converged, mf.e_tot)) if type(mf.mo_coeff) is tuple: mo_coeff = mf.mo_coeff[0] mo_coeff_B = mf.mo_coeff[1] # mo_occ = mf.mo_occ[0] # mo_occ_B = mf.mo_occ[1] else: # With PySCF 1.6.2, instead of a tuple of 2 dimensional arrays, its a 3 dimensional # array with the first dimension indexing to the coeff arrays for alpha and beta if len(mf.mo_coeff.shape) > 2: mo_coeff = mf.mo_coeff[0] mo_coeff_B = mf.mo_coeff[1] # mo_occ = mf.mo_occ[0] # mo_occ_B = mf.mo_occ[1] else: mo_coeff = mf.mo_coeff mo_coeff_B = None # mo_occ = mf.mo_occ # mo_occ_B = None norbs = mo_coeff.shape[0] if type(mf.mo_energy) is tuple: orbs_energy = mf.mo_energy[0] orbs_energy_B = mf.mo_energy[1] else: # See PYSCF 1.6.2 comment above - this was similarly changed if len(mf.mo_energy.shape) > 1: orbs_energy = mf.mo_energy[0] orbs_energy_B = mf.mo_energy[1] else: orbs_energy = mf.mo_energy orbs_energy_B = None if logger.isEnabledFor(logging.DEBUG): # Add some more to PySCF output... # First analyze() which prints extra information about MO energy and occupation mol.stdout.write('\n') mf.analyze() # Now labelled orbitals for contributions to the MOs for s,p,d etc of each atom mol.stdout.write('\n\n--- Alpha Molecular Orbitals ---\n\n') dump_mat.dump_mo(mol, mo_coeff, digits=7, start=1) if mo_coeff_B is not None: mol.stdout.write('\n--- Beta Molecular Orbitals ---\n\n') dump_mat.dump_mo(mol, mo_coeff_B, digits=7, start=1) mol.stdout.flush() hij = mf.get_hcore() mohij = np.dot(np.dot(mo_coeff.T, hij), mo_coeff) mohij_B = None if mo_coeff_B is not None: mohij_B = np.dot(np.dot(mo_coeff_B.T, hij), mo_coeff_B) eri = mol.intor('int2e', aosym=1) mo_eri = ao2mo.incore.full(mf._eri, mo_coeff, compact=False) mohijkl = mo_eri.reshape(norbs, norbs, norbs, norbs) mohijkl_BB = None mohijkl_BA = None if mo_coeff_B is not None: mo_eri_B = ao2mo.incore.full(mf._eri, mo_coeff_B, compact=False) mohijkl_BB = mo_eri_B.reshape(norbs, norbs, norbs, norbs) mo_eri_BA = ao2mo.incore.general( mf._eri, (mo_coeff_B, mo_coeff_B, mo_coeff, mo_coeff), compact=False) mohijkl_BA = mo_eri_BA.reshape(norbs, norbs, norbs, norbs) # dipole integrals mol.set_common_orig((0, 0, 0)) ao_dip = mol.intor_symmetric('int1e_r', comp=3) x_dip_ints = ao_dip[0] y_dip_ints = ao_dip[1] z_dip_ints = ao_dip[2] dm = mf.make_rdm1(mf.mo_coeff, mf.mo_occ) if hf_method == 'rohf' or hf_method == 'uhf': dm = dm[0] elec_dip = np.negative(np.einsum('xij,ji->x', ao_dip, dm).real) elec_dip = np.round(elec_dip, decimals=8) nucl_dip = np.einsum('i,ix->x', mol.atom_charges(), mol.atom_coords()) nucl_dip = np.round(nucl_dip, decimals=8) logger.info("HF Electronic dipole moment: {}".format(elec_dip)) logger.info("Nuclear dipole moment: {}".format(nucl_dip)) logger.info("Total dipole moment: {}".format(nucl_dip + elec_dip)) # Create driver level molecule object and populate _q_ = QMolecule() _q_.origin_driver_version = pyscf_version # Energies and orbits _q_.hf_energy = ehf _q_.nuclear_repulsion_energy = enuke _q_.num_orbitals = norbs _q_.num_alpha = mol.nelec[0] _q_.num_beta = mol.nelec[1] _q_.mo_coeff = mo_coeff _q_.mo_coeff_B = mo_coeff_B _q_.orbital_energies = orbs_energy _q_.orbital_energies_B = orbs_energy_B # Molecule geometry _q_.molecular_charge = mol.charge _q_.multiplicity = mol.spin + 1 _q_.num_atoms = mol.natm _q_.atom_symbol = [] _q_.atom_xyz = np.empty([mol.natm, 3]) atoms = mol.atom_coords() for _n in range(0, _q_.num_atoms): xyz = mol.atom_coord(_n) _q_.atom_symbol.append(mol.atom_pure_symbol(_n)) _q_.atom_xyz[_n][0] = xyz[0] _q_.atom_xyz[_n][1] = xyz[1] _q_.atom_xyz[_n][2] = xyz[2] # 1 and 2 electron integrals AO and MO _q_.hcore = hij _q_.hcore_B = None _q_.kinetic = mol.intor_symmetric('int1e_kin') _q_.overlap = mf.get_ovlp() _q_.eri = eri _q_.mo_onee_ints = mohij _q_.mo_onee_ints_B = mohij_B _q_.mo_eri_ints = mohijkl _q_.mo_eri_ints_BB = mohijkl_BB _q_.mo_eri_ints_BA = mohijkl_BA # dipole integrals AO and MO _q_.x_dip_ints = x_dip_ints _q_.y_dip_ints = y_dip_ints _q_.z_dip_ints = z_dip_ints _q_.x_dip_mo_ints = QMolecule.oneeints2mo(x_dip_ints, mo_coeff) _q_.x_dip_mo_ints_B = None _q_.y_dip_mo_ints = QMolecule.oneeints2mo(y_dip_ints, mo_coeff) _q_.y_dip_mo_ints_B = None _q_.z_dip_mo_ints = QMolecule.oneeints2mo(z_dip_ints, mo_coeff) _q_.z_dip_mo_ints_B = None if mo_coeff_B is not None: _q_.x_dip_mo_ints_B = QMolecule.oneeints2mo(x_dip_ints, mo_coeff_B) _q_.y_dip_mo_ints_B = QMolecule.oneeints2mo(y_dip_ints, mo_coeff_B) _q_.z_dip_mo_ints_B = QMolecule.oneeints2mo(z_dip_ints, mo_coeff_B) # dipole moment _q_.nuclear_dipole_moment = nucl_dip _q_.reverse_dipole_sign = True return _q_
def compute_integrals(atom, unit, charge, spin, basis, hf_method='rhf', max_memory=None): # Get config from input parameters # molecule is in PySCF atom string format e.g. "H .0 .0 .0; H .0 .0 0.2" # or in Z-Matrix format e.g. "H; O 1 1.08; H 2 1.08 1 107.5" # other parameters are as per PySCF got.Mole format atom = _check_molecule_format(atom) hf_method = hf_method.lower() if max_memory is None: max_memory = param.MAX_MEMORY try: mol = gto.Mole(atom=atom, unit=unit, basis=basis, max_memory=max_memory, verbose=pylogger.QUIET) mol.symmetry = False mol.charge = charge mol.spin = spin mol.build(parse_arg=False) ehf, enuke, norbs, mohij, mohijkl, mo_coeff, orbs_energy, x_dip, y_dip, z_dip, nucl_dip = _calculate_integrals( mol, hf_method) except Exception as exc: raise QiskitChemistryError( 'Failed electronic structure computation') from exc # Create driver level molecule object and populate _q_ = QMolecule() # Energies and orbits _q_.hf_energy = ehf _q_.nuclear_repulsion_energy = enuke _q_.num_orbitals = norbs _q_.num_alpha = mol.nelec[0] _q_.num_beta = mol.nelec[1] _q_.mo_coeff = mo_coeff _q_.orbital_energies = orbs_energy # Molecule geometry _q_.molecular_charge = mol.charge _q_.multiplicity = mol.spin + 1 _q_.num_atoms = mol.natm _q_.atom_symbol = [] _q_.atom_xyz = np.empty([mol.natm, 3]) atoms = mol.atom_coords() for _n in range(0, _q_.num_atoms): xyz = mol.atom_coord(_n) _q_.atom_symbol.append(mol.atom_pure_symbol(_n)) _q_.atom_xyz[_n][0] = xyz[0] _q_.atom_xyz[_n][1] = xyz[1] _q_.atom_xyz[_n][2] = xyz[2] # 1 and 2 electron integrals. h1 & h2 are ready to pass to FermionicOperator _q_.mo_onee_ints = mohij _q_.mo_eri_ints = mohijkl # dipole integrals _q_.x_dip_mo_ints = x_dip _q_.y_dip_mo_ints = y_dip _q_.z_dip_mo_ints = z_dip # dipole moment _q_.nuclear_dipole_moment = nucl_dip _q_.reverse_dipole_sign = True return _q_
def _parse_matrix_file(self, fname, useAO2E=False): # get_driver_class is used here because the discovery routine will load all the gaussian # binary dependencies, if not loaded already. It won't work without it. try: # add gauopen to sys.path so that binaries can be loaded gauopen_directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'gauopen') if gauopen_directory not in sys.path: sys.path.insert(0, gauopen_directory) from .gauopen.QCMatEl import MatEl except ImportError as mnfe: msg = 'qcmatrixio extension not found. See Gaussian driver readme to build qcmatrixio.F using f2py' \ if mnfe.name == 'qcmatrixio' else str(mnfe) logger.info(msg) raise QiskitChemistryError(msg) mel = MatEl(file=fname) logger.debug('MatrixElement file:\n{}'.format(mel)) # Create driver level molecule object and populate _q_ = QMolecule() # Energies and orbits _q_.hf_energy = mel.scalar('ETOTAL') _q_.nuclear_repulsion_energy = mel.scalar('ENUCREP') _q_.num_orbitals = 0 # updated below from orbital coeffs size _q_.num_alpha = (mel.ne + mel.multip - 1) // 2 _q_.num_beta = (mel.ne - mel.multip + 1) // 2 _q_.molecular_charge = mel.icharg # Molecule geometry _q_.multiplicity = mel.multip _q_.num_atoms = mel.natoms _q_.atom_symbol = [] _q_.atom_xyz = np.empty([mel.natoms, 3]) syms = mel.ian xyz = np.reshape(mel.c, (_q_.num_atoms, 3)) for _n in range(0, _q_.num_atoms): _q_.atom_symbol.append(QMolecule.symbols[syms[_n]]) for _i in range(xyz.shape[1]): coord = xyz[_n][_i] if abs(coord) < 1e-10: coord = 0 _q_.atom_xyz[_n][_i] = coord moc = self._getMatrix(mel, 'ALPHA MO COEFFICIENTS') _q_.num_orbitals = moc.shape[0] _q_.mo_coeff = moc orbs_energy = self._getMatrix(mel, 'ALPHA ORBITAL ENERGIES') _q_.orbital_energies = orbs_energy # 1 and 2 electron integrals hcore = self._getMatrix(mel, 'CORE HAMILTONIAN ALPHA') logger.debug('CORE HAMILTONIAN ALPHA {}'.format(hcore.shape)) mohij = QMolecule.oneeints2mo(hcore, moc) if useAO2E: # These are 2-body in AO. We can convert to MO via the QMolecule # method but using ints in MO already, as in the else here, is better eri = self._getMatrix(mel, 'REGULAR 2E INTEGRALS') logger.debug('REGULAR 2E INTEGRALS {}'.format(eri.shape)) mohijkl = QMolecule.twoeints2mo(eri, moc) else: # These are in MO basis but by default will be reduced in size by # frozen core default so to use them we need to add Window=Full # above when we augment the config mohijkl = self._getMatrix(mel, 'AA MO 2E INTEGRALS') logger.debug('AA MO 2E INTEGRALS {}'.format(mohijkl.shape)) _q_.mo_onee_ints = mohij _q_.mo_eri_ints = mohijkl # dipole moment dipints = self._getMatrix(mel, 'DIPOLE INTEGRALS') dipints = np.einsum('ijk->kji', dipints) _q_.x_dip_mo_ints = QMolecule.oneeints2mo(dipints[0], moc) _q_.y_dip_mo_ints = QMolecule.oneeints2mo(dipints[1], moc) _q_.z_dip_mo_ints = QMolecule.oneeints2mo(dipints[2], moc) nucl_dip = np.einsum('i,ix->x', syms, xyz) nucl_dip = np.round(nucl_dip, decimals=8) _q_.nuclear_dipole_moment = nucl_dip _q_.reverse_dipole_sign = True return _q_
truncation_threshold = 0.001 # geometry = 'Li 0.0 0.0 -{0}; Li 0.0 0.0 {0}' # atoms = ['Li','Li'] geometry = 'H 0.0 0.0 0.907632; F 0.0 0.0 -0.100848' atoms = ['H', 'F'] # geometry = 'H 0.0 0.0 -{0}; H 0.0 0.0 {0}' basis = 'cc-pvtz' # li2_distances = [1.0692, 1.136025, 1.20285, 1.269675, 1.3365, 1.403325, # 1.536975, 1.670625, 1.8, 1.9, 2.00475, 2.1, 2.338875, 2.4, 2.5, # 2.68, 3.0, 3.2, 3.425, 4., 5.] li2_distances = [2.9403 / 2.] # H2_dist = [0.7004] # LiH_dist = [1.5] qm = QMolecule() for key, dist in enumerate(li2_distances): ############### RUN PYSCF DRIVER ################ active_spatial_orbitals = 10 print('{} is the distance'.format(dist)) # driver = PySCFDriver(atom=geometry.format(dist), unit=UnitsType.ANGSTROM, charge=0, spin=0, basis=basis) driver = PySCFDriver(atom=geometry, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis=basis) molecule = driver.run() ################### INITIALIZE VARIABLES #################
def _calculate_integrals(molecule, basis='sto3g', hf_method='rhf', tol=1e-8, maxiters=100): """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in the given basis. Args: molecule (pyQuante2.molecule): A pyquante2 molecular object. basis (str) : The basis set for the electronic structure computation hf_method (str): rhf, uhf, rohf tol (float): tolerance maxiters (int): max. iterations Returns: QMolecule: QMolecule populated with driver integrals etc Raises: QiskitChemistryError: Invalid hf methods type """ bfs = basisset(molecule, basis) integrals = onee_integrals(bfs, molecule) hij = integrals.T + integrals.V hijkl = twoe_integrals(bfs) # convert overlap integrals to molecular basis # calculate the Hartree-Fock solution of the molecule if hf_method == 'rhf': solver = rhf(molecule, bfs) elif hf_method == 'rohf': solver = rohf(molecule, bfs) elif hf_method == 'uhf': solver = uhf(molecule, bfs) else: raise QiskitChemistryError( 'Invalid hf_method type: {}'.format(hf_method)) ehf = solver.converge(tol=tol, maxiters=maxiters) logger.debug('PyQuante2 processing information:\n%s', solver) if hasattr(solver, 'orbs'): orbs = solver.orbs orbs_b = None else: orbs = solver.orbsa orbs_b = solver.orbsb norbs = len(orbs) if hasattr(solver, 'orbe'): orbs_energy = solver.orbe orbs_energy_b = None else: orbs_energy = solver.orbea orbs_energy_b = solver.orbeb enuke = molecule.nuclear_repulsion() # Get ints in molecular orbital basis mohij = simx(hij, orbs) mohij_b = None if orbs_b is not None: mohij_b = simx(hij, orbs_b) eri = hijkl.transform(np.identity(norbs)) mohijkl = hijkl.transform(orbs) mohijkl_bb = None mohijkl_ba = None if orbs_b is not None: mohijkl_bb = hijkl.transform(orbs_b) mohijkl_ba = np.einsum('aI,bJ,cK,dL,abcd->IJKL', orbs_b, orbs_b, orbs, orbs, hijkl[...]) # Create driver level molecule object and populate _q_ = QMolecule() _q_.origin_driver_version = '?' # No version info seems available to access # Energies and orbits _q_.hf_energy = ehf[0] _q_.nuclear_repulsion_energy = enuke _q_.num_orbitals = norbs _q_.num_alpha = molecule.nup() _q_.num_beta = molecule.ndown() _q_.mo_coeff = orbs _q_.mo_coeff_b = orbs_b _q_.orbital_energies = orbs_energy _q_.orbital_energies_b = orbs_energy_b # Molecule geometry _q_.molecular_charge = molecule.charge _q_.multiplicity = molecule.multiplicity _q_.num_atoms = len(molecule) _q_.atom_symbol = [] _q_.atom_xyz = np.empty([len(molecule), 3]) atoms = molecule.atoms for n_i in range(0, _q_.num_atoms): atuple = atoms[n_i].atuple() _q_.atom_symbol.append(QMolecule.symbols[atuple[0]]) _q_.atom_xyz[n_i][0] = atuple[1] _q_.atom_xyz[n_i][1] = atuple[2] _q_.atom_xyz[n_i][2] = atuple[3] # 1 and 2 electron integrals _q_.hcore = hij _q_.hcore_b = None _q_.kinetic = integrals.T _q_.overlap = integrals.S _q_.eri = eri _q_.mo_onee_ints = mohij _q_.mo_onee_ints_b = mohij_b _q_.mo_eri_ints = mohijkl _q_.mo_eri_ints_bb = mohijkl_bb _q_.mo_eri_ints_ba = mohijkl_ba return _q_
def _parse_matrix_file(self, fname, useao2e=False): # get_driver_class is used here because the discovery routine will load all the gaussian # binary dependencies, if not loaded already. It won't work without it. try: # add gauopen to sys.path so that binaries can be loaded gauopen_directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'gauopen') if gauopen_directory not in sys.path: sys.path.insert(0, gauopen_directory) # pylint: disable=import-outside-toplevel from .gauopen.QCMatEl import MatEl except ImportError as mnfe: msg = ('qcmatrixio extension not found. ' 'See Gaussian driver readme to build qcmatrixio.F using f2py') \ if mnfe.name == 'qcmatrixio' else str(mnfe) logger.info(msg) raise QiskitChemistryError(msg) from mnfe mel = MatEl(file=fname) logger.debug('MatrixElement file:\n%s', mel) # Create driver level molecule object and populate _q_ = QMolecule() _q_.origin_driver_version = mel.gversion # Energies and orbits _q_.hf_energy = mel.scalar('ETOTAL') _q_.nuclear_repulsion_energy = mel.scalar('ENUCREP') _q_.num_orbitals = 0 # updated below from orbital coeffs size _q_.num_alpha = (mel.ne + mel.multip - 1) // 2 _q_.num_beta = (mel.ne - mel.multip + 1) // 2 moc = self._get_matrix(mel, 'ALPHA MO COEFFICIENTS') moc_b = self._get_matrix(mel, 'BETA MO COEFFICIENTS') if np.array_equal(moc, moc_b): logger.debug('ALPHA and BETA MO COEFFS identical, keeping only ALPHA') moc_b = None _q_.num_orbitals = moc.shape[0] _q_.mo_coeff = moc _q_.mo_coeff_b = moc_b orbs_energy = self._get_matrix(mel, 'ALPHA ORBITAL ENERGIES') _q_.orbital_energies = orbs_energy orbs_energy_b = self._get_matrix(mel, 'BETA ORBITAL ENERGIES') _q_.orbital_energies_b = orbs_energy_b if moc_b is not None else None # Molecule geometry _q_.molecular_charge = mel.icharg _q_.multiplicity = mel.multip _q_.num_atoms = mel.natoms _q_.atom_symbol = [] _q_.atom_xyz = np.empty([mel.natoms, 3]) syms = mel.ian xyz = np.reshape(mel.c, (_q_.num_atoms, 3)) for n_i in range(0, _q_.num_atoms): _q_.atom_symbol.append(QMolecule.symbols[syms[n_i]]) for idx in range(xyz.shape[1]): coord = xyz[n_i][idx] if abs(coord) < 1e-10: coord = 0 _q_.atom_xyz[n_i][idx] = coord # 1 and 2 electron integrals hcore = self._get_matrix(mel, 'CORE HAMILTONIAN ALPHA') logger.debug('CORE HAMILTONIAN ALPHA %s', hcore.shape) hcore_b = self._get_matrix(mel, 'CORE HAMILTONIAN BETA') if np.array_equal(hcore, hcore_b): # From Gaussian interfacing documentation: "The two # core Hamiltonians are identical unless # a Fermi contact perturbation has been applied." logger.debug('CORE HAMILTONIAN ALPHA and BETA identical, keeping only ALPHA') hcore_b = None logger.debug('CORE HAMILTONIAN BETA %s', '- Not present' if hcore_b is None else hcore_b.shape) kinetic = self._get_matrix(mel, 'KINETIC ENERGY') logger.debug('KINETIC ENERGY %s', kinetic.shape) overlap = self._get_matrix(mel, 'OVERLAP') logger.debug('OVERLAP %s', overlap.shape) mohij = QMolecule.oneeints2mo(hcore, moc) mohij_b = None if moc_b is not None: mohij_b = QMolecule.oneeints2mo(hcore if hcore_b is None else hcore_b, moc_b) eri = self._get_matrix(mel, 'REGULAR 2E INTEGRALS') logger.debug('REGULAR 2E INTEGRALS %s', eri.shape) if moc_b is None and mel.matlist.get('BB MO 2E INTEGRALS') is not None: # It seems that when using ROHF, where alpha and beta coeffs are # the same, that integrals # for BB and BA are included in the output, as well as just AA # that would have been expected # Using these fails to give the right answer (is ok for UHF). # So in this case we revert to # using 2 electron ints in atomic basis from the output and # converting them ourselves. useao2e = True logger.info( 'Identical A and B coeffs but BB ints are present - using regular 2E ints instead') if useao2e: # eri are 2-body in AO. We can convert to MO via the QMolecule # method but using ints in MO already, as in the else here, is better mohijkl = QMolecule.twoeints2mo(eri, moc) mohijkl_bb = None mohijkl_ba = None if moc_b is not None: mohijkl_bb = QMolecule.twoeints2mo(eri, moc_b) mohijkl_ba = QMolecule.twoeints2mo_general(eri, moc_b, moc_b, moc, moc) else: # These are in MO basis but by default will be reduced in size by # frozen core default so to use them we need to add Window=Full # above when we augment the config mohijkl = self._get_matrix(mel, 'AA MO 2E INTEGRALS') logger.debug('AA MO 2E INTEGRALS %s', mohijkl.shape) mohijkl_bb = self._get_matrix(mel, 'BB MO 2E INTEGRALS') logger.debug('BB MO 2E INTEGRALS %s', '- Not present' if mohijkl_bb is None else mohijkl_bb.shape) mohijkl_ba = self._get_matrix(mel, 'BA MO 2E INTEGRALS') logger.debug('BA MO 2E INTEGRALS %s', '- Not present' if mohijkl_ba is None else mohijkl_ba.shape) _q_.hcore = hcore _q_.hcore_b = hcore_b _q_.kinetic = kinetic _q_.overlap = overlap _q_.eri = eri _q_.mo_onee_ints = mohij _q_.mo_onee_ints_b = mohij_b _q_.mo_eri_ints = mohijkl _q_.mo_eri_ints_bb = mohijkl_bb _q_.mo_eri_ints_ba = mohijkl_ba # dipole moment dipints = self._get_matrix(mel, 'DIPOLE INTEGRALS') dipints = np.einsum('ijk->kji', dipints) _q_.x_dip_ints = dipints[0] _q_.y_dip_ints = dipints[1] _q_.z_dip_ints = dipints[2] _q_.x_dip_mo_ints = QMolecule.oneeints2mo(dipints[0], moc) _q_.x_dip_mo_ints_b = None _q_.y_dip_mo_ints = QMolecule.oneeints2mo(dipints[1], moc) _q_.y_dip_mo_ints_b = None _q_.z_dip_mo_ints = QMolecule.oneeints2mo(dipints[2], moc) _q_.z_dip_mo_ints_b = None if moc_b is not None: _q_.x_dip_mo_ints_b = QMolecule.oneeints2mo(dipints[0], moc_b) _q_.y_dip_mo_ints_b = QMolecule.oneeints2mo(dipints[1], moc_b) _q_.z_dip_mo_ints_b = QMolecule.oneeints2mo(dipints[2], moc_b) nucl_dip = np.einsum('i,ix->x', syms, xyz) nucl_dip = np.round(nucl_dip, decimals=8) _q_.nuclear_dipole_moment = nucl_dip _q_.reverse_dipole_sign = True return _q_
max_cycle=5000, max_memory=1024 * 128, basis='sto3g' ) #driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', # unit=UnitsType.ANGSTROM, # basis='sto3g') #FILENAME = "hdf5_files/femoco_sto3g_(-1,3).hdf5" #FILENAME = "hdf5_files/femoco_nosulfer_sto3g_(-1,3).hdf5" FILENAME = "hdf5_files/lih_sto3g_(0,0).hdf5" #FILENAME = "hdf5_files/hydrogen.hdf5" if os.path.exists(FILENAME): print(f"Found {FILENAME}. Loading...") molecule = QMolecule(FILENAME) molecule.load() else: # Regenerate print(f"Couldn't find {FILENAME}. Regenerating...") molecule = driver.run() molecule.save(FILENAME) #print("Loading 1 body integrals...") #one_body_integrals = molecule.one_body_integrals ##np.save("results/old/lih_1d.npy", one_body_integrals) #np.save("results/new/lih_1d.npy", one_body_integrals) # #print("Loading 2 body integrals...") #two_body_integrals = molecule.two_body_integrals #np.save("results/new/lih_2d.npy", two_body_integrals)
def _calculate_integrals(mol, hf_method='rhf', conv_tol=1e-9, max_cycle=50, init_guess='minao',outfile=None): """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in the given basis. Args: mol (gto.Mole) : A PySCF gto.Mole object. hf_method (str): rhf, uhf, rohf conv_tol (float): Convergence tolerance max_cycle (int): Max convergence cycles init_guess (str): Initial guess for SCF Returns: QMolecule: QMolecule populated with driver integrals etc Raises: QiskitChemistryError: Invalid hf method type """ enuke = gto.mole.energy_nuc(mol) if hf_method == 'rhf': m_f = scf.RHF(mol) elif hf_method == 'rohf': m_f = scf.ROHF(mol) elif hf_method == 'uhf': m_f = scf.UHF(mol) else: raise QiskitChemistryError('Invalid hf_method type: {}'.format(hf_method)) m_f.conv_tol = conv_tol m_f.max_cycle = max_cycle m_f.init_guess = init_guess ehf = m_f.kernel() from pyscf import tools from prettytable import PrettyTable C = m_f.mo_coeff irr = get_irreps(mol,C) table_ancillary_info = [[str(round(m_f.mo_energy[i],4)),irr[i],str(int(m_f.mo_occ[i]))] for i in range(mol.nao_nr())] outfile.write("SCF orbitals\n") t = PrettyTable(['MO']+mol.ao_labels()+['E','irr','occ']) for i in range(C.shape[1]): if(C[np.argmax(np.abs(C[:,i])),i]<0): C[:,i] *= -1 t.add_row([str(i)]+[str(round(x,4)) for x in C[:,i]]+table_ancillary_info[i]) outfile.write(str(t)) filename = 'mos' for i in range(m_f.mo_coeff.shape[1]): moldenfile = filename+'-'+str(i)+'.molden' tools.molden.from_mo(mol,moldenfile,m_f.mo_coeff) jmol_script = filename+'-'+str(i)+'.spt' fspt = open(jmol_script,'w') fspt.write(''' initialize; set background [xffffff]; set frank off set autoBond true; set bondRadiusMilliAngstroms 66; set bondTolerance 0.5; set forceAutoBond false; load %s ''' % moldenfile) fspt.write(''' zoom 130; rotate -20 z rotate -60 x axes MO COLOR [xff0020] [x0060ff]; MO COLOR translucent 0.25; MO fill noDots noMesh; MO titleformat ""; ''') fspt.write('MO %d cutoff 0.02;\n' % (i+1)) fspt.write('write IMAGE 400 400 PNG 180 "%s-%02d.png";\n' % (filename,i+1)) fspt.close() logger.info('PySCF kernel() converged: %s, e(hf): %s', m_f.converged, m_f.e_tot) if isinstance(m_f.mo_coeff, tuple): mo_coeff = m_f.mo_coeff[0] mo_coeff_b = m_f.mo_coeff[1] # mo_occ = m_f.mo_occ[0] # mo_occ_b = m_f.mo_occ[1] else: # With PySCF 1.6.2, instead of a tuple of 2 dimensional arrays, its a 3 dimensional # array with the first dimension indexing to the coeff arrays for alpha and beta if len(m_f.mo_coeff.shape) > 2: mo_coeff = m_f.mo_coeff[0] mo_coeff_b = m_f.mo_coeff[1] # mo_occ = m_f.mo_occ[0] # mo_occ_b = m_f.mo_occ[1] else: mo_coeff = m_f.mo_coeff mo_coeff_b = None # mo_occ = mf.mo_occ # mo_occ_b = None norbs = mo_coeff.shape[0] if isinstance(m_f.mo_energy, tuple): orbs_energy = m_f.mo_energy[0] orbs_energy_b = m_f.mo_energy[1] else: # See PYSCF 1.6.2 comment above - this was similarly changed if len(m_f.mo_energy.shape) > 1: orbs_energy = m_f.mo_energy[0] orbs_energy_b = m_f.mo_energy[1] else: orbs_energy = m_f.mo_energy orbs_energy_b = None if logger.isEnabledFor(logging.DEBUG): # Add some more to PySCF output... # First analyze() which prints extra information about MO energy and occupation mol.stdout.write('\n') m_f.analyze() # Now labelled orbitals for contributions to the MOs for s,p,d etc of each atom mol.stdout.write('\n\n--- Alpha Molecular Orbitals ---\n\n') dump_mat.dump_mo(mol, mo_coeff, digits=7, start=1) if mo_coeff_b is not None: mol.stdout.write('\n--- Beta Molecular Orbitals ---\n\n') dump_mat.dump_mo(mol, mo_coeff_b, digits=7, start=1) mol.stdout.flush() hij = m_f.get_hcore() mohij = np.dot(np.dot(mo_coeff.T, hij), mo_coeff) mohij_b = None if mo_coeff_b is not None: mohij_b = np.dot(np.dot(mo_coeff_b.T, hij), mo_coeff_b) eri = mol.intor('int2e', aosym=1) mo_eri = ao2mo.incore.full(m_f._eri, mo_coeff, compact=False) mohijkl = mo_eri.reshape(norbs, norbs, norbs, norbs) mohijkl_bb = None mohijkl_ba = None if mo_coeff_b is not None: mo_eri_b = ao2mo.incore.full(m_f._eri, mo_coeff_b, compact=False) mohijkl_bb = mo_eri_b.reshape(norbs, norbs, norbs, norbs) mo_eri_ba = ao2mo.incore.general(m_f._eri, (mo_coeff_b, mo_coeff_b, mo_coeff, mo_coeff), compact=False) mohijkl_ba = mo_eri_ba.reshape(norbs, norbs, norbs, norbs) # dipole integrals mol.set_common_orig((0, 0, 0)) ao_dip = mol.intor_symmetric('int1e_r', comp=3) x_dip_ints = ao_dip[0] y_dip_ints = ao_dip[1] z_dip_ints = ao_dip[2] d_m = m_f.make_rdm1(m_f.mo_coeff, m_f.mo_occ) if hf_method in ('rohf', 'uhf'): d_m = d_m[0] elec_dip = np.negative(np.einsum('xij,ji->x', ao_dip, d_m).real) elec_dip = np.round(elec_dip, decimals=8) nucl_dip = np.einsum('i,ix->x', mol.atom_charges(), mol.atom_coords()) nucl_dip = np.round(nucl_dip, decimals=8) logger.info("HF Electronic dipole moment: %s", elec_dip) logger.info("Nuclear dipole moment: %s", nucl_dip) logger.info("Total dipole moment: %s", nucl_dip+elec_dip) # Create driver level molecule object and populate _q_ = QMolecule() _q_.origin_driver_version = pyscf_version # Energies and orbits _q_.hf_energy = ehf _q_.nuclear_repulsion_energy = enuke _q_.num_orbitals = norbs _q_.num_alpha = mol.nelec[0] _q_.num_beta = mol.nelec[1] _q_.mo_coeff = mo_coeff _q_.mo_coeff_b = mo_coeff_b _q_.orbital_energies = orbs_energy _q_.orbital_energies_b = orbs_energy_b # Molecule geometry _q_.molecular_charge = mol.charge _q_.multiplicity = mol.spin + 1 _q_.num_atoms = mol.natm _q_.atom_symbol = [] _q_.atom_xyz = np.empty([mol.natm, 3]) _ = mol.atom_coords() for n_i in range(0, _q_.num_atoms): xyz = mol.atom_coord(n_i) _q_.atom_symbol.append(mol.atom_pure_symbol(n_i)) _q_.atom_xyz[n_i][0] = xyz[0] _q_.atom_xyz[n_i][1] = xyz[1] _q_.atom_xyz[n_i][2] = xyz[2] # 1 and 2 electron integrals AO and MO _q_.hcore = hij _q_.hcore_b = None _q_.kinetic = mol.intor_symmetric('int1e_kin') _q_.overlap = m_f.get_ovlp() _q_.eri = eri _q_.mo_onee_ints = mohij _q_.mo_onee_ints_b = mohij_b _q_.mo_eri_ints = mohijkl _q_.mo_eri_ints_bb = mohijkl_bb _q_.mo_eri_ints_ba = mohijkl_ba # dipole integrals AO and MO _q_.x_dip_ints = x_dip_ints _q_.y_dip_ints = y_dip_ints _q_.z_dip_ints = z_dip_ints _q_.x_dip_mo_ints = QMolecule.oneeints2mo(x_dip_ints, mo_coeff) _q_.x_dip_mo_ints_b = None _q_.y_dip_mo_ints = QMolecule.oneeints2mo(y_dip_ints, mo_coeff) _q_.y_dip_mo_ints_b = None _q_.z_dip_mo_ints = QMolecule.oneeints2mo(z_dip_ints, mo_coeff) _q_.z_dip_mo_ints_b = None if mo_coeff_b is not None: _q_.x_dip_mo_ints_b = QMolecule.oneeints2mo(x_dip_ints, mo_coeff_b) _q_.y_dip_mo_ints_b = QMolecule.oneeints2mo(y_dip_ints, mo_coeff_b) _q_.z_dip_mo_ints_b = QMolecule.oneeints2mo(z_dip_ints, mo_coeff_b) # dipole moment _q_.nuclear_dipole_moment = nucl_dip _q_.reverse_dipole_sign = True return _q_