From b1edb1c37799b06e33298832e3f59d9feee3fee3 Mon Sep 17 00:00:00 2001 From: antoniolrm <am@antoniomanesco.org> Date: Fri, 12 May 2023 15:05:24 +0200 Subject: [PATCH] more packaging and some clean up --- codes/hf.py | 53 ++++++++++++++++++++++++++++++---- codes/utils.py | 77 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/codes/hf.py b/codes/hf.py index 173f68c..be6d6a9 100644 --- a/codes/hf.py +++ b/codes/hf.py @@ -1,9 +1,11 @@ from scipy.signal import convolve2d import numpy as np import utils +from functools import partial +from scipy.optimize import anderson, minimize -def mean_field_F(vals, vecs, E_F): - N_ks = vecs.shape[0] + +def mean_field_F(vals, vecs, E_F, nk): unocc_vals = vals > E_F def mf_generator(i, j): @@ -12,9 +14,10 @@ def mean_field_F(vals, vecs, E_F): F_ij = occ_vecs @ occ_vecs.conj().T return F_ij - F = np.array([[mf_generator(i, j) for i in range(N_ks)] for j in range(N_ks)]) + F = np.array([[mf_generator(i, j) for i in range(nk)] for j in range(nk)]) return F + def convolution(M1, M2): cell_size = M2.shape[-1] V_output = np.array( @@ -29,12 +32,50 @@ def convolution(M1, M2): V_output = np.transpose(V_output, axes=(2, 3, 0, 1)) return V_output + def compute_mf(vals, vecs, filling, nk, H_int): - H0_int = H_int[0,0] + H0_int = H_int[0, 0] E_F = utils.get_fermi_energy(vals, filling) - F = mean_field_F(vals, vecs, E_F=E_F) + F = mean_field_F(vals, vecs, E_F=E_F, nk=nk) rho = np.diag(np.average(F, axis=(0, 1))) exchange_mf = convolution(F, H_int) * nk ** (-2) direct_mf = np.diag(np.einsum("i,ij->j", rho, H0_int)) - return direct_mf - exchange_mf \ No newline at end of file + return direct_mf - exchange_mf + + +def dm(mf0, mf): + return np.mean(np.abs(mf - mf0)) + + +def scf_loop(mf, H_int, nk, filling, hamiltonians_0, tol): + if np.linalg.norm(mf) < tol: + return 0 + # Generate the Hamiltonian + hamiltonians = hamiltonians_0 + mf + vals, vecs = np.linalg.eigh(hamiltonians) + vecs = np.linalg.qr(vecs)[0] + + mf_new = compute_mf(vals=vals, vecs=vecs, filling=filling, nk=nk, H_int=H_int) + + diff = mf_new - mf + + if np.linalg.norm(mf_new) < tol: + return 0 + else: + return diff + + +def find_groundstate_ham( + H_int, nk, filling, hamiltonians_0, tol, guess, mixing=0.5, order=1 +): + fun = partial( + scf_loop, + H_int=H_int, + nk=nk, + filling=filling, + hamiltonians_0=hamiltonians_0, + tol=tol, + ) + mf = anderson(fun, guess, f_tol=tol, w0=mixing, M=order) + return hamiltonians_0 + mf diff --git a/codes/utils.py b/codes/utils.py index a2fbf84..6d629c8 100644 --- a/codes/utils.py +++ b/codes/utils.py @@ -7,12 +7,12 @@ def get_fermi_energy(vals, filling): ne = len(vals_flat) ifermi = int(round(ne * filling / norbs)) if ifermi >= ne: - ifermi = ne - 1 - sorte = np.sort(vals_flat) # sorted eigenvalues - if ifermi == 0: - return sorte[0] - fermi = (sorte[ifermi - 1] + sorte[ifermi]) / 2.0 # fermi energy - return fermi + return vals_flat[-1] + elif ifermi == 0: + return vals_flat[0] + else: + fermi = (vals_flat[ifermi - 1] + vals_flat[ifermi]) / 2 + return fermi def syst2hamiltonian(kxs, kys, syst, params={}): def h_k(kx, ky): @@ -31,22 +31,25 @@ def potential2hamiltonian( wrapped_V = kwant.wraparound.wraparound(V).finalized() return syst2hamiltonian(kxs=ks, kys=ks, syst=wrapped_V, params=params) -def generate_guess(max_neighbor, norbs, lattice): +def generate_guess(max_neighbor, norbs, lattice, kxs, kys, dummy_syst): n_sub = len(lattice.sublattices) guess = np.zeros((n_sub + max_neighbor, 2, norbs, norbs)) for i in range(n_sub): # Real part - guess[i, 0] = np.random.rand(norbs, norbs) + guess[i, 0] = np.random.rand(norbs, norbs) - 0.5 guess[i, 0] += guess[i, 0].T # Imag part - guess[i, 1] = np.random.rand(norbs, norbs) + guess[i, 1] = np.random.rand(norbs, norbs) - 0.5 guess[i, 1] -= guess[i, 1].T for neighbor in range(max_neighbor): # Real part - guess[n_sub + neighbor, 0] = np.random.rand(norbs, norbs) + guess[n_sub + neighbor, 0] = np.random.rand(norbs, norbs) - 0.5 # Imag part - guess[n_sub + neighbor, 1] = np.random.rand(norbs, norbs) - return guess + guess[n_sub + neighbor, 1] = np.random.rand(norbs, norbs) - 0.5 + guess_k = syst2hamiltonian( + kxs=kxs, kys=kys, syst=dummy_syst, params=dict(mat=guess) + ) + return guess_k def extract_hopping_vectors(builder): keep=None @@ -69,7 +72,6 @@ def generate_scf_syst(max_neighbor, syst, lattice): scf = kwant.Builder(kwant.TranslationalSymmetry(*lattice.prim_vecs)) scf[syst.sites()] = scf_onsite for neighbor in range(max_neighbor): - def scf_hopping(site1, site2, mat): return ( mat[len(lattice.sublattices) + neighbor, 0] @@ -79,4 +81,51 @@ def generate_scf_syst(max_neighbor, syst, lattice): scf[lattice.neighbors(neighbor + 1)] = scf_hopping deltas = extract_hopping_vectors(scf) wrapped_scf = kwant.wraparound.wraparound(scf).finalized() - return wrapped_scf, deltas \ No newline at end of file + return wrapped_scf, deltas + +def hk2hop(hk, deltas, ks, dk): + kxx, kyy = np.meshgrid(ks, ks) + kxy = np.array([kxx, kyy]) + hopps = ( + np.sum( + np.einsum( + "ijk,jklm->ijklm", + np.exp(1j * np.einsum("ij,jkl->ikl", deltas, kxy)), + hk, + ), + axis=(1, 2), + ) + * (dk) ** 2 + / (2 * np.pi) ** 2 + ) + return hopps + + +def hk2syst(deltas, hk, ks, dk, max_neighbor, norbs, lattice): + hopps = hk2hop(hk, deltas, ks, dk) + bulk_scf = kwant.Builder(kwant.TranslationalSymmetry(*lattice.prim_vecs)) + for i, delta in enumerate(deltas): + for j, sublattice1 in enumerate(lattice.sublattices): + for k, sublattice2 in enumerate(lattice.sublattices): + if np.allclose(delta, [0, 0]): + bulk_scf[sublattice1.shape((lambda pos: True), (0, 0))] = hopps[ + i, j * norbs : (j + 1) * norbs, j * norbs : (j + 1) * norbs + ] + if k != j: + hopping = (delta, sublattice1, sublattice2) + bulk_scf[kwant.builder.HoppingKind(*hopping)] = hopps[ + i, j * norbs : (j + 1) * norbs, k * norbs : (k + 1) * norbs + ] + else: + for k, sublattice2 in enumerate(lattice.sublattices): + hopping = (delta, sublattice1, sublattice2) + bulk_scf[kwant.builder.HoppingKind(*hopping)] = hopps[ + i, j * norbs : (j + 1) * norbs, k * norbs : (k + 1) * norbs + ] + wrapped_scf_syst = kwant.wraparound.wraparound(bulk_scf).finalized() + return wrapped_scf_syst + +def calc_gap(vals, E_F): + emax = np.max(vals[vals <= E_F]) + emin = np.min(vals[vals > E_F]) + return np.abs(emin - emax) \ No newline at end of file -- GitLab