Skip to content

Commit

Permalink
Updated DefectAtSite class
Browse files Browse the repository at this point in the history
  • Loading branch information
bjmorgan committed Jul 4, 2021
1 parent ee29519 commit e2bb2a5
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 114 deletions.
80 changes: 48 additions & 32 deletions pyscses/defect_at_site.py
Original file line number Diff line number Diff line change
@@ -1,90 +1,106 @@
from __future__ import annotations
import math
from pyscses.constants import boltzmann_eV
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pyscses.site import Site

class Defect_at_Site:
class DefectAtSite:

"""
The Defect_at_Site class contains the information about each defect at each site, its valence, mole fraction and the segregation energy for that defect at that site.
The DefectAtSite class contains the information about each defect at each site, its valence, mole fraction and the segregation energy for that defect at that site.
The methods in this class combine to give the correct statistics for site occupation in solid electrolytes, derived from the electrochemical potentials of a Fermi-Dirac like distribution. This term has been split into three functions for simplicity. The resulting equations take into account that the probability that a site is occupied by a defect can not exceed 1, and also accounts for competition of like charged defects.
The methods in this class combine to give the correct statistics for site occupation in solid electrolytes, derived from the electrochemical potentials of a Fermi-Dirac like distribution. This term has been split into three functions for simplicity. The resulting equations take into account that the probability that a site is occupied by a defect can not exceed 1, and also accounts for competition of like charged defects.
A Mott-Schottky approximation can be enforced. The defects can be fixed to their bulk mole fractions throughout the system, equivalent to assuming that the defects are immobile and not allowed to redistribute through the system.
Attributes:
label (string): string describing the defect species i.e. 'Vo' for an oxygen vacancy.
label (string): string describing the defect species i.e. 'Vo' for an oxygen vacancy.
valence (float): The charge of the defect, in atomic units.
mole_fraction (float): The bulk mole fraction of the defect present in the system.
mobility (float): The bulk mobility of the defect species. Default = 0.0.
energy (float): The segregation energy for the defect when occupying the respective site.
site (:obj:`Site`): The pyscses.Site object that corresponding to each defect at each x coordinate.
fixed (bool): set whether this defect species can redistribute to an equilibrium distriution. Default=False.
mole_fraction (float): The bulk mole fraction of the defect present in the system.
mobility (float): The bulk mobility of the defect species. Default = 0.0. TODO Where is this default mobility set?
energy (float): The segregation energy for the defect when occupying the respective site.
site (:obj:`Site`): The pyscses.Site object that corresponding to each defect at each x coordinate.
fixed (bool): set whether this defect species can redistribute to an equilibrium distribution. Default=False.
"""
def __init__( self, label, valence, mole_fraction, mobility, energy, site, fixed = False ):
def __init__(self,
label: str,
valence: float,
mole_fraction: float,
mobility: float,
energy: float,
site: Site,
fixed: bool = False) -> None:
self.label = label
self.valence = valence
self.mole_fraction = mole_fraction
self.mobility = mobility
self.energy = energy
self.site = site
self.fixed = fixed

self.fixed = fixed

def potential_energy( self, phi ):
def potential_energy(self,
phi: float) -> float:
"""
Potential energy for the defect at this site.
Args:
phi (float): electrostatic potential at this site
phi (float): electrostatic potential at this site.
Returns:
float: The electrochemical potential.
"""
return ( phi * self.valence ) + self.energy

return (phi * self.valence) + self.energy

def boltzmann_one(self, phi, temp):
def boltzmann_one(self,
phi: float,
temp: float) -> float:
r"""Boltzmann statistics calculation - part one
.. math:: \exp\left(\frac{\Phi z+\Delta E}{k_BT}\right)
.. math:: \exp\left(\frac{-\Phi z+\Delta E}{k_BT}\right)
Args:
phi (float): Electrostatic potential.
temp (float): Temperature in Kelvin.
Returns:
float: Boltzmann factor.
"""
return math.exp(-self.potential_energy(phi) / (boltzmann_eV * temp))

