Source code for MDMC.readers.observables.LAMPSQw

"""Readers for dynamic data"""

import logging
from typing import IO, Iterable

import numpy as np

from MDMC.readers.observables.obs_reader import SQwReader

logger = logging.getLogger(__name__)

[docs] class LAMPSQw(SQwReader): """ A class for reading SQw files from LAMP LAMP's ascii output uses three files: 1 for independent variables and parameters (..._LAMP), another for dependent variables (..._LAMPascii), and a third for the errors in the dependent variables (...LAMPascii_e) Attributes ---------- file_indep : file File containing the independent variables file_dep : file File containing the dependent variables file_dep_err: file File containing the errors on the dependent variables """ def __init__(self, file_name: str): super().__init__(file_name) self._Y_dim = None self._X_dim = None self.file_dep_err = None self.file_dep = None self.file_indep = None def __enter__(self) -> None: """ Open the files for independent variables, dependent variables and errors on the dependent variables """ # pylint: disable=consider-using-with # as this is an abstracted open method self.file_indep = open(self.file_name, encoding='UTF-8') self.file_dep = open(self.file_name + 'ascii', encoding='UTF-8') self.file_dep_err = open(self.file_name + 'ascii_e', encoding='UTF-8') def __exit__(self, exception_type, exception_value, traceback) -> None: """Closes all three files after parsing""" self.file_indep.close() self.file_dep.close() self.file_dep_err.close()
[docs] def parse(self, **settings: dict) -> None: """ Parse into SQw format E is the energy transfer (in meV) Q is wavevector transfer (in Ang^-1) """ self.E, self.Q = self.parse_indep_var(self.file_indep) self.SQw = self.parse_dep_var(self.file_dep) self.SQw_err = self.parse_dep_var(self.file_dep_err) # LAMP sets errors -1 if the corresponding datum is 0. Change these to # inf so that error calculations can still be performed on them but # result in inf. if np.any(self.SQw_err <= 0.): self.SQw_err[np.where(self.SQw_err <= 0.)] = float('inf') msg = "We have set the error bar to infinity for any zero error values, this allows\ us to calculate chi-squared but effectively ignores these points, this may not\ be what you want to do, consider using a FoM which doesn't need errors if\ this is an issue" logger.warning(msg)
[docs] def parse_indep_var(self, file: IO) -> 'tuple[np.ndarray, np.ndarray]': """ Parses the independent variables Splits the file so that the data can be extracted into a ``array`` by ``self._get_data`` Parameters ---------- file : file Open file containing independent data Returns ------- tuple (X, Y) where X and Y are arrays of the two independent variables """ # pylint: disable=inconsistent-return-statements # as it breaks the function when changed to return None def get_n_elements(line): for i in line.split(" "): try: return np.int64(i) except ValueError: pass for line in file: if "X_SIZE" in line: self._X_dim = get_n_elements(line) elif "Y_SIZE" in line: self._Y_dim = get_n_elements(line) break for line in file: if "X_COORDINATES" in line: _ = next(file) break file_split = iter([word for line in file for word in line.split(" ") if "Y_COORDINATES" not in line]) X = self._get_data(file_split, self._X_dim) Y = self._get_data(file_split, self._Y_dim) return X, Y
[docs] def parse_dep_var(self, file: IO) -> np.ndarray: """ Parses the dependent variables or their errors. Parameters ---------- file : file Open file containing independent data Returns ------- numpy.ndarray A 2d array with dimensions of the two independent variables """ file_split = iter([word for line in file for word in line.split(" ")]) dep = self._get_data(file_split, self._Y_dim, self._X_dim) return dep
def _get_data(self, str_iter: Iterable, *dimensions: float) -> np.ndarray: """ Iterates over an iterator from a file and extracts the numerical values as data. Parameters ---------- str_iter : iterator An iterator of str *dimensions A `float` specifying the size for every dimension of the data Returns ------- numpy.ndarray An array of `float` with dimensions specified by ``*dimensions`` """ def get_row_data(dim): row_data = np.empty(dim) for j in range(dim): datum = None while datum is None: datum = self._make_float(next(str_iter)) row_data[j] = datum return row_data var = np.empty(dimensions) if len(dimensions) == 1: var = get_row_data(dimensions[0]) else: for k in range(dimensions[0]): var[k] = get_row_data(dimensions[1]) # For the 263K05Awat_LAMP data file the output is SQw structured such that: # np.shape(SQw) == (np.shape(Q), np.shape(E)) # this is consistent with SQw as we currently calculate it from MD return var