from __future__ import annotations # for 3.9 for typehint 'Band' in cc.band
from typing import TYPE_CHECKING
import math
import numpy as np
from ..units import radians_per_fs_to_THz
if TYPE_CHECKING:
from .band import Band
[docs]class ComplexCoordinate:
"""Class to work with the in general complex coordinates of lattice dynamics.
Can be cast to complex by `complex(cc)`
Example
-------
>>> cc.complex = 1.7j # doctest: +SKIP
>>> cc.amplitude = 3.8 # doctest: +SKIP
>>> cc.phase = 2*np.pi # doctest: +SKIP
"""
def __init__(self, q, s, mp):
"""The complex coordinate belongs to a q-point and band"""
self._q = q
self._s = s
self._mp = mp
def __repr__(self):
return str(self)
def __complex__(self):
return complex(getattr(self._mp, 'get_' + self.__class__.__name__)()[self._q, self._s])
@property
def band(self) -> 'Band':
"""The band to which this coordinate belongs"""
return self._mp[self._q][self._s]
@property
def complex(self):
"""The complex coordinate as a complex number"""
return complex(self)
@complex.setter
def complex(self, C):
C = complex(C)
prop = self.__class__.__name__
val = getattr(self._mp, 'get_' + prop)()
if self._mp[self._q].is_real:
assert np.isclose(C.imag, 0)
q2 = self._q
else:
q2 = self._mp[self._q].q_minus.index
val[self._q, self._s] = C
val[q2, self._s] = C.conjugate()
getattr(self._mp, 'set_' + prop)(val)
@property
def phase(self):
"""The phase of the complex coordinate"""
c = complex(self)
return math.atan2(c.imag, c.real)
@phase.setter
def phase(self, phase):
C = complex(self)
C = np.abs(C) * np.exp(1j * phase)
self.complex = C
@property
def amplitude(self):
"""The amplitude of the complex coordinate"""
c = complex(self)
return np.abs(c)
@amplitude.setter
def amplitude(self, amplitude):
C = amplitude * np.exp(1j * self.phase)
self.complex = C
class Q(ComplexCoordinate):
def __str__(self):
string = f"""### Mode coordinate Q ###
band: [{self.band.index}] {self.band.omega * radians_per_fs_to_THz:.2f} THz
q-point: [{self.band.qpoint.index}] {self.band.qpoint.q_reduced}
Value: {self.complex:.2f} Å√dmu
Amplitude: {self.amplitude:.2f} Å√dmu
Phase: {self.phase:.2f} radians
"""
return string
class P(ComplexCoordinate):
def __str__(self):
string = f"""### Mode momentum P ###
band: [{self.band.index}] {self.band.omega * radians_per_fs_to_THz:.2f} THz
q-point: [{self.band.qpoint.index}] {self.band.qpoint.q_reduced}
Value: {self.complex:.2f} Å√dmu/fs
Amplitude: {self.amplitude:.2f} Å√dmu/fs
Phase: {self.phase:.2f} radians
"""
return string
class F(ComplexCoordinate):
def __str__(self):
string = f"""### Mode force F ###
band: [{self.band.index}] {self.band.omega * radians_per_fs_to_THz:.2f} THz
q-point: [{self.band.qpoint.index}] {self.band.qpoint.q_reduced}
Value: {self.complex:.2f} Å√dmu/fs²
Amplitude: {self.amplitude:.2f} Å√dmu/fs²
Phase: {self.phase:.2f} radians
"""
return string