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
« 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
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
13class Band:
14 """Represents properties of a single band belonging to a q-point.
16 To modify the coordinates `Q`, `P` and `F` use `band.Q` and see doc for
17 :class:`~dynasor.modes.complex_coordinate.ComplexCoordinate`.
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
33 def __repr__(self):
34 return str(self)
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)
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
54 @property
55 def index(self) -> int:
56 """The index of the band at the q-point."""
57 return self._s
59 @property
60 def qpoint(self) -> 'QPoint':
61 """The q-point to which the band belongs."""
62 return self._mp[self._q]
64 @property
65 def omega(self) -> float:
66 """Frequency of this band in rad/fs."""
67 return self.qpoint.omegas[self.index]
69 @property
70 def polarization(self) -> NDArray[float]:
71 """Polarization vector of this band, shape ``(Np, 3)``."""
72 return self.qpoint.polarizations[self.index]
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]
79 @property
80 def potential_energy(self) -> float:
81 """Potential energy of this band in eV."""
82 return self.qpoint.potential_energies[self.index]
84 @property
85 def kinetic_energy(self) -> float:
86 """Kinetic energy of this band in eV."""
87 return self.qpoint.kinetic_energies[self.index]
89 @property
90 def virial_energy(self) -> float:
91 """Virial energy of this band in eV."""
92 return self.qpoint.virial_energies[self.index]
94 @property
95 def Q(self) -> float:
96 """The mode coordinate."""
97 return Q(self.qpoint.index, self.index, self._mp)
99 @property
100 def P(self) -> float:
101 """The mode momentum."""
102 return P(self.qpoint.index, self.index, self._mp)
104 @property
105 def F(self) -> NDArray[float]:
106 """The mode force."""
107 return F(self.qpoint.index, self.index, self._mp)