Source code for viperleed.calc.classes.beam

"""Module beam of viperleed.calc.classes.

Defines the Beam class, a container of information concerning a
diffraction beam.
"""

__authors__ = (
    'Florian Kraushofer (@fkraushofer)',
    'Alexander M. Imre (@amimre)',
    )
__copyright__ = 'Copyright (c) 2019-2024 ViPErLEED developers'
__created__ = '2019-12-03'
__license__ = 'GPLv3+'

import math

import numpy as np
from quicktions import Fraction


[docs]class Beam: """Class storing properties and data of a diffraction beam. Stores h,k, and can store intensity over energy. Attributes ---------- hkfrac : tuple (Fraction, Fraction) The h and k coordinates of the beam as Fractions hk : tuple (float, float) The h and k coordinates of the beam as float intens : dict {float: float} contains {energy: intensity} pairs complex_amplitude : dict {float: complex} contains {energy: amplitude} pairs label : str Label for the beam """
[docs] def __init__(self, hk, maxdenom=99): if all([isinstance(v, Fraction) for v in hk]): self.hkfrac = hk self.hk = (float(hk[0]), float(hk[1])) else: self.hk = hk self.hkfrac = (Fraction(hk[0]).limit_denominator(maxdenom), Fraction(hk[1]).limit_denominator(maxdenom)) self.intens = {} self.complex_amplitude = {} self.label, _ = self.getLabel()
@property def energies(self): return np.fromiter(self.intens.keys(), float) @property def intensities(self): return np.fromiter(self.intens.values(), float) def updateIndex(self, hk, maxdenom=99): """Keep values but change indices""" if all([isinstance(v, Fraction) for v in hk]): self.hkfrac = hk self.hk = (float(hk[0]), float(hk[1])) else: self.hk = hk self.hkfrac = (Fraction(hk[0]).limit_denominator(maxdenom), Fraction(hk[1]).limit_denominator(maxdenom)) self.label, _ = self.getLabel() def getLabel(self, style="plain", lwidth=-1): """ Returns a string of format '( 1/2 | -1 )', where a,b in '(a|b)' are justified to at least the given width. If h or k end up longer, the width of the other one will also be changed. Parameters ---------- style : str, optional Select a different style for the label. plain: UTF8-compatible, with hyphen '-' as minus, for log minus: replace hyphen by proper minus sign, '\u2212' overbar: use latex overbars instead of minus lwidth: int, optional width of each component of the label; total width = 2*lwidth+3. Leave negative to determine automatically Returns ------- out : str The new label. lwidth : int The width of the new label """ out = "" i = 0 if lwidth < 0: lwidth = 2 if style == "overbar": lwidth = 1 while i < 2: texlen = 0 # added length from tex commands if i == 0: wl = math.ceil((lwidth - 1) / 2) # width for numerator v = self.hkfrac[i] if v.denominator == 1: if style != "overbar": s = str(v.numerator).rjust(max(2, wl)) # use more space else: if v.numerator < 0: s = ((r"\overline{" + str(abs(v.numerator)) + "}") .rjust(wl + 11)) # 11 chars for the "\overline{}" texlen += 11 else: s = str(v.numerator).rjust(wl) else: if style != "overbar": s = str(v.numerator).rjust(wl)+"/"+str(v.denominator) else: if v.numerator < 0: s = ((r"\overline{" + str(abs(v.numerator)) + "/" + str(v.denominator) + "}") .rjust(wl + 11)) # 11 chars for the "\overline{}" texlen += 11 else: s = str(v.numerator).rjust(wl)+"/"+str(v.denominator) s = s.ljust(lwidth + texlen) if len(s) - texlen > lwidth: lwidth = len(s) - texlen i = -1 # start over elif i == 0: if style == "overbar": out = "$" else: out = "" out += "(" + s + "|" else: out += s + ")" if style == "overbar": out += "$" i += 1 if style == "minus": out = out.replace("-", "\u2212") return out, lwidth def normMax(self): """ Normalizes the beam to maximum, i.e. sets the highest value to 1.0 and rescales the others accordingly. """ if len(self.intens.values()) > 0: m = max(self.intens.values()) if m > 0: for en in self.intens: self.intens[en] /= m def isEqual(self, beam, eps=1e-4): """ Checks whether the beam is equal to another beam with a given tolerance. Returns True or False. """ if (abs(self.hk[0] - beam.hk[0]) < eps and abs(self.hk[1] - beam.hk[1]) < eps): return True return False def isEqual_hk(self, hk, eps=1e-4): """ Checks whether the beam hk is equal to a tuple hk with a given tolerance. Returns True or False. """ hk = [float(v) for v in hk] # in case Fractions were passed if (abs(self.hk[0] - hk[0]) < eps and abs(self.hk[1] - hk[1]) < eps): return True return False