From 34007ed7efd56e9809d2f97d927dbd6bc43daabb Mon Sep 17 00:00:00 2001 From: antoniolrm <am@antoniomanesco.org> Date: Fri, 27 Oct 2023 15:23:05 +0200 Subject: [PATCH] make compatible with finite systems --- codes/hf.py | 55 +++++++++++++++++++++++++++++++++----------------- codes/utils.py | 28 ++++++++++--------------- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/codes/hf.py b/codes/hf.py index 4c61590..7d2fdb5 100644 --- a/codes/hf.py +++ b/codes/hf.py @@ -24,23 +24,31 @@ def mean_field_F(vals, vecs, E_F): F : array_like mean field F[kx, ky, ..., i, j] where i,j are cell indices. """ - cell_size = vals.shape[-1] + norbs = vals.shape[-1] dim = len(vals.shape) - 1 nk = vals.shape[0] - vals_flat = vals.reshape(-1, cell_size) - unocc_vals = vals_flat > E_F - occ_vecs_flat = vecs.reshape(-1, cell_size, cell_size) - occ_vecs_flat = np.transpose(occ_vecs_flat, axes=[0, 2, 1]) - occ_vecs_flat[unocc_vals, :] = 0 - occ_vecs_flat = np.transpose(occ_vecs_flat, axes=[0, 2, 1]) + if dim > 0: + vals_flat = vals.reshape(-1, norbs) + unocc_vals = vals_flat > E_F + occ_vecs_flat = vecs.reshape(-1, norbs, norbs) + occ_vecs_flat = np.transpose(occ_vecs_flat, axes=[0, 2, 1]) + occ_vecs_flat[unocc_vals, :] = 0 + occ_vecs_flat = np.transpose(occ_vecs_flat, axes=[0, 2, 1]) + + # inner products between eigenvectors + F_ij = np.einsum("kie,kje->kij", occ_vecs_flat, occ_vecs_flat.conj()) + reshape_order = [nk for i in range(dim)] + reshape_order.extend([norbs, norbs]) + F = F_ij.reshape(*reshape_order) + else: + unocc_vals = vals > E_F + occ_vecs = vecs + occ_vecs[:, unocc_vals] = 0 - # inner products between eigenvectors - F_ij = np.einsum("kie,kje->kij", occ_vecs_flat, occ_vecs_flat.conj()) + # Outter products between eigenvectors + F = occ_vecs @ occ_vecs.T.conj() - reshape_order = [nk for i in range(dim)] - reshape_order.extend([cell_size, cell_size]) - F = F_ij.reshape(*reshape_order) return F @@ -95,14 +103,21 @@ def compute_mf(vals, vecs, filling, H_int): Meanf-field correction with same format as `H_int`. """ dim = len(vals.shape) - 1 + nk = vals.shape[0] - H0_int = H_int[*[0 for i in range(dim)]] E_F = utils.get_fermi_energy(vals, filling) F = mean_field_F(vals=vals, vecs=vecs, E_F=E_F) - rho = np.diag(np.average(F, axis=tuple([i for i in range(dim)]))) - exchange_mf = convolution(F, H_int) * nk ** (-dim) - direct_mf = np.diag(np.einsum("i,ij->j", rho, H0_int)) + + if dim > 0: + H0_int = H_int[*[0 for i in range(dim)]] + rho = np.diag(np.average(F, axis=tuple([i for i in range(dim)]))) + exchange_mf = convolution(F, H_int) * nk ** (-dim) + direct_mf = np.diag(np.einsum("i,ij->j", rho, H0_int)) + else: + rho = np.diag(F) + exchange_mf = F * H_int + direct_mf = np.diag(np.einsum("i,ij->j", rho, H_int)) return direct_mf - exchange_mf @@ -140,12 +155,12 @@ def find_groundstate_ham( int_model, filling, nk=10, - tol=1e-6, + tol=1e-5, guess=None, mixing=0.01, - order=5, + order=10, verbose=False, - return_mf=False + return_mf=False, ): """ Self-consistent loop to find groundstate Hamiltonian. @@ -175,6 +190,8 @@ def find_groundstate_ham( Groundstate Hamiltonian with same format as `H_int`. """ hamiltonians_0, ks = utils.kgrid_hamiltonian(nk, tb_model, return_ks=True) + if guess is None: + guess = utils.generate_guess(nk, tb_model, int_model, scale=np.max(np.abs(np.array([*int_model.values()])))) fun = partial( scf_loop, hamiltonians_0=hamiltonians_0, diff --git a/codes/utils.py b/codes/utils.py index 87322e2..4786e23 100644 --- a/codes/utils.py +++ b/codes/utils.py @@ -194,21 +194,14 @@ def kgrid_hamiltonian(nk, syst, params={}, return_ks=False): `k_m` corresponding to the k-point element along each direction and `i` and `j` are the internal degrees of freedom. """ - if type(syst) == kwant.builder.FiniteSystem: - try: - dim = len(syst._wrapped_symmetry.periods) - hk = kwant2hk(syst, params) - except: - return syst.hamiltonian_submatrix(params=params) - elif type(syst) == dict: - dim = len(next(iter(syst))) - if dim == 0: - if return_ks: - return syst[next(iter(syst))], None - else: - return syst[next(iter(syst))] + dim = len(next(iter(syst))) + if dim == 0: + if return_ks: + return syst[next(iter(syst))], None else: - hk = dict2hk(syst) + return syst[next(iter(syst))] + else: + hk = dict2hk(syst) ks = 2 * np.pi * np.linspace(0, 1, nk, endpoint=False) @@ -283,8 +276,9 @@ def generate_guess(nk, tb_model, int_model, scale=0.1): amplitude = np.random.rand(ndof, ndof) phase = 2 * np.pi * np.random.rand(ndof, ndof) rand_hermitian = amplitude * np.exp(1j * phase) - rand_hermitian += rand_hermitian.T.conj() - rand_hermitian /= 2 + if np.linalg.norm(np.array(vector)): + rand_hermitian += rand_hermitian.T.conj() + rand_hermitian /= 2 guess[vector] = rand_hermitian return kgrid_hamiltonian(nk, guess) * scale @@ -360,7 +354,7 @@ def hk2tb_model(hk, tb_model, int_model, ks=None): return tb_model else: - tb_model = {(): hk} + return {(): hk} def calc_gap(vals, E_F): -- GitLab