示例#1
0
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_
示例#3
0
    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
示例#4
0
    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_
示例#5
0
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
示例#6
0
    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
示例#7
0
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_
示例#8
0
    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
示例#9
0
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_
示例#10
0
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
示例#11
0
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))
示例#14
0
 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))
示例#15
0
    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)
示例#16
0
 def _check_valid():
     if PSI4_APP is None:
         raise QiskitChemistryError("Could not locate {}".format(PSI4))
示例#17
0
    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
示例#18
0
    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] = {}
示例#19
0
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_