# Path: vasppy/units.py

# 
# Path: vasppy/band.py
# class Band():
# 
#     def __init__( self, index, energy, occupancy, negative_occupancies='warn' ):
#         self.index = index
#         self.energy = energy
#         self.occupancy = handle_occupancy( occupancy, negative_occupancies=negative_occupancies )
# 
#     def __eq__( self, other ):
#         return ( ( self.index == other.index ) &
#                  ( self.energy == other.energy ) &
#                  ( self.occupancy == other.occupancy ) )


import numpy as np  # type: ignore
import re
import math
import warnings
import fortranformat as ff  # type: ignore
from .units import angstrom_to_bohr, ev_to_hartree
from .band import Band
from copy import deepcopy
from functools import reduce
        else:
            spins = list( range( self.spin_channels ) )
        if not ions:
            ions = [ self.number_of_ions ] # nions+1 is the `tot` index
        if not orbitals:
            orbitals = list( range( self.number_of_projections ) )
        if self.calculation[ 'spin_polarised' ]:
            band_energies = np.array( [ band.energy for band in self._bands ] ).reshape( self.spin_channels, self.number_of_k_points, self.number_of_bands )[ spins[0] ].T
        else:
            band_energies = np.array( [ band.energy for band in self._bands ] ).reshape( self.number_of_k_points, self.number_of_bands ).T
        orbital_projection = np.sum( self._data[ :, :, :, :, orbitals ], axis = 4 )
        ion_projection = np.sum( orbital_projection[ :, :, :, ions ], axis = 3 )
        spin_projection = np.sum( ion_projection[ :, :, spins ], axis = 2 )
        x_axis = self.x_axis( reciprocal_lattice )
        to_return = []
        for i in range( self.number_of_bands ):
            for k, ( e, p ) in enumerate( zip( band_energies[i], spin_projection.T[i] ) ):
                to_return.append( [ x_axis[ k ], e - e_fermi, p * scaling ] )
        to_return = np.array( to_return ).reshape( self.number_of_bands, -1, 3 )
        return to_return

    def effective_mass_calc( self, k_point_indices, band_index, reciprocal_lattice, spin=1, printing=False ):
        assert( spin <= self.k_point_blocks )
        assert( len( k_point_indices ) > 1 ) # we need at least 2 k-points
        band_energies = self._bands[:,1:].reshape( self.k_point_blocks, self.number_of_k_points, self.number_of_bands )
        frac_k_point_coords = np.array( [ self._k_points[ k - 1 ].frac_coords for k in k_point_indices ] )
        eigenvalues = np.array( [ band_energies[ spin - 1 ][ k - 1 ][ band_index - 1 ] for k in k_point_indices ] )
        if printing:
            print( '# h k l e' )
            [ print( ' '.join( [ str( f ) for f in row ] ) ) for row in np.concatenate( ( frac_k_point_coords, np.array( [ eigenvalues ] ).T ), axis = 1 ) ]

# Path: vasppy/units.py

# 
# Path: vasppy/band.py
# class Band():
# 
#     def __init__( self, index, energy, occupancy, negative_occupancies='warn' ):
#         self.index = index
#         self.energy = energy
#         self.occupancy = handle_occupancy( occupancy, negative_occupancies=negative_occupancies )
# 
#     def __eq__( self, other ):
#         return ( ( self.index == other.index ) &
#                  ( self.energy == other.energy ) &
#                  ( self.occupancy == other.occupancy ) )


# Path: vasppy/procar.py
import numpy as np  # type: ignore
import re
import math
import warnings
import fortranformat as ff  # type: ignore
from .units import angstrom_to_bohr, ev_to_hartree
from .band import Band
from copy import deepcopy
from functools import reduce

        else:
            spins = list( range( self.spin_channels ) )
        if not ions:
            ions = [ self.number_of_ions ] # nions+1 is the `tot` index
        if not orbitals:
            orbitals = list( range( self.number_of_projections ) )
        if self.calculation[ 'spin_polarised' ]:
            band_energies = np.array( [ band.energy for band in self._bands ] ).reshape( self.spin_channels, self.number_of_k_points, self.number_of_bands )[ spins[0] ].T
        else:
            band_energies = np.array( [ band.energy for band in self._bands ] ).reshape( self.number_of_k_points, self.number_of_bands ).T
        orbital_projection = np.sum( self._data[ :, :, :, :, orbitals ], axis = 4 )
        ion_projection = np.sum( orbital_projection[ :, :, :, ions ], axis = 3 )
        spin_projection = np.sum( ion_projection[ :, :, spins ], axis = 2 )
        x_axis = self.x_axis( reciprocal_lattice )
        to_return = []
        for i in range( self.number_of_bands ):
            for k, ( e, p ) in enumerate( zip( band_energies[i], spin_projection.T[i] ) ):
                to_return.append( [ x_axis[ k ], e - e_fermi, p * scaling ] )
        to_return = np.array( to_return ).reshape( self.number_of_bands, -1, 3 )
        return to_return

    def effective_mass_calc( self, k_point_indices, band_index, reciprocal_lattice, spin=1, printing=False ):
        assert( spin <= self.k_point_blocks )
        assert( len( k_point_indices ) > 1 ) # we need at least 2 k-points
        band_energies = self._bands[:,1:].reshape( self.k_point_blocks, self.number_of_k_points, self.number_of_bands )
        frac_k_point_coords = np.array( [ self._k_points[ k - 1 ].frac_coords for k in k_point_indices ] )
        eigenvalues = np.array( [ band_energies[ spin - 1 ][ k - 1 ][ band_index - 1 ] for k in k_point_indices ] )
        if printing:
            print( '# h k l e' )
            [ print( ' '.join( [ str( f ) for f in row ] ) ) for row in np.concatenate( ( frac_k_point_coords, np.array( [ eigenvalues ] ).T ), axis = 1 ) ]

        reciprocal_lattice = reciprocal_lattice * 2 * math.pi * angstrom_to_bohr