Chirality of a Weyl point (Quantum ESPRESSO)

In this example, the chirality of two Weyl points of MoP2 is calculated from first-principles using Quantum ESPRESSO. The Chern number is calculated for three different spheres: The first two surrounding one Weyl point each, and the third containing both Weyl points. Since the two Weyl points have the same chirality (-1), the Chern number adds up to be -2 for the third sphere. The results are shown in the figure below.

../../_images/mop2_qe_plot.svg

This example uses the new interface to Wannier90 2.1 and QE 6. The input files can be found on the github repository.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import shutil
import subprocess

import numpy as np
import matplotlib.pyplot as plt
import xml.etree.ElementTree as ET

import z2pack

# Edit the paths to your Quantum Espresso 6+ and Wannier90 2.1+ here
QEDIR = '/home/greschd/software/qe-6.0/bin/'
WANDIR = '/home/greschd/software/wannier90-2.1.0'

# Commands to run pw, pw2wannier90, wannier90
MPIRUN = 'mpirun -np 4 '
PWCMD = MPIRUN + os.path.join(QEDIR, 'pw.x ')
PW2WANCMD = MPIRUN + os.path.join(QEDIR, 'pw2wannier90.x ')
WANCMD = os.path.join(WANDIR, 'wannier90.x')

Z2CMD = (
    WANCMD + ' MoP2 -pp;' + PWCMD + '< MoP2.nscf.in >& pw.log;' + PW2WANCMD +
    '< MoP2.pw2wan.in >& pw2wan.log;'
)

# creating the results folder, running the SCF calculation if needed
os.makedirs('./plots', exist_ok=True)
os.makedirs('./results', exist_ok=True)
if not os.path.exists('./scf'):
    os.makedirs('./scf')
    print("Running the scf calculation")
    shutil.copyfile('input/MoP2.scf.in', 'scf/MoP2.scf.in')
    out = subprocess.call(
        PWCMD + ' < MoP2.scf.in > scf.out', shell=True, cwd='./scf'
    )
    if out != 0:
        raise RuntimeError(
            'Error in SCF call. Inspect scf folder for details, and delete it to re-run the SCF calculation.'
        )

# Copying the lattice parameters from MoP2.save/data-file.xml into MoP2.win
cell = ET.parse('scf/MoP2.save/data-file.xml'
                ).find('CELL').find('DIRECT_LATTICE_VECTORS')
unit = cell[0].attrib['UNITS']
lattice = '\n '.join([line.text.strip('\n ') for line in cell[1:]])

with open('input/tpl_MoP2.win', 'r') as f:
    tpl_MoP2_win = f.read()
with open('input/MoP2.win', 'w') as f:
    f.write(tpl_MoP2_win.format(unit=unit, lattice=lattice))

# Creating the System. Note that the SCF charge file does not need to be
# copied, but instead can be referenced in the .files file.
# The k-points input is appended to the .in file
input_files = [
    'input/' + name for name in ["MoP2.nscf.in", "MoP2.pw2wan.in", "MoP2.win"]
]
system = z2pack.fp.System(
    input_files=input_files,
    kpt_fct=[z2pack.fp.kpoint.qe_explicit, z2pack.fp.kpoint.wannier90_full],
    kpt_path=["MoP2.nscf.in", "MoP2.win"],
    command=Z2CMD,
    executable='/bin/bash',
    mmn_path='MoP2.mmn'
)

# Run the WCC calculations
# a small sphere around one Weyl point
result_1 = z2pack.surface.run(
    system=system,
    surface=z2pack.shape.Sphere(
        center=(0.6239797, 0.70845137, 0), radius=0.007
    ),
    save_file='./results/res1.json',
    load=True
)
# a small sphere around the other Weyl point
result_2 = z2pack.surface.run(
    system=system,
    surface=z2pack.shape.Sphere(
        center=(0.61197818, 0.70080602, 0), radius=0.007
    ),
    save_file='./results/res2.json',
    load=True
)
# a bigger sphere around both Weyl points
result_3 = z2pack.surface.run(
    system=system,
    surface=z2pack.shape.Sphere(
        center=(0.61797894, 0.7046287, 0.), radius=0.014
    ),
    save_file='./results/res3.json',
    load=True
)

# Combining the two plots
fig, ax = plt.subplots(1, 3, sharey=True, figsize=(14, 4))
for res, axis, title in zip([result_1, result_2, result_3], ax, [
    'Sphere around WP1', 'Sphere around WP2', 'Sphere around both WPs'
]):
    z2pack.plot.chern(res, axis=axis)
    axis.set_title(title)
    axis.set_xlabel(r'$\theta$')
    axis.xaxis.set_ticks([0, 1])
    axis.xaxis.set_ticklabels([r'$-\pi$', r'$0$'])
ax[0].set_ylabel(r'$\bar{\varphi}$', rotation='horizontal')
ax[0].yaxis.set_ticks([0, 1])
ax[0].yaxis.set_ticklabels([r'$0$', r'$2\pi$'])
plt.savefig('plots/plot.pdf', bbox_inches='tight')

print(
    'Chern number / Weyl chirality around WP1: {0:.2f}'.format(
        z2pack.invariant.chern(result_1)
    )
)
print(
    'Chern number / Weyl chirality around WP2: {0:.2f}'.format(
        z2pack.invariant.chern(result_2)
    )
)
print(
    'Chern number / Weyl chirality around both Weyl points: {0:.2f}'.format(
        z2pack.invariant.chern(result_3)
    )
)