# How to interpret WannierTools Python code that generates tight-binding model in the wannier90_hr.dat format? [closed]

I am getting myself acquainted with Wannier Tools. Wannier Tools requires two inputs, a wt.in file, and a .dat file. This .dat file should have the structure explained in the manual. This file may be parsed from other DFT software (such as Quantum ESPRESSO via Wannier90). However, it may also be generated manually, as the developers do in an example using a Python file.

I am going to focus on their implementation of the 2D Haldane model for the QAHE [1] (link to implementation). My issue is that I do not understand how they went from the tight-binding model to getting the matrix elements of the Hamiltonian. In particular, I do not understand why they use 7 points, and why each point gives each matrix element.

Here is the tight-binding model in first quantization [2] (I used another source because the original work only gives a Hamiltonian in k-space): $$\hat{H}=t\sum_{\langle i,j\rangle}|i\rangle\langle j|+t_2\sum_{\langle\langle i,j\rangle\rangle}|i\rangle\langle j|+M\bigg[\sum_{i\in A}|i\rangle\langle i|-\sum_{j\in B}|j\rangle\langle j|\bigg]$$

Here is part of an example Python file that they use to generate the .dat file. They use m instead of $$M$$, phi instead of $$\phi$$, and t1 instead of $$t$$:

# Chern = 1
m=0.2; phi= np.pi/2.0; t1=1.0; t2=m/3.0/np.sqrt(3)*2.0;

# maximum dimension for hr matrix
ndim = 2
nrpts = 7
num_patom=2

# hr matrix
norbs = num_patom*1
hmnr= np.zeros((norbs,norbs,nrpts),dtype = np.complex128)

# WS points
irvec   = np.zeros((3,nrpts),dtype = np.int32)

# degeneracy
dege   = np.zeros((nrpts),dtype = np.int32)+1

# complex unit
zi=1j

ir= 0
irvec[0, ir]= 0
irvec[1, ir]= 0
hmnr[0, 0, ir]=  m
hmnr[1, 1, ir]= -m
hmnr[0, 1, ir]=  t1
hmnr[1, 0, ir]=  t1

# 1 0
ir= ir+1
irvec[0, ir]= 1
irvec[1, ir]= 0
hmnr[0, 0, ir]= (np.cos(phi)-zi*np.sin(phi)) *t2
hmnr[1, 1, ir]= (np.cos(phi)+zi*np.sin(phi)) *t2
hmnr[0, 1, ir]= t1

# 0 1
ir= ir+1
irvec[0, ir]= 0
irvec[1, ir]= 1
hmnr[0, 0, ir]= (np.cos(phi)-zi*np.sin(phi)) *t2
hmnr[1, 1, ir]= (np.cos(phi)+zi*np.sin(phi)) *t2
hmnr[1, 0, ir]= t1

# 1 1
ir= ir+1
irvec[0, ir]= 1
irvec[1, ir]= 1
hmnr[0, 0, ir]= (np.cos(phi)+zi*np.sin(phi)) *t2
hmnr[1, 1, ir]= (np.cos(phi)-zi*np.sin(phi)) *t2

#-1 0
ir= ir+1
irvec[0, ir]=-1
irvec[1, ir]= 0
hmnr[0, 0, ir]= (np.cos(phi)+zi*np.sin(phi)) *t2
hmnr[1, 1, ir]= (np.cos(phi)-zi*np.sin(phi)) *t2
hmnr[1, 0, ir]= t1

# 0-1
ir= ir+1
irvec[0, ir]= 0
irvec[1, ir]=-1
hmnr[0, 0, ir]= (np.cos(phi)+zi*np.sin(phi)) *t2
hmnr[1, 1, ir]= (np.cos(phi)-zi*np.sin(phi)) *t2
hmnr[0, 1, ir]= t1

#-1-1
ir= ir+1
irvec[0, ir]=-1
irvec[1, ir]=-1
hmnr[0, 0, ir]= (np.cos(phi)-zi*np.sin(phi)) *t2
hmnr[1, 1, ir]= (np.cos(phi)+zi*np.sin(phi)) *t2

#print "dump hr.dat..."
with open('Haldane_hr.dat','w') as f:
line="Haldane model with m="+str(m)+", phi="+str(phi/np.pi)+"pi, t1="+str(t1)+", t2="+str(t2)+"Ref:Physical Review Letters 61, 18(1988)"+'\n'
f.write(line)
nl = np.int32(np.ceil(nrpts/15.0))
f.write(str(norbs)+'\n')
f.write(str(nrpts)+'\n')
for l in range(nl):
line="    "+'    '.join([str(np.int32(i)) for i in dege[l*15:(l+1)*15]])
f.write(line)
f.write('\n')
for irpt in range(nrpts):
rx = irvec[0,irpt];ry = irvec[1,irpt];rz = irvec[2,irpt]
for jatomorb in range(norbs):
for iatomorb in range(norbs):
rp =hmnr[iatomorb,jatomorb,irpt].real
ip =hmnr[iatomorb,jatomorb,irpt].imag
line="{:8d}{:8d}{:8d}{:8d}{:8d}{:20.10f}{:20.10f}\n".format(rx,ry,rz,jatomorb+1,iatomorb+1,rp,ip)
f.write(line)


