From 9c0f6cf7b2bfb6ebf93192d72f090dcbf6e28c2b Mon Sep 17 00:00:00 2001 From: Antonio Manesco <am@antoniomanesco.org> Date: Wed, 20 Dec 2023 12:07:31 +0100 Subject: [PATCH] adapt for finite-size systems --- codes/hf.py | 60 +++++++++++++++++++++++++++++++++++++++++--------- codes/model.py | 15 ++++++++----- codes/utils.py | 3 +++ 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/codes/hf.py b/codes/hf.py index 713345c..ce3cbb7 100644 --- a/codes/hf.py +++ b/codes/hf.py @@ -4,7 +4,7 @@ import codes.utils as utils from functools import partial from scipy import optimize -def density_matrix(vals, vecs, E_F): +def density_matrix(vals, vecs, E_F, dim): """ Returns the mean field F_ij(k) = <psi_i(k)|psi_j(k)> for all k-points and eigenvectors below the Fermi level. @@ -24,7 +24,6 @@ def density_matrix(vals, vecs, E_F): Density matrix rho=rho[kx, ky, ..., i, j] where i,j are cell indices. """ norbs = vals.shape[-1] - dim = len(vals.shape) - 1 nk = vals.shape[0] if dim > 0: @@ -81,7 +80,7 @@ def convolution(M1, M2): return V_output -def compute_mf(rho, H_int): +def compute_mf(rho, H_int, dim): """ Compute mean-field correction at self-consistent loop. @@ -99,7 +98,6 @@ def compute_mf(rho, H_int): """ nk = rho.shape[0] - dim = len(rho.shape) - 2 if dim > 0: H0_int = H_int[*([0]*dim)] @@ -155,8 +153,45 @@ def updated_matrices(mf_k, model): vals, vecs = np.linalg.eigh(hamiltonians) vecs = np.linalg.qr(vecs)[0] E_F = utils.get_fermi_energy(vals, model.filling) - rho = density_matrix(vals=vals, vecs=vecs, E_F=E_F) - return rho, compute_mf(rho=rho, H_int=model.H_int) - E_F * np.eye(model.hamiltonians_0.shape[-1]) + rho = density_matrix(vals=vals, vecs=vecs, E_F=E_F, dim=model.dim) + return rho, compute_mf( + rho=rho, + 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): + """ + Default cost function. + + Parameters: + ----------- + mf : nd-array + Mean-field correction evaluated on a k-point grid. + model : Model + Physical model. + + Returns: + -------- + cost : nd-array + Array with same shape as input. Is chosen to be the largest value between: + * Difference between intial and final mean-field correction. + * Non-hermitian part of the mean-field correction. + * The commutator between the mean-field Hamiltonian and density matrix. + """ + 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): """ @@ -197,11 +232,11 @@ def rspace_solver(model, optimizer, optimizer_kwargs): 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.matrix_to_flat(utils.complex_to_real(delta_mf)) + return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) _ = optimizer( cost_function, - utils.matrix_to_flat(utils.complex_to_real(mf)), + utils.complex_to_real(utils.matrix_to_flat(mf)), **optimizer_kwargs ) @@ -231,11 +266,11 @@ def kspace_solver(model, optimizer, optimizer_kwargs): 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.matrix_to_flat(utils.complex_to_real(delta_mf)) + return utils.complex_to_real(utils.matrix_to_flat(delta_mf)) _ = optimizer( cost_function, - utils.matrix_to_flat(utils.complex_to_real(model.mf_k)), + utils.complex_to_real(utils.matrix_to_flat(model.mf_k)), **optimizer_kwargs ) @@ -282,4 +317,7 @@ def find_groundstate_ham( 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) - return utils.hk2tb_model(model.hamiltonians_0 + model.mf_k, model.vectors, model.ks) + 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/model.py b/codes/model.py index e48086a..7eeacda 100644 --- a/codes/model.py +++ b/codes/model.py @@ -5,17 +5,22 @@ class Model: def __init__(self, tb_model, int_model=None, Vk=None, guess=None): self.tb_model = tb_model - self.hk = utils.model2hk(tb_model=tb_model) + self.dim = len([*tb_model.keys()][0]) + if self.dim > 0: + self.hk = utils.model2hk(tb_model=tb_model) self.int_model = int_model if self.int_model is not None: self.int_model = int_model - self.Vk = utils.model2hk(tb_model=int_model) + if self.dim > 0: + self.Vk = utils.model2hk(tb_model=int_model) else: - self.Vk = Vk - self.dim = len([*tb_model.keys()][0]) + if self.dim > 0: + self.Vk = Vk self.ndof = len([*tb_model.values()][0]) self.guess = guess - + if self.dim == 0: + self.hamiltonians_0 = tb_model[()] + self.H_int = int_model[()] def random_guess(self, vectors): if self.int_model is None: diff --git a/codes/utils.py b/codes/utils.py index bb3e915..22e9f71 100644 --- a/codes/utils.py +++ b/codes/utils.py @@ -362,7 +362,10 @@ def calc_gap(vals, E_F): def flat_to_matrix(flat, shape): matrix = np.zeros(shape, dtype=complex) + # if len(shape) > 2: matrix[..., *np.triu_indices(shape[-1])] = flat.reshape(*shape[:-2], -1) + # else: + # matrix[*np.triu_indices(shape[-1])] = flat indices = np.arange(shape[-1]) diagonal = matrix[..., indices, indices] matrix += np.moveaxis(matrix, -1, -2).conj() -- GitLab