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
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-15 07:34 +0000
1from __future__ import annotations
2import numpy as np
4from ..units import radians_per_fs_to_THz
5from .band import Band
8class QPoint:
9 """Representation of a single q-point and properties
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
18 # Dunders
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
33 def __repr__(self):
34 return str(self)
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)
41 @property
42 def q_minus(self) -> QPoint:
43 """The corresponding counter-propagating mode"""
44 return self._mp[self._mp.q_minus[self.index]]
46 @property
47 def polarizations(self):
48 """Slice, see :class:`dynasor.ModeProjector`"""
49 return self._mp.polarizations[self.index]
51 @property
52 def omegas(self):
53 """Slice, see :class:`dynasor.ModeProjector`"""
54 return self._mp.omegas[self.index]
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
61 @property
62 def index(self):
63 """q-point index corresponding to :class:`dynasor.ModeProjector.q_reduced`"""
64 return self._q
66 @property
67 def wavenumber(self):
68 """Wavenumber of mode in rad/Å"""
69 return np.linalg.norm(self._mp.q_cartesian[self.index])
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
76 @property
77 def q_reduced(self):
78 """Slice, see :class:`dynasor.ModeProjector`"""
79 return self._mp.q_reduced[self.index]
81 @property
82 def q_cartesian(self):
83 """Slice, see :class:`dynasor.ModeProjector`"""
84 return self._mp.q_cartesian[self.index]
86 @property
87 def eigenmodes(self):
88 """Slice, see :class:`dynasor.ModeProjector`"""
89 return self._mp.eigenmodes[self.index]
91 @property
92 def potential_energies(self):
93 """Slice, see :class:`dynasor.ModeProjector`"""
94 return self._mp.potential_energies[self.index]
96 @property
97 def kinetic_energies(self):
98 """Slice, see :class:`dynasor.ModeProjector`"""
99 return self._mp.kinetic_energies[self.index]
101 @property
102 def virial_energies(self):
103 """Slice, see :class:`dynasor.ModeProjector`"""
104 return self._mp.virial_energies[self.index]