@@ -1688,3 +1688,148 @@ def get_orb_from_str(orbs):
1688
1688
orbitals = [(int (orb [0 ]), Orbital (orb_labs .index (orb [1 :]))) for orb in orbs ]
1689
1689
orb_label = f"{ orbitals [0 ][0 ]} { orbitals [0 ][1 ].name } -{ orbitals [1 ][0 ]} { orbitals [1 ][1 ].name } " # type: ignore
1690
1690
return orb_label , orbitals
1691
+
1692
+
1693
+ class LobsterMatrices :
1694
+ """
1695
+ Class to read Matrices file generated by LOBSTER (e.g. hamiltonMatrices.lobster).
1696
+
1697
+ Attributes:
1698
+ for filename == "hamiltonMatrices.lobster"
1699
+ onsite_energies (list[np.arrays]): List real part of onsite energies from the matrices each k-point.
1700
+ average_onsite_energies (dict): dict with average onsite elements energies for all k-points with keys as
1701
+ basis used in the LOBSTER computation (uses only real part of matrix).
1702
+ hamilton_matrices (dict[np.arrays]) : dict with the complex hamilton matrix
1703
+ at each k-point with k-point and spin as keys
1704
+
1705
+ for filename == "coefficientMatrices.lobster"
1706
+
1707
+ onsite_coefficients (list[np.arrays]): List real part of onsite coefficients from the matrices each k-point.
1708
+ average_onsite_coefficient (dict): dict with average onsite elements coefficients for all k-points with keys as
1709
+ basis used in the LOBSTER computation (uses only real part of matrix).
1710
+ coefficient_matrices (dict[np.arrays]) : dict with the coefficients matrix
1711
+ at each k-point with k-point and spin as keys
1712
+
1713
+ for filename == "transferMatrices.lobster"
1714
+
1715
+ onsite_transfer (list[np.arrays]): List real part of onsite transfer coefficients from the matrices at each
1716
+ k-point.
1717
+ average_onsite_transfer (dict): dict with average onsite elements transfer coefficients for all k-points with
1718
+ keys as basis used in the LOBSTER computation (uses only real part of matrix).
1719
+ transfer_matrices (dict[np.arrays]) : dict with the coefficients matrix at
1720
+ each k-point with k-point and spin as keys
1721
+
1722
+ for filename == "overlapMatrices.lobster"
1723
+
1724
+ onsite_overlaps (list[np.arrays]): List real part of onsite overlaps from the matrices each k-point.
1725
+ average_onsite_overlaps (dict): dict with average onsite elements overlaps for all k-points with keys as
1726
+ basis used in the LOBSTER computation (uses only real part of matrix).
1727
+ overlap_matrices (dict[np.arrays]) : dict with the overlap matrix at
1728
+ each k-point with k-point as keys
1729
+ """
1730
+
1731
+ def __init__ (self , e_fermi = None , filename : str = "hamiltonMatrices.lobster" ):
1732
+ """
1733
+ Args:
1734
+ filename: filename for the hamiltonMatrices file, typically "hamiltonMatrices.lobster".
1735
+ e_fermi: fermi level in eV for the structure only
1736
+ relevant if input file contains hamilton matrices data
1737
+ """
1738
+
1739
+ self ._filename = filename
1740
+ # hamiltonMatrices
1741
+ with zopen (self ._filename , "rt" ) as f :
1742
+ file_data = f .readlines ()
1743
+ if len (file_data ) == 0 :
1744
+ raise OSError ("Please check provided input file, it seems to be empty" )
1745
+
1746
+ pattern_coeff_hamil_trans = r"(\d+)\s+kpoint\s+(\d+)" # regex pattern to extract spin and k-point number
1747
+ pattern_overlap = r"kpoint\s+(\d+)" # regex pattern to extract k-point number
1748
+
1749
+ if "hamilton" in self ._filename :
1750
+ if e_fermi is None :
1751
+ raise ValueError ("Please provide the fermi energy in eV " )
1752
+ self .onsite_energies , self .average_onsite_energies , self .hamilton_matrices = self ._parse_matrix (
1753
+ file_data = file_data , pattern = pattern_coeff_hamil_trans , e_fermi = e_fermi
1754
+ )
1755
+
1756
+ elif "coefficient" in self ._filename :
1757
+ self .onsite_coefficients , self .average_onsite_coefficient , self .coefficient_matrices = self ._parse_matrix (
1758
+ file_data = file_data , pattern = pattern_coeff_hamil_trans , e_fermi = 0
1759
+ )
1760
+
1761
+ elif "transfer" in self ._filename :
1762
+ self .onsite_transfer , self .average_onsite_transfer , self .transfer_matrices = self ._parse_matrix (
1763
+ file_data = file_data , pattern = pattern_coeff_hamil_trans , e_fermi = 0
1764
+ )
1765
+
1766
+ elif "overlap" in self ._filename :
1767
+ self .onsite_overlaps , self .average_onsite_overlaps , self .overlap_matrices = self ._parse_matrix (
1768
+ file_data = file_data , pattern = pattern_overlap , e_fermi = 0
1769
+ )
1770
+
1771
+ @staticmethod
1772
+ def _parse_matrix (file_data , pattern , e_fermi ):
1773
+ complex_matrices = {}
1774
+ matrix_diagonal_values = []
1775
+ start_inxs_real = []
1776
+ end_inxs_real = []
1777
+ start_inxs_imag = []
1778
+ end_inxs_imag = []
1779
+ # get indices of real and imaginary part of matrix for each k point
1780
+ for i , line in enumerate (file_data ):
1781
+ line = line .strip ()
1782
+ if "Real parts" in line :
1783
+ start_inxs_real .append (i + 1 )
1784
+ if i == 1 : # ignore the first occurrence as files start with real matrices
1785
+ pass
1786
+ else :
1787
+ end_inxs_imag .append (i - 1 )
1788
+ matches = re .search (pattern , file_data [i - 1 ])
1789
+ if matches and len (matches .groups ()) == 2 :
1790
+ k_point = matches .group (2 )
1791
+ complex_matrices [k_point ] = {}
1792
+ if "Imag parts" in line :
1793
+ end_inxs_real .append (i - 1 )
1794
+ start_inxs_imag .append (i + 1 )
1795
+ # explicitly add the last line as files end with imaginary matrix
1796
+ if i == len (file_data ) - 1 :
1797
+ end_inxs_imag .append (len (file_data ))
1798
+
1799
+ # extract matrix data and store diagonal elements
1800
+ for start_inx_real , end_inx_real , start_inx_imag , end_inx_imag in zip (
1801
+ start_inxs_real , end_inxs_real , start_inxs_imag , end_inxs_imag
1802
+ ):
1803
+ # matrix with text headers
1804
+ matrix_real = file_data [start_inx_real :end_inx_real ]
1805
+ matrix_imag = file_data [start_inx_imag :end_inx_imag ]
1806
+
1807
+ # extract only numerical data and convert to numpy arrays
1808
+ matrix_array_real = np .array ([line .split ()[1 :] for line in matrix_real [1 :]], dtype = float )
1809
+ matrix_array_imag = np .array ([line .split ()[1 :] for line in matrix_imag [1 :]], dtype = float )
1810
+
1811
+ # combine real and imaginary parts to create a complex matrix
1812
+ comp_matrix = matrix_array_real + 1j + matrix_array_imag
1813
+
1814
+ matches = re .search (pattern , file_data [start_inx_real - 2 ])
1815
+ if matches and len (matches .groups ()) == 2 :
1816
+ spin = Spin .up if matches .group (1 ) == "1" else Spin .down
1817
+ k_point = matches .group (2 )
1818
+ complex_matrices [k_point ].update ({spin : comp_matrix })
1819
+ elif matches and len (matches .groups ()) == 1 :
1820
+ k_point = matches .group (1 )
1821
+ complex_matrices .update ({k_point : comp_matrix })
1822
+ matrix_diagonal_values .append (comp_matrix .real .diagonal () - e_fermi )
1823
+
1824
+ # extract elements basis functions as list
1825
+ elements_basis_functions = [
1826
+ line .split ()[:1 ][0 ] for line in matrix_real if line .split ()[:1 ][0 ] != "basisfunction"
1827
+ ]
1828
+
1829
+ # get average row-wise
1830
+ average_matrix_diagonal_values = np .array (matrix_diagonal_values , dtype = float ).mean (axis = 0 )
1831
+
1832
+ # get a dict with basis functions as keys and average values as values
1833
+ average_average_matrix_diag_dict = dict (zip (elements_basis_functions , average_matrix_diagonal_values ))
1834
+
1835
+ return matrix_diagonal_values , average_average_matrix_diag_dict , complex_matrices
0 commit comments