def create_external_mol(**kwargs): """Builds a qforte Molecule object from an external json file containing the one and two electron integrals and numbers of alpha/beta electrons. Returns ------- Molecule The qforte Molecule object which holds the molecular information. """ qforte_mol = Molecule(multiplicity=kwargs['multiplicity'], charge=kwargs['charge'], filename=kwargs['filename']) # open json file with open(kwargs["filename"]) as f: external_data = json.load(f) # build sq hamiltonian qforte_sq_hamiltonian = qforte.SQOperator() qforte_sq_hamiltonian.add(external_data['scalar_energy']['data'], [], []) for p, q, h_pq in external_data['oei']['data']: qforte_sq_hamiltonian.add(h_pq, [p], [q]) for p, q, r, s, h_pqrs in external_data['tei']['data']: qforte_sq_hamiltonian.add(h_pqrs / 4.0, [p, q], [s, r]) # only works in C1 symmetry hf_reference = [0 for i in range(external_data['nso']['data'])] for n in range(external_data['na']['data'] + external_data['nb']['data']): hf_reference[n] = 1 qforte_mol.hf_reference = hf_reference qforte_mol.sq_hamiltonian = qforte_sq_hamiltonian qforte_mol.hamiltonian = qforte_sq_hamiltonian.jw_transform() return qforte_mol
def get_op_from_basis_idx(self, I): max_nbody = len(self._nbody_counts) nqb = len(self._ref) nel = int(sum(self._ref)) # TODO(Nick): incorparate more flexability into this na_el = int(nel / 2) nb_el = int(nel / 2) basis_I = qf.QubitBasis(I) nbody = 0 pn = 0 na_I = 0 nb_I = 0 holes = [] # i, j, k, ... particles = [] # a, b, c, ... parity = [] for p in range(nel): bit_val = int(basis_I.get_bit(p)) nbody += (1 - bit_val) pn += bit_val if (p % 2 == 0): na_I += bit_val else: nb_I += bit_val if (bit_val - 1): holes.append(p) if (p % 2 == 0): parity.append(1) else: parity.append(-1) for q in range(nel, nqb): bit_val = int(basis_I.get_bit(q)) pn += bit_val if (q % 2 == 0): na_I += bit_val else: nb_I += bit_val if (bit_val): particles.append(q) if (q % 2 == 0): parity.append(1) else: parity.append(-1) if (pn == nel and na_I == na_el and nb_I == nb_el): if (nbody == 0): return qf.SQOperator() if (nbody != 0 and nbody <= max_nbody): total_parity = 1 for z in parity: total_parity *= z if (total_parity == 1): K_temp = qf.SQOperator() K_temp.add(+1.0, particles, holes) K_temp.add(-1.0, holes[::-1], particles[::-1]) K_temp.simplify() return K_temp return qf.SQOperator()
def add_from_basis_idx(self, I): max_nbody = len(self._nbody_counts) nqb = len(self._ref) nel = int(sum(self._ref)) # TODO(Nick): incorparate more flexability into this na_el = int(nel / 2) nb_el = int(nel / 2) basis_I = qf.QubitBasis(I) nbody = 0 pn = 0 na_I = 0 nb_I = 0 holes = [] # i, j, k, ... particles = [] # a, b, c, ... parity = [] # for ( p=0; p<nel; p++) { for p in range(nel): bit_val = int(basis_I.get_bit(p)) nbody += (1 - bit_val) pn += bit_val if (p % 2 == 0): na_I += bit_val else: nb_I += bit_val if (bit_val - 1): holes.append(p) if (p % 2 == 0): parity.append(1) else: parity.append(-1) for q in range(nel, nqb): bit_val = int(basis_I.get_bit(q)) pn += bit_val if (q % 2 == 0): na_I += bit_val else: nb_I += bit_val if (bit_val): particles.append(q) if (q % 2 == 0): parity.append(1) else: parity.append(-1) if (pn == nel and na_I == na_el and nb_I == nb_el): if (nbody != 0 and nbody <= max_nbody): total_parity = 1 for z in parity: total_parity *= z if (total_parity == 1): K_temp = qf.SQOperator() K_temp.add(+1.0, particles, holes) K_temp.add(-1.0, holes[::-1], particles[::-1]) K_temp.simplify() # this is potentially slow self._Nm.insert(0, len(K_temp.jw_transform().terms())) self._nbody_counts[nbody - 1] += 1
def get_op_from_basis_idx(self, I): max_nbody = len(self._nbody_counts) nqb = len(self._ref) nel = int(sum(self._ref)) # TODO(Nick): incorparate more flexability into this na_el = int(nel / 2) nb_el = int(nel / 2) basis_I = qf.QuantumBasis(I) nbody = 0 pn = 0 na_I = 0 nb_I = 0 holes = [] # i, j, k, ... particles = [] # a, b, c, ... parity = [] for p in range(nel): bit_val = int(basis_I.get_bit(p)) nbody += (1 - bit_val) pn += bit_val if (p % 2 == 0): na_I += bit_val else: nb_I += bit_val if (bit_val - 1): holes.append(p) if (p % 2 == 0): parity.append(1) else: parity.append(-1) for q in range(nel, nqb): bit_val = int(basis_I.get_bit(q)) pn += bit_val if (q % 2 == 0): na_I += bit_val else: nb_I += bit_val if (bit_val): particles.append(q) if (q % 2 == 0): parity.append(1) else: parity.append(-1) if (pn == nel and na_I == na_el and nb_I == nb_el): if (nbody == 0): return "null_excitation" if (nbody != 0 and nbody <= max_nbody): total_parity = 1 for z in parity: total_parity *= z if (total_parity == 1): excitation = particles + holes dexcitation = list(reversed(excitation)) sigma_I = [1.0, tuple(excitation)] # need i, j, a, b K_temp = qf.SQOperator() K_temp.add_term(+1.0, excitation) K_temp.add_term(-1.0, dexcitation) K_temp.simplify() return K_temp return "invalid_op"
def create_psi_mol(**kwargs): """Builds a qforte Molecule object directly from a psi4 calculation. Returns ------- Molecule The qforte Molecule object which holds the molecular information. """ kwargs.setdefault('symmetry', 'c1') kwargs.setdefault('charge', 0) kwargs.setdefault('multiplicity', 1) mol_geometry = kwargs['mol_geometry'] basis = kwargs['basis'] multiplicity = kwargs['multiplicity'] charge = kwargs['charge'] qforte_mol = Molecule(mol_geometry=mol_geometry, basis=basis, multiplicity=multiplicity, charge=charge) if not use_psi4: raise ImportError("Psi4 was not imported correctely.") # By default, the number of frozen orbitals is set to zero kwargs.setdefault('num_frozen_docc', 0) kwargs.setdefault('num_frozen_uocc', 0) # run_scf is not read, because we always run SCF to get a wavefunction object. kwargs.setdefault('run_mp2', 0) kwargs.setdefault('run_ccsd', 0) kwargs.setdefault('run_cisd', 0) kwargs.setdefault('run_fci', 0) # Setup psi4 calculation(s) psi4.set_memory('2 GB') psi4.core.set_output_file(kwargs['filename'] + '.out', False) p4_geom_str = f"{int(charge)} {int(multiplicity)}" for geom_line in mol_geometry: p4_geom_str += f"\n{geom_line[0]} {geom_line[1][0]} {geom_line[1][1]} {geom_line[1][2]}" p4_geom_str += f"\nsymmetry {kwargs['symmetry']}" p4_geom_str += f"\nunits angstrom" print(' ==> Psi4 geometry <==') print('-------------------------') print(p4_geom_str) p4_mol = psi4.geometry(p4_geom_str) scf_ref_type = "rhf" if multiplicity == 1 else "rohf" psi4.set_options({ 'basis': basis, 'scf_type': 'pk', 'reference': scf_ref_type, 'e_convergence': 1e-8, 'd_convergence': 1e-8, 'ci_maxiter': 100, 'num_frozen_docc': kwargs['num_frozen_docc'], 'num_frozen_uocc': kwargs['num_frozen_uocc'] }) # run psi4 caclulation p4_Escf, p4_wfn = psi4.energy('SCF', return_wfn=True) # Run additional computations requested by the user if (kwargs['run_mp2']): qforte_mol.mp2_energy = psi4.energy('MP2') if (kwargs['run_ccsd']): qforte_mol.ccsd_energy = psi4.energy('CCSD') if (kwargs['run_cisd']): qforte_mol.cisd_energy = psi4.energy('CISD') if kwargs['run_fci']: if kwargs['num_frozen_uocc'] == 0: qforte_mol.fci_energy = psi4.energy('FCI') else: print( '\nWARNING: Skipping FCI computation due to a Psi4 bug related to FCI with frozen virtuals.\n' ) # Get integrals using MintsHelper. mints = psi4.core.MintsHelper(p4_wfn.basisset()) C = p4_wfn.Ca_subset("AO", "ALL") scalars = p4_wfn.scalar_variables() p4_Enuc_ref = scalars["NUCLEAR REPULSION ENERGY"] # Do MO integral transformation mo_teis = np.asarray(mints.mo_eri(C, C, C, C)) mo_oeis = np.asarray(mints.ao_kinetic()) + np.asarray(mints.ao_potential()) mo_oeis = np.einsum('uj,vi,uv', C, C, mo_oeis) nmo = np.shape(mo_oeis)[0] nalpha = p4_wfn.nalpha() nbeta = p4_wfn.nbeta() nel = nalpha + nbeta frozen_core = p4_wfn.frzcpi().sum() frozen_virtual = p4_wfn.frzvpi().sum() # Get symmetry information orbitals = [] for irrep, block in enumerate(p4_wfn.epsilon_a_subset("MO", "ACTIVE").nph): for orbital in block: orbitals.append([orbital, irrep]) orbitals.sort() hf_orbital_energies = [] orb_irreps_to_int = [] for row in orbitals: hf_orbital_energies.append(row[0]) orb_irreps_to_int.append(row[1]) del orbitals point_group = p4_mol.symmetry_from_input().lower() irreps = p4_mol.irrep_labels() orb_irreps = [irreps[i] for i in orb_irreps_to_int] # If frozen_core > 0, compute the frozen core energy and transform one-electron integrals frozen_core_energy = 0 if frozen_core > 0: for i in range(frozen_core): frozen_core_energy += 2 * mo_oeis[i, i] # Note that the two-electron integrals out of Psi4 are in the Mulliken notation for i in range(frozen_core): for j in range(frozen_core): frozen_core_energy += 2 * mo_teis[i, i, j, j] - mo_teis[i, j, j, i] # Incorporate in the one-electron integrals the two-electron integrals involving both frozen and non-frozen orbitals. # This also ensures that the correct orbital energies will be obtained. for p in range(frozen_core, nmo - frozen_virtual): for q in range(frozen_core, nmo - frozen_virtual): for i in range(frozen_core): mo_oeis[p, q] += 2 * mo_teis[p, q, i, i] - mo_teis[p, i, i, q] # Make hf_reference hf_reference = [1] * (nel - 2 * frozen_core) + [0] * ( 2 * (nmo - frozen_virtual) - nel) # Build second quantized Hamiltonian Hsq = qforte.SQOperator() Hsq.add(p4_Enuc_ref + frozen_core_energy, [], []) for i in range(frozen_core, nmo - frozen_virtual): ia = (i - frozen_core) * 2 ib = (i - frozen_core) * 2 + 1 for j in range(frozen_core, nmo - frozen_virtual): ja = (j - frozen_core) * 2 jb = (j - frozen_core) * 2 + 1 Hsq.add(mo_oeis[i, j], [ia], [ja]) Hsq.add(mo_oeis[i, j], [ib], [jb]) for k in range(frozen_core, nmo - frozen_virtual): ka = (k - frozen_core) * 2 kb = (k - frozen_core) * 2 + 1 for l in range(frozen_core, nmo - frozen_virtual): la = (l - frozen_core) * 2 lb = (l - frozen_core) * 2 + 1 if (ia != jb and kb != la): Hsq.add(mo_teis[i, l, k, j] / 2, [ia, jb], [kb, la]) # abba if (ib != ja and ka != lb): Hsq.add(mo_teis[i, l, k, j] / 2, [ib, ja], [ka, lb]) # baab if (ia != ja and ka != la): Hsq.add(mo_teis[i, l, k, j] / 2, [ia, ja], [ka, la]) # aaaa if (ib != jb and kb != lb): Hsq.add(mo_teis[i, l, k, j] / 2, [ib, jb], [kb, lb]) # bbbb # Set attributes qforte_mol.nuclear_repulsion_energy = p4_Enuc_ref qforte_mol.hf_energy = p4_Escf qforte_mol.hf_reference = hf_reference qforte_mol.sq_hamiltonian = Hsq qforte_mol.hamiltonian = Hsq.jw_transform() qforte_mol.point_group = [point_group, irreps] qforte_mol.orb_irreps = orb_irreps qforte_mol.orb_irreps_to_int = orb_irreps_to_int qforte_mol.hf_orbital_energies = hf_orbital_energies qforte_mol.frozen_core = frozen_core qforte_mol.frozen_virtual = frozen_virtual qforte_mol.frozen_core_energy = frozen_core_energy # Order Psi4 to delete its temporary files. psi4.core.clean() return qforte_mol