# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import numpy as np
from ..sile import add_sile, sile_fh_open, sile_raise_write
from .sile import SileSiesta
from sisl._internal import set_module
from sisl.unit.siesta import unit_convert
__all__ = ['kpSileSiesta', 'rkpSileSiesta']
Bohr2Ang = unit_convert('Bohr', 'Ang')
@set_module("sisl.io.siesta")
class kpSileSiesta(SileSiesta):
""" k-points file in 1/Bohr units """
[docs] @sile_fh_open()
def read_data(self, sc=None):
""" Returns K-points from the file (note that these are in reciprocal units)
Parameters
----------
sc : SuperCellChild, optional
if supplied the returned k-points will be in reduced coordinates
Returns
-------
k : k-points, in units 1/Bohr
w : weights for k-points
"""
nk = int(self.readline())
k = np.empty([nk, 3], np.float64)
w = np.empty([nk], np.float64)
for ik in range(nk):
l = self.readline().split()
k[ik, :] = float(l[1]), float(l[2]), float(l[3])
w[ik] = float(l[4])
# Correct units to 1/Ang
k /= Bohr2Ang
if sc is None:
return k, w
return np.dot(k, sc.cell.T / (2 * np.pi)), w
[docs] @sile_fh_open()
def write_data(self, k, weight, fmt='.9e'):
""" Writes K-points to file
Parameters
----------
k : array_like
k-points in units 1/Bohr
weight : array_like
same length as k, weights of k-points
fmt : str, optional
format for the k-values
"""
sile_raise_write(self)
nk = len(k)
self._write(f'{nk}\n')
_fmt = ('{:d}' + (' {:' + fmt + '}') * 4) + '\n'
for i, (kk, w) in enumerate(zip(np.atleast_2d(k), weight)):
self._write(_fmt.format(i + 1, kk[0], kk[1], kk[2], w))
[docs] @sile_fh_open()
def read_brillouinzone(self, sc):
""" Returns K-points from the file (note that these are in reciprocal units)
Parameters
----------
sc : SuperCellChild
required supercell for the BrillouinZone object
Returns
-------
bz : BrillouinZone
"""
k, w = self.read_data(sc)
from sisl.physics.brillouinzone import BrillouinZone
bz = BrillouinZone(sc)
bz._k = k
bz._w = w
return bz
[docs] @sile_fh_open()
def write_brillouinzone(self, bz, fmt='.9e'):
""" Writes BrillouinZone-points to file
Parameters
----------
bz : BrillouinZone
object contain all weights and k-points
fmt : str, optional
format for the k-values
"""
# And convert to 1/Bohr
k = bz.tocartesian(bz.k) * Bohr2Ang
self.write_data(k, bz.weight, fmt)
@set_module("sisl.io.siesta")
class rkpSileSiesta(kpSileSiesta):
""" Special k-point file with units in reciprocal lattice vectors
Its main usage is as input for the kgrid.File fdf-option, in which case this
file provides the k-points in the correct format.
"""
[docs] @sile_fh_open()
def read_data(self):
""" Returns K-points from the file (note that these are in reciprocal units)
Returns
-------
k : k-points, in units of the reciprocal lattice vectors
w : weights for k-points
"""
nk = int(self.readline())
k = np.empty([nk, 3], np.float64)
w = np.empty([nk], np.float64)
for ik in range(nk):
l = self.readline().split()
k[ik, :] = float(l[1]), float(l[2]), float(l[3])
w[ik] = float(l[4])
return k, w
[docs] @sile_fh_open()
def read_brillouinzone(self, sc):
""" Returns K-points from the file
Parameters
----------
sc : SuperCellChild
required supercell for the BrillouinZone object
Returns
-------
bz : BrillouinZone
"""
k, w = self.read_data()
from sisl.physics.brillouinzone import BrillouinZone
bz = BrillouinZone(sc)
bz._k = k
bz._w = w
return bz
[docs] @sile_fh_open()
def write_brillouinzone(self, bz, fmt='.9e'):
""" Writes BrillouinZone-points to file
Parameters
----------
bz : BrillouinZone
object contain all weights and k-points
fmt : str, optional
format for the k-values
"""
self.write_data(bz.k, bz.weight, fmt)
add_sile('KP', kpSileSiesta, gzip=True)
add_sile('RKP', rkpSileSiesta, gzip=True)