Source code for ectoolkits.analysis.dielectric_constant
import numpy as np
import numpy.typing as npt
from scipy.integrate import simpson
from cp2kdata import Cp2kCube
[docs]def get_induced_charge(rho_cube_1: Cp2kCube,
rho_cube_2: Cp2kCube,
axis: str = 'z'
):
"""
Compute the induced charge density between two systems.
Induced charge density is defined as rho_cube_2 - rho_cube_1.
Parameters
----------
rho_cube_1 : Cp2kCube
The first charge density cube.
rho_cube_2 : Cp2kCube
The second charge density cube.
axis : str, optional
The axis along which to compute the average charge density, by default 'z'.
Returns
-------
Tuple[np.ndarray, np.ndarray]
The coordinates and the induced charge density array.
"""
z_1, rho_1 = rho_cube_1.get_pav(axis=axis)
z_2, rho_2 = rho_cube_2.get_pav(axis=axis)
rho_induced = rho_2 - rho_1
return z_1, rho_induced
[docs]def get_integrated_array(x, y):
size = y.shape[0]
int_array = np.zeros(size)
for i in range(1, size+1):
int_array[i-1] = simpson(y[:i], x[:i])
return int_array
# get electric field
[docs]def get_micro_electric_field(x: npt.NDArray[np.float64],
rho: npt.NDArray[np.float64],
Delta_macro_Efield: float
) -> npt.NDArray[np.float64]:
"""
Calculate the micro electric field from the charge density and the macroscopic electric field difference.
Parameters
----------
x : numpy.ndarray
The grid points where the charge density is defined.
rho : numpy.ndarray
The charge density in atomic units.
Delta_macro_Efield : float
The macroscopic electric field difference between two systems in atomic units.
Returns
-------
numpy.ndarray
The micro electric field in atomic units.
Notes
-----
The micro electric field is calculated as follows:
1. Calculate the integrand as pi * 4 * rho.
2. Integrate the integrand over the grid points x to obtain the micro electric field.
3. Determine a constant such that the mean of the micro electric field matches the macroscopic electric field difference.
4. Add the constant to the micro electric field.
The units of the input and output arrays are atomic units (au).
"""
# atomic unit
integrand = np.pi * 4 * rho
micro_electric_field = get_integrated_array(x, integrand)
# determine constant
constant = Delta_macro_Efield - micro_electric_field.mean()
micro_electric_field += constant
return micro_electric_field
# get polarization
[docs]def get_micro_polarization(x: npt.NDArray[np.float64],
rho: npt.NDArray[np.float64],
Delta_macro_polarization: float
) -> npt.NDArray[np.float64]:
"""
Calculate the micro polarization from the induced charge density and the macroscopic polarization difference.
Parameters
----------
x : numpy.ndarray
The grid points where the charge density is defined.
rho : numpy.ndarray
The induced charge density in atomic units.
Delta_macro_polarization : float
The macroscopic polarization difference between two systems in atomic units.
Returns
-------
numpy.ndarray
The micro polarization in atomic units.
Notes
-----
The micro polarization is calculated as follows:
1. Calculate the integrand as -rho.
2. Integrate the integrand over the grid points x to obtain the micro polarization.
3. Determine a constant such that the mean of the micro polarization matches the macroscopic polarization difference.
4. Add the constant to the micro polarization.
The units of the input and output arrays are atomic units (au).
"""
# atomic unit
# the electron charge is negative!
integrand = -rho
micro_polarization = get_integrated_array(x, integrand)
# determine constant
constant = Delta_macro_polarization - micro_polarization.mean()
micro_polarization += constant
return micro_polarization
[docs]def get_dielectric_susceptibility(micro_polarization, micro_electric_field):
dielectric_susceptibility = micro_polarization / micro_electric_field
return dielectric_susceptibility
[docs]def get_dielectric_constant(dielectric_susceptibility):
dielectric_constant = dielectric_susceptibility*np.pi*4 + 1
return dielectric_constant
[docs]def get_dielectric_constant_profile(rho_1, rho_2, Delta_macro_Efield, Delta_macro_polarization, axis):
z, rho_induced = get_induced_charge(rho_1, rho_2, axis=axis)
# electron carries negative charge
rho_induced = -rho_induced
micro_electric_field = get_micro_electric_field(
z, rho_induced, Delta_macro_Efield=Delta_macro_Efield)
micro_polarization = get_micro_polarization(
z, rho_induced, Delta_macro_polarization=Delta_macro_polarization)
dielectric_susceptibility = get_dielectric_susceptibility(
micro_polarization, micro_electric_field)
dielectric_constant = get_dielectric_constant(dielectric_susceptibility)
return z, dielectric_constant