Source code for MDMC.readers.observables.xml_SQw

"""XML reader for SQw data"""
import logging
import xml.etree.ElementTree as ET
from typing import TextIO

import numpy as np

from MDMC.common import units
from MDMC.common.constants import h_bar
from MDMC.readers.observables.obs_reader import SQwReader

logger = logging.getLogger(__name__)

[docs]class XML_SQw(SQwReader): """ An XML reader for SQw data """
[docs] def parse(self, **settings: dict) -> None: """ Parses the xml file Currently only parses SQw files E is the energy transfer (in ``meV``) Q is wavevector transfer (in ``Ang^-1``) """ _tree = ET.parse(self.file) _root = _tree.getroot() _root_dict = self.dict_from_element(_root) n_Q = int(_root_dict['n-q-points']) n_w = int(_root_dict['n-omega-points']) Q_unit = units.Unit(_root_dict['q-unit']) w_unit = units.Unit(_root_dict['omega-unit']) # Local variable Q is used for setting self.Q after all children of # self._root have been parsed. This is required because a set cannot be # passed to self.Q and then the add method called, because the unit # decorator converts the set to an a UnitArray, which has no add method. # as the Q = set() w = set() self.SQw = [] self.SQw_err = [] for child in _root: if child.tag == 'SQomega': child_dict = self.dict_from_element(child) Q.add(float(child_dict['q'])) w.add(float(child_dict['omega'])) # Account for 'no data' in SQw SQw = child_dict['S'] if SQw == 'no data': self.SQw.append(0.) self.SQw_err.append(0.) else: self.SQw.append(float(SQw)) self.SQw_err.append(float(child_dict['error'])) # Account for unit conversion after creating the variables self.Q = np.sort(np.array(list(Q))) self.Q *= Q_unit.conversion_factor / self.Q.unit.conversion_factor self.w = np.sort(np.array(list(w))) self.w *= w_unit.conversion_factor / self.w.unit.conversion_factor self.E = self.w * 1e15 * h_bar # the way the Wells Ar data is structured and read in, # we need to reshape the self.SQw list with w points # in the outer index and Q points in the inner index. # we then need to transpose the result to make it consistent # with our approach of calculating SQw from MD. The resulting arrays must satisfy: # np.shape(SQw) == (np.size(Q), np.size(E)) self.SQw = np.transpose(np.reshape(np.array(self.SQw), [n_w, n_Q])) self.SQw_err = np.transpose(np.reshape( np.array(self.SQw_err), [n_w, n_Q])) # Change any zero error points to # inf so that error calculations can still be performed on them. if np.any(self.SQw_err <= 0.): self.SQw_err[np.where(self.SQw_err <= 0.)] = float('inf') msg = "\n 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 i f\ this is an issue \n" logger.error(msg)
[docs] @staticmethod def dict_from_element(element: TextIO) -> dict: """ Creates a dictionary from an XML element Parameters ---------- element : Element An XML element. Must have items method, which must return a list of 2 element tuples. Returns ------- dict For each tuple from the xml Element, The first index is the key and the second element is the value. """ return {item[0]: item[1] for item in element.items()}