529 lines
22 KiB
Python
529 lines
22 KiB
Python
import numpy as np
|
|
import scipy.integrate as integrate
|
|
from scipy.optimize import minimize
|
|
import numbers
|
|
import typing
|
|
from tqdm import tqdm
|
|
from echem.core.useful_funcs import nearest_array_index, ClassMethods
|
|
E_F_SHE_VAC = -4.5 # Fermi Energy of Standard Hydrogen Electrode with respect to vacuum
|
|
|
|
|
|
class GM(ClassMethods):
|
|
"""This class calculates the final Fermi and Redox species distributions according
|
|
to the Gerischer-Marcus formalism.
|
|
|
|
Parameters:
|
|
-----------
|
|
DOS: np.ndarray, optional
|
|
The values of DOS in 1D numpy array. If not specified values will be taken from saved data.
|
|
|
|
E: np.ndarray, optional
|
|
The corresponding to the DOS energy mesh. If not specified values will be taken from saved data.
|
|
|
|
efermi: np.ndarray. optional
|
|
System Fermi level. If not specified values will be taken from saved data.
|
|
|
|
vacuum_lvl: np.ndarray, optional
|
|
System vacuum level. If not specified values will be taken from saved data.
|
|
"""
|
|
def __init__(self, path_to_data='Saved_data', DOS=None, E=None, efermi=None, vacuum_lvl=None):
|
|
# variables that might be defined through __init__ function
|
|
self.E = E
|
|
self.DOS = DOS
|
|
self.efermi = efermi
|
|
self.vacuum_lvl = vacuum_lvl
|
|
|
|
# variables that should be defined through set_params function
|
|
self.C_EDL = None
|
|
self.T = None
|
|
self.l = None
|
|
self.sheet_area = None
|
|
|
|
# variables that will be created during calculations
|
|
self.sigma_Q_arr = None
|
|
|
|
# variable that define numerical parameters of quantum charge calculation
|
|
self.__SIGMA_0 = 0.5
|
|
self.__SIGMA_ACCURACY = 1e-3
|
|
self.__SIGMA_RANGE = 4
|
|
|
|
if DOS is None:
|
|
try:
|
|
self.DOS = np.load(path_to_data + '/DOS.npy')
|
|
except OSError:
|
|
print('File DOS.npy does not exist')
|
|
|
|
if E is None:
|
|
try:
|
|
self.E = np.load(path_to_data + '/E.npy')
|
|
except OSError:
|
|
print('File E_DOS.npy does not exist')
|
|
|
|
if efermi is None:
|
|
try:
|
|
self.efermi = np.load(path_to_data + '/efermi.npy')
|
|
except OSError:
|
|
print('File efermi.npy does not exist')
|
|
|
|
if vacuum_lvl is None:
|
|
try:
|
|
self.vacuum_lvl = np.load(path_to_data + '/vacuum_lvl.npy')
|
|
except OSError:
|
|
print('File vacuum_lvl.npy does not exist')
|
|
|
|
def set_params(self, C_EDL, T, l, sheet_area):
|
|
"""Sets parameters of calculation
|
|
|
|
Parameters:
|
|
----------
|
|
C_EDL: float, str
|
|
float: Capacitance of electric double layer (microF/cm^2)
|
|
str: 'Q' calculating in the Quantum Capacitance Dominating limit (C_Q << C_EDL)
|
|
str: 'Cl' calculating in the Classical limit (C_Q >> C_EDL)
|
|
|
|
T: int, float
|
|
Temperature. It is used in computing Fermi function and distribution function of redox system states
|
|
|
|
l: float
|
|
Reorganization energy in eV
|
|
"""
|
|
self.C_EDL = C_EDL
|
|
self.T = T
|
|
self.l = l
|
|
|
|
self.sheet_area = sheet_area
|
|
|
|
def set_params_advance(self, SIGMA_0=0.5, ACCURACY_SIGMA=1e-3, SIGMA_RANGE=4):
|
|
"""
|
|
Sets numerical parameters that are used in quantum charge density calculations. Delete cashed
|
|
results of charge calculations.
|
|
Args:
|
|
SIGMA_0: float, optional
|
|
Initial guess for charge at equilibrium
|
|
ACCURACY_SIGMA: float, optional
|
|
Accuracy of charge calculation
|
|
SIGMA_RANGE: float, optional
|
|
It defines the minimum and maximum calculated charge
|
|
"""
|
|
self.__SIGMA_0 = SIGMA_0
|
|
self.__SIGMA_ACCURACY = ACCURACY_SIGMA
|
|
self.__SIGMA_RANGE = SIGMA_RANGE
|
|
self.sigma_Q_arr = None
|
|
|
|
@staticmethod
|
|
def fermi_func(E, T):
|
|
"""
|
|
Calculates Fermi-Dirac Distribution
|
|
Args:
|
|
E: Energies
|
|
T: Temperature in K
|
|
"""
|
|
k = 8.617e-5 # eV/K
|
|
return 1 / (1 + np.exp(E / (k * T)))
|
|
|
|
@staticmethod
|
|
def W_ox(E, T, l):
|
|
"""
|
|
Distribution of oxidized states
|
|
Args:
|
|
E (np.array): Energies
|
|
T (float): Temperature
|
|
l (float): Reorganization energy
|
|
"""
|
|
k = 8.617e-5 # eV/K
|
|
W_0 = (1 / np.sqrt(4 * k * T * l))
|
|
return W_0 * np.exp(- (E - l) ** 2 / (4 * k * T * l))
|
|
|
|
@staticmethod
|
|
def W_red(E, T, l):
|
|
"""
|
|
Distribution of reduced states
|
|
Args:
|
|
E (np.array): Energies
|
|
T (float): Temperature
|
|
l (float): Reorganization energy
|
|
"""
|
|
k = 8.617e-5 # eV/K
|
|
W_0 = (1 / np.sqrt(4 * k * T * l))
|
|
return W_0 * np.exp(- (E + l) ** 2 / (4 * k * T * l))
|
|
|
|
def compute_C_quantum(self, dE_Q_arr):
|
|
"""
|
|
Calculates differential quantum capacitance
|
|
Q = e * int{DOS(E) * [f(E) - f(E + deltaE)] dE}
|
|
C_Q = - dQ/d(deltaE) = - (e / (4*k*T)) * int{DOS(E) * sech^2[(E+deltaE)/(2*k*T)] dE}
|
|
Args:
|
|
dE_Q_arr (np.array, float): Energy shift at which C_Q is calculated
|
|
Returns:
|
|
Quantum capacitance in accordance with energy displacement(s)
|
|
TODO check constants
|
|
"""
|
|
self.check_existence('T')
|
|
self.check_existence('sheet_area')
|
|
|
|
k = 8.617e-5 # eV/K
|
|
|
|
elementary_charge = 1.6e-19 # C
|
|
k_1 = 1.38e-23 # J/K
|
|
const = (1e6 * elementary_charge ** 2) / (4 * k_1 * self.sheet_area) # micro F / cm^2
|
|
|
|
if isinstance(dE_Q_arr, typing.Iterable):
|
|
|
|
C_q_arr = np.zeros_like(dE_Q_arr)
|
|
|
|
for i, dE_Q in enumerate(dE_Q_arr):
|
|
E_2 = self.E - dE_Q # energy range for cosh function
|
|
cosh = np.cosh(E_2 / (2 * k * self.T))
|
|
integrand = (self.DOS / cosh) / cosh
|
|
C_q = (const / self.T) * integrate.simps(integrand, self.E)
|
|
C_q_arr[i] = C_q
|
|
|
|
return C_q_arr
|
|
|
|
def compute_C_total(self, E_diff_arr, add_info=False):
|
|
|
|
sigma_arr = np.zeros_like(E_diff_arr)
|
|
for i, E_diff in tqdm(enumerate(E_diff_arr), total=len(E_diff_arr)):
|
|
sigma_arr[i] = self.compute_sigma(E_diff, sigma_0=sigma_arr[i-1])
|
|
|
|
C_tot_arr = np.zeros_like(E_diff_arr)
|
|
C_Q_arr = np.zeros_like(E_diff_arr)
|
|
|
|
for i, (E_diff, sigma) in enumerate(zip(E_diff_arr, sigma_arr)):
|
|
ind = nearest_array_index(self.sigma_Q_arr, sigma)
|
|
E_step = self.__SIGMA_ACCURACY
|
|
E_start = - self.__SIGMA_RANGE
|
|
dE_Q = E_start + E_step * ind
|
|
C_Q = self.compute_C_quantum([dE_Q])
|
|
C_Q_arr[i] = C_Q[0]
|
|
C_tot = C_Q * self.C_EDL / (C_Q + self.C_EDL)
|
|
C_tot_arr[i] = C_tot
|
|
|
|
if add_info is False:
|
|
return C_tot_arr
|
|
else:
|
|
return C_tot_arr, C_Q_arr, sigma_arr
|
|
|
|
def compute_sigma_EDL(self, dE_EDL):
|
|
"""
|
|
Calculates charge corresponding to the potential drop of -dE_EDL/|e|.
|
|
Takes into account integral capacitance C_EDL
|
|
Args:
|
|
dE_EDL (float, np.array): Electron energy shift due to potential drop
|
|
Returns:
|
|
Charge or Sequence of charges
|
|
"""
|
|
self.check_existence('C_EDL')
|
|
return - self.C_EDL * dE_EDL
|
|
|
|
def compute_sigma_quantum(self, dE_Q_arr):
|
|
"""
|
|
Computes surface charge density induced by depletion or excess of electrons
|
|
|
|
Parameters:
|
|
----------
|
|
dE_Q_arr: np.ndarray, float
|
|
Shift in Fermi level due to quantum capacitance
|
|
|
|
Returns:
|
|
-------
|
|
sigmas: np.ndarray, float
|
|
Computed values (or one value) of surface charge densities
|
|
"""
|
|
|
|
self.check_existence('T')
|
|
self.check_existence('sheet_area')
|
|
|
|
elementary_charge = 1.6e-13 # micro coulomb
|
|
|
|
if isinstance(dE_Q_arr, typing.Iterable):
|
|
y_fermi = self.fermi_func(self.E, self.T)
|
|
|
|
sigmas = []
|
|
|
|
for dE_Q in dE_Q_arr:
|
|
E_2 = self.E - dE_Q # energy range for shifted Fermi_Dirac function
|
|
y_fermi_shifted = self.fermi_func(E_2, self.T)
|
|
integrand = self.DOS * (y_fermi - y_fermi_shifted)
|
|
sigma = (elementary_charge / self.sheet_area) * integrate.simps(integrand, self.E)
|
|
sigmas.append(sigma)
|
|
|
|
return sigmas
|
|
|
|
elif isinstance(dE_Q_arr, numbers.Real):
|
|
y_fermi = self.fermi_func(self.E, self.T)
|
|
|
|
E_2 = self.E - dE_Q_arr # energy range for shifted Fermi_Dirac function
|
|
y_fermi_shifted = self.fermi_func(E_2, self.T)
|
|
integrand = self.DOS * (y_fermi - y_fermi_shifted)
|
|
sigma = (elementary_charge / self.sheet_area) * integrate.simps(integrand, self.E)
|
|
|
|
return sigma
|
|
else:
|
|
raise TypeError(f'Invalid type of dE_Q_arr: {type(dE_Q_arr)}')
|
|
|
|
def compute_sigma(self, E_diff, sigma_0=None):
|
|
|
|
def error_E_diff(sigma, E_diff, sigma_Q_arr):
|
|
ind = nearest_array_index(sigma_Q_arr, sigma)
|
|
dE_Q = E_start + E_step * ind
|
|
dE_EDL = - sigma / self.C_EDL
|
|
dE_total = dE_Q + dE_EDL
|
|
|
|
return (dE_total - E_diff) ** 2
|
|
|
|
for var in ['T', 'l', 'C_EDL']:
|
|
self.check_existence(var)
|
|
|
|
E_step = self.__SIGMA_ACCURACY
|
|
E_start = - self.__SIGMA_RANGE
|
|
if sigma_0 is None:
|
|
sigma_0 = self.__SIGMA_0
|
|
# check if we've already calculated sigma_Q_arr in another run
|
|
if self.sigma_Q_arr is None:
|
|
E_range = np.arange(E_start, -E_start, E_step)
|
|
sigma_Q_arr = self.compute_sigma_quantum(E_range)
|
|
self.sigma_Q_arr = sigma_Q_arr
|
|
else:
|
|
sigma_Q_arr = self.sigma_Q_arr
|
|
|
|
result = minimize(error_E_diff, np.array([sigma_0]), args=(E_diff, sigma_Q_arr))
|
|
sigma = result.x[0]
|
|
|
|
return sigma
|
|
|
|
def compute_distributions(self, V_std, overpot=0, reverse=False, add_info=False):
|
|
"""Computes Fermi-Dirac and Redox species distributions according to Gerischer-Markus formalism
|
|
with Quantum Capacitance
|
|
|
|
Parameters:
|
|
----------
|
|
V_std: float
|
|
Standard potential (vs SHE) of a redox couple (Volts)
|
|
overpot: float, optional
|
|
Overpotential (Volts). It shifts the electrode Fermi energy to -|e|*overpot
|
|
reverse: bool, optional
|
|
If reverse is False the process of electron transfer from electrode to the oxidized state of the
|
|
redox species is considered and vice versa
|
|
add_info: bool, optional
|
|
If False the func returns Fermi-Dirac and Redox species distributions
|
|
If True additionally returns dE_Q (Fermi energy shift due to the quantum capacitance),
|
|
sigma (surface charge) and E_diff (the whole energy shift with respect to the original Fermi level)
|
|
|
|
Returns:
|
|
-------
|
|
y_fermi: np.array
|
|
Fermi-Dirac distribution
|
|
y_redox: np.array
|
|
Redox species distributions
|
|
dE_Q: np.array, optional (if add_info == True)
|
|
Total shift of the Fermi energy due to the Quantum Capacitance
|
|
sigma: np.array, optional (if add_info == True)
|
|
surface charge in microF/cm^2
|
|
E_F_redox: np.array, optional (if add_info == True)
|
|
The sum of two energy displacement of the electrode due to the difference in Fermi level of Redox couple
|
|
and the electrode and overpotential. It splits into dE_Q and dE_EDL
|
|
"""
|
|
|
|
E_F_redox = E_F_SHE_VAC - self.efermi - V_std + self.vacuum_lvl - overpot
|
|
sigma = self.compute_sigma(E_F_redox)
|
|
|
|
ind = nearest_array_index(self.sigma_Q_arr, sigma)
|
|
E_step = self.__SIGMA_ACCURACY
|
|
E_start = - self.__SIGMA_RANGE
|
|
dE_Q = E_start + E_step * ind
|
|
|
|
E_fermi = self.E - dE_Q
|
|
E_DOS_redox = self.E - dE_Q - overpot
|
|
|
|
if reverse:
|
|
y_fermi = 1 - self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_red(E_DOS_redox, self.T, self.l)
|
|
else:
|
|
y_fermi = self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_ox(E_DOS_redox, self.T, self.l)
|
|
|
|
if not add_info:
|
|
return y_fermi, y_redox
|
|
else:
|
|
return y_fermi, y_redox, dE_Q, sigma, E_F_redox
|
|
|
|
def compute_k_HET(self, V_std_pot_arr, overpot_arr, reverse=False, add_info=False):
|
|
"""Computes integral k_HET using Gerischer-Markus formalism with quantum capacitance
|
|
|
|
Parameters:
|
|
----------
|
|
V_std_pot_arr: float, np.ndarray
|
|
A range of varying a standard potential
|
|
overpot_arr: float, np.ndarray
|
|
A range of varying an overpotential
|
|
reverse: bool, optional
|
|
if reverse is False the process of electron transfer from electrode to the oxidized state of the
|
|
redox mediator is considered and vice versa
|
|
|
|
Returns:
|
|
-------
|
|
k_HET: np.array
|
|
Calculated heterogeneous electron transfer rate constant according to Gerischer-Marcus model with quantum
|
|
capacitance
|
|
dE_Q_arr: np.ndarray, optional (if add_info == True)
|
|
Total shift of the Fermi energy due to the Quantum Capacitance for all calculated redox potentials or
|
|
overpotentials
|
|
sigma_arr: np.ndarray, optional (if add_info == True)
|
|
surface charge in microF/cm^2 for all calculated redox potentials or overpotentials
|
|
E_F_redox_arr: np.ndarray, optional (if add_info == True)
|
|
The sum of two energy displacement of the electrode due to the difference in Fermi level of Redox couple
|
|
and the electrode and overpotential. It splits into dE_Q and dE_EDL. For all calculated redox potentials
|
|
or overpotentials
|
|
y_fermi_arr: 2D np.ndarray, optional (if add_info == True)
|
|
Fermi-Dirac distribution for all calculated redox potentials or overpotentials
|
|
y_redox_arr: 2D np.ndarray, optional (if add_info == True)
|
|
Redox species distributions for all calculated redox potentials or overpotentials
|
|
"""
|
|
|
|
if isinstance(self.C_EDL, numbers.Real):
|
|
if isinstance(V_std_pot_arr, typing.Iterable) and isinstance(overpot_arr, numbers.Real):
|
|
k_HET = np.zeros_like(V_std_pot_arr)
|
|
if not add_info:
|
|
for i, V_std in tqdm(enumerate(V_std_pot_arr), total=len(V_std_pot_arr)):
|
|
y_fermi, y_redox = self.compute_distributions(V_std, reverse=reverse, overpot=overpot_arr)
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET[i] = integrate.simps(integrand, self.E) / self.sheet_area
|
|
return k_HET
|
|
else:
|
|
dE_Q_arr = np.zeros_like(V_std_pot_arr)
|
|
sigma_arr = np.zeros_like(V_std_pot_arr)
|
|
E_F_redox_arr = np.zeros_like(V_std_pot_arr)
|
|
y_fermi_arr = np.zeros((len(V_std_pot_arr), len(self.E)))
|
|
y_redox_arr = np.zeros((len(V_std_pot_arr), len(self.E)))
|
|
for i, V_std in tqdm(enumerate(V_std_pot_arr), total=len(V_std_pot_arr)):
|
|
y_fermi, y_redox, dE_Q, sigma, E_F_redox = self.compute_distributions(V_std, reverse=reverse,
|
|
overpot=overpot_arr,
|
|
add_info=add_info)
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET[i] = integrate.simps(integrand, self.E) / self.sheet_area
|
|
dE_Q_arr[i] = dE_Q
|
|
sigma_arr[i] = sigma
|
|
E_F_redox_arr[i] = E_F_redox
|
|
y_fermi_arr[i] = y_fermi
|
|
y_redox_arr[i] = y_redox
|
|
return k_HET, dE_Q_arr, sigma_arr, E_F_redox_arr, y_fermi_arr, y_redox_arr
|
|
|
|
elif isinstance(overpot_arr, typing.Iterable) and isinstance(V_std_pot_arr, numbers.Real):
|
|
k_HET = np.zeros_like(overpot_arr)
|
|
if not add_info:
|
|
for i, overpot in tqdm(enumerate(overpot_arr), total=len(overpot_arr)):
|
|
y_fermi, y_redox = self.compute_distributions(V_std_pot_arr, reverse=reverse, overpot=overpot)
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET[i] = integrate.simps(integrand, self.E) / self.sheet_area
|
|
|
|
return k_HET
|
|
else:
|
|
dE_Q_arr = np.zeros_like(overpot_arr)
|
|
sigma_arr = np.zeros_like(overpot_arr)
|
|
E_F_redox_arr = np.zeros_like(overpot_arr)
|
|
y_fermi_arr = np.zeros((len(overpot_arr), len(self.E)))
|
|
y_redox_arr = np.zeros((len(overpot_arr), len(self.E)))
|
|
for i, overpot in tqdm(enumerate(overpot_arr), total=len(overpot_arr)):
|
|
y_fermi, y_redox, dE_Q, sigma, E_F_redox = self.compute_distributions(V_std_pot_arr,
|
|
reverse=reverse,
|
|
overpot=overpot,
|
|
add_info=add_info)
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET[i] = integrate.simps(integrand, self.E) / self.sheet_area
|
|
dE_Q_arr[i] = dE_Q
|
|
sigma_arr[i] = sigma
|
|
E_F_redox_arr[i] = E_F_redox
|
|
y_fermi_arr[i] = y_fermi
|
|
y_redox_arr[i] = y_redox
|
|
return k_HET, dE_Q_arr, sigma_arr, E_F_redox_arr, y_fermi_arr, y_redox_arr
|
|
|
|
else:
|
|
raise ValueError('One and only one type of V_std_pot_arr and overpot arr must be Sequence. The other \
|
|
must be a Real number')
|
|
|
|
elif self.C_EDL == 'Cl':
|
|
if isinstance(V_std_pot_arr, typing.Iterable) and isinstance(overpot_arr, numbers.Real):
|
|
E_fermi = self.E
|
|
E_DOS_redox = self.E - overpot_arr
|
|
|
|
if reverse:
|
|
y_fermi = 1 - self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_red(E_DOS_redox, self.T, self.l)
|
|
else:
|
|
y_fermi = self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_ox(E_DOS_redox, self.T, self.l)
|
|
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET = np.ones_like(V_std_pot_arr) * integrate.simps(integrand, self.E)
|
|
|
|
return k_HET
|
|
|
|
elif isinstance(overpot_arr, typing.Sequence) and isinstance(V_std_pot_arr, numbers.Real):
|
|
k_HET = np.zeros_like(overpot_arr)
|
|
|
|
for i, overpot in tqdm(enumerate(overpot_arr), total=len(overpot_arr)):
|
|
E_fermi = self.E
|
|
E_DOS_redox = self.E - overpot
|
|
|
|
if reverse:
|
|
y_fermi = 1 - self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_red(E_DOS_redox, self.T, self.l)
|
|
else:
|
|
y_fermi = self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_ox(E_DOS_redox, self.T, self.l)
|
|
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET[i] = integrate.simps(integrand, self.E)
|
|
|
|
return k_HET
|
|
|
|
else:
|
|
raise ValueError('One and only one type of V_std_pot_arr and overpot arr must be Sequence. The other \
|
|
must be Real number')
|
|
|
|
elif self.C_EDL == 'Q':
|
|
if isinstance(V_std_pot_arr, typing.Iterable) and isinstance(overpot_arr, numbers.Real):
|
|
k_HET = np.zeros_like(V_std_pot_arr)
|
|
|
|
for i, V_std in tqdm(enumerate(V_std_pot_arr), total=len(V_std_pot_arr)):
|
|
E_F_redox = E_F_SHE_VAC - self.efermi - V_std + self.vacuum_lvl
|
|
E_DOS_redox = self.E - E_F_redox
|
|
E_fermi = E_DOS_redox - overpot_arr
|
|
|
|
if reverse:
|
|
y_fermi = 1 - self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_red(E_DOS_redox, self.T, self.l)
|
|
else:
|
|
y_fermi = self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_ox(E_DOS_redox, self.T, self.l)
|
|
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET[i] = integrate.simps(integrand, self.E)
|
|
|
|
return k_HET
|
|
|
|
elif isinstance(overpot_arr, typing.Iterable) and isinstance(V_std_pot_arr, numbers.Real):
|
|
k_HET = np.zeros_like(overpot_arr)
|
|
|
|
for i, overpot in tqdm(enumerate(overpot_arr), total=len(overpot_arr)):
|
|
E_F_redox = E_F_SHE_VAC - self.efermi - V_std_pot_arr + self.vacuum_lvl - overpot
|
|
E_fermi = self.E - E_F_redox
|
|
E_DOS_redox = self.E - E_F_redox - overpot
|
|
|
|
if reverse:
|
|
y_fermi = 1 - self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_red(E_DOS_redox, self.T, self.l)
|
|
else:
|
|
y_fermi = self.fermi_func(E_fermi, self.T)
|
|
y_redox = self.W_ox(E_DOS_redox, self.T, self.l)
|
|
|
|
integrand = self.DOS * y_fermi * y_redox
|
|
k_HET[i] = integrate.simps(integrand, self.E)
|
|
|
|
return k_HET
|
|
|
|
else:
|
|
raise ValueError('One and only one type of V_std_pot_arr and overpot arr must be Sequence. The other \
|
|
must be Real number')
|