Nota

Esta página fue generada a partir de docs/tutorials/01_electronic_structure.ipynb.

Estructura electrónica#

Introducción#

El Hamiltoniano molecular es

\[\mathcal{H} = - \sum_I \frac{\nabla_{R_I}^2}{M_I} - \sum_i \frac{\nabla_{r_i}^2}{m_e} - \sum_I\sum_i \frac{Z_I e^2}{|R_I-r_i|} + \sum_i \sum_{j>i} \frac{e^2}{|r_i-r_j|} + \sum_I\sum_{J>I} \frac{Z_I Z_J e^2}{|R_I-R_J|}\]

Cómo los núcleos son mucho más pesados que los electrones, no se mueven en la misma escala de tiempo, entonces, el comportamiento de los núcleos y los electrones puede estar desacoplado. Esta es la aproximación de Born-Oppenheimer.

Por lo tanto, primero se puede abordar el problema electrónico con las coordenadas nucleares ingresándolas solo como parámetros. Los niveles de energía de los electrones en la molécula se pueden encontrar resolviendo la ecuación de Schrödinger no relativista independiente del tiempo,

\[\mathcal{H}_{\text{el}} |\Psi_{n}\rangle = E_{n} |\Psi_{n}\rangle\]

donde

\[\mathcal{H}_{\text{el}} = - \sum_i \frac{\nabla_{r_i}^2}{m_e} - \sum_I\sum_i \frac{Z_I e^2}{|R_I-r_i|} + \sum_i \sum_{j>i} \frac{e^2}{|r_i-r_j|}.\]

En particular, la energía del estado fundamental está dada por:

\[E_0 = \frac{\langle \Psi_0 | H_{\text{el}} | \Psi_0 \rangle}{\langle \Psi_0 | \Psi_0 \rangle}\]

donde \(\Psi_0\) es el estado fundamental del sistema.

Sin embargo, la dimensionalidad de este problema crece exponencialmente con el número de grados de libertad. Para abordar este problema nos gustaría preparar \(\Psi_0\) en una computadora cuántica y medir el valor esperado del Hamiltoniano (o \(E_0\)) directamente.

Entonces, ¿cómo lo hacemos concretamente?

A partir de la solución Hartree-Fock#

Un buen punto de partida para resolver este problema es el método Hartree-Fock (HF). Este método aproxima el problema de N cuerpos mediante N problemas de un cuerpo donde cada electrón evoluciona en el campo medio de los demás. La resolución clásica de las ecuaciones de HF es eficiente y conduce a la energía de intercambio exacta, pero no incluye ninguna correlación de electrones. Por lo tanto, suele ser un buen punto de partida al que añadir la correlación.

Luego, el Hamiltoniano se puede volver a expresar en la base de las soluciones del método HF, también llamado Orbitales Moleculares (MOs):

\[\hat{H}_{elec}=\sum_{pq} h_{pq} \hat{a}^{\dagger}_p \hat{a}_q + \frac{1}{2} \sum_{pqrs} h_{pqrs} \hat{a}^{\dagger}_p \hat{a}^{\dagger}_q \hat{a}_r \hat{a}_s\]

con las integrales de 1 cuerpo

\[h_{pq} = \int \phi^*_p(r) \left( -\frac{1}{2} \nabla^2 - \sum_{I} \frac{Z_I}{R_I- r} \right) \phi_q(r)dr\]

y las integrales de 2 cuerpos

\[h_{pqrs} = \int \frac{\phi^*_p(r_1) \phi^*_q(r_2) \phi_r(r_2) \phi_s(r_1)}{|r_1-r_2|}dr_1dr_2.\]

Los MOs (\(\phi_u\)) pueden ser ocupados o virtuales (desocupados). Un MO puede contener 2 electrones. Sin embargo, en lo que sigue realmente trabajamos con orbitales de espín que están asociados con un espín de electrón hacia arriba (\(\alpha\)) o hacia abajo (\(\beta\)). Así, los orbitales de espín pueden contener un electrón o estar desocupados.

Nota: cuando nos referimos al número de orbitales, usaremos el número de orbitales espaciales. Esto se refiere a cualquier orbital en el espacio cartesiano (aquí no importa si es un orbital molecular o en otra base). Cada orbital espacial se divide generalmente en dos orbitales de espín.

Ahora mostramos cómo realizar estos pasos concretamente con Qiskit.

Obtención de una solución Hartree-Fock inicial#

Qiskit está interconectado con diferentes códigos clásicos que son capaces de encontrar las soluciones de HF. La interfaz entre Qiskit y los siguientes códigos ya está disponible:

  • Gaussian

  • Psi4

  • PySCF

A continuación, configuramos un controlador (driver) PySCF, para la molécula de hidrógeno en la longitud de enlace de equilibrio (0.735 angstrom) en el estado singlete y sin carga.

