Source code for rootpy.vector

from __future__ import absolute_import

import ROOT

import numbers
from copy import copy

from . import QROOT
from .base import Object
from .decorators import snake_case_methods

__all__ = [
    'Vector2',
    'Vector3',
    'LorentzVector',
    'Rotation',
    'LorentzRotation',
]


class _arithmetic_mixin:

    def __mul__(self, other):
        try:
            prod = self.__class__.__bases__[-1].__mul__(self, other)
            if isinstance(prod, self.__class__.__bases__[-1]):
                prod.__class__ = self.__class__
        except TypeError:
            raise TypeError(
                "unsupported operand type(s) for *: '{0}' and '{1}'".format(
                    self.__class__.__name__, other.__class__.__name__))
        return prod

    def __imul__(self, other):
        if isinstance(other, self.__class__):
            raise TypeError("Attemping to set vector to scalar quantity")
        try:
            prod = self * other
        except TypeError:
            raise TypeError(
                "unsupported operand type(s) for *: '{0}' and '{1}'".format(
                    self.__class__.__name__, other.__class__.__name__))
        self = prod
        return self

    def __rmul__(self, other):
        try:
            return self * other
        except TypeError:
            raise TypeError(
                "unsupported operand type(s) for *: '{0}' and '{1}'".format(
                    other.__class__.__name__, self.__class__.__name__))

    def __add__(self, other):
        if other == 0:
            return copy(self)
        try:
            clone = self.__class__.__bases__[-1].__add__(self, other)
            clone.__class__ = self.__class__
        except TypeError:
            raise TypeError(
                "unsupported operand type(s) for +: '{0}' and '{1}'".format(
                    self.__class__.__name__, other.__class__.__name__))
        return clone

    def __radd__(self, other):
        if other == 0:
            return copy(self)
        raise TypeError(
            "unsupported operand type(s) for +: '{0}' and '{1}'".format(
                other.__class__.__name__, self.__class__.__name__))

    def __iadd__(self, other):
        try:
            _sum = self + other
        except TypeError:
            raise TypeError(
                "unsupported operand type(s) for +: '{0}' and '{1}'".format(
                    self.__class__.__name__, other.__class__.__name__))
        self = _sum
        return self

    def __sub__(self, other):
        if other == 0:
            return copy(self)
        try:
            clone = self.__class__.__bases__[-1].__sub__(self, other)
            clone.__class__ = self.__class__
        except TypeError:
            raise TypeError(
                "unsupported operand type(s) for -: '{0}' and '{1}'".format(
                    self.__class__.__name__, other.__class__.__name__))
        return clone

    def __rsub__(self, other):
        if other == 0:
            return copy(self)
        raise TypeError(
                "unsupported operand type(s) for -: '{0}' and '{1}'".format(
                    other.__class__.__name__, self.__class__.__name__))

    def __isub__(self, other):
        try:
            diff = self - other
        except TypeError:
            raise TypeError(
                "unsupported operand type(s) for -: '{0}' and '{1}'".format(
                    self.__class__.__name__, other.__class__.__name__))
        self = diff
        return self

    def __copy__(self):
        _copy = self.__class__.__bases__[-1](self)
        _copy.__class__ = self.__class__
        return _copy


