{
"cells": [
{
"cell_type": "markdown",
"id": "02288820-5cb5-4c8b-8432-81a99ceeec0d",
"metadata": {},
"source": [
"# Excited states\n",
"\n",
"For the analysis of the excited states, it is common to simply study the molecular orbitals of the final states, and base assignments and other conclusions from this. This often works quite well, but the final state can be multi-determinational in nature, and the canonical orbitals of larger systems are often quite delocalized and hard to study. As such, many other analysis tools have been developed, two of which will be discussed here:\n",
"- [Natural transition orbitals](sec:vis_ntos) (NTOs), which constructs a compact, transition-dependent description of specific excitations\n",
"- [Attachment and detachment densities](sec:vis_attach_det), which are based on the one-particle density matrix and considers the density change involved in an excitation\n",
"\n",
"\n",
"As an illustration, we consider the first valence-excited state of water, as calculated using ADC(2):"
]
},
{
"cell_type": "markdown",
"id": "e10e61d1-a956-4d72-a5cb-fe661b39cf02",
"metadata": {},
"source": [
"```python\n",
"water_geom = \"\"\"\n",
"O 0.0000000000 0.1187290000 0.0000000000\n",
"H -0.7532010000 -0.4749160000 -0.0000000000\n",
"H 0.7532010000 -0.4749160000 0.0000000000\n",
"\"\"\"\n",
"\n",
"mol = gto.Mole()\n",
"mol.atom = water_geom\n",
"mol.basis = \"6-31G\"\n",
"mol.build()\n",
"\n",
"scf_gs = scf.HF(mol)\n",
"scf_gs.kernel()\n",
"\n",
"adc_state = adcc.adc2(scf_gs, n_singlets=2)\n",
"```\n",
"\n",
"Printing the results:\n",
"\n",
"```python\n",
"# Print results\n",
"print(adc_state.describe())\n",
"\n",
"# Print dominant amplitudes\n",
"print(adc_state.describe_amplitudes())\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "476b4390-a1c1-4ffe-aa36-9d7ef21a9ace",
"metadata": {
"tags": [
"hide-input"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"+--------------------------------------------------------------+\n",
"| adc2 singlet , converged |\n",
"+--------------------------------------------------------------+\n",
"| # excitation energy osc str |v1|^2 |v2|^2 |\n",
"| (au) (eV) |\n",
"| 0 0.3054352 8.311314 0.0142 0.9591 0.04089 |\n",
"| 1 0.3903211 10.62118 0.0000 0.9636 0.03637 |\n",
"+--------------------------------------------------------------+\n",
"\n",
"+---------------------------------------------------+\n",
"| State 0 , 0.3054352 au, 8.311314 eV |\n",
"+---------------------------------------------------+\n",
"| HOMO -> LUMO a ->a -0.691 |\n",
"| HOMO -> LUMO+4 a ->a +0.0451 |\n",
"| HOMO -> LUMO+7 a ->a +0.0227 |\n",
"| HOMO-2 HOMO -> LUMO+1 LUMO ab->ab +0.0306 |\n",
"| HOMO HOMO -> LUMO LUMO+3 ab->ab -0.0253 |\n",
"| HOMO-2 HOMO -> LUMO LUMO+1 aa->aa -0.0191 |\n",
"| HOMO-1 HOMO -> LUMO LUMO ab->ab -0.0191 |\n",
"| HOMO-3 HOMO -> LUMO LUMO ab->ab +0.0182 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+4 aa->aa -0.0174 |\n",
"| HOMO-1 HOMO -> LUMO+4 LUMO ab->ab +0.0152 |\n",
"| HOMO-2 HOMO -> LUMO+6 LUMO ab->ab -0.0152 |\n",
"| HOMO-1 HOMO -> LUMO+5 LUMO ab->ab -0.0147 |\n",
"| HOMO-2 HOMO -> LUMO LUMO+6 aa->aa +0.0139 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+5 aa->aa +0.0117 |\n",
"| HOMO-2 HOMO -> LUMO LUMO+1 ab->ab +0.0115 |\n",
"| HOMO-3 HOMO -> LUMO LUMO+7 aa->aa +0.0107 |\n",
"\n",
"+---------------------------------------------------+\n",
"| State 1 , 0.3903211 au, 10.62118 eV |\n",
"+---------------------------------------------------+\n",
"| HOMO -> LUMO+1 a ->a +0.69 |\n",
"| HOMO -> LUMO+6 a ->a -0.0598 |\n",
"| HOMO -> LUMO+2 a ->a -0.0431 |\n",
"| HOMO-2 HOMO -> LUMO+1 LUMO+1 ab->ab -0.0301 |\n",
"| HOMO HOMO -> LUMO+1 LUMO+3 ab->ab +0.0234 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+1 ab->ab +0.019 |\n",
"| HOMO-2 HOMO -> LUMO+1 LUMO+6 aa->aa -0.0189 |\n",
"| HOMO-1 HOMO -> LUMO+4 LUMO+1 ab->ab -0.0144 |\n",
"| HOMO-3 HOMO -> LUMO LUMO+1 ab->ab -0.0143 |\n",
"| HOMO-1 HOMO -> LUMO+1 LUMO+4 aa->aa +0.0133 |\n",
"| HOMO-2 HOMO -> LUMO+6 LUMO+1 ab->ab +0.013 |\n",
"| HOMO-1 HOMO -> LUMO+5 LUMO+1 ab->ab +0.0121 |\n",
"| HOMO-1 HOMO -> LUMO+1 LUMO+5 aa->aa -0.0109 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+1 aa->aa +0.0104 |\n"
]
}
],
"source": [
"print_results = \"\"\"+--------------------------------------------------------------+\n",
"| adc2 singlet , converged |\n",
"+--------------------------------------------------------------+\n",
"| # excitation energy osc str |v1|^2 |v2|^2 |\n",
"| (au) (eV) |\n",
"| 0 0.3054352 8.311314 0.0142 0.9591 0.04089 |\n",
"| 1 0.3903211 10.62118 0.0000 0.9636 0.03637 |\n",
"+--------------------------------------------------------------+\n",
"\n",
"+---------------------------------------------------+\n",
"| State 0 , 0.3054352 au, 8.311314 eV |\n",
"+---------------------------------------------------+\n",
"| HOMO -> LUMO a ->a -0.691 |\n",
"| HOMO -> LUMO+4 a ->a +0.0451 |\n",
"| HOMO -> LUMO+7 a ->a +0.0227 |\n",
"| HOMO-2 HOMO -> LUMO+1 LUMO ab->ab +0.0306 |\n",
"| HOMO HOMO -> LUMO LUMO+3 ab->ab -0.0253 |\n",
"| HOMO-2 HOMO -> LUMO LUMO+1 aa->aa -0.0191 |\n",
"| HOMO-1 HOMO -> LUMO LUMO ab->ab -0.0191 |\n",
"| HOMO-3 HOMO -> LUMO LUMO ab->ab +0.0182 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+4 aa->aa -0.0174 |\n",
"| HOMO-1 HOMO -> LUMO+4 LUMO ab->ab +0.0152 |\n",
"| HOMO-2 HOMO -> LUMO+6 LUMO ab->ab -0.0152 |\n",
"| HOMO-1 HOMO -> LUMO+5 LUMO ab->ab -0.0147 |\n",
"| HOMO-2 HOMO -> LUMO LUMO+6 aa->aa +0.0139 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+5 aa->aa +0.0117 |\n",
"| HOMO-2 HOMO -> LUMO LUMO+1 ab->ab +0.0115 |\n",
"| HOMO-3 HOMO -> LUMO LUMO+7 aa->aa +0.0107 |\n",
"\n",
"+---------------------------------------------------+\n",
"| State 1 , 0.3903211 au, 10.62118 eV |\n",
"+---------------------------------------------------+\n",
"| HOMO -> LUMO+1 a ->a +0.69 |\n",
"| HOMO -> LUMO+6 a ->a -0.0598 |\n",
"| HOMO -> LUMO+2 a ->a -0.0431 |\n",
"| HOMO-2 HOMO -> LUMO+1 LUMO+1 ab->ab -0.0301 |\n",
"| HOMO HOMO -> LUMO+1 LUMO+3 ab->ab +0.0234 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+1 ab->ab +0.019 |\n",
"| HOMO-2 HOMO -> LUMO+1 LUMO+6 aa->aa -0.0189 |\n",
"| HOMO-1 HOMO -> LUMO+4 LUMO+1 ab->ab -0.0144 |\n",
"| HOMO-3 HOMO -> LUMO LUMO+1 ab->ab -0.0143 |\n",
"| HOMO-1 HOMO -> LUMO+1 LUMO+4 aa->aa +0.0133 |\n",
"| HOMO-2 HOMO -> LUMO+6 LUMO+1 ab->ab +0.013 |\n",
"| HOMO-1 HOMO -> LUMO+5 LUMO+1 ab->ab +0.0121 |\n",
"| HOMO-1 HOMO -> LUMO+1 LUMO+5 aa->aa -0.0109 |\n",
"| HOMO-1 HOMO -> LUMO LUMO+1 aa->aa +0.0104 |\"\"\"\n",
"print(print_results)"
]
},
{
"cell_type": "markdown",
"id": "f46143bd-3180-436d-ac55-82a779d004bf",
"metadata": {},
"source": [
"Here we print the basic description of the excited states (energy, intensity, weight of double excitation amplitudes), as well as a break-down of the dominating amplitudes for each transition. From this we can start analysing the excited state by looking at the canonical MOs, but we will now use the results for a more involved analysis.\n",
"\n",
"\n",
"(sec:vis_ntos)=\n",
"## Natural transition orbitals\n",
"\n",
"[Natural transition orbitals](https://aip.scitation.org/doi/pdf/10.1063/1.1558471) (NTOs) are constructed to provide the most compact, transition-dependent transition orbitals of a specific excitation. With this, a single pair of NTOs corresponding to the hole and electron will typically dominate, and will thus provide a easily interpretable description of the excitation. For a pure HOMO to LUMO transition the NTOs would be the same as the HOMO (hole) and LUMO (electron) orbitals.\n",
"\n",
"The NTOs are constructed from a singular-value decomposition (SVD) of the transition density matrix ($\\mathbf{T}$):\n",
"\n",
"$$\n",
"\\mathbf{UTV}^{\\dagger} = \\mathbf{\\Lambda}\n",
"$$\n",
"\n",
"where $\\mathbf{U}$ and $\\mathbf{V}$ are the transformation matrices correspoding to the hole and electron, respectively, and $\\mathbf{\\Lambda}$ is a diagonal matrix measuring the relative importance of each pair of NTOs.\n",
"\n",
"The first pair of NTOs for the first excitation can now be constructed as:\n",
"\n",
"```{note}\n",
"The following scripts are not executed, and static image are instead loaded. This is merely for improved loading time of the webpage and to save disk space.\n",
"```\n",
"\n",
"```python\n",
"i = 0 # first state only\n",
"\n",
"# Load transition density matrix, combine alpha and beta, and transform to numpy\n",
"tdm_ao = adc_state.transition_dm[i].to_ao_basis()\n",
"p_tdm_tot = (tdm_ao[0] + tdm_ao[1]).to_ndarray()\n",
"\n",
"# Build NTOs by singular value decomposition\n",
"u, s, v = np.linalg.svd(p_tdm_tot)\n",
"\n",
"print('Dominant NTO of state {}'.format(i+1))\n",
"print('Relative importance:',np.around(s[0]/sum(s),3))\n",
"k = 0 # only look at dominant NTO pair \n",
"\n",
"# Initial\n",
"tools.cubegen.orbital(mol=mol, coeff=v[k],outfile=\"../../img/visualize/water_nto_{}_HONTO+{}.cube\".format(i,k))\n",
"# Final\n",
"tools.cubegen.orbital(mol=mol, coeff=u.T[k],outfile=\"../../img/visualize/water_nto_{}_LUNTO+{}.cube\".format(i,k))\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "421cd479-cce8-4350-bb65-ca71c6398efe",
"metadata": {
"tags": [
"hide-input"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Dominant NTO of state 1\n",
"Relative importance: 0.97\n",
"\n"
]
}
],
"source": [
"print_results = \"\"\"\n",
"Dominant NTO of state 1\n",
"Relative importance: 0.97\n",
"\"\"\"\n",
"print(print_results)"
]
},