Scalar field analysis

Once the electronic structure has been determined, a variety of scalar fields derived from the electron density can be analyzed and visualized. These fields provide insight into the spatial distribution of electronic properties and form the basis for interpreting exchange, correlation, and density-related quantities.

Electron density and its gradient

The pydft.DFT class exposes its internal matrices and a number of useful functions which we can readily use to interpret its operation. Let us start by generating a plot of the electron density using the method pydft.DFT.get_density_at_points().

 1import numpy as np
 2from pydft import MoleculeBuilder, DFT
 3import matplotlib.pyplot as plt
 4from mpl_toolkits.axes_grid1 import make_axes_locatable
 5
 6# perform DFT calculation on the CO molecule
 7co = MoleculeBuilder().from_name("CO")
 8dft = DFT(co, basis='sto3g')
 9res = dft.scf(1e-6, verbose=False)
10
11# generate grid of points and calculate the electron density for these points
12sz = 4      # size of the domain
13npts = 100  # number of sampling points per cartesian direction
14
15# produce meshgrid for the xz-plane
16x = np.linspace(-sz/2,sz/2,npts)
17zz, xx = np.meshgrid(x, x, indexing='ij')
18gridpoints = np.zeros((zz.shape[0], xx.shape[1], 3))
19gridpoints[:,:,0] = xx
20gridpoints[:,:,2] = zz
21gridpoints[:,:,1] = np.zeros_like(xx) # set y-values to 0
22gridpoints = gridpoints.reshape((-1,3))
23
24# calculate (logarithmic) scalar field and convert if back to an 2D array
25density = dft.get_density_at_points(gridpoints)
26density = np.log10(density.reshape((npts, npts)))
27
28# build contour plot
29fig, ax = plt.subplots(1,1, dpi=144, figsize=(4,4))
30im = ax.contourf(x, x, density, levels=np.linspace(-3,3,13, endpoint=True))
31ax.contour(x, x, density, colors='black', levels=np.linspace(-3,3,13, endpoint=True))
32ax.set_aspect('equal', 'box')
33ax.set_xlabel('x-coordinate [a.u.]')
34ax.set_ylabel('z-coordinate [a.u.]')
35divider = make_axes_locatable(ax)
36cax = divider.append_axes('right', size='5%', pad=0.05)
37fig.colorbar(im, cax=cax, orientation='vertical')
38ax.set_title('Electron density')
39plt.show()

Running the above script yields the electron density.

_images/01-electron-density.png

Logarithmic electron density of CO sampled in the molecular plane.

Using largely the same code, we can also readily build the electron density gradient magnitude using pydft.DFT.get_gradient_at_points().

 1import numpy as np
 2from pydft import MoleculeBuilder, DFT
 3import matplotlib.pyplot as plt
 4from mpl_toolkits.axes_grid1 import make_axes_locatable
 5
 6# perform DFT calculation on the CO molecule
 7co = MoleculeBuilder().from_name("CO")
 8dft = DFT(co, basis='sto3g')
 9res = dft.scf(1e-6, verbose=False)
10
11# generate grid of points and calculate the electron density for these points
12sz = 4      # size of the domain
13npts = 100  # number of sampling points per cartesian direction
14
15# produce meshgrid for the xz-plane
16x = np.linspace(-sz/2,sz/2,npts)
17zz, xx = np.meshgrid(x, x, indexing='ij')
18gridpoints = np.zeros((zz.shape[0], xx.shape[1], 3))
19gridpoints[:,:,0] = xx
20gridpoints[:,:,2] = zz
21gridpoints[:,:,1] = np.zeros_like(xx) # set y-values to 0
22gridpoints = gridpoints.reshape((-1,3))
23
24# calculate (logarithmic) scalar field and convert if back to an 2D array
25gradient = np.linalg.norm(dft.get_gradient_at_points(gridpoints), axis=1)
26gradient = np.log10(gradient.reshape((npts, npts)))
27
28# build contour plot
29fig, ax = plt.subplots(1,1, dpi=144, figsize=(4,4))
30im = ax.contourf(x, x, gradient, levels=np.linspace(-2,4,7, endpoint=True))
31ax.contour(x, x, gradient, colors='black', levels=np.linspace(-2,4,7, endpoint=True))
32ax.set_aspect('equal', 'box')
33ax.set_xlabel('x-coordinate [a.u.]')
34ax.set_ylabel('z-coordinate [a.u.]')
35divider = make_axes_locatable(ax)
36cax = divider.append_axes('right', size='5%', pad=0.05)
37fig.colorbar(im, cax=cax, orientation='vertical')
38ax.set_title('Electron density gradient magnitude')
_images/02-electron-density-gradient.png

Magnitude of the electron-density gradient in the same plane.

Exchange potential

