Source code for CADMium.pssolver.pssolver
"""
pssolver.py
"""
import numpy as np
from scipy.sparse import spdiags
from pydantic import BaseModel
from .calc_orbitals import calc_orbitals
from .calc_density import calc_density
from .calc_energy import calc_energy
from .calc_response import calc_response
from .iter_orbitals import iter_orbitals
from .normalize_orbitals import normalize_orbitals
from .get_homo import get_homo
from .calc_ked_WFI import calc_ked_WFI
from .get_ked_WFI import get_ked_WFI
eps = np.finfo(float).eps
class SolverOptions(BaseModel):
fractional : bool = False
sym : bool = False
iter_lin_solver : bool = True
disp : bool = True
tol_orbital : float = 1e-15
tol_lin_solver : float = 1e-4
[docs]def Pssolver(grid, Nmo, N, optSolver={}):
"""
Generates an array of solvers of shape Nmo[0]xNmo[1]
"""
Nmo = np.array(Nmo)
N = np.array(N)
solver = np.empty((Nmo.shape[0], Nmo.shape[1]), dtype=object)
for i in range(Nmo.shape[0]):
for j in range(Nmo.shape[1]):
solver[i,j] = i_solver(grid, Nmo[i,j], N[i,j],
i, Nmo.shape[1], optSolver)
return solver
class i_solver():
"""
Keeps track of eigenvalues/vectors and constructs densities and responses.
"""
def __init__(self, grid, Nmo, N,
Nlvls, pol, optSolver):
optSolver = {k.lower(): v for k, v in optSolver.items()}
for i in optSolver.keys():
if i not in SolverOptions().dict().keys():
raise ValueError(f"{i} is not a valid option for KohnSham")
optSolver = SolverOptions(**optSolver)
self.optSolver = optSolver
self.grid = grid
self.Nmo = Nmo
self.N = N
#Polarization of electrons handled by this solver
self.pol = pol
self.veff = None # Effective potential
self.H0 = None # Base Hamiltonian
self.phi = None # Molecular Orbitals
self.eig = None # Eigenvalues
self.e0 = -20 # Estimate of lowest energy value
self.eks = None # KohnSham energy
self.Vs = None # Kohn Sham potential
self.Ts = None # Kohn Sham kinetic energy
self.n = None # Electron density
self.chi = None # Change in density from given change in potential
self.homo = None # Highest occupied Molecular Orbital
#kinetic energy densities | Not uniquely defined
self.ked_WFI = None #Use laplacian
self.kedWFII = None #Use gradient
self.v0 = np.ones(self.grid.Nelem)
# self.default_e0 = -20.0
self.opt = {"tol" : 1e-16, "v0":np.ones((self.grid.Nelem, 1))}
self.Nlvls = Nlvls
self.pol = pol
if self.N == -1:
if self.polarization == 1:
self.N = 2 * self.Nmo
else:
self.N = self.Nmo
self.m = Nlvls
def hamiltonian(self):
"""
Construct basic Hamiltonian H_0
Includes effective potential due to angular momentum around bond axis
"""
Nelem = self.grid.Nelem
#Inverse volume element and angular momentum potential
W = spdiags(data=self.grid.w, diags=0, m=Nelem, n=Nelem)
f = spdiags(data=self.grid.f, diags=0, m=Nelem, n=Nelem)
#Choose the correct symmetry for m
if np.mod(self.m, 2) == 0:
#Even symmetry
eT = -0.5 * self.grid.elap
self.H0 = eT + self.m ** 2 * W @ f
else:
#Odd symmetry
oT = -0.5 * self.grid.olap
self.H0 = oT + self.m ** 2 * W @ f
def calc_orbitals(self, solver_id=None, return_dict=None):
calc_orbitals(self, solver_id, return_dict)
def calc_response(self):
calc_response(self)
def iter_orbitals(self, solver_id=None, return_dict=None):
iter_orbitals(self, solver_id, return_dict)
def normalize_orbitals(self):
normalize_orbitals(self)
def calc_density(self):
calc_density(self)
def calc_energy(self):
calc_energy(self)
def get_homo(self):
homo = get_homo(self)
return homo
def get_ked_WFI(self):
ked = get_ked_WFI(self)
def calc_ked_WFI(self):
calc_ked_WFI(self)
# def get_Ts(self):
# """
# Get total kinetic energy
# """
# Ts = 0.0
# self.calc_energy()
# for i in range(self.solver.shape[0]):
# for j in range(self.solver.shape[1]):
# Ts += np.sum( self.solver[i,j].Ts )
def setveff(self, veff):
"""
Distribute effective potential to solver object
Size of Potential array should match polarization
Assert solver(0).pol == len(veff, 1)
"""
self.veff = veff