Package: kpLib
KpLibKpLib is a C++ library for finding the optimal Generalized Monkhorst-Pack k-points grid. It can be imported into electronic-structure packages as a generator of efficient generalizedk-point grids, or be integrated into user scripts through the Python interfacekpLib.For questions of KpLib and underlying algorithms, you are welcomed to check our paper athereor send emails tokpoints@jhu.edu.Note: We have fixed inv.1.1.0(2023.04.08) a few bugs of the Python interface causing scripts to hang for monoclinic and trigonal system in $hR$ representation. We also reduced dependencies of external Python packages to the minimum to let users choose their favoriate package for structure IO. Please check theRELEASE.mdnote for details.UsageRoute I: Integrating KpLib as a C++ library in simulation packageCompile KpLib as a libraryWe usecmaketo detect native build environment and generate native build files. For Unix-like operating systems, users can build the project by:$ git clone https://gitlab.com/muellergroup/kplib.git
$ cd kplib
$ mkdir build
$ cd build
$ cmake ..
$ makeThen you can find a static library atbuild/libkpoints.aand a dynamic library atbuild/libkpoints.so.Use KpLib in C++ CodeThere are basically two steps:Copy the header filesrc/kPointLatticeGenerator.hto yourincludefolder, and add the following line to your source code#include "kPointLatticeGenerator.h"Link the library at the linking stage.For example, to link the static library and compile the objectmyapp.oto the final executablemyapp, you can$ g++ myapp.o -L /path/to/lib libkpoints.a -o myappIf you want to use the dynamic library, you can$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib
 $ g++ myapp.o -L /path/to/lib -lkpoints -o myappThe first line tells the loader,ld, where to find the shared library at runtime, since the dynamic linkage only puts a reference of the library in the executable.Then you are ready to go!An explanation of the API with more details can be found below, together with a demo C++ program (demo_kplib/src) created to demonstrate the usage of this API in C++ environment and the conventions the API assumes.Route II: Use KpLib as a Python packageInstallationInstall from PyPI usingpipThis will install the core KpLib module with minimal third-party dependencies. User will need to parse input structures and write out generatedK-point grid using their favorite matsci packages (e.g.aseandpymatgen).$ pip install --user pybind11 build wheel
$ pip install --user kplib       # Install only the core kplib package. 
$ pip install --user kplib[cli]  # To install the CLI tool `kpgen`. 
                                 # This will also install `pymatgen` and `click`Install from source usingpipThe Python interface is a thin wrapper of the C++ library. Building from source should be straight forward. It also provides a way to install a CLI command to be called in terminal (requiringpymatgenfor IO).Step 1. Download source code fromhttps://gitlab.com/muellergroup/kplib.$ git clone https://gitlab.com/muellergroup/kplib.gitStep 2. The C++-Python interface is written usingpybind11, and thesetup.pyimports it at the beginning for compiling the C++ code into a Python external module. So, it should be installed before installingkpLib.$ pip install --user pybind11