def boltzmann_two( self, phi, temp ):
def boltzmann_two(self,
phi: float,
temp: float) -> float:
r"""Boltzmann statistics calculation - part two
.. math:: x\exp\left(\frac{\Phi z+\Delta E}{K_BT}\right)
.. math:: x\exp\left(\frac{-\Phi z+\Delta E}{K_BT}\right)
Args:
phi (float): Electrostatic potential.
temp (float): Temperature of calculation.
Returns:
float: Boltzmann statistics * mole fraction
"""
return self.mole_fraction * self.boltzmann_one( phi, temp )
return self.mole_fraction * self.boltzmann_one(phi, temp)

def boltzmann_three( self, phi, temp ):
def boltzmann_three(self,
phi: float,
temp: float) -> float:
r"""Boltzmann statistics calculation - part three
.. math:: x\left(\exp\left(\frac{\Phi z+\Delta E}{K_BT}\right)-1\right)
.. math:: x\left(\exp\left(-\frac{\Phi z+\Delta E}{K_BT}\right)-1\right)
Args:
phi (float): Electrostatic potential.
temp (float): Temperature of calculation.
Returns:
float: ( Boltzmann statistics - 1 ) * mole fraction.
"""
return self.mole_fraction * ( self.boltzmann_one( phi, temp ) - 1.0 )
return self.mole_fraction * (self.boltzmann_one(phi, temp) - 1.0)
145 changes: 76 additions & 69 deletions pyscses/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
from pyscses.constants import boltzmann_eV
from bisect import bisect_left
from scipy.interpolate import griddata # type: ignore
from pyscses.grid_point import GridPoint

def phi_at_x( phi, coordinates, x ):
def phi_at_x(phi: np.ndarray,
coordinates: np.ndarray,
x: float) -> float:
"""
Assigns each site x coordinate a grid point and returns the electrostatic potential at the grid point clostest to the x coordinate.
Expand All @@ -14,13 +17,15 @@ def phi_at_x( phi, coordinates, x ):
x (float): Site x coordinate.
Returns:
phi[index] (float): The electrostatic potential at the x coordinate with position [index].
float: The electrostatic potential at the x coordinate with position [index].
"""

index = index_of_grid_at_x( coordinates, x )
return phi[ index ]
index = index_of_grid_at_x(coordinates, x)
return phi[index]

def energy_at_x( energy, coordinates, x ):
def energy_at_x(energy: np.ndarray,
coordinates: np.ndarray,
x: float) -> float:
"""
Assigns each site x coordinate a grid point and returns the segregation energy at the grid point clostest to the x coordinate.
Expand All @@ -30,13 +35,14 @@ def energy_at_x( energy, coordinates, x ):
x (float): Site x coordinate.
Returns:
energy[index] (float): The segregation energy at the x coordinate with position [index].
float: The segregation energy at the x coordinate with position [index].
"""

index = index_of_grid_at_x( coordinates, x )
return energy[ index ]
index = index_of_grid_at_x(coordinates, x)
return energy[index]

def index_of_grid_at_x( coordinates, x ):
def index_of_grid_at_x(coordinates: np.ndarray,
x: float) -> int:
"""
Assigns each site x coordinate to a position on a regularly or irregularly spaced grid.
Returns the index of the grid point clostest to the value x
Expand All @@ -48,9 +54,10 @@ def index_of_grid_at_x( coordinates, x ):
Returns:
closest_index (int): Index of grid position closest to the site x coordinate.
"""
return closest_index( coordinates, x )
return closest_index(coordinates, x)

def closest_index(myList, myNumber):
def closest_index(myList: np.ndarray,
myNumber: float) -> int:
"""
Assumes myList is sorted. Returns index of closest value to myNumber.
If two numbers are equally close, return the index of the smallest number.
Expand All @@ -62,7 +69,7 @@ def closest_index(myList, myNumber):
Returns:
pos (int): Index of position of number in myList which is closest to myNumber.
"""
pos = bisect_left(myList, myNumber)
pos = bisect_left(list(myList), myNumber)
if pos == 0:
return 0
if pos == len(myList):
Expand All @@ -89,61 +96,61 @@ def delta_x_from_grid( coordinates, limits ):
delta_x = np.insert( delta_x, len(delta_x), limits[1] )
return delta_x

class Grid_Point:
""" The Grid_Point class contains the information and calculations for each grid point individually """

def __init__( self, x, volume ):
"""
x (float): x coordinate of grid point.
volume (float): volume of site at grid point.
sites (list): defect sites at grid point.
"""
self.x = x
self.volume = volume
self.sites = []

