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 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() 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_
def run( self, qmolecule: QMolecule ) -> Tuple[WeightedPauliOperator, List[WeightedPauliOperator]]: """ run method""" logger.debug('Processing started...') # Save these values for later combination with the quantum computation result self._hf_energy = qmolecule.hf_energy self._nuclear_repulsion_energy = qmolecule.nuclear_repulsion_energy self._nuclear_dipole_moment = qmolecule.nuclear_dipole_moment self._reverse_dipole_sign = qmolecule.reverse_dipole_sign core_list = qmolecule.core_orbitals if self._freeze_core else [] reduce_list = self._orbital_reduction if self._freeze_core: logger.info( "Freeze_core specified. Core orbitals to be frozen: %s", core_list) if reduce_list: logger.info("Configured orbital reduction list: %s", reduce_list) reduce_list = [ x + qmolecule.num_orbitals if x < 0 else x for x in reduce_list ] freeze_list = [] remove_list = [] # Orbitals are specified by their index from 0 to n-1, where n is the number of orbitals the # molecule has. The combined list of the core orbitals, when freeze_core is true, with any # user supplied orbitals is what will be used. Negative numbers may be used to indicate the # upper virtual orbitals, so -1 is the highest, then -2 etc. and these will # be converted to the # positive 0-based index for computation. # In the combined list any orbitals that are occupied are added to a freeze list and an # energy is stored from these orbitals to be added later. # Unoccupied orbitals are just discarded. # Because freeze and eliminate is done in separate steps, # with freeze first, we have to re-base # the indexes for elimination according to how many orbitals were removed when freezing. # orbitals_list = list(set(core_list + reduce_list)) num_alpha = qmolecule.num_alpha num_beta = qmolecule.num_beta new_num_alpha = num_alpha new_num_beta = num_beta if orbitals_list: orbitals_list = np.array(orbitals_list) orbitals_list = \ orbitals_list[(cast(np.ndarray, orbitals_list) >= 0) & (orbitals_list < qmolecule.num_orbitals)] freeze_list_alpha = [i for i in orbitals_list if i < num_alpha] freeze_list_beta = [i for i in orbitals_list if i < num_beta] freeze_list = np.append( freeze_list_alpha, [i + qmolecule.num_orbitals for i in freeze_list_beta]) remove_list_alpha = [i for i in orbitals_list if i >= num_alpha] remove_list_beta = [i for i in orbitals_list if i >= num_beta] rla_adjust = -len(freeze_list_alpha) rlb_adjust = -len(freeze_list_alpha) - len( freeze_list_beta) + qmolecule.num_orbitals remove_list = np.append( [i + rla_adjust for i in remove_list_alpha], [i + rlb_adjust for i in remove_list_beta]) logger.info("Combined orbital reduction list: %s", orbitals_list) logger.info( " converting to spin orbital reduction list: %s", np.append(np.array(orbitals_list), np.array(orbitals_list) + qmolecule.num_orbitals)) logger.info(" => freezing spin orbitals: %s", freeze_list) logger.info( " => removing spin orbitals: %s (indexes accounting for freeze %s)", np.append(remove_list_alpha, np.array(remove_list_beta) + qmolecule.num_orbitals), remove_list) new_num_alpha -= len(freeze_list_alpha) new_num_beta -= len(freeze_list_beta) new_nel = [new_num_alpha, new_num_beta] fer_op = FermionicOperator(h1=qmolecule.one_body_integrals, h2=qmolecule.two_body_integrals) fer_op, self._energy_shift, did_shift = \ Hamiltonian._try_reduce_fermionic_operator(fer_op, freeze_list, remove_list) if did_shift: logger.info("Frozen orbital energy shift: %s", self._energy_shift) if self._transformation == TransformationType.PARTICLE_HOLE.value: fer_op, ph_shift = fer_op.particle_hole_transformation(new_nel) self._ph_energy_shift = -ph_shift logger.info("Particle hole energy shift: %s", self._ph_energy_shift) logger.debug('Converting to qubit using %s mapping', self._qubit_mapping) qubit_op = Hamiltonian._map_fermionic_operator_to_qubit( fer_op, self._qubit_mapping, new_nel, self._two_qubit_reduction) qubit_op.name = 'Electronic Hamiltonian' logger.debug(' num paulis: %s, num qubits: %s', len(qubit_op.paulis), qubit_op.num_qubits) aux_ops = [] def _add_aux_op(aux_op, name): aux_qop = Hamiltonian._map_fermionic_operator_to_qubit( aux_op, self._qubit_mapping, new_nel, self._two_qubit_reduction) aux_qop.name = name aux_ops.append(aux_qop) logger.debug(' num paulis: %s', aux_qop.paulis) logger.debug('Creating aux op for Number of Particles') _add_aux_op(fer_op.total_particle_number(), 'Number of Particles') logger.debug('Creating aux op for S^2') _add_aux_op(fer_op.total_angular_momentum(), 'S^2') logger.debug('Creating aux op for Magnetization') _add_aux_op(fer_op.total_magnetization(), 'Magnetization') if qmolecule.has_dipole_integrals(): def _dipole_op(dipole_integrals, axis): logger.debug('Creating aux op for dipole %s', axis) fer_op_ = FermionicOperator(h1=dipole_integrals) fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator( fer_op_, freeze_list, remove_list) if did_shift_: logger.info("Frozen orbital %s dipole shift: %s", axis, shift) ph_shift_ = 0.0 if self._transformation == TransformationType.PARTICLE_HOLE.value: fer_op_, ph_shift_ = fer_op_.particle_hole_transformation( new_nel) ph_shift_ = -ph_shift_ logger.info("Particle hole %s dipole shift: %s", axis, ph_shift_) qubit_op_ = self._map_fermionic_operator_to_qubit( fer_op_, self._qubit_mapping, new_nel, self._two_qubit_reduction) qubit_op_.name = 'Dipole ' + axis logger.debug(' num paulis: %s', len(qubit_op_.paulis)) return qubit_op_, shift, ph_shift_ op_dipole_x, self._x_dipole_shift, self._ph_x_dipole_shift = \ _dipole_op(qmolecule.x_dipole_integrals, 'x') op_dipole_y, self._y_dipole_shift, self._ph_y_dipole_shift = \ _dipole_op(qmolecule.y_dipole_integrals, 'y') op_dipole_z, self._z_dipole_shift, self._ph_z_dipole_shift = \ _dipole_op(qmolecule.z_dipole_integrals, 'z') aux_ops.append(op_dipole_x) aux_ops.append(op_dipole_y) aux_ops.append(op_dipole_z) logger.info('Molecule num electrons: %s, remaining for processing: %s', [num_alpha, num_beta], new_nel) nspinorbs = qmolecule.num_orbitals * 2 new_nspinorbs = nspinorbs - len(freeze_list) - len(remove_list) logger.info( 'Molecule num spin orbitals: %s, remaining for processing: %s', nspinorbs, new_nspinorbs) self._add_molecule_info(self.INFO_NUM_PARTICLES, (new_num_alpha, new_num_beta)) self._add_molecule_info(self.INFO_NUM_ORBITALS, new_nspinorbs) self._add_molecule_info( self.INFO_TWO_QUBIT_REDUCTION, self._two_qubit_reduction if self._qubit_mapping == 'parity' else False) z2symmetries = Z2Symmetries([], [], [], None) if self._z2symmetry_reduction is not None: logger.debug('Processing z2 symmetries') qubit_op, aux_ops, z2symmetries = self._process_z2symmetry_reduction( qubit_op, aux_ops) self._add_molecule_info(self.INFO_Z2SYMMETRIES, z2symmetries) logger.debug('Processing complete ready to run algorithm') return qubit_op, aux_ops
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
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 _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) 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_
def _calculate_integrals(mol, calc_type='rhf'): """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in the given basis. Args: mol : A PySCF gto.Mole object. calc_type: rhf, uhf, rohf Returns: ehf : Hartree-Fock energy enuke : Nuclear repulsion energy norbs : Number of orbitals mohij : One electron terms of the Hamiltonian. mohijkl : Two electron terms of the Hamiltonian. mo_coeff: Orbital coefficients orbs_energy: Orbitals energies x_dip_ints: x dipole moment integrals y_dip_ints: y dipole moment integrals z_dip_ints: z dipole moment integrals nucl_dipl : Nuclear dipole moment """ enuke = gto.mole.energy_nuc(mol) if calc_type == 'rhf': mf = scf.RHF(mol) elif calc_type == 'rohf': mf = scf.ROHF(mol) elif calc_type == 'uhf': mf = scf.UHF(mol) else: raise QiskitChemistryError('Invalid calc_type: {}'.format(calc_type)) ehf = mf.kernel() if type(mf.mo_coeff) is tuple: mo_coeff = mf.mo_coeff[0] mo_occ = mf.mo_occ[0] else: mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ norbs = mo_coeff.shape[0] orbs_energy = mf.mo_energy hij = mf.get_hcore() mohij = np.dot(np.dot(mo_coeff.T, hij), mo_coeff) eri = ao2mo.incore.full(mf._eri, mo_coeff, compact=False) mohijkl = eri.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 = QMolecule.oneeints2mo(ao_dip[0], mo_coeff) y_dip_ints = QMolecule.oneeints2mo(ao_dip[1], mo_coeff) z_dip_ints = QMolecule.oneeints2mo(ao_dip[2], mo_coeff) dm = mf.make_rdm1(mf.mo_coeff, mf.mo_occ) if calc_type == 'rohf' or calc_type == '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)) return ehf, enuke, norbs, mohij, mohijkl, mo_coeff, orbs_energy, x_dip_ints, y_dip_ints, z_dip_ints, nucl_dip
def compute_integrals(atom, unit, charge, spin, basis, max_memory, calc_type='rhf'): # 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) if max_memory is None: max_memory = param.MAX_MEMORY calc_type = calc_type.lower() 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, 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.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 _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 mol_r_matrices(MoleculeFlag,check_r_matrix_flag,is_atomic): mol = gto.Mole() #================================= # Hydrogen molecule #================================= if MoleculeFlag == 'H2': r_matrices=[] num_particles = 2 if is_atomic: try: data = np.load(MoleculeFlag+'ao.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['H',(0, 0, -0.3707)], ['H',(0,0.0,0.3707)]] mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals # np.savez(MoleculeFlag+'_ao.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: mol.atom = [['H',(0, 0, -0.3707)], ['H',(0,0.0,0.3707)]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 # Defining R-matrix --> r # Swapping the spatial orbitals. This involves swapping both the spin orbitals corresponding to a spatial orbital. # This could be treated as a reflection symmetry or rotational symmetry. r1 = np.zeros([4,4]) r1[0,1]=1 r1[1,0]=1 r1[2,3]=1 r1[3,2]=1 # Swapping the spin oritals. Spin symmetry. r2=np.zeros([4,4]) for i in range(4): if i<2: r2[i+2,i]=1. else: r2[i-2,i]=1. r_matrices.append(r1) r_matrices.append(r2) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Water molecule (with different basis sets) #================================= elif MoleculeFlag== 'H2O_L': r_matrices = [] print(MoleculeFlag) # Configuration from # mol.atom = [['O',(0.8638, 0.4573,0.0)], ['H',(0, 0, 0)], ['H',(1.7785,0.0,0.0)]] # mol.atom = [['O',(0.0, 0.0,0.0)],['H',(1, 0, 0)], ['H',(-1.0,0.0,0.0)]] #mol.atom = [['O',(0, 0, 0)], ['H',(0, 1, 0)], ['H@2',(0, 0, 1)]] #mol.basis = {'O': 'sto-3g', 'H': 'cc-pvdz', 'H@2': '6-31G'} num_particles=10 if is_atomic: try: data = np.load(MoleculeFlag+'ao.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['O',(0.0, 0.0,0.0)],['H',(1, 0, 0)], ['H',(-1.0,0.0,0.0)]] mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals # np.savez(MoleculeFlag+'_ao.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: mol.atom = [['O',(0.0, 0.0,0.0)],['H',(1, 0, 0)], ['H',(-1.0,0.0,0.0)]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 # R-matrix for plane of symmetry \sigma_{xy}. Everything remains the same, only pz-orbitals pick up negative sign. r1=np.zeros([14,14]) r1[0,0]=1 r1[1,1]=1 r1[2,2]=1 r1[3,3]=1 r1[4,4]=-1 r1[5,5]=1 r1[6,6]=1 r1[7,7]=1 r1[8,8]=1 r1[9,9]=1 r1[10,10]=1 r1[11,11]=-1 r1[12,12]=1 r1[13,13]=1 r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{xz}. Everything remains the same, only py-orbitals pick up negative sign. r2=np.eye(14) r2[3,3]=-1 r2[10,10]=-1 r_matrices.append(r2) # R-matrix for plane of symmetry \sigma_{yz}. Everything remains the same, only px-orbitals pick up negative sign and hydrogen atoms swap. r3=np.zeros([14,14]) r3[0,0]=1 r3[1,1]=1 r3[2,2]=-1 r3[3,3]=1 r3[4,4]=1 r3[5,6]=1 r3[6,5]=1 r3[7,7]=1 r3[8,8]=1 r3[9,9]=-1 r3[10,10]=1 r3[11,11]=1 r3[12,13]=1 r3[13,12]=1 r_matrices.append(r3) # R-matrix for symmetry-axis C_2. Linear water molecule has three axis of symmetry: # About z-axis r4=np.zeros([14,14]) r4[0,0]=1 r4[1,1]=1 r4[2,2]=-1 r4[3,3]=-1 r4[4,4]=1 r4[5,6]=1 r4[6,5]=1 r4[7,7]=1 r4[8,8]=1 r4[9,9]=-1 r4[10,10]=-1 r4[11,11]=1 r4[12,13]=1 r4[13,12]=1 r_matrices.append(r4) #About y-axis r5=np.zeros([14,14]) r5[0,0]=1 r5[1,1]=1 r5[2,2]=-1 r5[3,3]=1 r5[4,4]=-1 r5[5,6]=1 r5[6,5]=1 r5[7,7]=1 r5[8,8]=1 r5[9,9]=-1 r5[10,10]=1 r5[11,11]=-1 r5[12,13]=1 r5[13,12]=1 r_matrices.append(r5) #Symmetry about x-axis: r6=np.zeros([14,14]) r6[0,0]=1 r6[1,1]=1 r6[2,2]=1 r6[3,3]=-1 r6[4,4]=-1 r6[5,5]=1 r6[6,6]=1 r6[7,7]=1 r6[8,8]=1 r6[9,9]=1 r6[10,10]=-1 r6[11,11]=-1 r6[12,12]=1 r6[13,13]=1 r_matrices.append(r6) #Spin symmetry: r7=np.zeros([14,14]) for i in range(14): if i<7: r7[i+7,i]=1. else: r7[i-7,i]=1. r_matrices.append(r7) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Water molecule (with different basis sets) #================================= elif MoleculeFlag== 'H2O': r_matrices=[] print(MoleculeFlag) num_particles = 10 if is_atomic: try: data = np.load(MoleculeFlag+'ao.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['O',(0.0000, 0.0000, 0.0000)], ['H',(0.757, 0.586, 0.0)], ['H',(-0.757, 0.586, 0.0)]] # mol.atom = [['N', (0.0000, 0.0000, 0.0000)], # ['H', (0.0000, -1.,-0.3816)], # ['H', (0.8, 0.6 ,-0.3816)], # ['H', (-0.8, 0.6 ,-0.3816)]] mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals # np.savez(MoleculeFlag+'_ao.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: mol.atom = [['O',(0.0000, 0.0000, 0.0000)], ['H',(0.757, 0.586, 0.0)], ['H',(-0.757, 0.586, 0.0)]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 #Spin symmetry: r1=np.zeros([14,14]) for i in range(14): if i<7: r1[i+7,i]=1. else: r1[i-7,i]=1. # r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{xy}. Everything remains the same, only pz-orbitals pick up negative sign. r2=np.eye(14) r2[4,4]=-1 r2[11,11]=-1 r_matrices.append(r2) # R-matrix for plane of symmetry \sigma_{yz}. Everything remains the same, only px-orbitals pick up negative sign and the hydrogen atoms swap. r3=np.eye(14) r3[2,2]=-1 r3[9,9]=-1 r3[12,12]=0 r3[13,13]=0 r3[12,13]=1 r3[13,12]=1 r3[5,6]=1 r3[6,5]=1 r3[5,5]=0 r3[6,6]=0 # print(r) r_matrices.append(r3) #Axial symmetry about y-axis r4=np.zeros([14,14]) r4[0,0]=1 r4[1,1]=1 r4[2,2]=-1 r4[3,3]=1 r4[4,4]=-1 r4[5,6]=1 r4[6,5]=1 r4[7,7]=1 r4[8,8]=1 r4[9,9]=-1 r4[10,10]=1 r4[11,11]=-1 r4[12,13]=1 r4[13,12]=1 r_matrices.append(r4) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Ammonia molecule #================================= elif MoleculeFlag=='NH3': print(MoleculeFlag) num_particles = 10 if is_atomic: try: data = np.load(MoleculeFlag+'ao.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['N' , ( 0.0000000, 0.0000000, 0.1493220)], ['H' , ( 0.0000000 , 0.9474830 , -0.3484190)], ['H' , ( 0.8205440 , -0.4737420 , -0.3484190)], ['H' , ( -0.8205440 , -0.4737420 , -0.3484190)]] mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals # np.savez(MoleculeFlag+'_ao.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: mol.atom = [['N' , ( 0.0000000, 0.0000000, 0.1493220)], ['H' , ( 0.0000000 , 0.9474830 , -0.3484190)], ['H' , ( 0.8205440 , -0.4737420 , -0.3484190)], ['H' , ( -0.8205440 , -0.4737420 , -0.3484190)]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 r_matrices=[] #Spin symmetry: r1=np.zeros([16,16]) for i in range(16): if i<8: r1[i+8,i]=1. else: r1[i-8,i]=1. r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{yz}. Two hydrogen atoms are swapped and the px orbital picks up # a negative sign. r3=np.zeros([16,16]) r3[0,0]=1 r3[1,1]=1 r3[2,2]=-1 r3[3,3]=1 r3[4,4]=1 r3[5,5]=1 r3[6,7]=1 r3[7,6]=1 r3[8,8]=1 r3[9,9]=1 r3[10,10]=-1 r3[11,11]=1 r3[12,12]=1 r3[13,13]=1 r3[14,15]=1 r3[15,14]=1 r_matrices.append(r3) ###################################### # The following mtrices commute with Hamiltonian # and hence are symmetries, but these cannot be used # to taper off qubits. theta = -2*np.pi/3 r4 = np.eye(16) r4[5,5]=r4[6,6]=r4[7,7]=0 r4[13,13]=r4[14,14]=r4[15,15]=0 r4[5,6]=r4[6,7]=r4[7,5]=1 # r4[6,5]=r4[7,6]=r4[5,7]=1 r4[13,14]=r4[14,15]=r4[15,13]=1 # r4[14,13]=r4[15,14]=r4[13,15]=1 r4[2,2]=r4[3,3]=r4[10,10]=r4[11,11]=np.cos(theta) r4[2,3]= np.sin(theta) r4[3,2]= -np.sin(theta) r4[10,11]=np.sin(theta) r4[11,10]=-np.sin(theta) r5 = r4.copy() theta = np.pi/3 r4 = np.eye(16,dtype=complex) r4[5,5]=r4[6,6]=0 r4[13,13]=r4[14,14]=0 r4[5,6]=r4[6,5]=1 r4[13,14]=r4[14,13]=1 r4[2,2]=r4[10,10]=np.cos(theta) r4[3,3]=r4[11,11]=-np.cos(theta) r4[2,3]= np.sin(theta) r4[3,2]= np.sin(theta) r4[10,11]=np.sin(theta) r4[11,10]=np.sin(theta) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Methane molecule #================================= elif MoleculeFlag=='CH4': # print(MoleculeFlag) mol.atom=[['C', (0.0000 , 0.0000 , 0.0000 )], ['H', (0.6276 , 0.6276 , 0.6276 )], ['H', (0.6276 , -0.6276, -0.6276)], ['H', (-0.6276, 0.6276 , -0.6276)], ['H', (-0.6276, -0.6276, 0.6276 )]] mol.basis='sto-3g' mol.build() _q_=int_func.qmol_func(mol, atomic=True) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) # Spin symmetry: r1=np.zeros([18,18]) for i in range(18): if i<8: r1[i+9,i]=1. else: r1[i-9,i]=1. if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Carbon dioxide molecule #================================= elif MoleculeFlag=='CO2': r_matrices = [] # print(MoleculeFlag) mol.atom = [['C',(0., 0., 0.)], ['O',(-1.1621, 0., 0.)], ['O',(1.1621, 0., 0.)]] mol.basis='sto-3g' mol.build() _q_=int_func.qmol_func(mol, atomic=True) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) # Spin symmetry: r1=np.zeros([30,30]) for i in range(30): if i<15: r1[i+15,i]=1. else: r1[i-15,i]=1. r_matrices.append(r1) # Permutation matrix for inversion. \sigma{yz} All the oxygen orbitals are swapped. # Oxygen px orbital picks up a negative sign and the px of carbon picks up a # negative sign. r2=np.zeros([30,30]) r2[0,0]=1 r2[1,1]=1 r2[3,3]=1 r2[2,2]=-1 r2[4,4]=r2[19,19]=1 r2[5,10]=r2[10,5]=1 r2[11,6]=r2[6,11]=1 r2[7,12]=r2[12,7]=-1 r2[8,13]=r2[13,8]=1 r2[14,9]=r2[9,14]=1 r2[15,15]=1 r2[16,16]=1 r2[17,17]=-1 r2[18,18]=1 r2[20,25]=r2[25,20]=1 r2[21,26]=r2[26,21]=1 r2[22,27]=r2[27,22]=-1 r2[23,28]=r2[28,23]=1 r2[24,29]=r2[29,24]=1 r_matrices.append(r2) # Permutation matrix for inversion. \sigma{xy} # pz orbitals of oxygen and carbon pick up negative sign r3=np.eye(30) r3[4,4]=-1 r3[19,19]=-1 r3[9,9]=-1 r3[14,14]=-1 r3[24,24]=-1 r3[29,29]=-1 r_matrices.append(r3) # Permutation matrix for inversion. \sigma{xz} # py orbitals of oxygen and carbon pick up negative sign r4=np.eye(30) r4[3,3]=-1 r4[18,18]=-1 r4[8,8]=-1 r4[13,13]=-1 r4[23,23]=-1 r4[28,28]=-1 r_matrices.append(r4) # Permutation matrix for axial symmetry. C_2{x} # pz and py orbitals of oxygen and carbon pick up negative sign r5=np.eye(30) r5[3,3]=-1 r5[18,18]=-1 r5[8,8]=-1 r5[13,13]=-1 r5[23,23]=-1 r5[28,28]=-1 r5[4,4]=-1 r5[19,19]=-1 r5[9,9]=-1 r5[14,14]=-1 r5[24,24]=-1 r5[29,29]=-1 r_matrices.append(r5) # Permutation matrix for axial symmetry. C_2{y} All the oxygen orbitals are swapped. # Oxygen px and pz orbital picks up a negative sign and the px and pz of carbon picks up a # negative sign. r6=np.zeros([30,30]) r6[0,0]=r6[1,1]=1 r6[3,3]=r6[18,18]=1 r6[17,17]=r6[2,2]=-1 r6[4,4]=r6[19,19]=-1 r6[5,10]=r6[10,5]=1 r6[11,6]=r6[6,11]=1 r6[7,12]=r6[12,7]=-1 r6[8,13]=r6[13,8]=1 r6[14,9]=r6[9,14]=-1 r6[15,15]=r6[16,16]=1 r6[20,25]=r6[25,20]=1 r6[21,26]=r6[26,21]=1 r6[22,27]=r6[27,22]=-1 r6[23,28]=r6[28,23]=1 r6[24,29]=r6[29,24]=-1 r_matrices.append(r6) # Permutation matrix for axial symmetry. C_2{z} All the oxygen orbitals are swapped. # Oxygen px and py orbital picks up a negative sign and the px and py of carbon picks up a # negative sign. r7=np.zeros([30,30]) r7[0,0]=r7[1,1]=1 r7[3,3]=r7[18,18]=-1 r7[17,17]=r7[2,2]=-1 r7[4,4]=r7[19,19]=1 r7[5,10]=r7[10,5]=1 r7[11,6]=r7[6,11]=1 r7[7,12]=r7[12,7]=-1 r7[8,13]=r7[13,8]=-1 r7[14,9]=r7[9,14]=1 r7[15,15]=r7[16,16]=1 r7[20,25]=r7[25,20]=1 r7[21,26]=r7[26,21]=1 r7[22,27]=r7[27,22]=-1 r7[23,28]=r7[28,23]=-1 r7[24,29]=r7[29,24]=1 r_matrices.append(r7) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Ethyne molecule #================================= elif MoleculeFlag=='C2H2': r_matrices =[] print(MoleculeFlag) num_particles = 14 if is_atomic: try: data = np.load(MoleculeFlag+'.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['C',(-0.6000, 0.0000, 0.0000 )], ['C',(0.6000, 0.0000, 0.0000 )], ['H',(-1.6650,0.0000, 0.000 )], ['H',(1.6650,0.0000, 0.000 )]] mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals # np.savez(MoleculeFlag+'_ao.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: mol.atom = [['C',(-0.6000, 0.0000, 0.0000 )], ['C',(0.6000, 0.0000, 0.0000 )], ['H',(-1.6650,0.0000, 0.000 )], ['H',(1.6650,0.0000, 0.000 )]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 # Spin symmetry: r1=np.zeros([24,24]) for i in range(24): if i<12: r1[i+12,i]=1. else: r1[i-12,i]=1. # r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{xy}. Everything remains the same, only pz-orbitals pick up negative sign. r2=np.eye(24) r2[4,4]=-1 r2[9,9]=-1 r2[16,16]=-1 r2[21,21]=-1 # R-matrix for plane of symmetry \sigma_{xz}. Everything remains the same, only py-orbitals pick up negative sign. r3=np.eye(24) r3[3,3]=-1 r3[8,8]=-1 r3[15,15]=-1 r3[20,20]=-1 # R-matrix for plane of symmetry \sigma_{yz}. r4=np.zeros([24,24]) #Swapping px picks up a negative sign r4[2,7]=r4[7,2]=-1 r4[14,19]=r4[19,14]=-1 #Swapping 1s, 2s, 2py and 2pz of Carbon r4[0,5]=r4[5,0]=1 r4[1,6]=r4[6,1]=1 r4[12,17]=r4[17,12]=1 r4[13,18]=r4[18,13]=1 r4[3,8]=r4[8,3]=1 r4[15,20]=r4[20,15]=1 r4[21,16]=r4[16,21]=1 r4[9,4]=r4[4,9]=1 #Swapping 1s of hydrogen r4[10,11]=r4[11,10]=1 r4[22,23]=r4[23,22]=1 # R-matrix for axis of symmetry C_2 around y axis. r5=np.zeros([24,24]) #Swapping px picks up a negative sign r5[2,7]=r5[7,2]=-1 r5[14,19]=r5[19,14]=-1 r5[21,16]=r5[16,21]=-1 r5[9,4]=r5[4,9]=-1 #Swapping 1s, 2s, 2py and 2pz of Carbon r5[0,5]=r5[5,0]=1 r5[1,6]=r5[6,1]=1 r5[12,17]=r5[17,12]=1 r5[13,18]=r5[18,13]=1 r5[3,8]=r5[8,3]=1 r5[15,20]=r5[20,15]=1 #Swapping 1s of hydrogen r5[10,11]=r5[11,10]=1 r5[22,23]=r5[23,22]=1 # R-matrix for axis of symmetry C_2 around z axis. r6=np.zeros([24,24]) #Swapping px picks up a negative sign r6[2,7]=r6[7,2]=-1 r6[14,19]=r6[19,14]=-1 r6[15,20]=r6[20,15]=-1 r6[3,8]=r6[8,3]=-1 #Swapping 1s, 2s, 2py and 2pz of Carbon r6[0,5]=r6[5,0]=1 r6[1,6]=r6[6,1]=1 r6[12,17]=r6[17,12]=1 r6[13,18]=r6[18,13]=1 r6[9,4]=r6[4,9]=1 r6[21,16]=r6[16,21]=1 #Swapping 1s of hydrogen r6[10,11]=r6[11,10]=1 r6[22,23]=r6[23,22]=1 # R-matrix for x-axis symmetry. pz and py orbitals of both the carbon atoms pick up a negative sign. r7=np.eye(24) r7[3,3]=-1 r7[4,4]=-1 r7[8,8]=-1 r7[9,9]=-1 r7[16,16]=-1 r7[15,15]=-1 r7[20,20]=-1 r7[21,21]=-1 r_matrices.append(r7) r_matrices.append(r6) r_matrices.append(r5) r_matrices.append(r2) r_matrices.append(r3) r_matrices.append(r4) r_matrices.append(r1) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Ethylene molecule #================================= elif MoleculeFlag=='C2H4': r_matrices =[] print(MoleculeFlag) try: data = np.load(MoleculeFlag+'.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['C',( 0.6695, 0.0000 , 0.0000)], ['C',(-0.6695, 0.0000 , 0.0000)], ['H',( 1.2321, 0.9289 , 0.0000)], ['H',( 1.2321, -0.9289, 0.0000)], ['H',(-1.2321, 0.9289 , 0.0000)], ['H',(-1.2321, -0.9289, 0.0000)]] mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals np.savez(MoleculeFlag+'.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) fer_op = FermionicOperator(h1=one_b, h2=two_b) r_matrices = [] # Spin symmetry: r1=np.zeros([28,28]) for i in range(28): if i<14: r1[i+14,i]=1. else: r1[i-14,i]=1. # r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{xy}. Everything remains the same, only pz-orbitals pick up negative sign. r2=np.eye(28) r2[4,4]=-1 r2[9,9]=-1 r2[18,18]=-1 r2[23,23]=-1 # R-matrix for plane of symmetry \sigma_{xz}. r3=np.eye(28) r3[3,3]=-1 r3[8,8]=-1 r3[17,17]=-1 r3[22,22]=-1 r3[10,10]=r3[11,11]=r3[12,12]=r3[13,13]=0 r3[24,24]=r3[25,25]=r3[26,26]=r3[27,27]=0 r3[10,11]=r3[11,10]=r3[12,13]=r3[13,12]=1 r3[24,25]=r3[25,24]=r3[26,27]=r3[27,26]=1 # R-matrix for plane of symmetry \sigma_{yz}. r4=np.zeros([28,28]) # #Swapping px picks up a negative sign r4[2,7]=r4[7,2]=-1 r4[16,21]=r4[21,16]=-1 # #Swapping 1s, 2s, 2py and 2pz of Carbon r4[0,5]=r4[5,0]=1 r4[1,6]=r4[6,1]=1 r4[3,8]=r4[8,3]=1 r4[4,9]=r4[9,4]=1 r4[14,19]=r4[19,14]=1 r4[15,20]=r4[20,15]=1 r4[17,22]=r4[22,17]=1 r4[18,23]=r4[23,18]=1 # #Swapping 1s of hydrogen r4[10,12]=r4[12,10]=1 r4[24,26]=r4[26,24]=1 r4[11,13]=r4[13,11]=1 r4[25,27]=r4[27,25]=1 # R-matrix for axis of symmetry C_2 around y axis. r5=np.zeros([28,28]) #Swapping px picks up a negative sign r5[2,7]=r5[7,2]=-1 r5[4,9]=r5[9,4]=-1 r5[16,21]=r5[21,16]=-1 r5[18,23]=r5[23,18]=-1 #Swapping 1s, 2s, 2py and 2pz of Carbon r5[0,5]=r5[5,0]=1 r5[1,6]=r5[6,1]=1 r5[3,8]=r5[8,3]=1 r5[14,19]=r5[19,14]=1 r5[15,20]=r5[20,15]=1 r5[17,22]=r5[22,17]=1 #Swapping 1s of hydrogen r5[10,12]=r5[12,10]=1 r5[24,26]=r5[26,24]=1 r5[11,13]=r5[13,11]=1 r5[25,27]=r5[27,25]=1 # R-matrix for axis of symmetry C_2 around z axis. r6=np.zeros([28,28]) #Swapping px picks up a negative sign r6[2,7]=r6[7,2]=-1 r6[3,8]=r6[8,3]=-1 r6[16,21]=r6[21,16]=-1 r6[17,22]=r6[22,17]=-1 #Swapping 1s, 2s, 2py and 2pz of Carbon r6[0,5]=r6[5,0]=1 r6[1,6]=r6[6,1]=1 r6[4,9]=r6[9,4]=1 r6[14,19]=r6[19,14]=1 r6[15,20]=r6[20,15]=1 r6[18,23]=r6[23,18]=1 #Swapping 1s of hydrogen r6[10,13]=r6[13,10]=1 r6[24,27]=r6[27,24]=1 r6[11,12]=r6[12,11]=1 r6[25,26]=r6[26,25]=1 # # R-matrix for x-axis symmetry. pz and py orbitals of both the carbon atoms pick up a negative sign. r7=np.eye(28) r7[3,3]=-1 r7[4,4]=-1 r7[8,8]=-1 r7[9,9]=-1 r7[17,17]=-1 r7[18,18]=-1 r7[22,22]=-1 r7[23,23]=-1 r7[10,10]=r7[11,11]=r7[12,12]=r7[13,13]=0 r7[24,24]=r7[25,25]=r7[26,26]=r7[27,27]=0 r7[10,11]=r7[11,10]=r7[12,13]=r7[13,12]=1 r7[24,25]=r7[25,24]=r7[26,27]=r7[27,26]=1 r_matrices.append(r1) r_matrices.append(r2) r_matrices.append(r3) r_matrices.append(r4) r_matrices.append(r5) r_matrices.append(r6) r_matrices.append(r7) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Boron trifluoride molecule #================================= elif MoleculeFlag == 'BF3': r_matrices = [] try: data = np.load(MoleculeFlag+'.npz') one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['B',(0.0000 ,0.0000 ,0.000000 )], ['F',(0.0000 ,1.3070 ,0.00000 )], ['F',(1.1319 ,-0.6535, 0.000 )], ['F',(-1.1319 ,-0.6535, 0.00)]] mol.basis = 'sto-3g' mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals np.savez(MoleculeFlag+'.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) fer_op = FermionicOperator(h1=one_b, h2=two_b) # Spin symmetry: r1=np.zeros([40,40]) for i in range(40): if i<20: r1[i+20,i]=1. else: r1[i-20,i]=1. r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{xy}. r2=np.eye(40) r2[4,4]=-1 r2[9,9]=-1 r2[14,14]=-1 r2[19,19]=-1 r2[24,24]=-1 r2[29,29]=-1 r2[34,34]=-1 r2[39,39]=-1 r_matrices.append(r2) # R-matrix for plane of symmetry \sigma_{yz}. r3=np.eye(40) r3[2,2]=-1 r3[7,7]=-1 r3[22,22]=-1 r3[27,27]=-1 for i in range(5): r3[10+i,10+i]=0 r3[15+i,15+i]=0 r3[30+i,30+i]=0 r3[35+i,35+i]=0 r3[10+i,15+i]=1 r3[15+i,10+i]=1 r3[30+i,35+i]=1 r3[35+i,30+i]=1 r3[12,17]=-1 r3[17,12]=-1 r3[32,37]=-1 r3[37,32]=-1 r_matrices.append(r3) # R-matrix for axis of symmetry C_2 around y axis. r4=np.eye(40) r4[2,2]=-1 r4[4,4]=-1 r4[7,7]=-1 r4[9,9]=-1 r4[22,22]=-1 r4[24,24]=-1 r4[29,29]=-1 r4[27,27]=-1 for i in range(5): r4[10+i,10+i]=0 r4[15+i,15+i]=0 r4[30+i,30+i]=0 r4[35+i,35+i]=0 r4[10+i,15+i]=1 r4[15+i,10+i]=1 r4[30+i,35+i]=1 r4[35+i,30+i]=1 r4[12,17]=-1 r4[17,12]=-1 r4[14,19]=-1 r4[19,14]=-1 r4[32,37]=-1 r4[37,32]=-1 r4[34,39]=-1 r4[39,34]=-1 r_matrices.append(r4) # R-matrix for plane of symmetry \sigma_{yz}. # r4=np.zeros([24,24]) # #Swapping px picks up a negative sign # r4[2,7]=r4[7,2]=-1 # r4[14,19]=r4[19,14]=-1 # #Swapping 1s, 2s, 2py and 2pz of Carbon # r4[0,5]=r4[5,0]=1 # r4[1,6]=r4[6,1]=1 # r4[12,17]=r4[17,12]=1 # r4[13,18]=r4[18,13]=1 # r4[3,8]=r4[8,3]=1 # r4[15,20]=r4[20,15]=1 # r4[21,16]=r4[16,21]=1 # r4[9,4]=r4[4,9]=1 # #Swapping 1s of hydrogen # r4[10,11]=r4[11,10]=1 # r4[22,23]=r4[23,22]=1 # # R-matrix for axis of symmetry C_2 around z axis. # r6=np.zeros([24,24]) # #Swapping px picks up a negative sign # r6[2,7]=r6[7,2]=-1 # r6[14,19]=r6[19,14]=-1 # r6[15,20]=r6[20,15]=-1 # r6[3,8]=r6[8,3]=-1 # #Swapping 1s, 2s, 2py and 2pz of Carbon # r6[0,5]=r6[5,0]=1 # r6[1,6]=r6[6,1]=1 # r6[12,17]=r6[17,12]=1 # r6[13,18]=r6[18,13]=1 # r6[9,4]=r6[4,9]=1 # r6[21,16]=r6[16,21]=1 # #Swapping 1s of hydrogen # r6[10,11]=r6[11,10]=1 # r6[22,23]=r6[23,22]=1 # # R-matrix for x-axis symmetry. pz and py orbitals of both the carbon atoms pick up a negative sign. # r7=np.eye(24) # r7[3,3]=-1 # r7[4,4]=-1 # r7[8,8]=-1 # r7[9,9]=-1 # r7[16,16]=-1 # r7[15,15]=-1 # r7[20,20]=-1 # r7[21,21]=-1 # print(r4) # print(np.real(fer_op.h1[0:int(np.size(fer_op.h1,0)/2),0:int(np.size(fer_op.h1,0)/2)])) # fer_op.transform(r4) # # print(np.real(fer_op.h1[0:int(np.size(fer_op.h1,0)/2),0:int(np.size(fer_op.h1,0)/2)])) # # print(np.real(fer_op.h1[0:int(np.size(fer_op.h1,0)/2),0:int(np.size(fer_op.h1,0)/2)]-_q_.one_body_integrals[0:int(np.size(fer_op.h1,0)/2),0:int(np.size(fer_op.h1,0)/2)])) # # print(np.real(fer_op.h1[int(np.size(fer_op.h1,0)/2):int(np.size(fer_op.h1,0)),int(np.size(fer_op.h1,0)/2):int(np.size(fer_op.h1,0))]-_q_.one_body_integrals[int(np.size(fer_op.h1,0)/2):int(np.size(fer_op.h1,0)),int(np.size(fer_op.h1,0)/2):int(np.size(fer_op.h1,0))])) # print(MoleculeFlag) # # print(np.real(fer_op.h1[0:int(np.size(fer_op.h1,0)/2),0:int(np.size(fer_op.h1,0)/2)])) # # print(np.real(fer_op.h1[int(np.size(fer_op.h1,0)/2):int(np.size(fer_op.h1,0)),int(np.size(fer_op.h1,0)/2):int(np.size(fer_op.h1,0))])) # # print(np.real(fer_op.h1[0:int(np.size(fer_op.h1,0)/2),0:int(np.size(fer_op.h1,0)/2)])) # print(np.all(np.abs(fer_op.h1-_q_.one_body_integrals)<1.e-14)) # print(np.all(np.abs(fer_op.h2-_q_.two_body_integrals)<1.e-14)) # print(np.linalg.norm(fer_op.h2-_q_.two_body_integrals)) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Lithium hydride #================================= elif MoleculeFlag == "LiH": r_matrices =[] print(MoleculeFlag) if is_atomic: try: data = np.load(MoleculeFlag+'.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['Li',(0.000, 0.0000, 0.0000 )], ['H',(1.5949,0.0000, 0.000 )]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals np.savez(MoleculeFlag+'_ao.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) print(_q_.one_body_integrals) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: mol.atom = [['Li',(0.000, 0.0000, 0.0000 )], ['H',(1.5949,0.0000, 0.000 )]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 # Spin symmetry: r1=np.zeros([12,12]) for i in range(12): if i<6: r1[i+6,i]=1. else: r1[i-6,i]=1. r_matrices.append(r1) # sigma{xy} r2 = np.eye(12) r2[4,4]=-1 r2[10,10]=-1 r_matrices.append(r2) #sigma(yz) r3 = np.eye(12) r3[3,3]=-1 r3[9,9]=-1 r_matrices.append(r3) if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') #================================= # Beryllium hydride #================================= elif MoleculeFlag == "BeH2": num_particles = 6 r_matrices =[] print(MoleculeFlag) if is_atomic: try: data = np.load(MoleculeFlag+'.npz') data.files one_b = data['one_b'] two_b = data['two_b'] except IOError: mol.atom = [['Be',(0.000, 0.0000, 0.0000 )], ['H',(1.291,0.0000, 0.000 )], ['H',(-1.291,0.0000, 0.000 )]] mol.build() _q_=int_func.qmol_func(mol, atomic=True) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals # np.savez(MoleculeFlag+'_ao.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: mol.atom = [['Be',(0.000, 0.0000, 0.0000 )], ['H',(1.291,0.0000, 0.000 )], ['H',(-1.291,0.0000, 0.000 )]] mol.build() _q_=int_func.qmol_func(mol, atomic=is_atomic) one_b=_q_.one_body_integrals two_b=_q_.two_body_integrals fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 # fer_op = FermionicOperator(h1=one_b, h2=two_b) # R-matrix for plane of symmetry \sigma_{xy}. Everything remains the same, only pz-orbitals pick up negative sign. r1=np.zeros([14,14]) r1[0,0]=1 r1[1,1]=1 r1[2,2]=1 r1[3,3]=1 r1[4,4]=-1 r1[5,5]=1 r1[6,6]=1 r1[7,7]=1 r1[8,8]=1 r1[9,9]=1 r1[10,10]=1 r1[11,11]=-1 r1[12,12]=1 r1[13,13]=1 r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{xz}. Everything remains the same, only py-orbitals pick up negative sign. r2=np.eye(14) r2[3,3]=-1 r2[10,10]=-1 r_matrices.append(r2) # R-matrix for plane of symmetry \sigma_{yz}. Everything remains the same, only px-orbitals pick up negative sign and hydrogen atoms swap. r3=np.zeros([14,14]) r3[0,0]=1 r3[1,1]=1 r3[2,2]=-1 r3[3,3]=1 r3[4,4]=1 r3[5,6]=1 r3[6,5]=1 r3[7,7]=1 r3[8,8]=1 r3[9,9]=-1 r3[10,10]=1 r3[11,11]=1 r3[12,13]=1 r3[13,12]=1 r_matrices.append(r3) # R-matrix for symmetry-axis C_2. Linear water molecule has three axis of symmetry: # About z-axis r4=np.zeros([14,14]) r4[0,0]=1 r4[1,1]=1 r4[2,2]=-1 r4[3,3]=-1 r4[4,4]=1 r4[5,6]=1 r4[6,5]=1 r4[7,7]=1 r4[8,8]=1 r4[9,9]=-1 r4[10,10]=-1 r4[11,11]=1 r4[12,13]=1 r4[13,12]=1 # r_matrices.append(r4) #About y-axis r5=np.zeros([14,14]) r5[0,0]=1 r5[1,1]=1 r5[2,2]=-1 r5[3,3]=1 r5[4,4]=-1 r5[5,6]=1 r5[6,5]=1 r5[7,7]=1 r5[8,8]=1 r5[9,9]=-1 r5[10,10]=1 r5[11,11]=-1 r5[12,13]=1 r5[13,12]=1 # r_matrices.append(r5) #Symmetry about x-axis: r6=np.zeros([14,14]) r6[0,0]=1 r6[1,1]=1 r6[2,2]=1 r6[3,3]=-1 r6[4,4]=-1 r6[5,5]=1 r6[6,6]=1 r6[7,7]=1 r6[8,8]=1 r6[9,9]=1 r6[10,10]=-1 r6[11,11]=-1 r6[12,12]=1 r6[13,13]=1 # r_matrices.append(r6) #Spin symmetry: r7=np.zeros([14,14]) for i in range(14): if i<7: r7[i+7,i]=1. else: r7[i-7,i]=1. r_matrices.append(r7) if check_r_matrix_flag and is_atomic: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') elif MoleculeFlag == "test": r_matrices =[] num_particles = 6 print(MoleculeFlag) # try: # data = np.load(MoleculeFlag+'.npz') # data.files # one_b = data['one_b'] # two_b = data['two_b'] # except IOError: mol.atom = [['Be',(0.000, 0.0000, 0.0000 )], ['H',(1.3264,0.0000, 0.000 )], ['H',(-1.3264,0.0000, 0.000 )]] mol.atom = [['Be',(0.000, 0.0000, 0.0000 )], ['H',(1.291,0.0000, 0.000 )], ['H',(-1.291,0.0000, 0.000 )]] mol.atom = [['Be',(0.000, 0.0000, 0.0000 )], ['H',(1.3,0.0000, 0.000 )], ['H',(-1.3,0.0000, 0.000 )]] mol.basis = 'sto-6g' # mol.symmetry=True # mol.atom = [['H',(0, 0, -0.3707)], ['H',(0,0.0,0.3707)]] mol.build() # is_atomic = _q_ = qmol_func(mol, atomic=is_atomic) if is_atomic: two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) two_body_temp = QMolecule.twoe_to_spin(temp_int) mol = gto.M(atom=mol.atom, basis='sto-3g') O = get_ovlp(mol) X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=two_body_temp) fer_op.transform(X) else: fer_op = FermionicOperator(h1=_q_.one_body_integrals, h2=_q_.two_body_integrals) one_b = fer_op.h1 two_b = fer_op.h2 # np.savez(MoleculeFlag+'.npz',one_b=_q_.one_body_integrals,two_b=_q_.two_body_integrals) # fer_op = FermionicOperator(h1=one_b, h2=two_b) # print(fer_op.h1) # exit() # r_matrices.append(np.eye(14)) # R-matrix for plane of symmetry \sigma_{xy}. Everything remains the same, only pz-orbitals pick up negative sign. r1=np.zeros([14,14]) r1[0,0]=1 r1[1,1]=1 r1[2,2]=1 r1[3,3]=1 r1[4,4]=-1 r1[5,5]=1 r1[6,6]=1 r1[7,7]=1 r1[8,8]=1 r1[9,9]=1 r1[10,10]=1 r1[11,11]=-1 r1[12,12]=1 r1[13,13]=1 r_matrices.append(r1) # R-matrix for plane of symmetry \sigma_{xz}. Everything remains the same, only py-orbitals pick up negative sign. r2=np.eye(14) r2[3,3]=-1 r2[10,10]=-1 r_matrices.append(r2) # R-matrix for plane of symmetry \sigma_{yz}. Everything remains the same, only px-orbitals pick up negative sign and hydrogen atoms swap. r3=np.zeros([14,14]) r3[0,0]=1 r3[1,1]=1 r3[2,2]=-1 r3[3,3]=1 r3[4,4]=1 r3[5,6]=1 r3[6,5]=1 r3[7,7]=1 r3[8,8]=1 r3[9,9]=-1 r3[10,10]=1 r3[11,11]=1 r3[12,13]=1 r3[13,12]=1 r_matrices.append(r3) # R-matrix for symmetry-axis C_2. Linear water molecule has three axis of symmetry: # About z-axis r4=np.zeros([14,14]) r4[0,0]=1 r4[1,1]=1 r4[2,2]=-1 r4[3,3]=-1 r4[4,4]=1 r4[5,6]=1 r4[6,5]=1 r4[7,7]=1 r4[8,8]=1 r4[9,9]=-1 r4[10,10]=-1 r4[11,11]=1 r4[12,13]=1 r4[13,12]=1 # r_matrices.append(r4) #About y-axis r5=np.zeros([14,14]) r5[0,0]=1 r5[1,1]=1 r5[2,2]=-1 r5[3,3]=1 r5[4,4]=-1 r5[5,6]=1 r5[6,5]=1 r5[7,7]=1 r5[8,8]=1 r5[9,9]=-1 r5[10,10]=1 r5[11,11]=-1 r5[12,13]=1 r5[13,12]=1 # r_matrices.append(r5) #Symmetry about x-axis: r6=np.zeros([14,14]) r6[0,0]=1 r6[1,1]=1 r6[2,2]=1 r6[3,3]=-1 r6[4,4]=-1 r6[5,5]=1 r6[6,6]=1 r6[7,7]=1 r6[8,8]=1 r6[9,9]=1 r6[10,10]=-1 r6[11,11]=-1 r6[12,12]=1 r6[13,13]=1 # r_matrices.append(r6) #Spin symmetry: r7=np.zeros([14,14]) for i in range(14): if i<7: r7[i+7,i]=1. else: r7[i-7,i]=1. # r_matrices.append(r7) r8=np.zeros([14,14]) r8[0,0]=1 r8[1,1]=1 r8[2,2]=-1 r8[3,3]=-1 r8[4,4]=-1 r8[5,6]=1 r8[6,5]=1 r8[7,7]=1 r8[8,8]=1 r8[9,9]=-1 r8[10,10]=-1 r8[11,11]=-1 r8[12,13]=1 r8[13,12]=1 # r_matrices.append(r8) # r_matrices=[] # r_matrices.append(np.eye(fer_op.modes)) if check_r_matrix_flag: if bool(check_r_mat(r_matrices,fer_op,one_b,two_b)): print('All the above matrices work!') if is_atomic: return [r_matrices,fer_op,num_particles] else: r_matrices =[] r_matrices.append(np.eye(fer_op.modes)) return [r_matrices,fer_op, num_particles]
def _do_transform( self, qmolecule: QMolecule, aux_operators: Optional[List[FermionicOperator]] = None ) -> Tuple[WeightedPauliOperator, List[WeightedPauliOperator]]: """ Args: qmolecule: qmolecule aux_operators: Additional ``FermionicOperator``s to map to a qubit operator. Returns: (qubit operator, auxiliary operators) """ logger.debug('Processing started...') # Save these values for later combination with the quantum computation result self._hf_energy = qmolecule.hf_energy self._nuclear_repulsion_energy = qmolecule.nuclear_repulsion_energy self._nuclear_dipole_moment = qmolecule.nuclear_dipole_moment self._reverse_dipole_sign = qmolecule.reverse_dipole_sign core_list = qmolecule.core_orbitals if self._freeze_core else [] reduce_list = self._orbital_reduction if self._freeze_core: logger.info( "Freeze_core specified. Core orbitals to be frozen: %s", core_list) if reduce_list: logger.info("Configured orbital reduction list: %s", reduce_list) reduce_list = [ x + qmolecule.num_orbitals if x < 0 else x for x in reduce_list ] freeze_list = [] remove_list = [] # Orbitals are specified by their index from 0 to n-1, where n is the number of orbitals the # molecule has. The combined list of the core orbitals, when freeze_core is true, with any # user supplied orbitals is what will be used. Negative numbers may be used to indicate the # upper virtual orbitals, so -1 is the highest, then -2 etc. and these will # be converted to the # positive 0-based index for computation. # In the combined list any orbitals that are occupied are added to a freeze list and an # energy is stored from these orbitals to be added later. # Unoccupied orbitals are just discarded. # Because freeze and eliminate is done in separate steps, # with freeze first, we have to re-base # the indexes for elimination according to how many orbitals were removed when freezing. # orbitals_list = list(set(core_list + reduce_list)) num_alpha = qmolecule.num_alpha num_beta = qmolecule.num_beta new_num_alpha = num_alpha new_num_beta = num_beta if orbitals_list: orbitals_list = np.array(orbitals_list) orbitals_list = orbitals_list[ (cast(np.ndarray, orbitals_list) >= 0) & (orbitals_list < qmolecule.num_orbitals)] freeze_list_alpha = [i for i in orbitals_list if i < num_alpha] freeze_list_beta = [i for i in orbitals_list if i < num_beta] freeze_list = np.append( freeze_list_alpha, [i + qmolecule.num_orbitals for i in freeze_list_beta]) remove_list_alpha = [i for i in orbitals_list if i >= num_alpha] remove_list_beta = [i for i in orbitals_list if i >= num_beta] rla_adjust = -len(freeze_list_alpha) rlb_adjust = -len(freeze_list_alpha) - len( freeze_list_beta) + qmolecule.num_orbitals remove_list = np.append( [i + rla_adjust for i in remove_list_alpha], [i + rlb_adjust for i in remove_list_beta]) logger.info("Combined orbital reduction list: %s", orbitals_list) logger.info( " converting to spin orbital reduction list: %s", np.append(np.array(orbitals_list), np.array(orbitals_list) + qmolecule.num_orbitals)) logger.info(" => freezing spin orbitals: %s", freeze_list) logger.info( " => removing spin orbitals: %s (indexes accounting for freeze %s)", np.append(remove_list_alpha, np.array(remove_list_beta) + qmolecule.num_orbitals), remove_list) new_num_alpha -= len(freeze_list_alpha) new_num_beta -= len(freeze_list_beta) new_nel = [new_num_alpha, new_num_beta] # construct the fermionic operator fer_op = FermionicOperator(h1=qmolecule.one_body_integrals, h2=qmolecule.two_body_integrals) # try to reduce it according to the freeze and remove list fer_op, self._energy_shift, did_shift = \ FermionicTransformation._try_reduce_fermionic_operator(fer_op, freeze_list, remove_list) # apply same transformation for the aux operators if aux_operators is not None: aux_operators = [ FermionicTransformation._try_reduce_fermionic_operator( op, freeze_list, remove_list)[0] for op in aux_operators ] if did_shift: logger.info("Frozen orbital energy shift: %s", self._energy_shift) # apply particle hole transformation, if specified if self._transformation == FermionicTransformationType.PARTICLE_HOLE.value: fer_op, ph_shift = fer_op.particle_hole_transformation(new_nel) self._ph_energy_shift = -ph_shift logger.info("Particle hole energy shift: %s", self._ph_energy_shift) # apply the same transformation for the aux operators if aux_operators is not None: aux_operators = [ op.particle_hole_transformation(new_nel)[0] for op in aux_operators ] logger.debug('Converting to qubit using %s mapping', self._qubit_mapping) qubit_op = FermionicTransformation._map_fermionic_operator_to_qubit( fer_op, self._qubit_mapping, new_nel, self._two_qubit_reduction) qubit_op.name = 'Fermionic Operator' logger.debug(' num paulis: %s, num qubits: %s', len(qubit_op.paulis), qubit_op.num_qubits) aux_ops = [] # list of the aux operators def _add_aux_op(aux_op: FermionicOperator, name: str) -> None: """ Add auxiliary operators Args: aux_op: auxiliary operators name: name """ aux_qop = FermionicTransformation._map_fermionic_operator_to_qubit( aux_op, self._qubit_mapping, new_nel, self._two_qubit_reduction) aux_qop.name = name aux_ops.append(aux_qop) logger.debug(' num paulis: %s', aux_qop.paulis) # the first three operators are hardcoded to number of particles, angular momentum # and magnetization in this order logger.debug('Creating aux op for Number of Particles') _add_aux_op(fer_op.total_particle_number(), 'Number of Particles') logger.debug('Creating aux op for S^2') _add_aux_op(fer_op.total_angular_momentum(), 'S^2') logger.debug('Creating aux op for Magnetization') _add_aux_op(fer_op.total_magnetization(), 'Magnetization') # the next three are dipole moments, if supported by the qmolecule if qmolecule.has_dipole_integrals(): self._has_dipole_moments = True def _dipole_op(dipole_integrals: np.ndarray, axis: str) \ -> Tuple[WeightedPauliOperator, float, float]: """ Dipole operators Args: dipole_integrals: dipole integrals axis: axis for dipole moment calculation Returns: (qubit_op_, shift, ph_shift_) """ logger.debug('Creating aux op for dipole %s', axis) fer_op_ = FermionicOperator(h1=dipole_integrals) fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator( fer_op_, freeze_list, remove_list) if did_shift_: logger.info("Frozen orbital %s dipole shift: %s", axis, shift) ph_shift_ = 0.0 if self._transformation == FermionicTransformationType.PARTICLE_HOLE.value: fer_op_, ph_shift_ = fer_op_.particle_hole_transformation( new_nel) ph_shift_ = -ph_shift_ logger.info("Particle hole %s dipole shift: %s", axis, ph_shift_) qubit_op_ = self._map_fermionic_operator_to_qubit( fer_op_, self._qubit_mapping, new_nel, self._two_qubit_reduction) qubit_op_.name = 'Dipole ' + axis logger.debug(' num paulis: %s', len(qubit_op_.paulis)) return qubit_op_, shift, ph_shift_ op_dipole_x, self._x_dipole_shift, self._ph_x_dipole_shift = \ _dipole_op(qmolecule.x_dipole_integrals, 'x') op_dipole_y, self._y_dipole_shift, self._ph_y_dipole_shift = \ _dipole_op(qmolecule.y_dipole_integrals, 'y') op_dipole_z, self._z_dipole_shift, self._ph_z_dipole_shift = \ _dipole_op(qmolecule.z_dipole_integrals, 'z') aux_ops += [op_dipole_x, op_dipole_y, op_dipole_z] # add user specified auxiliary operators if aux_operators is not None: for aux_op in aux_operators: if hasattr(aux_op, 'name'): name = aux_op.name else: name = '' _add_aux_op(aux_op, name) logger.info('Molecule num electrons: %s, remaining for processing: %s', [num_alpha, num_beta], new_nel) nspinorbs = qmolecule.num_orbitals * 2 new_nspinorbs = nspinorbs - len(freeze_list) - len(remove_list) logger.info( 'Molecule num spin orbitals: %s, remaining for processing: %s', nspinorbs, new_nspinorbs) self._molecule_info['num_particles'] = (new_num_alpha, new_num_beta) self._molecule_info['num_orbitals'] = new_nspinorbs reduction = self._two_qubit_reduction if self._qubit_mapping == 'parity' else False self._molecule_info['two_qubit_reduction'] = reduction self._untapered_qubit_op = qubit_op z2symmetries = Z2Symmetries([], [], [], None) if self._z2symmetry_reduction is not None: logger.debug('Processing z2 symmetries') qubit_op, aux_ops, z2symmetries = self._process_z2symmetry_reduction( qubit_op, aux_ops) self._molecule_info['z2_symmetries'] = z2symmetries logger.debug('Processing complete ready to run algorithm') return qubit_op, aux_ops
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 _calculate_integrals(mol, calc_type='rhf', atomic=False): """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in the given basis. Args: mol : A PySCF gto.Mole object. calc_type: rhf, uhf, rohf Returns: ehf : Hartree-Fock energy enuke : Nuclear repulsion energy norbs : Number of orbitals mohij : One electron terms of the Hamiltonian. mohijkl : Two electron terms of the Hamiltonian. mo_coeff: Orbital coefficients orbs_energy: Orbitals energies x_dip_ints: x dipole moment integrals y_dip_ints: y dipole moment integrals z_dip_ints: z dipole moment integrals nucl_dipl : Nuclear dipole moment """ enuke = gto.mole.energy_nuc(mol) if calc_type == 'rhf': mf = scf.RHF(mol) elif calc_type == 'rohf': mf = scf.ROHF(mol) elif calc_type == 'uhf': mf = scf.UHF(mol) else: raise QiskitChemistryError('Invalid calc_type: {}'.format(calc_type)) ehf = mf.kernel() if type(mf.mo_coeff) is tuple: mo_coeff = mf.mo_coeff[0] mo_occ = mf.mo_occ[0] else: mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ norbs = mo_coeff.shape[0] orbs_energy = mf.mo_energy # print(np.dot(mo_coeff,mo_coeff.T)) O = get_ovlp(mol) # print(np.dot(O,O.T)) mo_tr = np.dot(np.dot(O, mo_coeff), O.T) # print(np.dot(mo_tr,mo_tr.T)) # two_body_temp = QMolecule.twoe_to_spin(_q_.mo_eri_ints) # temp_int = np.einsum('ijkl->ljik', _q_.mo_eri_ints) # two_body_temp = QMolecule.twoe_to_spin(temp_int) # mol = gto.M(atom=mol.atom, basis='sto-3g') # X = np.kron(np.identity(2), np.linalg.inv(scipy.linalg.sqrtm(O))) ### for atomic basis if atomic: mo_coeff = np.identity(len(mo_coeff)) ### # print(mo_coeff) hij = mf.get_hcore() mohij = np.dot(np.dot(mo_coeff.T, hij), mo_coeff) # mohij = hij eri = ao2mo.incore.full(mf._eri, mo_coeff, compact=False) # eri_1 = mf._eri # print(np.shape(eri)) # print(np.shape(eri_1)) mohijkl = eri.reshape(norbs, norbs, norbs, norbs) # exit() # dipole integrals mol.set_common_orig((0, 0, 0)) ao_dip = mol.intor_symmetric('int1e_r', comp=3) x_dip_ints = QMolecule.oneeints2mo(ao_dip[0], mo_coeff) y_dip_ints = QMolecule.oneeints2mo(ao_dip[1], mo_coeff) z_dip_ints = QMolecule.oneeints2mo(ao_dip[2], mo_coeff) dm = mf.make_rdm1(mf.mo_coeff, mf.mo_occ) if calc_type == 'rohf' or calc_type == '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)) return ehf, enuke, norbs, mohij, mohijkl, mo_coeff, orbs_energy, x_dip_ints, y_dip_ints, z_dip_ints, nucl_dip
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 _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_