def test_to_hdf5(self): """Test to_hdf5.""" random = np.random.rand(2, 2, 2, 2) ints = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (random, random, random, random)) with tempfile.TemporaryFile() as tmp_file: with h5py.File(tmp_file, "w") as file: ints.to_hdf5(file)
def test_add(self): """Test addition.""" mat_aa = np.arange(16).reshape((2, 2, 2, 2)) mat_bb = np.arange(-16, 0).reshape((2, 2, 2, 2)) ints_aa = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (mat_aa, None, None, None)) ints_bb = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (mat_bb, None, None, None)) ints_sum = ints_aa + ints_bb self.assertTrue(isinstance(ints_sum, TwoBodyElectronicIntegrals)) self.assertTrue(np.allclose(ints_sum._matrices[0], mat_aa + mat_bb))
def setUp(self): """Setup.""" super().setUp() self.ints_1_ao = OneBodyElectronicIntegrals(ElectronicBasis.AO, (np.eye(2), None)) self.ints_1_mo = OneBodyElectronicIntegrals(ElectronicBasis.MO, (np.eye(2), None)) self.ints_2_ao = TwoBodyElectronicIntegrals( ElectronicBasis.AO, (np.ones((2, 2, 2, 2)), None, None, None) ) self.ints_2_mo = TwoBodyElectronicIntegrals( ElectronicBasis.MO, (np.ones((2, 2, 2, 2)), None, None, None) ) self.prop = IntegralProperty( "test", [self.ints_1_ao, self.ints_1_mo, self.ints_2_ao, self.ints_2_mo] )
def run(self) -> ElectronicStructureDriverResult: """Returns an ElectronicStructureDriverResult instance out of a FCIDump file.""" fcidump_data = parse(self._fcidump_input) hij = fcidump_data.get("hij", None) hij_b = fcidump_data.get("hij_b", None) hijkl = fcidump_data.get("hijkl", None) hijkl_ba = fcidump_data.get("hijkl_ba", None) hijkl_bb = fcidump_data.get("hijkl_bb", None) multiplicity = fcidump_data.get("MS2", 0) + 1 num_beta = (fcidump_data.get("NELEC") - (multiplicity - 1)) // 2 num_alpha = fcidump_data.get("NELEC") - num_beta particle_number = ParticleNumber( num_spin_orbitals=fcidump_data.get("NORB") * 2, num_particles=(num_alpha, num_beta), ) electronic_energy = ElectronicEnergy( [ OneBodyElectronicIntegrals(ElectronicBasis.MO, (hij, hij_b)), TwoBodyElectronicIntegrals(ElectronicBasis.MO, (hijkl, hijkl_ba, hijkl_bb, None)), ], nuclear_repulsion_energy=fcidump_data.get("ecore", None), ) driver_result = ElectronicStructureDriverResult() driver_result.add_property(electronic_energy) driver_result.add_property(particle_number) return driver_result
def test_from_hdf5(self): """Test from_hdf5.""" random = np.random.rand(2, 2, 2, 2) ints = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (random, random, random, random)) with tempfile.TemporaryFile() as tmp_file: with h5py.File(tmp_file, "w") as file: ints.to_hdf5(file) with h5py.File(tmp_file, "r") as file: new_ints = TwoBodyElectronicIntegrals.from_hdf5( file["TwoBodyElectronicIntegrals"]) self.assertEqual(ints, new_ints)
def test_compose(self): """Test composition.""" mat_aa = np.arange(16).reshape((2, 2, 2, 2)) mat_b = np.arange(-4, 0).reshape((2, 2)) ints_aa = TwoBodyElectronicIntegrals(ElectronicBasis.AO, (mat_aa, None, None, None)) ints_b = OneBodyElectronicIntegrals(ElectronicBasis.AO, (mat_b, None)) einsum = "ijkl,ji->kl" composition = ints_aa.compose(ints_b, einsum) expected = np.einsum(einsum, mat_aa, mat_b) self.assertTrue(isinstance(composition, OneBodyElectronicIntegrals)) self.assertTrue(composition._basis, ElectronicBasis.AO) self.assertTrue(np.allclose(composition._matrices[0], expected))
def _populate_driver_result_electronic_energy( self, driver_result: ElectronicStructureDriverResult) -> None: # pylint: disable=import-error from pyquante2 import onee_integrals from pyquante2.ints.integrals import twoe_integrals basis_transform = driver_result.get_property(ElectronicBasisTransform) integrals = onee_integrals(self._bfs, self._mol) hij = integrals.T + integrals.V hijkl = twoe_integrals(self._bfs) one_body_ao = OneBodyElectronicIntegrals(ElectronicBasis.AO, (hij, None)) two_body_ao = TwoBodyElectronicIntegrals( ElectronicBasis.AO, (hijkl.transform(np.identity(self._nmo)), None, None, None), ) one_body_mo = one_body_ao.transform_basis(basis_transform) two_body_mo = two_body_ao.transform_basis(basis_transform) electronic_energy = ElectronicEnergy( [one_body_ao, two_body_ao, one_body_mo, two_body_mo], nuclear_repulsion_energy=self._mol.nuclear_repulsion(), reference_energy=self._calc.energy, ) if hasattr(self._calc, "orbe"): orbs_energy = self._calc.orbe orbs_energy_b = None else: orbs_energy = self._calc.orbea orbs_energy_b = self._calc.orbeb orbital_energies = ((orbs_energy, orbs_energy_b) if orbs_energy_b is not None else orbs_energy) electronic_energy.orbital_energies = np.asarray(orbital_energies) electronic_energy.kinetic = OneBodyElectronicIntegrals( ElectronicBasis.AO, (integrals.T, None)) electronic_energy.overlap = OneBodyElectronicIntegrals( ElectronicBasis.AO, (integrals.S, None)) driver_result.add_property(electronic_energy)
def test_init(self): """Test construction.""" random = np.random.rand(2, 2, 2, 2) with self.subTest("Normal"): TwoBodyElectronicIntegrals(ElectronicBasis.MO, (random, None, None, None)) with self.subTest("Alpha and beta"): TwoBodyElectronicIntegrals(ElectronicBasis.MO, (random, random, random, random)) with self.subTest("Alpha and beta but transpose last one"): TwoBodyElectronicIntegrals(ElectronicBasis.MO, (random, random, random, None)) with self.subTest("Spin"): TwoBodyElectronicIntegrals(ElectronicBasis.SO, random) with self.subTest("Mismatching basis and number of matrices"): with self.assertRaises(TypeError): TwoBodyElectronicIntegrals(ElectronicBasis.MO, random) with self.subTest("Mismatching basis and number of matrices 2"): with self.assertRaises(TypeError): TwoBodyElectronicIntegrals(ElectronicBasis.SO, (random, None, None, None)) with self.subTest("Missing alpha"): with self.assertRaises(TypeError): TwoBodyElectronicIntegrals(ElectronicBasis.MO, (None, random, random, random))
def test_mul(self): """Test multiplication.""" mat_aa = np.arange(16).reshape((2, 2, 2, 2)) ints_aa = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (mat_aa, None, None, None)) ints_mul = 2.0 * ints_aa self.assertTrue(isinstance(ints_mul, TwoBodyElectronicIntegrals)) self.assertTrue(np.allclose(ints_mul._matrices[0], 2.0 * mat_aa))
def _populate_driver_result_electronic_energy( self, driver_result: ElectronicStructureDriverResult) -> None: # pylint: disable=import-error from pyscf import gto basis_transform = driver_result.get_property(ElectronicBasisTransform) one_body_ao = OneBodyElectronicIntegrals( ElectronicBasis.AO, (self._calc.get_hcore(), None), ) two_body_ao = TwoBodyElectronicIntegrals( ElectronicBasis.AO, (self._mol.intor("int2e", aosym=1), None, None, None), ) one_body_mo = one_body_ao.transform_basis(basis_transform) two_body_mo = two_body_ao.transform_basis(basis_transform) electronic_energy = ElectronicEnergy( [one_body_ao, two_body_ao, one_body_mo, two_body_mo], nuclear_repulsion_energy=gto.mole.energy_nuc(self._mol), reference_energy=self._calc.e_tot, ) electronic_energy.kinetic = OneBodyElectronicIntegrals( ElectronicBasis.AO, (self._mol.intor_symmetric("int1e_kin"), None), ) electronic_energy.overlap = OneBodyElectronicIntegrals( ElectronicBasis.AO, (self._calc.get_ovlp(), None), ) orbs_energy, orbs_energy_b = self._extract_mo_data("mo_energy") orbital_energies = ((orbs_energy, orbs_energy_b) if orbs_energy_b is not None else orbs_energy) electronic_energy.orbital_energies = np.asarray(orbital_energies) driver_result.add_property(electronic_energy)
def test_to_spin(self): """Test to_spin""" mat_aa = np.arange(16).reshape((2, 2, 2, 2)) mat_ba = np.arange(16, 32).reshape((2, 2, 2, 2)) mat_bb = np.arange(-16, 0).reshape((2, 2, 2, 2)) with self.subTest("Only alpha"): ints = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (mat_aa, None, None, None)) mat_so = ints.to_spin() expected = np.fromfile( self.get_resource_path( "two_body_test_to_spin_only_alpha_expected.numpy.bin", "properties/second_quantization/electronic/integrals/resources", )).reshape((4, 4, 4, 4)) self.assertTrue(np.allclose(mat_so, expected)) with self.subTest("Alpha and beta"): ints = TwoBodyElectronicIntegrals( ElectronicBasis.MO, (mat_aa, mat_ba, mat_bb, mat_ba.T)) mat_so = ints.to_spin() expected = np.fromfile( self.get_resource_path( "two_body_test_to_spin_alpha_and_beta_expected.numpy.bin", "properties/second_quantization/electronic/integrals/resources", )).reshape((4, 4, 4, 4)) self.assertTrue(np.allclose(mat_so, expected))
def test_aux_ops_reusability(self): """Test that the auxiliary operators can be reused""" # Regression test against #1475 solver = NumPyMinimumEigensolverFactory() calc = GroundStateEigensolver(self.qubit_converter, solver) modes = 4 h_1 = np.eye(modes, dtype=complex) h_2 = np.zeros((modes, modes, modes, modes)) aux_ops = ElectronicEnergy([ OneBodyElectronicIntegrals(ElectronicBasis.MO, (h_1, None)), TwoBodyElectronicIntegrals(ElectronicBasis.MO, (h_2, None, None, None)), ], ).second_q_ops() aux_ops_copy = copy.deepcopy(aux_ops) _ = calc.solve(self.electronic_structure_problem) assert all( frozenset(a.to_list()) == frozenset(b.to_list()) for a, b in zip(aux_ops, aux_ops_copy))
def test_aux_ops_reusability(self): """Test that the auxiliary operators can be reused""" # Regression test against #1475 solver = VQEUCCFactory( QuantumInstance(BasicAer.get_backend("statevector_simulator"))) calc = AdaptVQE(self.qubit_converter, solver) modes = 4 h_1 = np.eye(modes, dtype=complex) h_2 = np.zeros((modes, modes, modes, modes)) aux_ops = ElectronicEnergy([ OneBodyElectronicIntegrals(ElectronicBasis.MO, (h_1, None)), TwoBodyElectronicIntegrals(ElectronicBasis.MO, (h_2, None, None, None)), ]).second_q_ops() aux_ops_copy = copy.deepcopy(aux_ops) _ = calc.solve(self.problem) assert all( frozenset(a.to_list()) == frozenset(b.to_list()) for a, b in zip(aux_ops, aux_ops_copy))
def build_ferm_op_from_ints( one_body_integrals: np.ndarray, two_body_integrals: np.ndarray = None) -> FermionicOp: """**DEPRECATED!** Builds a fermionic operator based on 1- and/or 2-body integrals. Integral values are used for the coefficients of the second-quantized Hamiltonian that is built. If integrals are stored in the '*chemist*' notation h2(i,j,k,l) --> adag_i adag_k a_l a_j they are required to be in block spin format and also have indices reordered as follows 'ijkl->ljik'. There is another popular notation, the '*physicist*' notation h2(i,j,k,l) --> adag_i adag_j a_k a_l If you are using the '*physicist*' notation, you need to convert it to the '*chemist*' notation. E.g. h2=numpy.einsum('ikmj->ijkm', h2) The :class:`~qiskit_nature.drivers.QMolecule` class has :attr:`~qiskit_nature.drivers.QMolecule.one_body_integrals` and :attr:`~qiskit_nature.drivers.QMolecule.two_body_integrals` properties that can be directly supplied to the `h1` and `h2` parameters here respectively. Args: one_body_integrals (numpy.ndarray): One-body integrals stored in the chemist notation. two_body_integrals (numpy.ndarray): Two-body integrals stored in the chemist notation. Returns: FermionicOp: FermionicOp built from 1- and/or 2-body integrals. """ integrals: List[ElectronicIntegrals] = [] integrals.append( OneBodyElectronicIntegrals(ElectronicBasis.SO, one_body_integrals)) if two_body_integrals is not None: integrals.append( TwoBodyElectronicIntegrals(ElectronicBasis.SO, two_body_integrals)) prop = IntegralProperty("", integrals) fermionic_op = prop.second_q_ops()[0] return fermionic_op
def run(self) -> ElectronicStructureDriverResult: """Returns an ElectronicStructureDriverResult instance out of a FCIDump file.""" fcidump_data = parse(self._fcidump_input) hij = fcidump_data.get("hij", None) hij_b = fcidump_data.get("hij_b", None) hijkl = fcidump_data.get("hijkl", None) hijkl_ba = fcidump_data.get("hijkl_ba", None) hijkl_bb = fcidump_data.get("hijkl_bb", None) multiplicity = fcidump_data.get("MS2", 0) + 1 num_beta = (fcidump_data.get("NELEC") - (multiplicity - 1)) // 2 num_alpha = fcidump_data.get("NELEC") - num_beta particle_number = ParticleNumber( num_spin_orbitals=fcidump_data.get("NORB") * 2, num_particles=(num_alpha, num_beta), ) electronic_energy = ElectronicEnergy( [ OneBodyElectronicIntegrals(ElectronicBasis.MO, (hij, hij_b)), TwoBodyElectronicIntegrals(ElectronicBasis.MO, (hijkl, hijkl_ba, hijkl_bb, None)), ], nuclear_repulsion_energy=fcidump_data.get("ecore", None), ) # NOTE: under Python 3.6, pylint appears to be unable to properly identify this case of # nested abstract classes (cf. https://github.com/Qiskit/qiskit-nature/runs/3245395353). # However, since the tests pass I am adding an exception for this specific case. # pylint: disable=abstract-class-instantiated driver_result = ElectronicStructureDriverResult() driver_result.add_property(electronic_energy) driver_result.add_property(particle_number) return driver_result
def test_to_second_q_op(self): """Test to_second_q_op""" mat_aa = np.arange(16).reshape((2, 2, 2, 2)) mat_ba = np.arange(16, 32).reshape((2, 2, 2, 2)) mat_bb = np.arange(-16, 0).reshape((2, 2, 2, 2)) with self.subTest("Only alpha"): ints = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (mat_aa, None, None, None)) op = ints.to_second_q_op() with open( self.get_resource_path( "two_body_test_to_second_q_op_only_alpha_expected.json", "properties/second_quantization/electronic/integrals/resources", ), "r", encoding="utf8", ) as file: expected = json.load(file) for (real_label, real_coeff), (exp_label, exp_coeff) in zip(op.to_list(), expected): self.assertEqual(real_label, exp_label) self.assertTrue(np.isclose(real_coeff, exp_coeff)) with self.subTest("Alpha and beta"): ints = TwoBodyElectronicIntegrals( ElectronicBasis.MO, (mat_aa, mat_ba, mat_bb, mat_ba.T)) op = ints.to_second_q_op() with open( self.get_resource_path( "two_body_test_to_second_q_op_alpha_and_beta_expected.json", "properties/second_quantization/electronic/integrals/resources", ), "r", encoding="utf8", ) as file: expected = json.load(file) for (real_label, real_coeff), (exp_label, exp_coeff) in zip(op.to_list(), expected): self.assertEqual(real_label, exp_label) self.assertTrue(np.isclose(real_coeff, exp_coeff))
def test_transform_basis(self): """Test transform_basis""" mat_aa = np.arange(16).reshape((2, 2, 2, 2)) mat_ba = np.arange(16, 32).reshape((2, 2, 2, 2)) mat_bb = np.arange(-16, 0).reshape((2, 2, 2, 2)) transform = ElectronicBasisTransform(ElectronicBasis.AO, ElectronicBasis.MO, 2 * np.eye(2)) with self.subTest("Pure Alpha"): ints_ao = TwoBodyElectronicIntegrals(ElectronicBasis.AO, (mat_aa, None, None, None)) ints_mo = ints_ao.transform_basis(transform) self.assertTrue(np.allclose(ints_mo._matrices[0], 16 * mat_aa)) self.assertIsNone(ints_mo._matrices[1]) self.assertIsNone(ints_mo._matrices[2]) self.assertIsNone(ints_mo._matrices[3]) with self.subTest("Alpha and Beta"): ints_ao = TwoBodyElectronicIntegrals( ElectronicBasis.AO, (mat_aa, mat_ba, mat_bb, mat_ba.T)) ints_mo = ints_ao.transform_basis(transform) self.assertTrue(np.allclose(ints_mo._matrices[0], 16 * mat_aa)) self.assertTrue(np.allclose(ints_mo._matrices[1], 16 * mat_ba)) self.assertTrue(np.allclose(ints_mo._matrices[2], 16 * mat_bb)) self.assertTrue(np.allclose(ints_mo._matrices[3], 16 * mat_ba.T)) with self.subTest("Beta custom coeff with only alpha"): transform_beta = ElectronicBasisTransform(ElectronicBasis.AO, ElectronicBasis.MO, 2 * np.eye(2), 3 * np.eye(2)) ints_ao = TwoBodyElectronicIntegrals(ElectronicBasis.AO, (mat_aa, None, None, None)) ints_mo = ints_ao.transform_basis(transform_beta) self.assertTrue(np.allclose(ints_mo._matrices[0], 16 * mat_aa)) self.assertTrue(np.allclose(ints_mo._matrices[1], 36 * mat_aa)) self.assertTrue(np.allclose(ints_mo._matrices[2], 81 * mat_aa)) self.assertTrue(np.allclose(ints_mo._matrices[3], 36 * mat_aa)) with self.subTest("Beta custom coeff"): transform_beta = ElectronicBasisTransform(ElectronicBasis.AO, ElectronicBasis.MO, 2 * np.eye(2), 3 * np.eye(2)) ints_ao = TwoBodyElectronicIntegrals( ElectronicBasis.AO, (mat_aa, mat_ba, mat_bb, mat_ba.T)) ints_mo = ints_ao.transform_basis(transform_beta) self.assertTrue(np.allclose(ints_mo._matrices[0], 16 * mat_aa)) self.assertTrue(np.allclose(ints_mo._matrices[1], 36 * mat_ba)) self.assertTrue(np.allclose(ints_mo._matrices[2], 81 * mat_bb)) self.assertTrue(np.allclose(ints_mo._matrices[3], 36 * mat_ba.T)) with self.subTest("Final basis match"): ints_ao = TwoBodyElectronicIntegrals(ElectronicBasis.MO, (mat_aa, None, None, None)) ints_mo = ints_ao.transform_basis(transform) self.assertEqual(ints_ao, ints_mo) with self.subTest("Inital basis mismatch"): with self.assertRaises(QiskitNatureError): ints_ao = TwoBodyElectronicIntegrals(ElectronicBasis.SO, mat_aa) ints_ao.transform_basis(transform)
def test_arbitrary_active_orbitals(self): """Test manual selection of active orbital indices.""" driver = HDF5Driver(hdf5_input=self.get_resource_path( "H2_631g.hdf5", "transformers/second_quantization/electronic")) driver_result = driver.run() trafo = ActiveSpaceTransformer(num_electrons=2, num_molecular_orbitals=2, active_orbitals=[0, 2]) driver_result_reduced = trafo.transform(driver_result) expected = ElectronicStructureDriverResult() expected.add_property( ElectronicEnergy( [ OneBodyElectronicIntegrals( ElectronicBasis.MO, ( np.asarray([[-1.24943841, -0.16790838], [-0.16790838, -0.18307469]]), None, ), ), TwoBodyElectronicIntegrals( ElectronicBasis.MO, ( np.asarray([ [ [[0.65209847, 0.16790822], [0.16790822, 0.53250905]], [[0.16790822, 0.10962908], [0.10962908, 0.11981429]], ], [ [[0.16790822, 0.10962908], [0.10962908, 0.11981429]], [[0.53250905, 0.11981429], [0.11981429, 0.46345617]], ], ]), None, None, None, ), ), ], energy_shift={"ActiveSpaceTransformer": 0.0}, )) expected.add_property( ElectronicDipoleMoment([ DipoleMoment( "x", [ OneBodyElectronicIntegrals(ElectronicBasis.MO, (np.zeros((2, 2)), None)) ], shift={"ActiveSpaceTransformer": 0.0}, ), DipoleMoment( "y", [ OneBodyElectronicIntegrals(ElectronicBasis.MO, (np.zeros((2, 2)), None)) ], shift={"ActiveSpaceTransformer": 0.0}, ), DipoleMoment( "z", [ OneBodyElectronicIntegrals( ElectronicBasis.MO, (np.asarray([[0.69447435, 0.0], [0.0, 0.69447435] ]), None), ) ], shift={"ActiveSpaceTransformer": 0.0}, ), ])) self.assertDriverResult(driver_result_reduced, expected)
def test_tuple_num_electrons_with_manual_orbitals(self): """Regression test against https://github.com/Qiskit/qiskit-nature/issues/434.""" driver = HDF5Driver(hdf5_input=self.get_resource_path( "H2_631g.hdf5", "transformers/second_quantization/electronic")) driver_result = driver.run() trafo = ActiveSpaceTransformer( num_electrons=(1, 1), num_molecular_orbitals=2, active_orbitals=[0, 1], ) driver_result_reduced = trafo.transform(driver_result) expected = ElectronicStructureDriverResult() expected.add_property( ElectronicEnergy( [ OneBodyElectronicIntegrals( ElectronicBasis.MO, (np.asarray([[-1.24943841, 0.0], [0.0, -0.547816138] ]), None), ), TwoBodyElectronicIntegrals( ElectronicBasis.MO, ( np.asarray([ [ [[0.652098466, 0.0], [0.0, 0.433536565]], [[0.0, 0.0794483182], [0.0794483182, 0.0]], ], [ [[0.0, 0.0794483182], [0.0794483182, 0.0]], [[0.433536565, 0.0], [0.0, 0.385524695]], ], ]), None, None, None, ), ), ], energy_shift={"ActiveSpaceTransformer": 0.0}, )) expected.add_property( ElectronicDipoleMoment([ DipoleMoment( "x", [ OneBodyElectronicIntegrals(ElectronicBasis.MO, (np.zeros((2, 2)), None)) ], shift={"ActiveSpaceTransformer": 0.0}, ), DipoleMoment( "y", [ OneBodyElectronicIntegrals(ElectronicBasis.MO, (np.zeros((2, 2)), None)) ], shift={"ActiveSpaceTransformer": 0.0}, ), DipoleMoment( "z", [ OneBodyElectronicIntegrals( ElectronicBasis.MO, ( np.asarray([[0.69447435, -1.01418298], [-1.01418298, 0.69447435]]), None, ), ) ], shift={"ActiveSpaceTransformer": 0.0}, ), ])) self.assertDriverResult(driver_result_reduced, expected)
def _parse_matrix_file( fname: str, useao2e: bool = False) -> ElectronicStructureDriverResult: """ 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 QiskitNatureError(msg) from mnfe mel = MatEl(file=fname) logger.debug("MatrixElement file:\n%s", mel) driver_result = ElectronicStructureDriverResult() # molecule coords = np.reshape(mel.c, (len(mel.ian), 3)) geometry: list[tuple[str, list[float]]] = [] for atom, xyz in zip(mel.ian, coords): geometry.append((PERIODIC_TABLE[atom], BOHR * xyz)) driver_result.molecule = Molecule( geometry, multiplicity=mel.multip, charge=mel.icharg, ) # driver metadata driver_result.add_property(DriverMetadata("GAUSSIAN", mel.gversion, "")) # basis transform moc = GaussianDriver._get_matrix(mel, "ALPHA MO COEFFICIENTS") moc_b = GaussianDriver._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 nmo = moc.shape[0] basis_transform = ElectronicBasisTransform(ElectronicBasis.AO, ElectronicBasis.MO, moc, moc_b) driver_result.add_property(basis_transform) # particle number num_alpha = (mel.ne + mel.multip - 1) // 2 num_beta = (mel.ne - mel.multip + 1) // 2 driver_result.add_property( ParticleNumber(num_spin_orbitals=nmo * 2, num_particles=(num_alpha, num_beta))) # electronic energy hcore = GaussianDriver._get_matrix(mel, "CORE HAMILTONIAN ALPHA") logger.debug("CORE HAMILTONIAN ALPHA %s", hcore.shape) hcore_b = GaussianDriver._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, ) one_body_ao = OneBodyElectronicIntegrals(ElectronicBasis.AO, (hcore, hcore_b)) one_body_mo = one_body_ao.transform_basis(basis_transform) eri = GaussianDriver._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" ) two_body_ao = TwoBodyElectronicIntegrals(ElectronicBasis.AO, (eri, None, None, None)) two_body_mo: TwoBodyElectronicIntegrals if useao2e: # eri are 2-body in AO. We can convert to MO via the ElectronicBasisTransform but using # ints in MO already, as in the else here, is better two_body_mo = two_body_ao.transform_basis(basis_transform) 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 = GaussianDriver._get_matrix(mel, "AA MO 2E INTEGRALS") logger.debug("AA MO 2E INTEGRALS %s", mohijkl.shape) mohijkl_bb = GaussianDriver._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 = GaussianDriver._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, ) two_body_mo = TwoBodyElectronicIntegrals( ElectronicBasis.MO, (mohijkl, mohijkl_ba, mohijkl_bb, None)) electronic_energy = ElectronicEnergy( [one_body_ao, two_body_ao, one_body_mo, two_body_mo], nuclear_repulsion_energy=mel.scalar("ENUCREP"), reference_energy=mel.scalar("ETOTAL"), ) kinetic = GaussianDriver._get_matrix(mel, "KINETIC ENERGY") logger.debug("KINETIC ENERGY %s", kinetic.shape) electronic_energy.kinetic = OneBodyElectronicIntegrals( ElectronicBasis.AO, (kinetic, None)) overlap = GaussianDriver._get_matrix(mel, "OVERLAP") logger.debug("OVERLAP %s", overlap.shape) electronic_energy.overlap = OneBodyElectronicIntegrals( ElectronicBasis.AO, (overlap, None)) orbs_energy = GaussianDriver._get_matrix(mel, "ALPHA ORBITAL ENERGIES") logger.debug("ORBITAL ENERGIES %s", overlap.shape) orbs_energy_b = GaussianDriver._get_matrix(mel, "BETA ORBITAL ENERGIES") logger.debug("BETA ORBITAL ENERGIES %s", overlap.shape) orbital_energies = ( orbs_energy, orbs_energy_b) if moc_b is not None else orbs_energy electronic_energy.orbital_energies = np.asarray(orbital_energies) driver_result.add_property(electronic_energy) # dipole moment dipints = GaussianDriver._get_matrix(mel, "DIPOLE INTEGRALS") dipints = np.einsum("ijk->kji", dipints) x_dip_ints = OneBodyElectronicIntegrals(ElectronicBasis.AO, (dipints[0], None)) y_dip_ints = OneBodyElectronicIntegrals(ElectronicBasis.AO, (dipints[1], None)) z_dip_ints = OneBodyElectronicIntegrals(ElectronicBasis.AO, (dipints[2], None)) x_dipole = DipoleMoment( "x", [x_dip_ints, x_dip_ints.transform_basis(basis_transform)]) y_dipole = DipoleMoment( "y", [y_dip_ints, y_dip_ints.transform_basis(basis_transform)]) z_dipole = DipoleMoment( "z", [z_dip_ints, z_dip_ints.transform_basis(basis_transform)]) nucl_dip = np.einsum("i,ix->x", mel.ian, coords) nucl_dip = np.round(nucl_dip, decimals=8) driver_result.add_property( ElectronicDipoleMoment( [x_dipole, y_dipole, z_dipole], nuclear_dipole_moment=nucl_dip, reverse_dipole_sign=True, )) # extra properties # TODO: once https://github.com/Qiskit/qiskit-nature/issues/312 is fixed we can stop adding # these properties by default. # if not settings.dict_aux_operators: driver_result.add_property(AngularMomentum(nmo * 2)) driver_result.add_property(Magnetization(nmo * 2)) return driver_result