def average_site_energy( self, method = 'mean' ):
"""
Returns the average segregation energy for all sites based on a specified method
Args:
method (str): The method in which the average segregation energies will be calculated.
'mean' - Returns the sum of all values at that site divided by the number of values at that site.
'min' - Returns the minimum segregation energy value for that site (appropriate for low temperature calculations).
Returns:
average site energies (np.array): Average segregation energies on a 1D grid.
"""

if self.sites:
return avg( np.array( [ s.energies() for s in self.sites ] ), method )
else:
return [None]

def avg( energies, method = 'mean' ):
"""
Returns the average segregation energy for a site based on a specified method
Args:
energies (np.array): Segregation energies on 1D grid.
method (str): The method in which the average segregation energies will be calculated.
'mean' - Returns the sum of all values at that site divided by the number of values at that site.
'min' - Returns the minimum segregation energy value for that site (appropriate for low temperature calculations).
Returns:
average site energies (np.array): Average segregation energies on a 1D grid.
"""

if method == 'mean':
return [ np.mean( row ) for row in energies.T ]
elif method == 'min':
return [ np.min( row ) for row in energies.T ]
else:
raise ValueError( "method: {}".format( method ) )
# class Grid_Point:
# """ The Grid_Point class contains the information and calculations for each grid point individually """
#
# def __init__( self, x, volume ):
# """
# x (float): x coordinate of grid point.
# volume (float): volume of site at grid point.
# sites (list): defect sites at grid point.
# """
# self.x = x
# self.volume = volume
# self.sites = []
#
# def average_site_energy( self, method = 'mean' ):
# """
#
# Returns the average segregation energy for all sites based on a specified method
#
# Args:
# method (str): The method in which the average segregation energies will be calculated.
# 'mean' - Returns the sum of all values at that site divided by the number of values at that site.
# 'min' - Returns the minimum segregation energy value for that site (appropriate for low temperature calculations).
#
# Returns:
# average site energies (np.array): Average segregation energies on a 1D grid.
#
# """
#
# if self.sites:
# return avg( np.array( [ s.energies() for s in self.sites ] ), method )
# else:
# return [None]
#
# def avg( energies, method = 'mean' ):
# """
#
# Returns the average segregation energy for a site based on a specified method
#
# Args:
# energies (np.array): Segregation energies on 1D grid.
# method (str): The method in which the average segregation energies will be calculated.
# 'mean' - Returns the sum of all values at that site divided by the number of values at that site.
# 'min' - Returns the minimum segregation energy value for that site (appropriate for low temperature calculations).
#
# Returns:
# average site energies (np.array): Average segregation energies on a 1D grid.
#
# """
#
# if method == 'mean':
# return [ np.mean( row ) for row in energies.T ]
# elif method == 'min':
# return [ np.min( row ) for row in energies.T ]
# else:
# raise ValueError( "method: {}".format( method ) )

class Grid:
def __init__( self, x_coordinates, b, c, limits, limits_for_laplacian, set_of_sites):
Expand All @@ -154,7 +161,7 @@ def __init__( self, x_coordinates, b, c, limits, limits_for_laplacian, set_of_si
Args:
delta_x (np.array): Distance between the midpoint of each consecutive grid point.
volumes (np.array): Volume of each consecutive grid point.
points (list): Grid_Point object at each grid point in Grid.
points (list): GridPoint object at each grid point in Grid.
x (np.array): The x-coordinates for each grid point.
limits(list): distance between the midpoint of the endmost sites and the midpoint of the next site outside of the calculation region for the first and last sites respectively.
limits_for_laplacian(list): distance between the endmost sites and the next site outside of the calculation region for the first and last sites respectively.
Expand All @@ -168,7 +175,7 @@ def __init__( self, x_coordinates, b, c, limits, limits_for_laplacian, set_of_si
"""
self.delta_x = delta_x_from_grid( x_coordinates, limits )
self.volumes = self.delta_x * b * c
self.points = [ Grid_Point( x, v ) for x, v in zip( x_coordinates, self.volumes ) ]
self.points = [GridPoint(x, v) for x, v in zip(x_coordinates, self.volumes)]
self.x = x_coordinates
self.limits = limits
self.limits_for_laplacian = limits_for_laplacian
Expand Down
Loading

0 comments on commit e2bb2a5

Please sign in to comment.