
{
"cell_type": "markdown",
"id": "c1535452-e2f6-45d7-a80b-d05b7d7bc639",
"metadata": {},
"source": [
"```{figure} ../../img/visualize/water-ntos-dens.png\n",
"---\n",
"name: water-ntos-dens\n",
"```\n",
"\n",
"This shows a strong dominance (0.97) of the first NTO pair.\n",
"\n",
"\n",
"(sec:vis_attach_det)=\n",
"## Attachment and detachment densities\n",
"\n",
"A different method for visualizing the transitions is to consider the attachment (A) and detachment (D) densities, which are constructed to show the density change related to an excitation. For a simple HOMO-LUMO transition they would simply correspond to the square of the dominant NTOs, with meaning:\n",
"\n",
"- Hole/detachment density representing where electrons go from\n",
"- Electron/attachment density representing where electrons go to\n",
"\n",
"These densities can then be used to look at properties such as hole and electron size, distance between the centroid (and thus level of charge-transfer), and more. D/A densities are constructed from the one-particle difference density matrix (1DDM), which is simply the difference between the on-particle density matrices of the initial and final state:\n",
"\n",
"$$\n",
"\\rho_{\\Delta} = \\rho_f - \\rho_i\n",
"$$\n",
"\n",
"Diagonalizing this\n",
"\n",
"$$\n",
"\\mathbf{U} \\rho_{\\Delta} \\mathbf{U}^{\\dagger} = \\delta\n",
"$$\n",
"\n",
"The attachment and detachment densities are constructed by considering the negative and positive eigenvalues.\n",
"\n",
"Looking at the attachment and detachment density of the first excited state:\n",
"\n",
"```python\n",
"# Load transition density matrix, combine alpha and beta, and transform to numpy\n",
"p_state = adc_state.state_diffdm[i].to_ao_basis()\n",
"p_state_ao = (p_state[0] + p_state[1]).to_ndarray()\n",
"\n",
"# Diagonalize the 1DDM\n",
"k, w = np.linalg.eigh(p_state_ao)\n",
"k_detach = k.copy()\n",
"k_attach = k.copy()\n",
"# Detachment: set positive eigenvalues to 0\n",
"k_detach[k > 0] = 0\n",
"# Attachment: set negative eigenvalues to 0\n",
"k_attach[k < 0] = 0\n",
"# Back-transform with numpy\n",
"detach_ao = w @ np.diag(k_detach) @ w.T\n",
"attach_ao = w @ np.diag(k_attach) @ w.T\n",
"\n",
"# Write cube-files\n",
"de = tools.cubegen.density(\n",
" mol, dm=detach_ao, outfile=\"../../img/visualize/water_detachment_{}.cube\".format(i)\n",
")\n",
"at = tools.cubegen.density(\n",
" mol, dm=attach_ao, outfile=\"../../img/visualize/water_attachment_{}.cube\".format(i)\n",
")\n",
"```\n",
"\n",
"```{figure} ../../img/visualize/water-att-det-dens.png\n",
"---\n",
"name: water-att-det-dens\n",
"```\n",
"\n",
"We see that these states are more compact (as we are looking on *densities*) than above NTOs. For a discussion on NTOs and D/A densities, see, *e.g.*, [this paper](https://onlinelibrary.wiley.com/doi/10.1002/jcc.23975)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.15"
}
},
"nbformat": 4,
"nbformat_minor": 5
}