From 6bcbbdc87eb6c9ad3b141b1be014994167d65880 Mon Sep 17 00:00:00 2001 From: Antonio Manesco <am@antoniomanesco.org> Date: Thu, 21 Dec 2023 20:22:50 +0100 Subject: [PATCH] create solvers and interface modules Co-authored-by: RonjaZijd <RonjaZijd@users.noreply.github.com> --- codes/hf.py | 143 --------------------------------------------- codes/interface.py | 50 ++++++++++++++++ codes/solvers.py | 97 ++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 143 deletions(-) create mode 100644 codes/interface.py create mode 100644 codes/solvers.py diff --git a/codes/hf.py b/codes/hf.py index 01c6245..af103d3 100644 --- a/codes/hf.py +++ b/codes/hf.py @@ -1,7 +1,6 @@ from scipy.ndimage import convolve import numpy as np import codes.utils as utils -from scipy import optimize def density_matrix(vals, vecs, E_F, dim): """ @@ -158,145 +157,3 @@ def updated_matrices(mf_k, model): H_int=model.H_int, dim=model.dim) - E_F * np.eye(model.hamiltonians_0.shape[-1]) -def finite_system_solver(model, optimizer, optimizer_kwargs): - """ - Real-space solver for finite systems. - - Parameters: - ----------- - model : model.Model - Physical model containting interacting and non-interacting Hamiltonian. - optimizer : function - Optimization function. - optimizer_kwargs : dict - Extra arguments passed to optimizer. - """ - mf = model.guess[()] - shape = mf.shape - - def cost_function(mf): - mf = utils.flat_to_matrix(utils.real_to_complex(mf), shape) - model.rho, model.mf_k = updated_matrices(mf_k=mf, model=model) - delta_mf = model.mf_k - mf - return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) - - _ = optimizer( - cost_function, - utils.complex_to_real(utils.matrix_to_flat(mf)), - **optimizer_kwargs - ) - -def rspace_solver(model, optimizer, optimizer_kwargs): - """ - Real-space solver for infinite systems. - - Parameters: - ----------- - model : model.Model - Physical model containting interacting and non-interacting Hamiltonian. - optimizer : function - Optimization function. - optimizer_kwargs : dict - Extra arguments passed to optimizer. - """ - model.kgrid_evaluation(nk=model.nk) - mf = np.array([*model.guess.values()]) - shape = mf.shape - - def cost_function(mf): - mf = utils.flat_to_matrix(utils.real_to_complex(mf), shape) - mf_dict = {} - for i, key in enumerate(model.guess.keys()): - mf_dict[key] = mf[i] - mf = utils.kgrid_hamiltonian( - nk=model.nk, - hk=utils.model2hk(mf_dict), - dim=model.dim, - hermitian=False - ) - model.rho, model.mf_k = updated_matrices(mf_k=mf, model=model) - model.energy = total_energy(h=model.hamiltonians_0 + model.mf_k, rho=model.rho) - delta_mf = model.mf_k - mf - delta_mf = utils.hk2tb_model(delta_mf, model.vectors, model.ks) - delta_mf = np.array([*delta_mf.values()]) - return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) - - _ = optimizer( - cost_function, - utils.complex_to_real(utils.matrix_to_flat(mf)), - **optimizer_kwargs - ) - - -def kspace_solver(model, optimizer, optimizer_kwargs): - """ - k-space solver. - - Parameters: - ----------- - model : model.Model - Physical model containting interacting and non-interacting Hamiltonian. - optimizer : function - Optimization function. - optimizer_kwargs : dict - Extra arguments passed to optimizer. - """ - model.kgrid_evaluation(nk=model.nk) - def cost_function(mf): - mf = utils.flat_to_matrix(utils.real_to_complex(mf), model.mf_k.shape) - model.rho, model.mf_k = updated_matrices(mf_k=mf, model=model) - model.energy = total_energy(h=model.hamiltonians_0 + model.mf_k, rho=model.rho) - delta_mf = model.mf_k - mf - return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) - - _ = optimizer( - cost_function, - utils.complex_to_real(utils.matrix_to_flat(model.mf_k)), - **optimizer_kwargs - ) - -def find_groundstate_ham( - model, - cutoff_Vk, - filling, - nk=10, - solver=kspace_solver, - optimizer=optimize.anderson, - optimizer_kwargs={'M':0, 'verbose': False}, -): - """ - Self-consistent loop to find groundstate Hamiltonian. - - Parameters: - ----------- - tb_model : dict - Tight-binding model. Must have the following structure: - - Keys are tuples for each hopping vector (in units of lattice vectors). - - Values are hopping matrices. - filling: int - Number of electrons per cell. - guess : nd-array - Initial guess. Same format as `H_int`. - return_mf : bool - Returns mean-field result. Useful if wanted to reuse as guess in upcoming run. - - Returns: - -------- - scf_model : dict - Tight-binding model of Hartree-Fock solution. - """ - model.nk=nk - model.filling=filling - if model.int_model is not None: - model.vectors=[*model.int_model.keys()] - else: - model.vectors = utils.generate_vectors(cutoff_Vk, model.dim) - if model.guess is None: - model.random_guess(model.vectors) - solver(model, optimizer, optimizer_kwargs) - model.vectors=[*model.vectors, *model.tb_model.keys()] - assert np.allclose((model.mf_k - np.moveaxis(model.mf_k, -1, -2).conj())/2, 0, atol=1e-15) - if model.dim > 0: - return utils.hk2tb_model(model.hamiltonians_0 + model.mf_k, model.vectors, model.ks) - else: - return {() : model.hamiltonians_0 + model.mf_k} diff --git a/codes/interface.py b/codes/interface.py new file mode 100644 index 0000000..cb45810 --- /dev/null +++ b/codes/interface.py @@ -0,0 +1,50 @@ +from scipy import optimize +from . import utils, solvers +import numpy as np + +def find_groundstate_ham( + model, + cutoff_Vk, + filling, + nk=10, + solver=solvers.kspace_solver, + cost_function=solvers.kspace_cost, + optimizer=optimize.anderson, + optimizer_kwargs={'M':0, 'verbose': False}, +): + """ + Self-consistent loop to find groundstate Hamiltonian. + + Parameters: + ----------- + tb_model : dict + Tight-binding model. Must have the following structure: + - Keys are tuples for each hopping vector (in units of lattice vectors). + - Values are hopping matrices. + filling: int + Number of electrons per cell. + guess : nd-array + Initial guess. Same format as `H_int`. + return_mf : bool + Returns mean-field result. Useful if wanted to reuse as guess in upcoming run. + + Returns: + -------- + scf_model : dict + Tight-binding model of Hartree-Fock solution. + """ + model.nk=nk + model.filling=filling + if model.int_model is not None: + model.vectors=[*model.int_model.keys()] + else: + model.vectors = utils.generate_vectors(cutoff_Vk, model.dim) + if model.guess is None: + model.random_guess(model.vectors) + solver(model, optimizer, cost_function, optimizer_kwargs) + model.vectors=[*model.vectors, *model.tb_model.keys()] + assert np.allclose((model.mf_k - np.moveaxis(model.mf_k, -1, -2).conj())/2, 0, atol=1e-15) + if model.dim > 0: + return utils.hk2tb_model(model.hamiltonians_0 + model.mf_k, model.vectors, model.ks) + else: + return {() : model.hamiltonians_0 + model.mf_k} diff --git a/codes/solvers.py b/codes/solvers.py new file mode 100644 index 0000000..cab61ae --- /dev/null +++ b/codes/solvers.py @@ -0,0 +1,97 @@ +import numpy as np +from . import utils +from .hf import updated_matrices +from functools import partial + +def optimize(mf, cost_function, optimizer, optimizer_kwargs): + _ = optimizer( + cost_function, + mf, + **optimizer_kwargs + ) + +def finite_system_cost(mf, model): + shape = mf.shape + mf = utils.flat_to_matrix(utils.real_to_complex(mf), shape) + model.rho, model.mf_k = updated_matrices(mf_k=mf, model=model) + delta_mf = model.mf_k - mf + return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) + +def finite_system_solver(model, optimizer, cost_function, optimizer_kwargs): + """ + Real-space solver for finite systems. + + Parameters: + ----------- + model : model.Model + Physical model containting interacting and non-interacting Hamiltonian. + optimizer : function + Optimization function. + optimizer_kwargs : dict + Extra arguments passed to optimizer. + """ + initial_mf = model.guess[()] + partial_cost = partial(cost_function, model=model) + optimize(initial_mf, partial_cost, optimizer, optimizer_kwargs) + +def real_space_cost(mf, model): + shape = mf.shape + mf = utils.flat_to_matrix(utils.real_to_complex(mf), shape) + mf_dict = {} + for i, key in enumerate(model.guess.keys()): + mf_dict[key] = mf[i] + mf = utils.kgrid_hamiltonian( + nk=model.nk, + hk=utils.model2hk(mf_dict), + dim=model.dim, + hermitian=False + ) + model.rho, model.mf_k = updated_matrices(mf_k=mf, model=model) + delta_mf = model.mf_k - mf + delta_mf = utils.hk2tb_model(delta_mf, model.vectors, model.ks) + delta_mf = np.array([*delta_mf.values()]) + return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) + +def rspace_solver(model, optimizer, cost_function, optimizer_kwargs): + """ + Real-space solver for infinite systems. + + Parameters: + ----------- + model : model.Model + Physical model containting interacting and non-interacting Hamiltonian. + optimizer : function + Optimization function. + optimizer_kwargs : dict + Extra arguments passed to optimizer. + """ + model.kgrid_evaluation(nk=model.nk) + initial_mf = np.array([*model.guess.values()]) + initial_mf = utils.complex_to_real(utils.matrix_to_flat(initial_mf)) + partial_cost = partial(cost_function, model=model) + optimize(initial_mf, partial_cost, optimizer, optimizer_kwargs) + +def kspace_cost(mf, model): + mf = utils.flat_to_matrix(utils.real_to_complex(mf), model.mf_k.shape) + model.rho, model.mf_k = updated_matrices(mf_k=mf, model=model) + delta_mf = model.mf_k - mf + return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) + +def kspace_solver(model, optimizer, cost_function, optimizer_kwargs): + """ + k-space solver. + + Parameters: + ----------- + model : model.Model + Physical model containting interacting and non-interacting Hamiltonian. + optimizer : function + Optimization function. + optimizer_kwargs : dict + Extra arguments passed to optimizer. + """ + model.kgrid_evaluation(nk=model.nk) + initial_mf = model.mf_k + initial_mf = utils.complex_to_real(utils.matrix_to_flat(initial_mf)) + partial_cost = partial(cost_function, model=model) + optimize(initial_mf, partial_cost, optimizer, optimizer_kwargs) \ No newline at end of file -- GitLab