A Python code for calculating the mean-value (Baldereschi’s) point for any crystal structure
Abstract
A python code (mvp.py) is presented for computing the mean-value point (MVP) in the Brillouin zone first introduced by Baldereschi [1]. The code allows calculations of the MVP for any input crystal structure. Having MVP allows approximating the Brillouin zone integrals of relatively smooth, periodic functions defined in the reciprocal space by the value of the same function at only one, mean-value, -point. This approximation decreases computational cost at a relatively small decrease in accuracy. The MVP coordinates for the 14 Bravais lattices are evaluated and the underlying theory is discussed.
I Introduction
In his original paper Baldereschi defined the mean-value point in the Brillouin zone as: “the point such that the value which any given periodic function of wave vector assumes at this point is an excellent approximation to the average value of the same function throughout the Brillouin zone” [1]. The conditions that define the mean-value point (MVP) follow from the expansion of any periodic function defined on the -space into plane waves:
(1) |
where stands for a periodic function of the wave vector , the represent vectors of the direct (Bravais) lattice, which take the role of the wave vectors in the above expansion, and are the Fourier components of the function . Generally, the function needs to fulfill Dirichlet conditions for the expansion from eq. (1) to converge to .
From eq. (1) it is easy to show that the integral of over the entire Brilloiun zone equals the term in the expansion multiplied by the volume of the Brilloiun zone (). Hence, if there were a point at which the sum of all terms in the expansion above, excluding the term, vanishes, the value would be exactly equal to the integral of over the entire Brillouin zone. The existence of is guaranteed by the mean-value theorem of the integral calculus, but its coordinates are dependent on the function . The mean-value point from Baldereschi’s work is a point defined by the symmetry of the crystal that is independent of , at which the value of a function is an “excellent” approximation of its integral over the Brillouin zone.
Hence, approximating the integral of over the entire Brillouin zone can be reduced to finding , provided that is known. In the original work of Baldereschi [1], the coordinates of are evaluated for the three cubic Bravais lattices, face centered cubic (fcc), body centered cubic (bcc), and simple cubic (sc). Subsequently, the mean-value point has been found for some non cubic lattices (see for example [2]). However, to the best of my knowledge, the mean-value point has not been evaluated for all 14 Bravais lattices, and a general, stndalone code for doing so for any input crystal structure is not available. Herein, both the mvp.py code and the resulting MVPs for the 14 Bravais lattice are presented, and various aspects of the procedure are discussed.
II Problem setup and code description
The key to evaluating the MVP for a given crystal structure is the requirement that the sum of all terms in eq. (1) for vanishes at some . These conditions provide a system of equations whose solution(s) define . For the purpose of finding an approximate, function independent the sum from eq. (1) can be rewritten in a more suitable form using the symmetry of the crystal. As already discussed by Baldereschi in Ref. [1] one can assume, without any loss of generality, that all are equal for vectors that are connected by the point group symmetry operations, that is, that belong to the same star of . One can then write:
(2) |
where goes over all stars of , counts all the lattice vectors within a given star, and are the “symmetrized” plane waves belonging to the (fully symmetric) irreducible representation of the point group.
Hence, the -independent conditions that determine are that all for any . This is, of course, too much to ask and this system of equations does not have a solution. However, two simplifications can be made. First, one can assume that decrease sufficiently fast with , so that after a relatively small number of terms the non-zero value of becomes irrelevant. Second, even if the number of zero terms is smaller than three, which is necessary for all three components of to be uniquely determined, the values can be chosen so to minimize the first nonzero . These two assumptions allowed Baldereschi to evaluate the coordinates of the mean-value points for the three cubic systems (sc, bcc, fcc).
The mvp.py code follows the outlined protocol. For any given crystal structure, a set of lattice vectors is constructed. Here are the unit cell vectors and the integers are chosen to cover a range of values so that a sufficiently large number of s is produced; large enough to enclose the first 4 stars of (). The number of vectors is controlled by the R_range input integer variable ( R_range R_range), whose default value is 4. All results presented in this paper are obtained with R_range = 4.
Then the point group symmetry operations are found with the help of spglib library [3]. For this purpose the tolerance factors for the spglib are set to symprec = 1e-02 Å (length) and angle_tolerance = (angles). The full set of orthogonal transformations (rotations and mirror planes) including those that are parts of screw axes and glide planes is used for the classification of vectors into stars. Conveniently, the spglib library provides a separation of the of the space group operations into orthogonal parts (labeled “rotations”) and associated translational parts (fractional translations for the glide planes and screw axes). The mvp.py code takes the entire set of orthogonal parts, and uses that set to classify into stars.
In the next step, the vectors are classified into classes of symmetry equivalent members forming the stars. This is done by applying the entire set of orthogonal transformations successively on vectors and grouping them with those they transform into. The equality of a given and some is determined using the condition with the tolerance factor gen_tol = 1e-5. Also, applying the symmetry operations may map a given to itself. All these duplicate occurrences are removed when constructing the stars. In the next step the functions are constructed for .
The roots of functions are found in the following way. First, a -point grid is constructed spanning the one unit cell of the reciprocal lattice. The number of -points is controlled by the nkpts input parameter (default value 2e+7). When constructing the -point grid the unit vectors of the reciprocal lattice are divided into sub-divisions so that the grid spacing is uniform. The grid spacing is computed as and . Then, the values of are evaluated over the entire grid and its zeros are used as starting points near which the simultaneous roots of the , and will be evaluated. The situation in which no zeros of are found for any grid point is easily remedied by increasing the nkpts.
In the mvp.py code the -points at which 1e-12 (input parameter zero) are extracted and the function fsolve from scipy.optimize package is used to find roots of a vector function near every one of those -points. If the roots of exist then the roots that minimize are extracted and those that are possibly outside the reciprocal unit cell are mapped back inside. The list of these -points then represents the list of mean-value points (symmetry equivalent). User can then extract (on their own) those that belong to the first Brillouin zone, or choose to output only the -point from this set with the lowest norm (input parameter only_lowest_norm). In case has no roots, the roots of are then solved for and those that minimize are extracted and mapped back into the reciprocal unit cell. Lastly, our tests indicate that relatively large default value of nkpts is unfortunately required to converge the MVP value. Using different solvers might help converge the MVP faster, but that will be explored in the future.
The mvp.py code is available on github [4] as part of the toolbox package [5] for pylada [6], a collection of python tools for structure prediction (random structure generation), surface cutting, various structure manipulations, etc. All dependencies include: python, numpy, scipy, spglib, pylada, and toolbox. The mvp.py is constructed around the pylada structure object but is easily adaptable to use other structure objects from other codes (e.g ASE [7], aflow [8], pymatgen [9],…), which will remove the pylada dependency.
Finally, the choice to write the mvp.py in Cartesian rather then more elegant crystal coordinates is mainly driven by the differences in how the integers are treated between python2 and python3. In this way the code works with both versions. The price to pay is the introduction of various tolerance factors whose default values are set to best reflect extensive testing. That said, the convergence of the results with respect to various tolerance factors needs to be tested before use.
III Results
Table LABEL:tab:results below lists the MVP coordinates for the 14 Bravais lattices. For clarity, the specific unit cells that are used are displayed together with the choice of unit vectors and their coordinates. The corresponding first Brillouin zones are also displayed as well as the location of the MVP points. In the first three rows the original results of Baldereschi are reproduced. The coordinates of the MVPs for the simple cubic, face centered and body centered cubic lattices correspond well to those reported in Ref. [1]. The rest are original results.
Importantly, coordinates of the MVPs in general depend on the choice of the lattice parameters. Table LABEL:tab:results only lists MVP coordinates for the specific choices provided in the table. For other lattice parameters users should compute the MVPs on their own.
lattice vectors [] | MVP coordinaties | ||||
Lattice | Unit cell | Brillouin zone with MVP | [] [crystal] | ||
Simple cubic |
![]() |
![]() |
|||
Face centerred cubic |
![]() |
![]() |
|||
Body centerred cubic |
![]() |
![]() |
|||
Hexagonal |
![]() |
![]() |
|||
Rhombohedral |
![]() |
![]() |
|||
Tetragonal |
![]() |
![]() |
|||
Tetragonal body centered |
![]() |
![]() |
|||
Orthorhombic |
![]() |
![]() |
|||
Orthorhombic base centered |
![]() |
![]() |
|||
Orthorhombic body centered |
![]() |
![]() |
|||
Orthorhombic face centered |
![]() |
![]() |
|||
Monoclinic |
![]() |
![]() |
|||
Monoclinic base centered |
![]() |
![]() |
|||
Triclinic |
![]() |
![]() |
|||
IV Discussion
Here I would like to make several remarks, which may be relevant when using the code and/or understanding its structure.
It is first important to note that the systems of equations or are non-linear in with being an integer multiple of . As there is no general approach of solving such systems of equations (to my knowledge at least) the choice was to use scipy.optimize.fsolve function that finds roots near a certain starting point. It turns out that a relatively large number of those starting points are needed to cover most, if not all, zeros of , which then allows for the roots of or to be found. Converged values of MVPs in Table LABEL:tab:results are obtained using nkpts between 1e+6 (simple cubic) and 3e+7 (hexagonal lattice). While this might look excessive, it is necessary for the scipy.optimize.fsolve to find correct solutions. The typical time needed for the mvp.py to solve the equations (on a personal computer) is measured in minutes.
Second, by default mvp.py code uses all orthogonal parts (reflections, rotations) belonging to the entire space group rather then the point group operations only. This is done so to account the fact that the entire set of orthogonal transformations may be larger than the point group alone, and that the a group of all pure translations is invariant under the operations of all orthogonal transformations including those belongin to screw axes and glide planes. Hence, when classifying vectors into stars all orthogonal transformations need to be used. While this is only relevant when dealing with real crystals (not Bravais lattices), the mvp.py code is written in this way to provide access to all symmetry operations in Cartesian coordinates, which may be useful for other purposes.
Next, the MVPs are not invariant under the supercell transformations in spite of supercells being just different representations of the same crystal/lattice. That is easy to prove just by considering the three cubic lattices. Both fcc and bcc can be represented as simple cubic using their conventional unit cells. However, the -point in the crystal coordinates, which is the MPV for simple cubic lattice is not an MVP for neither fcc nor bcc. This is because the first star of for both fcc and bcc (set of 12 and 8 lattice vectors, respectively) is not accounted for in the simple cubic lattice and consequently for both of them at . The second star of for fcc and bcc is the same as the first star for simple cubic, which then implies at and so on.
Lastly, it is important to keep in mind that the MVP coordinates do in general depend on the choice of the lattice parameters. This is true for Cartesian as well as the crystal coordinates as already discussed in Ref. [2] for tetragonal and rhombohedral lattices. It is precisely this dependence that motivated writing the mvp.py code rather then tabulating all cases for all 14 Bravais lattices.
V Conclusions
In conclusion, the mvp.py code is presented for computing the mean-value (Baldereschi’s) point in the Brillouin zone for any crystal structure. The underlying theory is also presented and discussed as are various aspects of the specific implementation in the mvp.py code. The code itself relies on the pylada python package [6] a high-throughput computational physics framework, but is easily adaptable to other similar packages.
Acknowledgements.
I would like to acknowledge discussions with Prof. A. Baldereschi. They were instrumental for many things I have done, this work included. The work is supported by the US National Science Foundation, Grant No. DMR-1945010.References
- Baldereschi [1973] A. Baldereschi, Mean-Value Point in the Brillouin Zone, Physical Review B 7, 5212 (1973).
- Bashenov et al. [1977] V. K. Bashenov, M. Bardashova, and A. M. Mutal, Baldereschi points for some noncubic lattices, physica status solidi (b) 80, K89 (1977).
- Togo et al. [2018] A. Togo, K. Shinohara, and I. Tanaka, Spglib: a software library for crystal symmetry search, arXiv:1808.01590 [cond-mat.mtrl-sci] (2018).
- [4] mvp.py, github.com/vstevano/toolbox/blob/main/mvp.py.
- [5] toolbox package, github.com/vstevano/toolbox.
- [6] pylada package, github.com/pylada.
- Larsen et al. [2017] A. H. Larsen, J. J. Mortensen, J. Blomqvist, I. E. Castelli, R. Christensen, M. Dułak, J. Friis, M. N. Groves, B. Hammer, C. Hargus, E. D. Hermes, P. C. Jennings, P. B. Jensen, J. Kermode, J. R. Kitchin, E. L. Kolsbjerg, J. Kubal, K. Kaasbjerg, S. Lysgaard, J. B. Maronsson, T. Maxson, T. Olsen, L. Pastewka, A. Peterson, C. Rostgaard, J. Schiøtz, O. Schütt, M. Strange, K. S. Thygesen, T. Vegge, L. Vilhelmsen, M. Walter, Z. Zeng, and K. W. Jacobsen, The atomic simulation environment—a python library for working with atoms, Journal of Physics: Condensed Matter 29, 273002 (2017).
- Oses et al. [2023] C. Oses, M. Esters, D. Hicks, S. Divilov, H. Eckert, R. Friedrich, M. J. Mehl, A. Smolyanyuk, X. Campilongo, A. van de Walle, J. Schroers, A. G. Kusne, I. Takeuchi, E. Zurek, M. Buongiorno Nardelli, M. Fornari, Y. Lederer, O. Levy, C. Toher, and S. Curtarolo, aflow++: a C++ framework for autonomous materials design, Comp. Mat. Sci. 217, 111889 (2023).
- Ong et al. [2013] S. P. Ong, W. D. Richards, A. Jain, G. Hautier, M. Kocher, S. Cholia, D. Gunter, V. L. Chevrier, K. A. Persson, and G. Ceder, Python materials genomics (pymatgen): A robust, open-source python library for materials analysis, Computational Materials Science 68, 314 (2013).