## Current understanding

I am not sure what the seven cases indicated by comments # 1 0, #-1 0, etc are. However, I figured they corresponded to real space $$(x,y)$$ points because there are 7 such code blocks, and there is nrpts = 7. Assuming that each hmnr value corresponds to a matrix element of the Hamiltonian (i.e. it can be a hopping, on-site energy, etc), I do not see why we need 7 points when we could have used 4 to capture all on-site, NN and NNN potentials/interactions. Indeed, it appears as if 3 of these code blocks have values identical to another block. So, why 7? It makes the resulting matrix larger...

Next, I figured that the $$\cos\phi \pm i \sin\phi$$ came from the Peierls substitution for the NNN hopping parameter $$t_2 \rightarrow t_2 e^{\pm i \phi} = t_2 (\cos\phi \pm i \sin\phi)$$. This checks out.

But, what still doesn't make sense is how each of the 7 points makes them assign only some matrix elements. To illustrate this, I annotated the initial code block with my interpretation:

ir=0  #a number that iterates through all 7 points
irvec[0, ir]=0 #set x coordinate of point to 0
irvec[1, ir]=0 #set y coordinate of point to 0
hmnr[0, 0, ir]=m #set (0,0) Hamiltonian matrix element value to +m
hmnr[1, 1, ir]=-m #set (1,1) Hamiltonian matrix element value to -m
hmnr[0, 1, ir]=t1 #set (0,1) Hamiltonian matrix element value to t1
hmnr[1, 0, ir]=t1 #set (1,0) Hamiltonian matrix element value to t1


I took this to mean that the Hamiltonian at this point is $$\begin{bmatrix} \langle m | H_{00} | m \rangle & \langle m | H_{01} | n \rangle \\ \langle n | H_{10} | m \rangle & \langle n | H_{11} | n \rangle \end{bmatrix} = \begin{bmatrix} m & t_1 \\ t_1 & -m \end{bmatrix}$$

But, how exactly do they determine the values assigned to each matrix element? In addition to the above, I don't understand why the point $$(0,1)$$ gives $$\begin{bmatrix} t_2 (\cos\phi + i \sin\phi) & 0 \\ t_1 & t_2 (\cos\phi - i \sin\phi) \end{bmatrix}.$$ What justifies setting the $$\langle m | H_{01} | n \rangle$$ element to 0? Clearly, I have either misinterpreted what the code stands for, or just don't understand what's going on. I also considered interpreting aforementioned seven points as pairs of values of $$(i,j)$$ or some other vector. But it's very hard to decrypt this without knowing too well the context the authors wrote this in. So, any help would be appreciated!

I tried comparing this syntax with other tools such as PythTB and TBmodels, but they don't match too well with this syntax.

1. F. D. M. Haldane Phys. Rev. Lett. 61, 2015 DOI
2. Michel Fruchart and David Carpentier, https://arxiv.org/abs/1310.0255 DOI
• Hi TribalChief! I've been going through the unanswered queue to try to help get some of them answered, and noticed that this question is quite long! Is there a way to give a much more compact summary of the question, or to split it up into several questions if this question involves a lot? Since it's been over 6 months since you asked this, is there any update from you? Oct 30, 2021 at 20:16
• @NikeDattani, I apologize. I gave up on trying to understand this a while ago. My question itself is the first paragraph (apart from code). The rest is my attempt to answer my question. I am not sure how I could simplify this... Thanks for your work! Nov 23, 2021 at 22:35
• The code is a bit of a mess and seems to have a lot of redundancies. For example, the Github repo has basically this same script 4 different times, where the only difference between them is the definition of m, phi, t1, and t2. As you note, there also seems to be redundancy in setting elements of the Hamiltonian. and I would agree that the off-diagonal elements not being complex conjugates of each other is odd. How confident are you that the code is correct? Have you run the later steps using this generated Hamiltonian and gotten reasonable results?
– Tyberius
Dec 1, 2021 at 19:12
• This question has been closed as it seems to be abandoned. It can be reopened if someone wants to add an answer or the OP addresses questions/suggestions in the comments.
– Tyberius
Dec 13, 2021 at 19:18