Source code for MDMC.readers.observables.obs_reader

"""Module for observable reader abstract class"""

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Union

import numpy as np

from MDMC.common import units
from MDMC.common.decorators import repr_decorator, unit_decorator
from MDMC.readers.reader import Reader

if TYPE_CHECKING:
    from MDMC.trajectory_analysis.observables.obs import Observable

[docs] @repr_decorator('data') class ObservableReader(Reader): """ Abstract class that defines methods common to all readers for observables ObservableReaders are created using ObservableReaderFactory """
[docs] def assign(self, observable: 'Observable') -> None: # disable pylint warning about writing to the `Observable` #pylint: disable=protected-access """ Abstract method to assign the parsed information into the `Observable` Parameters ---------- observable : `Observable` An MDMC `Observable` that will be assigned the data parsed by the reader. """ observable._independent_variables = self.independent_variables observable._dependent_variables = self.dependent_variables observable._errors = self.errors
@property def data(self) -> dict: """ A dictionary of dictionaries containing the independent variables, dependent variables and the associated errors. Returns ------- dict The independent variables, dependent variables and the errors on the dependent variables """ return {"independent": self.independent_variables, "dependent": self.dependent_variables, "errors": self.errors} @property @abstractmethod def independent_variables(self) -> dict: """ The independent variables Returns ------- dict A dictionary of the independent variables """ raise NotImplementedError @property @abstractmethod def dependent_variables(self) -> None: """ The dependent variables Returns ------- dict A dictionary of the dependent variables """ raise NotImplementedError @property @abstractmethod def errors(self) -> None: """ The errors on the dependent variables Returns ------- dict A dictionary of the errors on the dependent variables """ raise NotImplementedError @staticmethod def _make_float(i: Any) -> Union[float, None]: """ Casts the input to a `float`, or passes if the input cannot be cast Parameters ---------- i : numeric Input to be cast to `float` Returns ------- float A non-negative `float`, if the input can be converted to a `float`. """ try: return np.float64(i) except ValueError: return None
[docs] class SQwReader(ObservableReader, ABC): """Abstract base subclass that adds attributes & methods common to all SQw readers""" # pylint: disable=attribute-defined-outside-init # to avoid it flagging up on private attributes in getters def __init__(self, file_name: str): super().__init__(file_name) self.SQw = None self.SQw_err = None @property def independent_variables(self) -> dict: """ Get the independent variables, Q (in ``Ang^-1``) and E (``meV``) Returns ------- dict The independent variables Q and E """ return {"Q": self.Q, "E": self.E} @property def dependent_variables(self) -> dict: """ Get the dependent variables, SQw (in ``arb``) Returns ------- dict The dependent variables, SQw (in ``arb``) """ return {"SQw": [self.SQw]} @property def errors(self) -> dict: """ Get the errors on the dependent variables Returns ------- dict The error on SQw (in ``arb``) """ return {"SQw": [self.SQw_err]} @property def w(self) -> float: """ Get or set the energy transfer expressed in angular frequency, w, in ``1 / ps`` Returns ------- array Energy transfer as angular frequency, w, in ``1 / ps`` """ return self._w @w.setter @unit_decorator(unit=units.Unit('ps') ** -1) def w(self, value: float) -> None: self._w = value @property def E(self) -> float: """ Get or set the energy transfer, E, in ``meV`` Returns ------- array Energy transfer, E, in ``meV`` """ return self._E @E.setter @unit_decorator(unit=units.ENERGY_TRANSFER) def E(self, value: float) -> None: self._E = value @property def Q(self) -> float: """ Get or set the momentum transfer, Q, in ``Ang^-1`` Returns ------- array Momentum transfer, Q, in ``Ang^-1`` """ return self._Q @Q.setter @unit_decorator(unit=units.LENGTH ** -1) def Q(self, value: float) -> None: self._Q = value
[docs] class PDFReader(ObservableReader, ABC): """Abstract base subclass that adds attributes & methods common to all PDF readers""" def __init__(self, file_name: str): super().__init__(file_name) self.PDF = None self.PDF_err = None self.partial_pdfs = None @property def independent_variables(self) -> dict: """ Get the independent variable r (in ``Ang^-1``) Returns ------- dict The independent variable r (in ``Ang^-1``) """ return {"r": self.r} @property def dependent_variables(self) -> dict: """ Get the dependent variable PDF, the pair distribution function (in ``barn``) Returns ------- dict The dependent variable, PDF (in ``barn``) """ return {"PDF": self.PDF} @property def errors(self) -> dict: """ Get the errors on the dependent variable Returns ------- dict The error on PDF (in ``barn``) """ return {"PDF": self.PDF_err} @property def r(self) -> float: """ Get or set the value of the atomic separation distance (in ``Ang``) """ return self._r @r.setter @unit_decorator(unit=units.Unit('Ang')) def r(self, value) -> None: self._r = value @property def PDF(self) -> np.ndarray: """ Get or set the total pair distribution function between pairs (in ``barn``) Returns ------- numpy.ndarray total pair distribution function (in ``barn``) """ return self._PDF @PDF.setter @unit_decorator(unit=units.Unit('barn')) def PDF(self, value: float) -> None: self._PDF = value @property def PDF_err(self) -> np.ndarray: """ Get or set the error on the total pair distribution function between pairs (in ``barn``) Returns ------- numpy.ndarray error on the total pair distribution function (in ``barn``) """ return self._PDF_err @PDF_err.setter @unit_decorator(unit=units.Unit('barn')) def PDF_err(self, value: float) -> None: self._PDF_err = value