Source code for xrayutilities.io.rotanode_alignment

# This file is part of xrayutilities.
#
# xrayutilities is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# Copyright (c) 2010-2020, 2023 Dominik Kriegner <dominik.kriegner@gmail.com>

"""
parser for the alignment log file of the rotating anode
"""

import re

import numpy

from .. import config, utilities
from .helper import xu_open

LOG_comment = re.compile(r"^#C")
LOG_peakname = re.compile(r"^#P")
LOG_motorname = re.compile(r"^#M")
LOG_datetime = re.compile(r"^#D")
LOG_tagline = re.compile(r"^#")
# denotes a numeric value
LOG_num_value = re.compile(r"[+-]*\d*\.*\d*e*[+-]*\d+")


[docs] class RA_Alignment: """ class to parse the data file created by the alignment routine (tpalign) at the rotating anode spec installation this routine does an iterative alignment procedure and saves the center of mass values were it moves after each scan. It iterates between two different peaks and iteratively aligns at each peak between two different motors (om/chi at symmetric peaks, om/phi at asymmetric peaks) """
[docs] def __init__(self, filename): """ initialization function to initialize the objects variables and opens the file Parameters ---------- filename : str filename of the alignment log file """ self.filename = filename try: self.fid = xu_open(self.filename) except OSError: self.fid = None raise IOError(f"error opening alignment log file {self.filename}") self.peaks = [] self.alignnames = [] self.motorpos = [] self.intensities = [] self.iterations = [] self.Parse()
[docs] def Parse(self): """ parser to read the alignment log and obtain the aligned values at every iteration. """ currentpeakname = None currentmotname = None opencommenttag = False dataline = False iteration = 0 if self.fid is None: raise Exception("RA_Alignment: file was not opened by " "initialization!") for line in self.fid.readlines(): # for loop to read every line in the file line = line.decode('ascii') # check for new tag in the current line if LOG_tagline.match(line): opencommenttag = False if LOG_comment.match(line): # comment line or block starts opencommenttag = True continue if LOG_datetime.match(line): # data is so far ignored continue if LOG_peakname.match(line): # line with peak name found pname = LOG_peakname.sub("", line) pname = pname.strip() # check if we found a new peakname try: self.peaks.index(pname) except ValueError: self.peaks.append(pname) currentpeakname = pname # set current peak name iteration += 1 # increment iteration counter elif LOG_motorname.match(line): # line with motorname is found motname = LOG_motorname.sub("", line) motname = motname.strip() # check if a peakname is already set if currentpeakname is None: if config.VERBOSITY >= config.INFO_LOW: print("RA_Alignment: Warning: a peakname should " "be given before a motor data line") currentpeakname = "somepeak" currentmotname = currentpeakname + "_" + motname # check if we found a new peak/motor name combination try: self.alignnames.index(currentmotname) except ValueError: # new peak/motor combination self.alignnames.append(currentmotname) # create necessary data structures self.motorpos.append([]) self.intensities.append([]) self.iterations.append([]) # next line contains motor position and intensity dataline = True elif opencommenttag: # ignore line because it is part of a comment block continue elif dataline: # dataline with motorposition and intensity is found line_list = LOG_num_value.findall(line) idx = self.alignnames.index(currentmotname) self.motorpos[idx].append(float(line_list[0])) self.intensities[idx].append(float(line_list[1])) self.iterations[idx].append(iteration) dataline = False # convert data to numpy array and combine position and intensity self.data = [] for i, _ in enumerate(self.keys()): self.data.append(numpy.array((self.motorpos[i], self.intensities[i], self.iterations[i])))
def __str__(self): """ returns a string describing the content of the alignment file """ ostr = "" ostr += "Peaknames: " + repr(self.peaks) + "\n" ostr += "aligned values: " + repr(self.alignnames) return ostr def __del__(self): try: self.fid.close() except AttributeError: pass
[docs] def keys(self): """ returns a list of keys for which aligned values were parsed """ return self.alignnames
[docs] def get(self, key): return self.__getitem__(key)
def __getitem__(self, key): """ returns the values to the corresponding key """ if key in self.alignnames: i = self.alignnames.index(key) return self.data[i] raise KeyError("RA_Alignment: unknown key given!")
[docs] def plot(self, pname): """ function to plot the alignment history for a given peak Parameters ---------- pname : str peakname for which the alignment should be plotted """ flag, plt = utilities.import_matplotlib_pyplot('XU.io.RA_ALignment') if not flag: return if pname not in self.peaks: print("RA_Alignment.plot: error peakname not found!") return # get number aligned axis for the current peak axnames = [] for k in self.keys(): if k.find(pname) >= 0: axnames.append(k) _, ax = plt.subplots(nrows=len(axnames), sharex=True) for an, axis in zip(axnames, ax): d = self.get(an) plt.sca(axis) plt.plot(d[2], d[0], '.-k') plt.ylabel(re.sub(pname + "_", "", an)) axis.twinx() plt.plot(d[2], d[1], '.-r') plt.ylabel("Int (cps)", color='r') plt.grid() plt.xlabel("Peak iteration number") plt.suptitle(pname)