$ pip install --user build wheel # Python build toolchain that you might already have.Step 3. If you would like to choose your own structure parser (such aspymatgen,aseand other wonderful packages), you can install only the core module ofkpLibwith a minimal dependencies:$ cd kplib
$ pip install --user .If you would like to use the CLI command toolkpgen, you can use the following code to installkpLib. This will additionally installpymatgen(as a parser) andclick(to provide a nice CLI interface):$ cd kplib
$ pip install --user .[cli]
$ which kpgenIf you want to test your installation, you can installkpLibwith dependencies
that enables the test suite (pymatgenandpytest). After installation, you can run tests to make sure everything is correctly installed.$ cd kplib
$ pip install --user .[tests]
$ pytestUsing KpLib in Python scriptThekpLibPython package is written in the way to provide an interface
for the core KpLib function and allow maximal usage flexibility. The choice
of packages for parsing input structure and for writing the generated k-points
grid to a desired format is left to users. The following section will first
describe the signature of theget_kpointsfunction, and then give two
example scripts using the two popular packagespymatgenandasefor I/O.kpLib.interface::get_kpointsis the core and only function thekpLibPython
package provides. Its signature is as follows:def get_kpoints(
    lattice:            List[List[float]] or numpy.ndarray,
    fractional_coords:  List[List[float]] or numpy.ndarray,
    atomic_numbers:     List[int] or Tuple[int],
    min_distance:       float = 0.1,
    min_total_kpoints:  int = 1,
    include_gamma:      str = "auto",
    symprec:            float = 1e-5,
    use_scale_factor:   bool = False,
) -> Dictget_kpointsuses the 3 positional arguments to define a structure. The rest of the keyword
arguments define requirements of the outputK-point grid. The size requirement ofK-point grids is defined bymin_distanceandmin_total_kpoints. They can be used
separately or together. We recommand usingmin_distance. For an example of correlating
the conventional way of specifying a Monkhorst-Pack grid by three integersm1 x m2 x m3tomin_distance, see the section below.The meaning of all arguments are as follows:lattice: A 3x3 matrix representing the lattice vectors of the unit cell of the input structure. Each row represents a vector, i.e. in the format of [a,b,c]. It can be a list of list or anumpy.ndarray.fractional_coords: A list of 3-dimensional coordinates in the fractional format relative to the lattice vectors. It can be a list of list or anumpy.ndarray.atomic_numbers: A list of atomic numbers, the i-th number of which defines the element of the i-th atom at the positionfractional_coords[i]. It can be a list or a tuple.min_distance: The minimum required distance in real-space between any pair of lattice points in the superlattice corresponding to the returnedK-point grid. It specifys the
size of the requiredK-point grid and has a unit of Angstrom. The larger the value ofmin_distance, the denser the returned grid will be (i.e., more symmetrically distinctK-point).min_total_kpoints: Minimum number of totalK-points required in the returnedK-point grid. Note, it is not the number of symmetrically distinctK-points that
are actually used in a calculation. The total set ofK-points will be reduced by symmetry
to the minimal set of distinctK-points, which will be used in a calculation.include_gamma: It can have valuestrueorfalse, orauto. Usetrueto include the Gamma point (i.e. [0, 0, 0] of reciprocal space) in the return grid.
Usefalseto exclude the Gamma point. Useautoto let kplib choose between
the two types of grid and return the one with a smaller number of symmetrically
distinctK-points. If they have the same number of distinctK-points, return
the one with larger effecitive min_distance.symprec: Precision in real space when determining structure symmetries. The default
is1E-5. Atomic coordinates with a difference less thansymprecwill be determined
as equivalent. If you want to include more symmetries, use a larger value.use_scale_factor: A scheme to speed up the search at the cost of returning a sub-optimialK-point grid. Default behaviour is to not use the scheme. You can consider use this scheme
when the code takes a very long time to return a grid. For a detailed explanation,
see the end of this README.Theget_kpointsfunction returns theK-point grid as adict. The keys are:min_periodic_distance: The minimum distance between any pair of lattice points of the real-space superlattice corresponding to the returnedK-point grid.num_distinct_kpts: The number of symmetrically distinctK-points. This is the number ofK-points actually used in a calculation.distinct_coords: Fractional coordinates of symmetrically distinctK-points.distinct_weights: Weights of corresponding symmetrically distinctK-point indistinct_coords.num_total_kpts: The number of totalK-points.coords: Fractional coordinates of allK-points.weights: Weights of correspondingK-points incoords.Usually the coordinates and weights of distinctK-points are enough to define an
input file of a calculation.Making sense of "min_distance""Minimum distance" means the minimum periodic distance between any pairs of
lattice points on a real-space lattice. The reciprocal lattice of a primitive unit cell
is a supercell in the reciprocal space of the reciprocal lattice of a super cell in real space. It implys eachK-point grid corresponds to a real-space superlattice. Therefore, we can use the "minimum distance" of a real-space superlattice to specify the size its correspondingK-point grid in the reciprocal space. The larger themin_distance, the larger the supercell and hence the denser theK-point grid.For example, consider an artificial tetragonal structure with a lattice as $[[2, 0, 0], [0, 2, 0], [0, 0, 3]]$ and a single atom at the origin. Its space group is $P4/mmm$. A traditional Monkhorst-Pack 4x4x4 grid with the Gamma point would correspond to a supercell of $[[8, 0, 0], [0, 8, 0], [0, 0, 12]]$ and has18symmetrically distinctK-points. The minimum periodic distance in this case is 8 Angstroms.When usingkpLibwithmin_distance= 8, the Gamma-centered result would have only9symmetrically distinctK-points and an effective minimum distance of 8.485. For
shifted grids, the result would be a grid with6symmetrically distinctK-points
and an effective minimum distance of 8. Similar calculation accuracy but three times
less the number of distinctK-points.Example Python ScriptsHere, we give two examples of usingkpLibin Python script, using the popularpymatgenandasepackages respectively for IO.fromkplibimportget_kpointsfrompymatgen.coreimportStructurefrompymatgen.io.vasp.inputsimportKpoints,Kpoints_supported_modesstruct=Structure.from_file("./POSCAR")kpts=get_kpoints(struct.lattice.matrix,struct.frac_coords,struct.atomic_numbers,min_distance=25.0,include_gamma="auto")kpoints_file=Kpoints(style=Kpoints_supported_modes.Reciprocal,num_kpts=kpts["num_distinct_kpts"]kpts=kpts["distinct_coords"],kpts_weights=["distinct_weights"])kpoints_file.write_file("./KPOINTS")fromkpLib.interfaceimportget_kpointsimportasestruct=ase.io.read("./POSCAR",format="vasp")kpts=get_kpoints(struct.get_cell()[:],struct.get_scaled_positions(),# Note: the atomic coordinates are in fractional format, not Cartesian.struct.get_atomic_numbers(),min_distance=25.0,include_gamma="gamma")# ... User can then use the kpts dict to build VASP calculator and perform other tasksCommand-line interfacekpgenFor users' convenience, the Python package also provides a command-line interface
that can be called in terminal. It usespymatgenas a structure parser and
output theK-point grid to a vasp-formatKPOINTSfile.A simple example is:$kpgen-gauto-d25.0./POSCAR./KPOINTS-gis short for--gammaand it defined the type ofK-point grid, a gamma-centered, shifted or
auto-determined grid.-dis short for--distanceand specifiesmin_distance. This is a simple
wrapper of theget_kpiontsfunction discussed above. All the options
thatget_kpointsaccepts, this CLI accepts. Usekpgen --helpto get a full list of
permitted arguments and options.The defaultpip install kplibdoes not install this CLI. To enable this feature, after
cloning the source code, run:$pipinstall--user.[cli]The "[cli]" part instructs thesetup.pyto installpymatgenandclick.How to citeIf you use the kplib or theK-point Grid Generator in generating generalizedk-point grids, please cite the following paper:Wang, Y., Wisesa, P., Balasubramanian, A., Dwaraknath, S. & Mueller, T. Rapid generation of optimal generalized Monkhorst-Pack grids. Comp Mater Sci, 110100, doi:https://doi.org/10.1016/j.commatsci.2020.110100(2020).DocumentationConventionsThis section specifies the conventions we assume in the arguments to theKPointLatticeGeneratorconstructor in C++. The Python interfacekpLibis written
in the same manner that aligns with these conventions.Lattice VectorsLattice vectors are expressed as row vectors in the lattice matrix:doubleprimtiveVectors[3][3]={{a_x,a_y,a_z},{b_x,b_y,b_z},{c_a,c_z,c_y}}Point OperatorsEach operatir is a 3x3 integer matrix, representing how afractional coordinatein theprimitive lattice basisis transformed under this operation.int latticePointOperations[][3][3];Because of the lattice vectors are expressed as rows, each symmetry operation is done through ${x'}^T = {x}^T\cdot R$.Conventional Lattice VectorsThe algorithm we developed to efficiently iterate symmetry-preserving superlattices assumes
the following conditions on the input conventional lattice vectors, additional to the usual
conventions (e.g., see the standard unit cell inspglibdocumentation).For all crystal sysmtes, except fortriclinic, the $\mathbf{c}$-vector should be along the axis
of the highest-order rotational operation, i.e the 4-fold, 6-fold, 3-fold, 4-fold, any 2-fold,
and 2-fold rotation forcubic,hexagonal,trigonal,tetragonal,orthorhombic, andmonocliniclattices, respectively. This direction is commonly
referred as the "primary symmetry direction" in crystallography textbooks. The conventions
in the International Tables of Crystallograph (seeChapter 9.1) already satisfy this except for monoclinic lattice.For monoclinic crystal system, the international convention assumes the $\mathbf{b}$-unique setting, in which the $\beta$ angle is the non-acute angle, the two-fold rotation axis is along the $\mathbf{b}$ vector and the one-face-centered lattice point in the $\mathbf{a}$-$\mathbf{b}$ plane (i.e. "C" in the space group symbol). But kplib library assumes the two-fold rotation to be along the $\mathbf{c}$-vector, or in other words, the $\mathbf{b}$-unique setting. A simple transformation is to just rotate the vectors like the following: $\mathbf{b} \rightarrow \mathbf{c}$, $\mathbf{c} \rightarrow \mathbf{a}$, and $\mathbf{a} \rightarrow \mathbf{b}$.Fortrigonallattices, no matter in $hR$ or $hP$ representation, the conventional lattices should be primitive hexagonal lattices, i.e. the rhombohedrally-centered hexagonal lattice. This is the same as the international convention.The algorithm doesn't put constraints on triclinic system, or on the centering type of orthorhombic
lattices.(Note: User could get the primary directions from the point symmetry opeartions.)The C++ APIClass:KPointLatticeGeneratortemplate<typenameT>usingTensor=std::vector<std::vector<T>>;/*** Constructor.** To see how the variables are defined, check the "Conventions" section below)** @param primVectorsArray            3x3 matrix with primitive lattice vectors in rows.* @param conventionalVectorsArray    3x3 matrix with conventional lattice vectors in rows.* @param latticePointOperatorsArray  point operators of the Laue Classof the input structure, expressedin the basis of primitive lattice vectors* @param numOperators                number of point operators in above array* @param isConventionalHexaognal     whether the conventional lattice ishexagonal*/KPointLatticeGenerator(constdoubleprimVectorsArray[][3],constdoubleconventionalVectorsArray[][3],constintlatticePointOperatorsArray[][3][3],constintnumOperators,constboolisConventionalHexagonal);/** Specify whether to generate a gamma-centered grid or a shifted grid.* The available shifts are:*     {{0.0, 0.0, 0.5}, {0.0, 0.5, 0.0}, {0.5, 0.0, 0.0}, {0.5, 0.5, 0.0},*      {0.5, 0.0, 0.5}, {0.0, 0.5, 0.5}, {0.5, 0.5, 0.5}}* Basiclly, side centers, face centers and the body center.** @param includeGamma   TRUE:  gamma-centered grid*                       FALSE: grid with one of the above shift*                       AUTO:  search both shifted and gamma-centered grid*                              and return the best one.*/enumINCLUDE_GAMMA{TRUE,FALSE,AUTO};voidincludeGamma(INCLUDE_GAMMAincludeGamma);/** @param minDistance  The returned grid should have a corresponding*                     real-space superlattice whose "minimum periodic distance"*                     is no smaller than this value.* @param minSize      Minimum number of total k-points of grids returned.*/KPointLatticegetKPointLattice(constdoubleminDistance,constintminSize);Class:KPointLatticeIt's meant to hold the found k-point grid and provide query functions.
The main query routines of this type:double getMinPeriodicDistance();
int getNumDistinctKPoints();
int numTotalKPoints();

/*
 * @return Tensor<double> 2D arrays of coordinates. It's basically a wrapper
 *                        of "double coords[][3]".
 */
Tensor<double> getKPointCoordinates();

/*
 * @return vector<int>  1D array of k-points weights.
 */
std::vector<int> getKPointWeights();Example: Using KpLib in C++ Code --demo_kplibTo demonstrate the usage of the kpbib, we implemented a simple C++ application to generate optimized Generalised Monkhorst-Pack k-point grids. It usespglibto find symmetries (Togo and Tanaka, 2010) and output the k-point grid in the format of VASP KPOINTS file.It is under the folderdemo_kplib. We have included a pre-built binary of the spglib library. User can also choose to build the latest version ofspglibfrom source and replace it. The executabledemo_kplibcan be built following these commands:$ cd demo_kplib
$ mkdir build
$ cd build
$ cmake ..
$ makeThe binary will be placed at./build/demo_kplib. To call it, use:$ ./demo_kplib /path/to/POSCAR /path/to/PRECALC > KPOINTSThePOSCARis one of the standard VASP input file. ThePRECALCfile is the input file ofdemo_kpliband users can find its specifications on ourwebsite. Since it's for demonstration purposes, only the parametersMINDISTANCE,MINTOTALKPOINTS, andINCLUDEGAMMAare valid.Examples of using this app for different crystal systems can be found indemo_kplib/examples.KPOINTS_refareKPOINTSfiles generated byour server.KPOINTS_kplibare files created by thedemo_kplibapp.For a stand-alone application with more funcnalities, like automatic detection of slabs, please check ourK-point Grid GeneratorandK-point Server.Code snippet of demo_kpibBelow are excerpts from thedemo_kplibapplication to show how to use the KpLib API.demo_kplib/src/main.cpp:#include"kPointLatticeGenerator.h"#include"utils.h"#include"precalc.h"#include"poscar.h"#include<iostream>intmain(intargc,char**argv){if(argc<3){std::cerr<<"Usage: ./main /path/to/POSCAR /path/to/PRECALC"<<std::endl;return1;}// Parse POSCAR and PRECALC.Poscarposcar;poscar.readFromPoscar(std::string(argv[1]));Precalcprecalc(argv[2]);// Execute the main routines.KPointLatticeGeneratorgenerator=initializeKPointLatticeGeneratorObject(poscar.primitiveLattice,poscar.coordinates,poscar.atomTypes);if(precalc.getIncludeGamma()=="TRUE"){generator.includeGamma(TRUE);}elseif(precalc.getIncludeGamma()=="FALSE"){generator.includeGamma(FALSE);}elseif(precalc.getIncludeGamma()=="AUTO"){generator.includeGamma(AUTO);}KPointLatticelatticeGamma=generator.getKPointLattice(precalc.getMinDistance(),precalc.getMinTotalKpoints());outputLattice(latticeGamma);}demo_kplib/src/utils.cpp:#include"utils.h"#include"spglib.h"...// other includes and functions// Wrapper of the KPointLatticeGenerator constructor.KPointLatticeGeneratorinitializeKPointLatticeGeneratorObject(Tensor<double>primitiveLattice,Tensor<double>coordinates,std::vector<int>atomTypes){doubleprimLatticeArray[3][3]={0};doubleconventionalLatticeArray[3][3]={0};introtation[192][3][3]={0};intsize=0;boolisConventionalHexagonal=false;// use spglib to get necessary parameters for the consturctor// of KPointLatticeGenerator....KPointLatticeGeneratorgenerator=KPointLatticeGenerator(primLatticeArray,conventionalLatticeArray,rotation,size,isConventionalHexagonal);if(useScaleFactor=="TRUE"){generator.useScaleFactor(spaceGroup);// Otherwise, use the fully dynamic search.}returngenerator;}Using scale factor to accelerate searchScale factor is a scheme implemented to speed up the search of optimized generalized
grids at the cost of returning a sub-optimalK-point grid. It is controlled
byKPointsLatticeGenerator::useScaleFactorin the C++ library and the flaguse_scale_factorin the Python interface.Whenuse_scale_factoris set toTrueinkpLib.interface::get_kpointsfunction or in
the CLI commandkpgen, the code will
search exhaustively up to a pre-defined threshold of total number ofK-points. If no grids are
found with effective minimum distance at leastmin_distance,
the user-givenmin_distancewill be divide bynand then kplib search again for a grid
satifyingmin_distance/n. If there are still no valid grids, kplib will incrementnby 1
and search again until it find a valid grid. When a valid grid is finally found,
the grid will be scaled up byn(i.e. total number ofK-points is increased byn^3times) before being returned to satisfy themin_distancerequirement.
Currently the maximum value ofnis set to 3. The thresholds of maximum total number ofK-points for exhaustive search are 729 (9x9x9) for triclinic structures,
1728 (12x12x12) for monoclinic structures, 5832 (18x18x18) for orthorhombic, tetragonal,
trigonal and hexagonal structures, and 46656 (36x36x36) for cubic structures. User can
increase the maximum value ofnand these thresholds inKPointLatticeGenerator::useScaleFactorand recompile.The C++ library turns on and off this scheme through the functionKPointLatticeGenerator::useScaleFactor. It accepts the space group numbers of input structures
to provide the flexibility of selectively using this scheme for a subset of user selected lattice
types.