[1]:
from qiskit_nature.units import DistanceUnit
from qiskit_nature.second_q.drivers import PySCFDriver

driver = PySCFDriver(
    atom="H 0 0 0; H 0 0 0.735",
    basis="sto3g",
    charge=0,
    spin=0,
    unit=DistanceUnit.ANGSTROM,
)

Ejecutar este controlador generará un ElectronicStructureProblem, la representación de Qiskit Nature del problema de estructura electrónica que nos interesa resolver. Para obtener más información sobre los controladores, consulta https://qiskit.org/documentation/nature/apidocs/qiskit_nature.second_q.drivers.html

[2]:
problem = driver.run()
print(problem)
<qiskit_nature.second_q.problems.electronic_structure_problem.ElectronicStructureProblem object at 0x7f3bc13406a0>

El ElectronicStructureProblem y sus componentes#

Dediquemos un tiempo a comprender esta instancia del problema y sus componentes.

El Hamiltoniano ElectronicEnergy#

El aspecto más importante es el Hamiltoniano interno; en este caso un Hamiltoniano ElectronicEnergy. Esta clase es capaz de generar el operador de segunda cuantización a partir de las integrales de 1 y 2 cuerpos que el código clásico ha calculado para nosotros.

IMPORTANTE: ¡La clase contenedora para los coeficientes integrales (PolynomialTensor) requiere que los términos de 2 cuerpos se proporcionen en orden del físico!

[3]:
hamiltonian = problem.hamiltonian

coefficients = hamiltonian.electronic_integrals
print(coefficients.alpha)
Polynomial Tensor
 "+-":
[[-1.25633907e+00 -6.21867875e-17]
 [-7.78036432e-17 -4.71896007e-01]]
 "++--":
[[[[6.75710155e-01 1.12401641e-16]
   [1.56722377e-16 1.80931200e-01]]

  [[1.92605510e-16 1.80931200e-01]
   [6.64581730e-01 2.59298923e-16]]]


 [[[8.68926823e-17 6.64581730e-01]
   [1.80931200e-01 1.82411770e-16]]

  [[1.80931200e-01 2.57172666e-16]
   [7.20426423e-17 6.98573723e-01]]]]
[4]:
second_q_op = hamiltonian.second_q_op()
print(second_q_op)
Fermionic Operator
number spin orbitals=4, number terms=36
  -1.2563390730032498 * ( +_0 -_0 )
+ -0.47189600728114245 * ( +_1 -_1 )
+ -1.2563390730032498 * ( +_2 -_2 )
+ -0.47189600728114245 * ( +_3 -_3 )
+ 0.33785507740175813 * ( +_0 +_0 -_0 -_0 )
+ 0.09046559989211565 * ( +_0 +_0 -_1 -_1 )
+ 0.09046559989211556 * ( +_0 +_1 -_0 -_1 )
+ 0.33229086512764827 * ( +_0 +_1 -_1 -_0 )
+ 0.33785507740175813 * ( +_0 +_2 -_2 -_0 )
+ 0.09046559989211565 * ( +_0 +_2 -_3 -_1 )
+ 0.09046559989211556 * ( +_0 +_3 -_2 -_1 )
+ 0.33229086512764827 * ( +_0 +_3 -_3 -_0 )
+ 0.33229086512764816 * ( +_1 +_0 -_0 -_1 )
+ 0.09046559989211574 * ( +_1 +_0 -_1 -_0 )
+ 0.09046559989211564 * ( +_1 +_1 -_0 -_0 )
+ 0.34928686136600906 * ( +_1 +_1 -_1 -_1 )
+ 0.33229086512764816 * ( +_1 +_2 -_2 -_1 )
+ 0.09046559989211574 * ( +_1 +_2 -_3 -_0 )
+ 0.09046559989211564 * ( +_1 +_3 -_2 -_0 )
+ 0.34928686136600906 * ( +_1 +_3 -_3 -_1 )
+ 0.33785507740175813 * ( +_2 +_0 -_0 -_2 )
+ 0.09046559989211565 * ( +_2 +_0 -_1 -_3 )
+ 0.09046559989211556 * ( +_2 +_1 -_0 -_3 )
+ 0.33229086512764827 * ( +_2 +_1 -_1 -_2 )
+ 0.33785507740175813 * ( +_2 +_2 -_2 -_2 )
+ 0.09046559989211565 * ( +_2 +_2 -_3 -_3 )
+ 0.09046559989211556 * ( +_2 +_3 -_2 -_3 )
+ 0.33229086512764827 * ( +_2 +_3 -_3 -_2 )
+ 0.33229086512764816 * ( +_3 +_0 -_0 -_3 )
+ 0.09046559989211574 * ( +_3 +_0 -_1 -_2 )
+ 0.09046559989211564 * ( +_3 +_1 -_0 -_2 )
+ 0.34928686136600906 * ( +_3 +_1 -_1 -_3 )
+ 0.33229086512764816 * ( +_3 +_2 -_2 -_3 )
+ 0.09046559989211574 * ( +_3 +_2 -_3 -_2 )
+ 0.09046559989211564 * ( +_3 +_3 -_2 -_2 )
+ 0.34928686136600906 * ( +_3 +_3 -_3 -_3 )

Ten en cuenta que esto es puramente el Hamiltoniano electrónico del sistema. Eso significa que la energía de repulsión nuclear no está incluida. En su lugar, Qiskit Nature agregará esta compensación de energía constante en un paso de posprocesamiento para calcular la energía total de tu sistema. Para saber cómo incluir la energía de repulsión nuclear en este operador, consulta la documentación de la clase ElectronicEnergy aquí.

[5]:
hamiltonian.nuclear_repulsion_energy  # NOT included in the second_q_op above
[5]:
0.7199689944489797

Más atributos del ElectronicStructureProblem#

A continuación, enumeramos algunos atributos adicionales de nuestra instancia problem:

[6]:
problem.molecule
[6]:
MoleculeInfo(symbols=['H', 'H'], coords=[(0.0, 0.0, 0.0), (0.0, 0.0, 1.3889487015553204)], multiplicity=1, charge=0, units=<DistanceUnit.BOHR: 'Bohr'>, masses=[1, 1])
[7]:
problem.reference_energy
[7]:
-1.1169989967540035
[8]:
problem.num_particles
[8]:
(1, 1)
[9]:
problem.num_spatial_orbitals
[9]:
2
[10]:
problem.basis
[10]:
<ElectronicBasis.MO: 'molecular'>

Para obtener más información sobre la base de tu problema, consulta el tutorial sobre `BasisTransformer <05_problem_transformers.ipynb>`__.

Observables adicionales#

El ElectronicStructureProblem también contiene fábricas de operadores adicionales, que generarán observables para ser evaluados en los estados fundamental y excitado al final de tu cálculo.

[11]:
problem.properties
[11]:
<qiskit_nature.second_q.problems.electronic_properties_container.ElectronicPropertiesContainer at 0x7f3bc1340790>
[12]:
problem.properties.particle_number
[12]:
<qiskit_nature.second_q.properties.particle_number.ParticleNumber at 0x7f3bc1340820>
[13]:
problem.properties.angular_momentum
[13]:
<qiskit_nature.second_q.properties.angular_momentum.AngularMomentum at 0x7f3bc1340700>
[14]:
problem.properties.magnetization
[14]:
<qiskit_nature.second_q.properties.magnetization.Magnetization at 0x7f3bc1340760>
[15]:
problem.properties.electronic_dipole_moment
[15]:
<qiskit_nature.second_q.properties.dipole_moment.ElectronicDipoleMoment at 0x7f3bc1340880>

Para obtener más información sobre estas propiedades, consulta su tutorial.

Resolviendo el ElectronicStructureProblem#

A continuación, calcularemos el estado fundamental de nuestra instancia del problema. Para obtener más información sobre los componentes individuales que se incluyen en GroundStateSolver, consulta el tutorial de estado fundamental.

[16]:
from qiskit_algorithms import NumPyMinimumEigensolver
from qiskit_nature.second_q.algorithms import GroundStateEigensolver
from qiskit_nature.second_q.mappers import JordanWignerMapper

solver = GroundStateEigensolver(
    JordanWignerMapper(),
    NumPyMinimumEigensolver(),
)
[17]:
result = solver.solve(problem)
print(result)
=== GROUND STATE ENERGY ===

* Electronic ground state energy (Hartree): -1.857275030202
  - computed part:      -1.857275030202
~ Nuclear repulsion energy (Hartree): 0.719968994449
> Total ground state energy (Hartree): -1.137306035753

=== MEASURED OBSERVABLES ===

  0:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000

=== DIPOLE MOMENTS ===

~ Nuclear dipole moment (a.u.): [0.0  0.0  1.3889487]

  0:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.3889487]
    - computed part:      [0.0  0.0  1.3889487]
  > Dipole moment (a.u.): [0.0  0.0  0.0]  Total: 0.0
                 (debye): [0.0  0.0  0.0]  Total: 0.0

[18]:
import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.24.0.dev0+2b3686f
qiskit-aer0.11.2
qiskit-ibmq-provider0.19.2
qiskit-nature0.6.0
System information
Python version3.9.16
Python compilerGCC 12.2.1 20221121 (Red Hat 12.2.1-4)
Python buildmain, Dec 7 2022 00:00:00
OSLinux
CPUs8
Memory (Gb)62.50002670288086
Thu Apr 06 08:53:41 2023 CEST

This code is a part of Qiskit

© Copyright IBM 2017, 2023.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.