diff --git a/CHANGE.log b/CHANGE.log index ad094383..5ae6dd79 100644 --- a/CHANGE.log +++ b/CHANGE.log @@ -4,3 +4,4 @@ - Added fp.kpoint.wannier90_nnkpts and fp.kpoint.wannier90_full - In fp.System's input_files, and file_names, it is now required that the input is a list of strings (previously, a single string was also allowed). - Default saving is now JSON (change due to fsc.iohelper). Quiet loading doesn't ignore when the file ending is absent or serializer is not set. +- Elk first principles (http://elk.sourceforge.net/) example files are included, and an additional function in kpoints.py was added to allow Z2pack to interface with Elk diff --git a/examples/fp/elk/Bi/input/elk.in b/examples/fp/elk/Bi/input/elk.in new file mode 100644 index 00000000..8585c3bf --- /dev/null +++ b/examples/fp/elk/Bi/input/elk.in @@ -0,0 +1,68 @@ +tasks +0 + +highq +.true. + +spinorb +.true. + +epsband +1.e-8 + +primcell +.false. + +nempty +10 + +autoswidth +.true. + +lmirep +.true. + +sppath +'/home-2/epogue1@jhu.edu/Z2pack/elk-6.8.4/species/' + +ngridk +6 6 6 + + + +! Atomic positions generated by spacegroup version 1.2.01 +! Hermann-Mauguin symbol : R-3m:H +! Hall symbol : -R 3 2" +! Schoenflies symbol : D3d^5 +! space group number : 166:H +! lattice constants (a,b,c) : 8.590712580 8.590712580 22.41597726 +! angles in degrees (bc,ac,ab) : 90.00000000 90.00000000 120.0000000 +! number of conventional unit cells : 1 1 1 +! reduction to primitive cell : T +! Wyckoff positions : +! species : 1, Bi +! 0.000000000 0.000000000 0.2338900000 + +scale + 1.0 + +scale1 + 1.0 + +scale2 + 1.0 + +scale3 + 1.0 + +avec + 4.295356290 7.439775331 0.000000000 + 8.590712580 0.000000000 0.000000000 + 0.8881784197E-15 4.959850221 -7.471992420 + +atoms + 1 : nspecies +'Bi.in' : spfname + 2 : natoms; atpos, bfcmt below + 0.46778000 0.26611000 0.29833000 0.00000000 0.00000000 0.00000000 + -0.46778000 -0.26611000 -0.29833000 0.00000000 0.00000000 0.00000000 diff --git a/examples/fp/elk/Bi/input/elkWannBands.in b/examples/fp/elk/Bi/input/elkWannBands.in new file mode 100644 index 00000000..8446e17e --- /dev/null +++ b/examples/fp/elk/Bi/input/elkWannBands.in @@ -0,0 +1,86 @@ +tasks +1 +550 + +reducek +0 + +highq +.true. + +spinorb +.true. + +epsband +1.e-8 + +primcell +.false. + +nempty +10 + +autoswidth +.true. + +lmirep +.true. + +sppath +'/home-2/epogue1@jhu.edu/Z2pack/elk-6.8.4/species/' + + +idxw90 +1-29 + +num_iter +0 + +maxscl +1 + +! Atomic positions generated by spacegroup version 1.2.01 +! Hermann-Mauguin symbol : R-3m:H +! Hall symbol : -R 3 2" +! Schoenflies symbol : D3d^5 +! space group number : 166:H +! lattice constants (a,b,c) : 8.590712580 8.590712580 22.41597726 +! angles in degrees (bc,ac,ab) : 90.00000000 90.00000000 120.0000000 +! number of conventional unit cells : 1 1 1 +! reduction to primitive cell : T +! Wyckoff positions : +! species : 1, Bi +! 0.000000000 0.000000000 0.2338900000 + +scale + 1.0 + +scale1 + 1.0 + +scale2 + 1.0 + +scale3 + 1.0 + +avec + 4.295356290 7.439775331 0.000000000 + 8.590712580 0.000000000 0.000000000 + 0.8881784197E-15 4.959850221 -7.471992420 + +atoms + 1 : nspecies +'Bi.in' : spfname + 2 : natoms; atpos, bfcmt below + 0.46778000 0.26611000 0.29833000 0.00000000 0.00000000 0.00000000 + -0.46778000 -0.26611000 -0.29833000 0.00000000 0.00000000 0.00000000 + + + +xlwin +postproc_setup : true +begin projections +random +end projections +shell_list 1 diff --git a/examples/fp/elk/Bi/run.py b/examples/fp/elk/Bi/run.py new file mode 100644 index 00000000..47ff0f3d --- /dev/null +++ b/examples/fp/elk/Bi/run.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +''' +run.py can be used to interface ELK and Z2Pack. To use, change elkdir to your location of elk. +Wannier90 is run by Elk in library mode. Check http://elk.sourceforge.net/ for installation +instructions. +''' +import os +import shutil +import subprocess + +import matplotlib.pyplot as plt +import z2pack + +# Edit the paths to your Elk and Wannier90 here +elkdir = '$HOME/Z2pack/elk-6.8.4/src/elk' + +# creating the results folder, running the SCF calculation if needed +if not os.path.exists('./plots'): + os.mkdir('./plots') +if not os.path.exists('./results'): + os.mkdir('./results') +if not os.path.exists('./ground'): + os.makedirs('./ground') + print("Running the ground state calculation") + #do initial ground-state calculation in the ground folder using elk.in in the input folder + shutil.copyfile('input/elk.in', 'ground/elk.in') + subprocess.call(elkdir + ' >& elkWannier.log', shell=True, cwd='./ground') + +# Collecting the files for the surface calculation +# The k-point nearest neighbors list/kpoints string is appended to the .in file, +# starting on the last line, and there can be no extra lines in between the shell_list +# and the nnkpts lines. The nnkpts line should be added directly to the end of elkWannBands.in +# automatically by Z2pack during the surface calculation (becomes build/elk.in). +input_files = [ + 'ground/' + name for name in [ + "elk.in", "STATE.OUT", "INFO.OUT", "GEOMETRY.OUT", "LINENGY.OUT", + "DTOTENERGY.OUT", "EFERMI.OUT", "EIGVAL.OUT", "EQATOMS.OUT", + "EVALCORE.OUT", "EVALFV.OUT", "EVALSV.OUT", "EVECFV.OUT", "EVECSV.OUT", + "FERMIDOS.OUT", "GAP.OUT", "GEOMETRY.OUT", "IADIST.OUT", "LATTICE.OUT", + "KPOINTS.OUT", "MOMENT.OUT", "MOMENTM.OUT", "OCCSV.OUT", "RMSDVS.OUT", + "SYMCRYS.OUT", "SYMLAT.OUT", "SYMSITE.OUT", "TOTENERGY.OUT" + ] +] + +# Note that this ensures that elkWannBands.in is used +# rather than what was used for the Ground state calculation. +shutil.copyfile('input/elkWannBands.in', 'ground/elk.in') + +# Create the Z2Pack system. +system = z2pack.fp.System( + input_files=input_files, + kpt_fct=z2pack.fp.kpoint.elk, + kpt_path="elk.in", + command=elkdir + ' >& elk.log', + mmn_path='wannier.mmn' +) + +# Run the WCC calculations +result_0 = z2pack.surface.run( + system=system, + surface=lambda s, t: [0, s / 2, t], + save_file='./results/res_0.json', + load=True +) + +print( + 'Z2 topological invariant at kx = 0: {0}'.format( + z2pack.invariant.z2(result_0) + ) +) + +# Plot the WCC +fig, ax = plt.subplots(1, 1, sharey=True, figsize=(9, 5)) +z2pack.plot.wcc(result_0, axis=ax) +plt.savefig('plots/plot.pdf', bbox_inches='tight') diff --git a/examples/fp/elk/Bi2Se3/clean.sh b/examples/fp/elk/Bi2Se3/clean.sh new file mode 100644 index 00000000..def1f4e5 --- /dev/null +++ b/examples/fp/elk/Bi2Se3/clean.sh @@ -0,0 +1,2 @@ +#!/bin/bash +rm -rf ground build results plots diff --git a/examples/fp/elk/Bi2Se3/input/elk.in b/examples/fp/elk/Bi2Se3/input/elk.in new file mode 100644 index 00000000..d2b02f3e --- /dev/null +++ b/examples/fp/elk/Bi2Se3/input/elk.in @@ -0,0 +1,91 @@ +tasks +0 +20 + +highq +.true. + +spinorb +.true. + +epsband +1.e-8 + +primcell +.false. + +nempty +10 + +autoswidth +.true. + +lmirep +.true. + +sppath +'/home-2/epogue1@jhu.edu/Z2pack2/elk-6.8.4/species/' + +ngridk +12 12 5 + +idxw90 +1-112 + +xlwin +postproc_setup : true +begin projections +random +end projections + +plot1d +4 400 +0.677219 0.322781 0.500000 :B +0.000000 0.000000 0.500000 :Z +0.000000 0.000000 0.000000 :gamma +0.67721904 0.33860952 0.33860952 :X + +! Atomic positions generated by spacegroup version 1.2.01 +! Hermann-Mauguin symbol : R-3m:R +! Hall symbol : -P 3* 2 +! Schoenflies symbol : D3d^5 +! space group number : 166:R +! lattice constants (a,b,c) : 18.59302275 18.59302275 18.59302275 +! angles in degrees (bc,ac,ab) : 24.40000000 24.40000000 24.40000000 +! number of conventional unit cells : 1 1 1 +! reduction to primitive cell : T +! Wyckoff positions : +! species : 1, Bi +! 0.3990000000 0.3990000000 0.3990000000 +! species : 2, Se +! 0.000000000 0.000000000 0.000000000 +! 0.7940000000 0.7940000000 0.7940000000 + +scale + 1.0 + +scale1 + 1.0 + +scale2 + 1.0 + +scale3 + 1.0 + +avec + 1.660660727 -3.660906252 -6.752286776 + 1.660660727 -7.680860062 0.000000000 + 18.59302275 0.000000000 0.000000000 + +atoms + 2 : nspecies +'Bi.in' : spfname + 2 : natoms; atpos, bfcmt below + 0.10100000 0.10100000 0.19700000 0.00000000 0.00000000 0.00000000 + -0.10100000 -0.10100000 -0.19700000 0.00000000 0.00000000 0.00000000 +'Se.in' : spfname + 3 : natoms; atpos, bfcmt below + 0.50000000 0.50000000 0.00000000 0.00000000 0.00000000 0.00000000 + -0.29400000 -0.29400000 0.38200000 0.00000000 0.00000000 0.00000000 + 0.29400000 0.29400000 -0.38200000 0.00000000 0.00000000 0.00000000 diff --git a/examples/fp/elk/Bi2Se3/input/elkWannBands.in b/examples/fp/elk/Bi2Se3/input/elkWannBands.in new file mode 100644 index 00000000..97d59fb3 --- /dev/null +++ b/examples/fp/elk/Bi2Se3/input/elkWannBands.in @@ -0,0 +1,94 @@ +tasks +1 +550 + +reducek +0 + +highq +.true. + +spinorb +.true. + +epsband +1.e-8 + +primcell +.false. + +nempty +10 + +autoswidth +.true. + +lmirep +.true. + +sppath +'/home-2/epogue1@jhu.edu/Z2pack2/elk-6.8.4/species/' + + +idxw90 +1-78 + +num_iter +0 + +maxscl +1 + +! Atomic positions generated by spacegroup version 1.2.01 +! Hermann-Mauguin symbol : R-3m:R +! Hall symbol : -P 3* 2 +! Schoenflies symbol : D3d^5 +! space group number : 166:R +! lattice constants (a,b,c) : 18.59302275 18.59302275 18.59302275 +! angles in degrees (bc,ac,ab) : 24.40000000 24.40000000 24.40000000 +! number of conventional unit cells : 1 1 1 +! reduction to primitive cell : T +! Wyckoff positions : +! species : 1, Bi +! 0.3990000000 0.3990000000 0.3990000000 +! species : 2, Se +! 0.000000000 0.000000000 0.000000000 +! 0.7940000000 0.7940000000 0.7940000000 + +scale + 1.0 + +scale1 + 1.0 + +scale2 + 1.0 + +scale3 + 1.0 + +avec + 1.660660727 -3.660906252 -6.752286776 + 1.660660727 -7.680860062 0.000000000 + 18.59302275 0.000000000 0.000000000 + +atoms + 2 : nspecies +'Bi.in' : spfname + 2 : natoms; atpos, bfcmt below + 0.10100000 0.10100000 0.19700000 0.00000000 0.00000000 0.00000000 + -0.10100000 -0.10100000 -0.19700000 0.00000000 0.00000000 0.00000000 +'Se.in' : spfname + 3 : natoms; atpos, bfcmt below + 0.50000000 0.50000000 0.00000000 0.00000000 0.00000000 0.00000000 + -0.29400000 -0.29400000 0.38200000 0.00000000 0.00000000 0.00000000 + 0.29400000 0.29400000 -0.38200000 0.00000000 0.00000000 0.00000000 + + + +xlwin +postproc_setup : true +begin projections +random +end projections +shell_list 1 diff --git a/examples/fp/elk/Bi2Se3/run.py b/examples/fp/elk/Bi2Se3/run.py new file mode 100644 index 00000000..47ff0f3d --- /dev/null +++ b/examples/fp/elk/Bi2Se3/run.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +''' +run.py can be used to interface ELK and Z2Pack. To use, change elkdir to your location of elk. +Wannier90 is run by Elk in library mode. Check http://elk.sourceforge.net/ for installation +instructions. +''' +import os +import shutil +import subprocess + +import matplotlib.pyplot as plt +import z2pack + +# Edit the paths to your Elk and Wannier90 here +elkdir = '$HOME/Z2pack/elk-6.8.4/src/elk' + +# creating the results folder, running the SCF calculation if needed +if not os.path.exists('./plots'): + os.mkdir('./plots') +if not os.path.exists('./results'): + os.mkdir('./results') +if not os.path.exists('./ground'): + os.makedirs('./ground') + print("Running the ground state calculation") + #do initial ground-state calculation in the ground folder using elk.in in the input folder + shutil.copyfile('input/elk.in', 'ground/elk.in') + subprocess.call(elkdir + ' >& elkWannier.log', shell=True, cwd='./ground') + +# Collecting the files for the surface calculation +# The k-point nearest neighbors list/kpoints string is appended to the .in file, +# starting on the last line, and there can be no extra lines in between the shell_list +# and the nnkpts lines. The nnkpts line should be added directly to the end of elkWannBands.in +# automatically by Z2pack during the surface calculation (becomes build/elk.in). +input_files = [ + 'ground/' + name for name in [ + "elk.in", "STATE.OUT", "INFO.OUT", "GEOMETRY.OUT", "LINENGY.OUT", + "DTOTENERGY.OUT", "EFERMI.OUT", "EIGVAL.OUT", "EQATOMS.OUT", + "EVALCORE.OUT", "EVALFV.OUT", "EVALSV.OUT", "EVECFV.OUT", "EVECSV.OUT", + "FERMIDOS.OUT", "GAP.OUT", "GEOMETRY.OUT", "IADIST.OUT", "LATTICE.OUT", + "KPOINTS.OUT", "MOMENT.OUT", "MOMENTM.OUT", "OCCSV.OUT", "RMSDVS.OUT", + "SYMCRYS.OUT", "SYMLAT.OUT", "SYMSITE.OUT", "TOTENERGY.OUT" + ] +] + +# Note that this ensures that elkWannBands.in is used +# rather than what was used for the Ground state calculation. +shutil.copyfile('input/elkWannBands.in', 'ground/elk.in') + +# Create the Z2Pack system. +system = z2pack.fp.System( + input_files=input_files, + kpt_fct=z2pack.fp.kpoint.elk, + kpt_path="elk.in", + command=elkdir + ' >& elk.log', + mmn_path='wannier.mmn' +) + +# Run the WCC calculations +result_0 = z2pack.surface.run( + system=system, + surface=lambda s, t: [0, s / 2, t], + save_file='./results/res_0.json', + load=True +) + +print( + 'Z2 topological invariant at kx = 0: {0}'.format( + z2pack.invariant.z2(result_0) + ) +) + +# Plot the WCC +fig, ax = plt.subplots(1, 1, sharey=True, figsize=(9, 5)) +z2pack.plot.wcc(result_0, axis=ax) +plt.savefig('plots/plot.pdf', bbox_inches='tight') diff --git a/tests/fp/test_fp_kpoint.py b/tests/fp/test_fp_kpoint.py index 54075399..4ed56c81 100644 --- a/tests/fp/test_fp_kpoint.py +++ b/tests/fp/test_fp_kpoint.py @@ -69,6 +69,16 @@ def kpt(line): STRAIGHT_ANY_DIRECTION + STRAIGHT_UNEQUAL_SPACING + STRAIGHT_MULTIPLE_BZ + NON_STRAIGHT + INVALID }, + z2pack.fp.kpoint.elk.__name__: { + 'fct': + z2pack.fp.kpoint.elk, + 'valid_comparable': + STRAIGHT_SIMPLE, + 'valid_incomparable': [], + 'invalid': + STRAIGHT_ANY_DIRECTION + STRAIGHT_UNEQUAL_SPACING + + STRAIGHT_MULTIPLE_BZ + NON_STRAIGHT + INVALID + }, z2pack.fp.kpoint.qe.__name__: { 'fct': z2pack.fp.kpoint.qe, 'valid_comparable': VALID_COMPARABLE, diff --git a/z2pack/fp/kpoint.py b/z2pack/fp/kpoint.py index 081a1c29..9250d682 100644 --- a/z2pack/fp/kpoint.py +++ b/z2pack/fp/kpoint.py @@ -199,6 +199,53 @@ def vasp(kpt): return string +@export +@_check_dim +@_check_closed +def elk(kpt): + """ + Creates a k-point input for **ELK**. It uses the automatic generation scheme with a Gamma centered grid. Note that VASP does **not** support any kind of k-point line **unless** they are exactly along one of the reciprocal lattice vectors, and the k-points are evenly spaced. + """ + # VALIDITY CHECKS + # check if the points are equally-spaced + delta = _check_equal_spacing(kpt, 'ELK') + + num_kpt = len(kpt) - 1 + # check if it's positive x, y or z direction + nonzero = [] + mesh = [] + for i, spacing in enumerate(delta): + if np.isclose(spacing, 0): + mesh.append('1') + elif np.isclose(spacing, 1 / num_kpt): + nonzero.append(i) + mesh.append(str(num_kpt)) + else: + raise ValueError( + 'The k-points must be aligned in (positive) kx-, ky- or kz-direction for ELK runs.' + ) + + if len(nonzero) != 1: + raise ValueError( + 'The k-points can change only in kx-, ky- or kz direction for ELK runs. The given k-points change in {} directions.' + .format(len(nonzero)) + ) + + start_point = kpt[0] + if not np.isclose(start_point[nonzero[0]], 0): + raise ValueError( + 'The k-points must start at k{0} = 0 for ELK runs, since they change in k{0}-direction.' + .format(['x', 'y', 'z'][nonzero[0]]) + ) + s = wannier90_nnkpts(kpt) + string = s + '\n\nngridk\n' + '1 1 ' + str(num_kpt) + '\n\n' + string += 'vkloff\n' + for coord in start_point: + string += str(coord).replace('e', 'd') + ' ' + string += '\n' + return string + + def _check_equal_spacing(kpt, run_type): """Checks if the k-points are equally spaced, and throws an error if not. run_type is added in the error message.""" deltas = [(k2 - k1) % 1 for k2, k1 in zip(kpt[1:], kpt[:-1])]