Coverage for dynasor / modes / band.py: 56%

57 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-16 12:31 +0000

1from __future__ import annotations 

2from typing import TYPE_CHECKING 

3from numpy.typing import NDArray 

4from ..units import radians_per_fs_to_THz 

5from .tools import make_table 

6from .complex_coordinate import Q, P, F 

7 

8if TYPE_CHECKING: 8 ↛ 9line 8 didn't jump to line 9 because the condition on line 8 was never true

9 from .qpoint import QPoint 

10 from .mode_projector import ModeProjector 

11 

12 

13class Band: 

14 """Represents properties of a single band belonging to a q-point. 

15 

16 To modify the coordinates `Q`, `P` and `F` use `band.Q` and see doc for 

17 :class:`~dynasor.modes.complex_coordinate.ComplexCoordinate`. 

18 

19 Parameters 

20 ---------- 

21 q_index 

22 q-point index. 

23 band_index 

24 Band index. 

25 mp 

26 Mode projector. 

27 """ 

28 def __init__(self, q_index: int, band_index: int, mp: ModeProjector): 

29 self._q = q_index 

30 self._s = band_index 

31 self._mp = mp 

32 

33 def __repr__(self): 

34 return str(self) 

35 

36 def __str__(self): 

37 s = ['### Band ###'] 

38 s += [f'Band index: {self.index}'] 

39 s += [f'q-point: [{self.qpoint.index}] {self.qpoint.q_reduced}'] 

40 s += [f'Frequency: {self.omega * radians_per_fs_to_THz:.2f} THz'] 

41 s += ['Polarization:'] 

42 string = '\n'.join(s) 

43 

44 string += make_table(self.polarization) 

45 string += f""" 

46 {'Q':<20}{'P':<20}{'F':<20} 

47Value: {self.Q.complex:<20.2f}{self.P.complex:<20.2f}{self.F.complex:<20.2f} 

48Amplitude: {self.Q.amplitude:<20.2f}{self.P.amplitude:<20.2f}{self.F.amplitude:<20.2f} 

49Phase: {self.Q.phase:<20.2f}{self.P.phase:<20.2f}{self.F.phase:<20.2f} 

50Energy: {self.potential_energy:<20.2f}{self.kinetic_energy:<20.2f}{self.virial_energy:<20.2f} 

51""" 

52 return string 

53 

54 @property 

55 def index(self) -> int: 

56 """The index of the band at the q-point.""" 

57 return self._s 

58 

59 @property 

60 def qpoint(self) -> 'QPoint': 

61 """The q-point to which the band belongs.""" 

62 return self._mp[self._q] 

63 

64 @property 

65 def omega(self) -> float: 

66 """Frequency of this band in rad/fs.""" 

67 return self.qpoint.omegas[self.index] 

68 

69 @property 

70 def polarization(self) -> NDArray[float]: 

71 """Polarization vector of this band, shape ``(Np, 3)``.""" 

72 return self.qpoint.polarizations[self.index] 

73 

74 @property 

75 def eigenmode(self) -> NDArray[float]: 

76 """Eigenmode in the supercell for this band, shape ``(N, 3)``.""" 

77 return self.qpoint.eigenmodes[self.index] 

78 

79 @property 

80 def potential_energy(self) -> float: 

81 """Potential energy of this band in eV.""" 

82 return self.qpoint.potential_energies[self.index] 

83 

84 @property 

85 def kinetic_energy(self) -> float: 

86 """Kinetic energy of this band in eV.""" 

87 return self.qpoint.kinetic_energies[self.index] 

88 

89 @property 

90 def virial_energy(self) -> float: 

91 """Virial energy of this band in eV.""" 

92 return self.qpoint.virial_energies[self.index] 

93 

94 @property 

95 def Q(self) -> float: 

96 """The mode coordinate.""" 

97 return Q(self.qpoint.index, self.index, self._mp) 

98 

99 @property 

100 def P(self) -> float: 

101 """The mode momentum.""" 

102 return P(self.qpoint.index, self.index, self._mp) 

103 

104 @property 

105 def F(self) -> NDArray[float]: 

106 """The mode force.""" 

107 return F(self.qpoint.index, self.index, self._mp)