Exemplo n.º 1
0
    def _rotate_orbitals_in_qmolecule(
            qmolecule: QMolecule, orbital_rotation: 'OrbitalRotation') -> None:
        """
        Rotates the orbitals by applying a modified a anti-hermitian matrix
        (orbital_rotation.matrix_a) onto the MO coefficients matrix and recomputes all the
        quantities dependent on the MO coefficients. Be aware that qmolecule is modified
        when this executes.
        Args:
            qmolecule: instance of QMolecule class
            orbital_rotation: instance of OrbitalRotation class
        """

        # 1 and 2 electron integrals (required) from AO to MO basis
        qmolecule.mo_coeff = np.matmul(qmolecule.mo_coeff,
                                       orbital_rotation.matrix_a)
        qmolecule.mo_onee_ints = qmolecule.oneeints2mo(qmolecule.hcore,
                                                       qmolecule.mo_coeff)
        # support for unrestricted spins
        if qmolecule.mo_coeff_b is not None:
            qmolecule.mo_coeff_b = np.matmul(qmolecule.mo_coeff_b,
                                             orbital_rotation.matrix_b)
            qmolecule.mo_onee_ints_b = qmolecule.oneeints2mo(
                qmolecule.hcore, qmolecule.mo_coeff)

        qmolecule.mo_eri_ints = qmolecule.twoeints2mo(qmolecule.eri,
                                                      qmolecule.mo_coeff)
        if qmolecule.mo_coeff_b is not None:
            mo_eri_b = qmolecule.twoeints2mo(qmolecule.eri,
                                             qmolecule.mo_coeff_b)
            norbs = qmolecule.mo_coeff.shape[0]
            qmolecule.mo_eri_ints_bb = mo_eri_b.reshape(
                norbs, norbs, norbs, norbs)
            qmolecule.mo_eri_ints_ba = qmolecule.twoeints2mo_general(
                qmolecule.eri, qmolecule.mo_coeff_b, qmolecule.mo_coeff_b,
                qmolecule.mo_coeff, qmolecule.mo_coeff)
            qmolecule.mo_eri_ints_ba = qmolecule.mo_eri_ints_ba.reshape(
                norbs, norbs, norbs, norbs)
        # dipole integrals (if available) from AO to MO
        if qmolecule.x_dip_ints is not None:
            qmolecule.x_dip_mo_ints = qmolecule.oneeints2mo(
                qmolecule.x_dip_ints, qmolecule.mo_coeff)
            qmolecule.y_dip_mo_ints = qmolecule.oneeints2mo(
                qmolecule.y_dip_ints, qmolecule.mo_coeff)
            qmolecule.z_dip_mo_ints = qmolecule.oneeints2mo(
                qmolecule.z_dip_ints, qmolecule.mo_coeff)
        # support for unrestricted spins
        if qmolecule.mo_coeff_b is not None and qmolecule.x_dip_ints is not None:
            qmolecule.x_dip_mo_ints_b = qmolecule.oneeints2mo(
                qmolecule.x_dip_ints, qmolecule.mo_coeff_b)
            qmolecule.y_dip_mo_ints_b = qmolecule.oneeints2mo(
                qmolecule.y_dip_ints, qmolecule.mo_coeff_b)
            qmolecule.z_dip_mo_ints_b = qmolecule.oneeints2mo(
                qmolecule.z_dip_ints, qmolecule.mo_coeff_b)
Exemplo n.º 2
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)

            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_
Exemplo n.º 3
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_