To construct the exchange potential at arbitrary grid points, we can use the script as shown below which uses the pydft.MolecularGrid.get_exchange_potential_at_points() method.

 1from pydft import DFT
 2from pyqint import MoleculeBuilder
 3import numpy as np
 4import matplotlib.pyplot as plt
 5from mpl_toolkits.axes_grid1 import make_axes_locatable
 6
 7# perform DFT calculation on the CO molecule
 8co = MoleculeBuilder().from_name("CO")
 9dft = DFT(co, basis='sto3g')
10res = dft.scf(1e-6, verbose=False)
11
12# grab molecular orbital energies and coefficients
13orbc = res['orbc']
14orbe = res['orbe']
15
16# generate grid of points and calculate the electron density for these points
17sz = 4      # size of the domain
18npts = 100  # number of sampling points per cartesian direction
19
20# produce meshgrid for the xz-plane
21x = np.linspace(-sz/2,sz/2,npts)
22zz, xx = np.meshgrid(x, x, indexing='ij')
23gridpoints = np.zeros((zz.shape[0], xx.shape[1], 3))
24gridpoints[:,:,0] = xx
25gridpoints[:,:,2] = zz
26gridpoints[:,:,1] = np.zeros_like(xx) # set y-values to 0
27gridpoints = gridpoints.reshape((-1,3))
28
29# grab a copy of the MolecularGrid object
30molgrid = dft.get_molgrid_copy()
31
32# construct exchange potential
33field = molgrid.get_exchange_potential_at_points(gridpoints, res['density'])
34field = field.reshape((npts, npts))
35
36# plot field
37fig, ax = plt.subplots(1, 1, dpi=144, figsize=(4,4))
38levels = np.linspace(-6,6,25, endpoint=True)
39im = ax.contourf(x, x, field, levels=levels, cmap='PiYG')
40ax.contour(x, x, field, levels=levels, colors='black', linewidths=0.5)
41ax.set_aspect('equal', 'box')
42ax.set_xlabel('x-coordinate [a.u.]')
43ax.set_ylabel('z-coordinate [a.u.]')
44divider = make_axes_locatable(ax)
45cax = divider.append_axes('right', size='5%', pad=0.05)
46fig.colorbar(im, cax=cax, orientation='vertical')
47ax.set_title('Exchange potential')
_images/08-exchange-potential.png

Exchange potential evaluated on an arbitrary two-dimensional grid.

Correlation potential

In a similar fashion as for the exchange potential, we can use the method pydft.MolecularGrid.get_correlation_potential_at_points() to obtain the correlation potential field.

 1from pydft import DFT
 2from pyqint import MoleculeBuilder
 3import numpy as np
 4import matplotlib.pyplot as plt
 5from mpl_toolkits.axes_grid1 import make_axes_locatable
 6
 7# perform DFT calculation on the CO molecule
 8co = MoleculeBuilder().from_name("CO")
 9dft = DFT(co, basis='sto3g')
10res = dft.scf(1e-6, verbose=False)
11
12# grab molecular orbital energies and coefficients
13orbc = res['orbc']
14orbe = res['orbe']
15
16# generate grid of points and calculate the electron density for these points
17sz = 4      # size of the domain
18npts = 100  # number of sampling points per cartesian direction
19
20# produce meshgrid for the xz-plane
21x = np.linspace(-sz/2,sz/2,npts)
22zz, xx = np.meshgrid(x, x, indexing='ij')
23gridpoints = np.zeros((zz.shape[0], xx.shape[1], 3))
24gridpoints[:,:,0] = xx
25gridpoints[:,:,2] = zz
26gridpoints[:,:,1] = np.zeros_like(xx) # set y-values to 0
27gridpoints = gridpoints.reshape((-1,3))
28
29# grab a copy of the MolecularGrid object
30molgrid = dft.get_molgrid_copy()
31
32# construct correlation potential
33field = molgrid.get_correlation_potential_at_points(gridpoints, res['density'])
34field = field.reshape((npts, npts))
35
36# plot field
37fig, ax = plt.subplots(1, 1, dpi=144, figsize=(4,4))
38levels = np.linspace(-0.2,0.2,101, endpoint=True)
39im = ax.contourf(x, x, field, levels=levels, cmap='PiYG')
40ax.contour(x, x, field, levels=levels, colors='black', linewidths=0.5)
41ax.set_aspect('equal', 'box')
42ax.set_xlabel('x-coordinate [a.u.]')
43ax.set_ylabel('z-coordinate [a.u.]')
44divider = make_axes_locatable(ax)
45cax = divider.append_axes('right', size='5%', pad=0.05)
46fig.colorbar(im, cax=cax, orientation='vertical')
47ax.set_title('Correlation potential')
_images/08-correlation-potential.png

Correlation potential evaluated on the same grid.