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: get_driver_class('GAUSSIAN') 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_
def _augment_config(self, fname, cfg): cfgaug = "" with io.StringIO() as outf: with io.StringIO(cfg) as inf: # Add our Route line at the end of any existing ones line = "" added = False while not added: line = inf.readline() if not line: break if line.startswith('#'): outf.write(line) while not added: line = inf.readline() if not line: raise QiskitChemistryError('Unexpected end of Gaussian input') if not line.strip(): outf.write('# Window=Full Int=NoRaff Symm=(NoInt,None) ' 'output=(matrix,i4labels,mo2el) tran=full\n') added = True outf.write(line) else: outf.write(line) # Now add our filename after the title and molecule but # before any additional data. We located # the end of the # section by looking for a blank line after # the first #. Allows comment lines # to be inter-mixed with Route lines if that's ever done. # From here we need to see two sections # more, the title and molecule so we can add the filename. added = False section_count = 0 blank = True while not added: line = inf.readline() if not line: raise QiskitChemistryError('Unexpected end of Gaussian input') if not line.strip(): blank = True if section_count == 2: break else: if blank: section_count += 1 blank = False outf.write(line) outf.write(line) outf.write(fname) outf.write('\n\n') # Whatever is left in the original config we just append without further inspection while True: line = inf.readline() if not line: break outf.write(line) cfgaug = outf.getvalue() return cfgaug
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_
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 _process_z2symmetry_reduction(self, qubit_op, aux_ops): z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) if z2_symmetries.is_empty(): logger.debug('No Z2 symmetries found') z2_qubit_op = qubit_op z2_aux_ops = [] z2_symmetries = None else: logger.debug( '%s Z2 symmetries found: %s', len(z2_symmetries.symmetries), ','.join( [symm.to_label() for symm in z2_symmetries.symmetries])) # Check auxiliary operators commute with man operator's symmetry logger.debug('Checking operators commute with symmetry:') symmetry_ops = [] for symmetry in z2_symmetries.symmetries: symmetry_ops.append( WeightedPauliOperator(paulis=[[1.0, symmetry]])) commutes = Hamiltonian._check_commutes(symmetry_ops, qubit_op) if not commutes: raise QiskitChemistryError( 'Z2 symmetry failure main operator must commute ' 'with symmetries found from it') for i, aux_op in enumerate(aux_ops): commutes = Hamiltonian._check_commutes(symmetry_ops, aux_op) if not commutes: aux_ops[ i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': hf_state = HartreeFock( num_orbitals=self._molecule_info[self.INFO_NUM_ORBITALS], qubit_mapping=self._qubit_mapping, two_qubit_reduction=self._two_qubit_reduction, num_particles=self._molecule_info[self.INFO_NUM_PARTICLES]) z2_symmetries = Hamiltonian._pick_sector( z2_symmetries, hf_state.bitstr) else: if len(self._z2symmetry_reduction) != len( z2_symmetries.symmetries): raise QiskitChemistryError( 'z2symmetry_reduction tapering values list has ' 'invalid length {} should be {}'.format( len(self._z2symmetry_reduction), len(z2_symmetries.symmetries))) valid = np.all(np.isin(self._z2symmetry_reduction, [-1, 1])) if not valid: raise QiskitChemistryError( 'z2symmetry_reduction tapering values list must ' 'contain -1\'s and/or 1\'s only was {}'.format( self._z2symmetry_reduction, )) z2_symmetries.tapering_values = self._z2symmetry_reduction logger.debug('Apply symmetry with tapering values %s', z2_symmetries.tapering_values) z2_qubit_op = z2_symmetries.taper(qubit_op) z2_aux_ops = [] for aux_op in aux_ops: z2_aux_ops.append( z2_symmetries.taper(aux_op) if aux_op is not None else None ) return z2_qubit_op, z2_aux_ops, z2_symmetries
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 not (isinstance(d_m, np.ndarray) and d_m.ndim == 2): d_m = d_m[0] + d_m[1] 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 _process_z2symmetry_reduction( self, qubit_op: WeightedPauliOperator, aux_ops: List[WeightedPauliOperator]) -> Tuple: """ Implement z2 symmetries in the qubit operator Args: qubit_op : qubit operator aux_ops: auxiliary operators Returns: (z2_qubit_op, z2_aux_ops, z2_symmetries) Raises: QiskitChemistryError: Invalid input """ z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) if z2_symmetries.is_empty(): logger.debug('No Z2 symmetries found') z2_qubit_op = qubit_op z2_aux_ops = aux_ops z2_symmetries = Z2Symmetries([], [], [], None) else: logger.debug( '%s Z2 symmetries found: %s', len(z2_symmetries.symmetries), ','.join( [symm.to_label() for symm in z2_symmetries.symmetries])) # Check auxiliary operators commute with main operator's symmetry logger.debug('Checking operators commute with symmetry:') symmetry_ops = [] for symmetry in z2_symmetries.symmetries: symmetry_ops.append( WeightedPauliOperator(paulis=[[1.0, symmetry]])) commutes = FermionicTransformation._check_commutes( symmetry_ops, qubit_op) if not commutes: raise QiskitChemistryError( 'Z2 symmetry failure main operator must commute ' 'with symmetries found from it') for i, aux_op in enumerate(aux_ops): commutes = FermionicTransformation._check_commutes( symmetry_ops, aux_op) if not commutes: aux_ops[ i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': hf_state = HartreeFock( num_orbitals=self._molecule_info['num_orbitals'], qubit_mapping=self._qubit_mapping, two_qubit_reduction=self._two_qubit_reduction, num_particles=self._molecule_info['num_particles']) z2_symmetries = FermionicTransformation._pick_sector( z2_symmetries, hf_state.bitstr) else: if len(self._z2symmetry_reduction) != len( z2_symmetries.symmetries): raise QiskitChemistryError( 'z2symmetry_reduction tapering values list has ' 'invalid length {} should be {}'.format( len(self._z2symmetry_reduction), len(z2_symmetries.symmetries))) valid = np.all(np.isin(self._z2symmetry_reduction, [-1, 1])) if not valid: raise QiskitChemistryError( 'z2symmetry_reduction tapering values list must ' 'contain -1\'s and/or 1\'s only was {}'.format( self._z2symmetry_reduction, )) z2_symmetries.tapering_values = self._z2symmetry_reduction logger.debug('Apply symmetry with tapering values %s', z2_symmetries.tapering_values) chop_to = 0.00000001 # Use same threshold as qubit mapping to chop tapered operator z2_qubit_op = z2_symmetries.taper(qubit_op).chop(chop_to) z2_aux_ops = [] for aux_op in aux_ops: if aux_op is None: z2_aux_ops += [None] else: z2_aux_ops += [z2_symmetries.taper(aux_op).chop(chop_to)] return z2_qubit_op, z2_aux_ops, z2_symmetries
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 parse(fcidump: str) -> Dict[str, Any]: # pylint: disable=wrong-spelling-in-comment """Parses a FCIDump output. Args: fcidump: Path to the FCIDump file. Raises: QiskitChemistryError: If the input file cannot be found, if a required field in the FCIDump file is missing, if wrong integral indices are encountered, or if the alpha/beta or beta/alpha 2-electron integrals are mixed. Returns: A dictionary storing the parsed data. """ try: with open(fcidump, 'r') as file: fcidump_str = file.read() except OSError as ex: raise QiskitChemistryError( "Input file '{}' cannot be read!".format(fcidump)) from ex output = {} # type: Dict[str, Any] # FCIDump starts with a Fortran namelist of meta data namelist_end = re.search('(/|&END)', fcidump_str) metadata = fcidump_str[:namelist_end.start(0)] metadata = ' '.join( metadata.split()) # replace duplicate whitespace and newlines # we know what elements to look for so we don't get too fancy with the parsing # pattern explanation: # .*? any text # (*|*), match either part of this group followed by a comma # [-+]? match up to a single - or + # \d*.\d+ number format pattern = r'.*?([-+]?\d*\.\d+|[-+]?\d+),' # we parse the values in the order in which they are listed in Knowles1989 _norb = re.search('NORB' + pattern, metadata) if _norb is None: raise QiskitChemistryError( "The required NORB entry of the FCIDump format is missing!") norb = int(_norb.groups()[0]) output['NORB'] = norb _nelec = re.search('NELEC' + pattern, metadata) if _nelec is None: raise QiskitChemistryError( "The required NELEC entry of the FCIDump format is missing!") output['NELEC'] = int(_nelec.groups()[0]) # the rest of these values may occur and are set to their defaults otherwise _ms2 = re.search('MS2' + pattern, metadata) output['MS2'] = int(_ms2.groups()[0]) if _ms2 else 0 _isym = re.search('ISYM' + pattern, metadata) output['ISYM'] = int(_isym.groups()[0]) if _isym else 1 # ORBSYM holds a list, thus it requires a little different treatment _orbsym = re.search(r'ORBSYM.*?' + r'(\d+),' * norb, metadata) output['ORBSYM'] = [int(s) for s in _orbsym.groups()] if _orbsym else [1] * norb _iprtim = re.search('IPRTIM' + pattern, metadata) output['IPRTIM'] = int(_iprtim.groups()[0]) if _iprtim else -1 _int = re.search('INT' + pattern, metadata) output['INT'] = int(_int.groups()[0]) if _int else 5 _memory = re.search('MEMORY' + pattern, metadata) output['MEMORY'] = int(_memory.groups()[0]) if _memory else 10000 _core = re.search('CORE' + pattern, metadata) output['CORE'] = float(_core.groups()[0]) if _core else 0.0 _maxit = re.search('MAXIT' + pattern, metadata) output['MAXIT'] = int(_maxit.groups()[0]) if _maxit else 25 _thr = re.search('THR' + pattern, metadata) output['THR'] = float(_thr.groups()[0]) if _thr else 1e-5 _thrres = re.search('THRRES' + pattern, metadata) output['THRRES'] = float(_thrres.groups()[0]) if _thrres else 0.1 _nroot = re.search('NROOT' + pattern, metadata) output['NROOT'] = int(_nroot.groups()[0]) if _nroot else 1 # If the FCIDump file resulted from an unrestricted spin calculation the indices will label spin # rather than molecular orbitals. This means, that a line must exist which encodes the # coefficient for the spin orbital with index (norb*2, norb*2). By checking for such a line we # can distinguish between unrestricted and restricted FCIDump files. _uhf = bool( re.search(r'.*(\s+{}\s+{}\s+0\s+0)'.format(norb * 2, norb * 2), fcidump_str[namelist_end.start(0):])) # the rest of the FCIDump will hold lines of the form x i a j b # a few cases have to be treated differently: # i, a, j and b are all zero: x is the core energy # TODO: a, j and b are all zero: x is the energy of the i-th MO (often not supported) # j and b are both zero: x is the 1e-integral between i and a (x = <i|h|a>) # otherwise: x is the Coulomb integral ( x = (ia|jb) ) hij = np.zeros((norb, norb)) hij_elements = set(itertools.product(range(norb), repeat=2)) hijkl = np.zeros((norb, norb, norb, norb)) hijkl_elements = set(itertools.product(range(norb), repeat=4)) hij_b = hijkl_ab = hijkl_ba = hijkl_bb = None hij_b_elements = hijkl_ab_elements = hijkl_ba_elements = hijkl_bb_elements = set( ) if _uhf: beta_range = [n + norb for n in range(norb)] hij_b = np.zeros((norb, norb)) hij_b_elements = set(itertools.product(beta_range, repeat=2)) hijkl_ab = np.zeros((norb, norb, norb, norb)) hijkl_ba = np.zeros((norb, norb, norb, norb)) hijkl_bb = np.zeros((norb, norb, norb, norb)) hijkl_ab_elements = set( itertools.product(range(norb), range(norb), beta_range, beta_range)) hijkl_ba_elements = set( itertools.product(beta_range, beta_range, range(norb), range(norb))) hijkl_bb_elements = set(itertools.product(beta_range, repeat=4)) orbital_data = fcidump_str[namelist_end.end(0):].split('\n') for orbital in orbital_data: if not orbital: continue x = float(orbital.split()[0]) # Note: differing naming than ijkl due to E741 and this iajb is inline with this: # https://hande.readthedocs.io/en/latest/manual/integrals.html#fcidump-format i, a, j, b = [int(i) for i in orbital.split()[1:]] # pylint: disable=invalid-name if i == a == j == b == 0: output['ecore'] = x elif a == j == b == 0: # TODO: x is the energy of the i-th MO continue elif j == b == 0: try: hij_elements.remove((i - 1, a - 1)) hij[i - 1][a - 1] = x except KeyError as ex: if _uhf: hij_b_elements.remove((i - 1, a - 1)) hij_b[i - 1 - norb][a - 1 - norb] = x else: raise QiskitChemistryError( "Unkown 1-electron integral indices encountered in \ '{}'".format((i, a))) from ex else: try: hijkl_elements.remove((i - 1, a - 1, j - 1, b - 1)) hijkl[i - 1][a - 1][j - 1][b - 1] = x except KeyError as ex: if _uhf: try: hijkl_ab_elements.remove((i - 1, a - 1, j - 1, b - 1)) hijkl_ab[i - 1][a - 1][j - 1 - norb][b - 1 - norb] = x except KeyError: try: hijkl_ba_elements.remove( (i - 1, a - 1, j - 1, b - 1)) hijkl_ba[i - 1 - norb][a - 1 - norb][j - 1][b - 1] = x except KeyError: hijkl_bb_elements.remove( (i - 1, a - 1, j - 1, b - 1)) hijkl_bb[i - 1 - norb][a - 1 - norb][j - 1 - norb][b - 1 - norb] = x else: raise QiskitChemistryError( "Unkown 2-electron integral indices encountered in \ '{}'".format((i, a, j, b))) from ex # iterate over still empty elements in 1-electron matrix and populate with symmetric ones # if any elements are not populated these will be zero _permute_1e_ints(hij, hij_elements, norb) if _uhf: # do the same for beta spin _permute_1e_ints(hij_b, hij_b_elements, norb, beta=True) # do the same of the 2-electron 4D matrix _permute_2e_ints(hijkl, hijkl_elements, norb) if _uhf: # do the same for beta spin _permute_2e_ints(hijkl_bb, hijkl_bb_elements, norb, beta=2) _permute_2e_ints(hijkl_ab, hijkl_ab_elements, norb, beta=1) # type: ignore _permute_2e_ints(hijkl_ba, hijkl_ba_elements, norb, beta=1) # type: ignore # assert that EITHER hijkl_ab OR hijkl_ba were given if np.allclose(hijkl_ab, 0.0) == np.allclose(hijkl_ba, 0.0): raise QiskitChemistryError( "Encountered mixed sets of indices for the 2-electron \ integrals. Either alpha/beta or beta/alpha matrix should be specified." ) if np.allclose(hijkl_ba, 0.0): hijkl_ba = hijkl_ab.transpose() output['hij'] = hij output['hij_b'] = hij_b output['hijkl'] = hijkl output['hijkl_ba'] = hijkl_ba output['hijkl_bb'] = hijkl_bb return output
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 check_driver_valid(): if psi4 is None: raise QiskitChemistryError("Could not locate {}".format(PSI4))
def check_valid() -> None: """ Checks if Gaussian is installed and available""" if _G16PROG is None: raise QiskitChemistryError( "Could not locate {} executable '{}'. Please check that it is installed correctly." .format(_GAUSSIAN_16_DESC, _GAUSSIAN_16))
def check_driver_valid(): if g16prog is None: raise QiskitChemistryError("Could not locate {} executable '{}'. Please check that it is installed correctly." .format(GAUSSIAN_16_DESC, GAUSSIAN_16))
def parse(self): """Parse the data.""" if self._inputdict is None: if self._filename is None: raise QiskitChemistryError("Missing input file") section = None self._sections = OrderedDict() contents = '' with open(self._filename, 'rt', encoding="utf8", errors='ignore') as f: for line in f: contents += line section = self._process_line(section, line) if self._sections: # convert to aqua compatible json dictionary based on schema driver_configs = OrderedDict() for driver_name in local_drivers(): driver_configs[driver_name.lower( )] = get_driver_configuration(driver_name) json_dict = OrderedDict() for section_name, section in self._sections.items(): types = [] if section_name.lower() in driver_configs: config = driver_configs[section_name.lower()] input_schema = copy.deepcopy( config['input_schema'] ) if 'input_schema' in config else { 'type': 'string' } if 'type' not in input_schema: input_schema['type'] = 'string' types = [input_schema['type']] else: types = self.get_section_types(section_name.lower()) if 'string' in types: json_dict[section_name] = section[ 'data'] if 'data' in section else '' else: json_dict[section_name] = section[ 'properties'] if 'properties' in section else OrderedDict( ) self._sections = json_dict else: contents = contents.strip().replace('\n', '').replace('\r', '') if len(contents) > 0: # check if input file was dictionary try: v = ast.literal_eval(contents) if isinstance(v, dict): self._inputdict = json.loads(json.dumps(v)) self._load_parser_from_dict() except: pass else: self._load_parser_from_dict() # check for old enable_substitutions name old_enable_substitutions = self.get_section_property( JSONSchema.PROBLEM, InputParser._OLD_ENABLE_SUBSTITUTIONS) if old_enable_substitutions is not None: self.delete_section_property(JSONSchema.PROBLEM, InputParser._OLD_ENABLE_SUBSTITUTIONS) self.set_section_property(JSONSchema.PROBLEM, InputParser.AUTO_SUBSTITUTIONS, old_enable_substitutions) self.json_schema.update_backend_schema(self) self.json_schema.update_pluggable_schemas(self) self._update_driver_input_schemas() self._update_operator_input_schema() self._sections = self._order_sections(self._sections) self._original_sections = copy.deepcopy(self._sections)
def _check_valid(): if PSI4_APP is None: raise QiskitChemistryError("Could not locate {}".format(PSI4))
def _update_operator_input_schema(self): # find operator default_name = self.get_property_default_value(InputParser.OPERATOR, JSONSchema.NAME) operator_name = self.get_section_property(InputParser.OPERATOR, JSONSchema.NAME, default_name) if operator_name is None: # find the first valid input for the problem problem_name = self.get_section_property(JSONSchema.PROBLEM, JSONSchema.NAME) if problem_name is None: problem_name = self.get_property_default_value( JSONSchema.PROBLEM, JSONSchema.NAME) if problem_name is None: raise QiskitChemistryError( "No algorithm 'problem' section found on input.") for name in local_chemistry_operators(): if problem_name in self.get_operator_problems(name): # set to the first input to solve the problem operator_name = name break if operator_name is None: # just remove fromm schema if none solves the problem if InputParser.OPERATOR in self.json_schema.schema['properties']: del self.json_schema.schema['properties'][InputParser.OPERATOR] return if default_name is None: default_name = operator_name config = {} try: config = get_chemistry_operator_configuration(operator_name) except: pass input_schema = config[ 'input_schema'] if 'input_schema' in config else {} properties = input_schema[ 'properties'] if 'properties' in input_schema else {} properties[JSONSchema.NAME] = {'type': 'string'} required = input_schema[ 'required'] if 'required' in input_schema else [] additionalProperties = input_schema[ 'additionalProperties'] if 'additionalProperties' in input_schema else True if default_name is not None: properties[JSONSchema.NAME]['default'] = default_name required.append(JSONSchema.NAME) if InputParser.OPERATOR not in self.json_schema.schema['properties']: self.json_schema.schema['properties'][InputParser.OPERATOR] = { 'type': 'object' } self.json_schema.schema['properties'][ InputParser.OPERATOR]['properties'] = properties self.json_schema.schema['properties'][ InputParser.OPERATOR]['required'] = required self.json_schema.schema['properties'][InputParser.OPERATOR][ 'additionalProperties'] = additionalProperties
def __init__( self, transformation: FermionicTransformationType = FermionicTransformationType.FULL, qubit_mapping: FermionicQubitMappingType = FermionicQubitMappingType .PARITY, two_qubit_reduction: bool = True, freeze_core: bool = False, orbital_reduction: Optional[List[int]] = None, z2symmetry_reduction: Optional[Union[str, List[int]]] = None) -> None: """ Args: transformation: full or particle_hole qubit_mapping: 'jordan_wigner', 'parity' or 'bravyi_kitaev' two_qubit_reduction: Whether two qubit reduction should be used, when parity mapping only freeze_core: Whether to freeze core orbitals when possible orbital_reduction: Orbital list to be frozen or removed z2symmetry_reduction: If z2 symmetry reduction should be applied to resulting qubit operators that are computed. For each symmetry detected the operator will be split in two where each requires one qubit less for computation. So for example 3 symmetries will split in the original operator into 8 new operators each requiring 3 less qubits. Now only one of these operators will have the ground state and be the correct symmetry sector needed for the ground state. Setting 'auto' will use an automatic computation of the correct sector. If from other experiments, with the z2symmetry logic, the sector is known, then the tapering values of that sector can be provided (a list of int of values -1, and 1). The default is None meaning no symmetry reduction is done. Note that dipole and other operators such as spin, num particles etc are also symmetry reduced according to the symmetries found in the main operator if this operator commutes with the main operator symmetry. If it does not then the operator will be discarded since no meaningful measurement can take place. Raises: QiskitChemistryError: Invalid symmetry reduction """ transformation = transformation.value # type: ignore orbital_reduction = orbital_reduction if orbital_reduction is not None else [] super().__init__() self._transformation = transformation self._qubit_mapping = qubit_mapping.value self._two_qubit_reduction = two_qubit_reduction self._freeze_core = freeze_core self._orbital_reduction = orbital_reduction if z2symmetry_reduction is not None: if isinstance(z2symmetry_reduction, str): if z2symmetry_reduction != 'auto': raise QiskitChemistryError( 'Invalid z2symmetry_reduction value') self._z2symmetry_reduction = z2symmetry_reduction self._has_dipole_moments = False self._untapered_qubit_op = None # Store values that are computed by the classical logic in order # that later they may be combined with the quantum result self._hf_energy = None self._nuclear_repulsion_energy = None self._nuclear_dipole_moment = None self._reverse_dipole_sign = None # The following shifts are from freezing orbitals under orbital reduction self._energy_shift = 0.0 self._x_dipole_shift = 0.0 self._y_dipole_shift = 0.0 self._z_dipole_shift = 0.0 # The following shifts are from particle_hole transformation self._ph_energy_shift = 0.0 self._ph_x_dipole_shift = 0.0 self._ph_y_dipole_shift = 0.0 self._ph_z_dipole_shift = 0.0 self._molecule_info: Dict[str, Any] = {}
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_