[docs]@snake_case_methods class Vector2(_arithmetic_mixin, Object, QROOT.TVector2): """ A subclass of `ROOT.TVector2 <http://root.cern.ch/root/html/TVector2.html>`_. Examples -------- >>> from rootpy.vector import Vector2 >>> vect = Vector2(2, 4) >>> vect Vector2(x=2.000000, y=4.000000) """ _ROOT = QROOT.TVector2 @property def x(self): return self.X() @property def y(self): return self.Y() def __getitem__(self, i): if i == 0: return self.X() elif i == 1: return self.Y() raise IndexError("index {0:d} out of bounds".format(i)) def __repr__(self): return '{0}(x={1:f}, y={2:f})'.format( self.__class__.__name__, self.X(), self.Y()) def __mul__(self, other): if isinstance(other, self.__class__): prod = self.X() * other.X() + \ self.Y() * other.Y() elif isinstance(other, numbers.Real): prod = Vector2(other * self.X(), other * self.Y()) else: raise TypeError( "unsupported operand type(s) for *: '{0}' and '{1}'".format( self.__class__.__name__, other.__class__.__name__)) return prod def __add__(self, other): if isinstance(other, ROOT.TVector2): _sum = Vector3(self.X() + other.X(), self.Y() + other.Y()) else: raise TypeError( "unsupported operand type(s) for *: '{0}' and '{1}'".format( self.__class__.__name__, other.__class__.__name__)) return _sum
[docs]@snake_case_methods class Vector3(_arithmetic_mixin, Object, QROOT.TVector3): """ A subclass of `ROOT.TVector3 <http://root.cern.ch/root/html/TVector3.html>`_. Examples -------- >>> from rootpy.vector import Vector3 >>> vect = Vector3(1, 2, 3) >>> vect Vector3(x=1.000000, y=2.000000, z=3.000000) """ _ROOT = QROOT.TVector3 @property def x(self): return self.X() @property def y(self): return self.Y() @property def z(self): return self.Z() def __getitem__(self, i): if i == 0: return self.X() elif i == 1: return self.Y() elif i == 2: return self.Z() raise IndexError("index {0:d} out of bounds".format(i)) def __repr__(self): return '{0}(x={1:f}, y={2:f}, z={3:f})'.format( self.__class__.__name__, self.X(), self.Y(), self.Z()) def Angle(self, other): if isinstance(other, LorentzVector): return other.Angle(self) return ROOT.TVector3.Angle(self, other) def __mul__(self, other): if isinstance(other, ROOT.TVector3): prod = self.X() * other.X() + \ self.Y() * other.Y() + \ self.Z() * other.Z() elif isinstance(other, numbers.Real): prod = Vector3(other * self.X(), other * self.Y(), other * self.Z()) else: raise TypeError( "unsupported operand type(s) for *: '{0}' and '{1}'".format( self.__class__.__name__, other.__class__.__name__)) return prod def __add__(self, other): if isinstance(other, ROOT.TVector3): _sum = Vector3(self.X() + other.X(), self.Y() + other.Y(), self.Z() + other.Z()) else: raise TypeError( "unsupported operand type(s) for +: '{0}' and '{1}'".format( self.__class__.__name__, other.__class__.__name__)) return _sum def __sub__(self, other): if isinstance(other, ROOT.TVector3): _dif = Vector3(self.X() - other.X(), self.Y() - other.Y(), self.Z() - other.Z()) else: raise TypeError( "unsupported operand type(s) for -: '{0}' and '{1}'".format( self.__class__.__name__, other.__class__.__name__)) return _dif
[docs]@snake_case_methods class LorentzVector(_arithmetic_mixin, Object, QROOT.TLorentzVector): """ A subclass of `ROOT.TLorentzVector <http://root.cern.ch/root/html/TLorentzVector.html>`_. Examples -------- >>> from rootpy.vector import LorentzVector >>> vect = LorentzVector(1, 2, 3, 4) >>> vect LorentzVector(px=1.000000, py=2.000000, pz=3.000000, E=4.000000) """ _ROOT = QROOT.TLorentzVector @property def px(self): return self.Px() @property def py(self): return self.Py() @property def pz(self): return self.Pz() @property def e(self): return self.E() def __getitem__(self, i): if i == 0: return self.Px() elif i == 1: return self.Py() elif i == 2: return self.Pz() elif i == 3: return self.E() raise IndexError("index {0:d} out of bounds".format(i)) def __repr__(self): return "{0}(px={1:f}, py={2:f}, pz={3:f}, E={4:f})".format( self.__class__.__name__, self.Px(), self.Py(), self.Pz(), self.E()) def Angle(self, other): if isinstance(other, ROOT.TLorentzVector): return ROOT.TLorentzVector.Angle(self, other.Vect()) return ROOT.TLorentzVector.Angle(self, other) def BoostVector(self): vector = ROOT.TLorentzVector.BoostVector(self) vector.__class__ = Vector3 return vector
[docs]@snake_case_methods class Rotation(_arithmetic_mixin, Object, QROOT.TRotation): """ A subclass of `ROOT.TRotation <http://root.cern.ch/root/html/TRotation.html>`_. """ _ROOT = QROOT.TRotation def __repr__(self): return ("[[{0:f}, {1:f}, {2:f}],\n" " [{3:f}, {4:f}, {5:f}],\n" " [{6:f}, {7:f}, {8:f}]]").format( self.XX(), self.XY(), self.XZ(), self.YX(), self.YY(), self.YZ(), self.ZX(), self.ZY(), self.ZZ())
[docs]@snake_case_methods class LorentzRotation(_arithmetic_mixin, Object, QROOT.TLorentzRotation): """ A subclass of `ROOT.TLorentzRotation <http://root.cern.ch/root/html/TLorentzRotation.html>`_. """ _ROOT = QROOT.TLorentzRotation def __repr__(self): return ("[[{0:f}, {1:f}, {2:f}, {3:f}],\n" " [{4:f}, {5:f}, {6:f}, {7:f}],\n" " [{8:f}, {9:f}, {10:f}, {11:f}],\n" " [{12:f}, {13:f}, {14:f}, {15:f}]]").format( self.XX(), self.XY(), self.XZ(), self.XT(), self.YX(), self.YY(), self.YZ(), self.YT(), self.ZX(), self.ZY(), self.ZZ(), self.ZT(), self.TX(), self.TY(), self.TZ(), self.TT())