Coverage for local_installation/dynasor/modes/qpoint.py: 91%

55 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-15 07:34 +0000

1from __future__ import annotations 

2import numpy as np 

3 

4from ..units import radians_per_fs_to_THz 

5from .band import Band 

6 

7 

8class QPoint: 

9 """Representation of a single q-point and properties 

10 

11 The bands can be accessed by e.g. `qp[2]` to get band index 2 in the form 

12 of a :class:`dynasor.modes.band.Band` object 

13 """ 

14 def __init__(self, q, mp): 

15 self._mp = mp 

16 self._q = q 

17 

18 # Dunders 

19 

20 def __str__(self): 

21 string = f"""### q-point ### 

22Index: {self.index} 

23Reduced: {self.q_reduced} 

24Cartesian: [{self.q_cartesian[0]:.2f}, {self.q_cartesian[1]:.2f}, {self.q_cartesian[2]:.2f}] rad/Å 

25Wavenumber: {self.wavenumber:.2f} rad/Å 

26Wavelength: {self.wavelength:.2f} Å 

27q-minus: {self.q_minus.index} {self.q_minus.q_reduced} 

28Real: {self.is_real}""" 

29 string += (""" 

30Omegas: [""" + ', '.join(f'{t * radians_per_fs_to_THz:.2f}' for t in self.omegas) + '] THz') 

31 return string 

32 

33 def __repr__(self): 

34 return str(self) 

35 

36 def __getitem__(self, s): 

37 if s >= self._mp.primitive.n_atoms * 3: 

38 raise IndexError 

39 return Band(self.index, s, self._mp) 

40 

41 @property 

42 def q_minus(self) -> QPoint: 

43 """The corresponding counter-propagating mode""" 

44 return self._mp[self._mp.q_minus[self.index]] 

45 

46 @property 

47 def polarizations(self): 

48 """Slice, see :class:`dynasor.ModeProjector`""" 

49 return self._mp.polarizations[self.index] 

50 

51 @property 

52 def omegas(self): 

53 """Slice, see :class:`dynasor.ModeProjector`""" 

54 return self._mp.omegas[self.index] 

55 

56 @property 

57 def is_real(self): 

58 """If the q-point has purely real mode coordinates, 'q=-q'""" 

59 return self.index == self.q_minus.index 

60 

61 @property 

62 def index(self): 

63 """q-point index corresponding to :class:`dynasor.ModeProjector.q_reduced`""" 

64 return self._q 

65 

66 @property 

67 def wavenumber(self): 

68 """Wavenumber of mode in rad/Å""" 

69 return np.linalg.norm(self._mp.q_cartesian[self.index]) 

70 

71 @property 

72 def wavelength(self): 

73 """Wavelength of mode in Å""" 

74 return np.inf if self.wavenumber == 0 else 2*np.pi / self.wavenumber 

75 

76 @property 

77 def q_reduced(self): 

78 """Slice, see :class:`dynasor.ModeProjector`""" 

79 return self._mp.q_reduced[self.index] 

80 

81 @property 

82 def q_cartesian(self): 

83 """Slice, see :class:`dynasor.ModeProjector`""" 

84 return self._mp.q_cartesian[self.index] 

85 

86 @property 

87 def eigenmodes(self): 

88 """Slice, see :class:`dynasor.ModeProjector`""" 

89 return self._mp.eigenmodes[self.index] 

90 

91 @property 

92 def potential_energies(self): 

93 """Slice, see :class:`dynasor.ModeProjector`""" 

94 return self._mp.potential_energies[self.index] 

95 

96 @property 

97 def kinetic_energies(self): 

98 """Slice, see :class:`dynasor.ModeProjector`""" 

99 return self._mp.kinetic_energies[self.index] 

100 

101 @property 

102 def virial_energies(self): 

103 """Slice, see :class:`dynasor.ModeProjector`""" 

104 return self._mp.virial_energies[self.index]