Are there any known codes or scripts to generate an adaptive k-mesh for DFT calculations? For example, I'd like to make the k-mesh near the $$\Gamma$$ point (e.g., half the zone) more denser ($$20\times20\times20$$) than other region ($$8\times8\times8$$).

• +1. Welcome again to the site! Perhaps this is 2 questions: "Is there a software that implements an adaptive k-mesh?" and "How can I efficiently implement an adaptive k-mesh with correct symmetry and weight?" Sep 8 '20 at 16:45

In sisl one can create a Monkhorst-Pack grid with zooming capabilities.

Here is a small Python snippet which creates the k-points for the zoomed in region.

import numpy as np
import sisl

# time-reversal-symmetry
trs = True

# first argument is the lattice vectors (in case you want them in 1/Ang)
# in this case it is just a square box of side-lengths 1 Ang
MP_3x3 = sisl.MonkhorstPack(1, [3, 3, 1], trs=trs)
assert np.allclose(MP_3x3.weight.sum(), 1.)

MP_3x3_zoom = sisl.MonkhorstPack(1, [3, 3, 1], size=[1/3, 1/3, 1], trs=trs)
# density is only 1 / 9
assert np.allclose(MP_3x3_zoom.weight.sum(), 1. / 3 ** 2)

MP = MP_3x3.copy()
MP.replace([0] * 3, MP_3x3_zoom)
assert np.allclose(MP.weight.sum(), 1.)

# List k-points
print(MP_3x3.k[:, :2])
print(MP_3x3_zoom.k[:, :2])
print(MP.k[:, :2])

import matplotlib.pyplot as plt
def kplot(MP):
plt.scatter(MP.k[:, 0], MP.k[:, 1], MP.weight * 500, alpha=0.5)
#kplot(MP_3x3)
#kplot(MP_3x3_zoom)
kplot(MP)

plt.show()


For trs=False you find a grid looking like this (sizes of k-points correspond to the weights associated with a BZ integration):

The script in sisl also checks whether weights are preserved and whether the sizes of the BZ correspond to each other.

For your case you could do:

# Replace a single point (Gamma) with higher density
MP = sisl.MonkhorstPack(1, [8] * 3, trs=trs)
MP_20 = sisl.MonkhorstPack(1, [20] * 3, size=[1/8] * 3,trs=trs)
MP.replace([0] * 3, MP_20)

# Replace 3x3x3 k-points around Gamma by
MP = sisl.MonkhorstPack(1, [8] * 3, trs=trs)
MP_20 = sisl.MonkhorstPack(1, [20] * 3, size=[3/8] * 3,trs=trs)
MP.replace([0] * 3, MP_20)


If you try to do something that is invalid, you'll get error messages ;) E.g. if the weight/volume of the replaced k-point(s) does not match the weights of the inserted k-points. Note, with the above machinery you can nest as many zoom regions as necessary.

Disclaimer: I am the author of the package.

• +1 this is a very nice package! How do you determine the weight of the various k-points when the grid is non-uniform? Sep 9 '20 at 10:06
• @ProfM what do you mean, exactly? In the above there is a well-defined volume that each k-point encapsulates due to the Monkhorst Pack algorithm. However, the above procedure wouldn't be viable if one used Gauss-Legendre points since the occupied volume isn't well-defined (start and end-points are not at least). Perhaps I misunderstand you? ;) Sep 9 '20 at 11:40
• thanks for the explanation. Perhaps my question is silly, I was just wondering what happens when you have two different densities of k-points in two different regions of the BZ at the boundary between the two regions. Is it then always possible to assign a volume with each k-point in the usual MP way? Sep 9 '20 at 12:28
• Ok, I think I get it. What MP does is simply cutting the BZ into equal "squares". Any such square may be replaced by any number of sub-squares so long as the original square is completely filled by sub-squares. Any BZ integral won't know of the division, just like one could use Gauss-Kronrod quadratures for converging some property. In any case; any infinitesimal point in the BZ will inherently belong to one, and only one, of the discretized k-points. So there will be some continuity problems if the two grids are of very different density. But that is a property dependent problem. Sep 9 '20 at 12:40