向量类和实用工具
项目描述
矢量:二维、三维和洛伦兹矢量的数组
矢量是一个Python 3.8+库(Python 3.6和3.7分别支持到v0.9.0
和v1.0.0
),用于二维、三维和洛伦兹矢量(特别是矢量数组),以NumPy类似的方式解决常见的物理问题。
矢量的主要功能
- 纯Python,仅依赖NumPy。这使得它更容易安装。
- 矢量可以用各种坐标系表示:笛卡尔、圆柱、伪斜率以及这些坐标系的任何组合,对于洛伦兹矢量还包括时间或固有时间。总共有12个坐标系:{x-y 与 ρ-φ 在方位平面内} × {z 与 θ 与 η 纵向} × {t 与 τ 时间上}。
- 使用由ROOT的TLorentzVector和Math::LorentzVector以及scikit-hep/math、uproot-methods TLorentzVector、henryiii/hepvector和coffea.nanoevents.methods.vector设定的名称和约定。
- 在多种后端实现
- 纯Python对象
- SymPy矢量
- 矢量NumPy数组(作为结构化数组子类)
- Awkward Arrays矢量数组
- 更多可能性:CuPy、TensorFlow、Torch...
- Awkward后端也在Numba中实现,用于矢量的即时编译计算。
- 通过Awkward Arrays支持JAX和Dask。
- 几何矢量(具有最少的属性和方法名称)与表示动量的矢量(具有如
pt
=rho
、energy
=t
、mass
=tau
的同义词)之间的区别。
安装
要安装,使用pip install vector
或您喜欢的环境安装方式。
概述
本概述基于此处的文档。
import vector
import numpy as np
import awkward as ak # at least v2.0.0 (vector v1.4.* supports awkward v1 and v2 both)
import numba as nb
构建一个矢量或矢量数组
创建一个或多个矢量的最简单方法是使用辅助函数
vector.obj
创建一个纯Python矢量对象,vector.arr
创建一个矢量NumPy数组(或小写的array
,如np.array
),vector.awk
创建一个矢量Awkward数组(或大写的Array
,如ak.Array
)。vector.zip
用于创建向量数组(类似于ak.zip
)
纯Python向量
您可以直接使用 VectorObject
和 MomentumObject
类来构建对象类型向量
vector.VectorObject2D(x=1.1, y=2.2)
vector.MomentumObject3D(px=1.1, py=2.2, pz=3.3)
vector.VectorObject4D(x=1.1, y=2.2, eta=3.3, tau=4.4)
每个类都是如此。
或者,您可以使用单个包装函数来构建所有可能的对象类型向量组合
# Cartesian 2D vector
vector.obj(x=3, y=4)
# same in polar coordinates
vector.obj(rho=5, phi=0.9273)
# use "isclose" unless they are exactly equal
vector.obj(x=3, y=4).isclose(vector.obj(rho=5, phi=0.9273))
# Cartesian 3D vector
vector.obj(x=3, y=4, z=-2)
# Cartesian 4D vector
vector.obj(x=3, y=4, z=-2, t=10)
# in rho-phi-eta-t cylindrical coordinates
vector.obj(rho=5, phi=0.9273, eta=-0.39, t=10)
# use momentum-synonyms to get a momentum vector
vector.obj(pt=5, phi=0.9273, eta=-0.39, E=10)
vector.obj(rho=5, phi=0.9273, eta=-0.39, t=10) == vector.obj(
pt=5, phi=0.9273, eta=-0.390035, E=10
)
# geometrical vectors have to use geometrical names ("tau", not "mass")
vector.obj(rho=5, phi=0.9273, eta=-0.39, t=10).tau
# momentum vectors can use momentum names (as well as geometrical ones)
vector.obj(pt=5, phi=0.9273, eta=-0.39, E=10).mass
# any combination of azimuthal, longitudinal, and temporal coordinates is allowed
vector.obj(pt=5, phi=0.9273, theta=1.9513, mass=8.4262)
vector.obj(x=3, y=4, z=-2, t=10).isclose(
vector.obj(pt=5, phi=0.9273, theta=1.9513, mass=8.4262)
)
# Test instance type for any level of granularity.
(
# is a vector or array of vectors
isinstance(vector.obj(x=1.1, y=2.2), vector.Vector),
# is 2D (not 3D or 4D)
isinstance(vector.obj(x=1.1, y=2.2), vector.Vector2D),
# is a vector object (not an array)
isinstance(vector.obj(x=1.1, y=2.2), vector.VectorObject),
# has momentum synonyms
isinstance(vector.obj(px=1.1, py=2.2), vector.Momentum),
# has transverse plane (2D, 3D, or 4D)
isinstance(vector.obj(x=1.1, y=2.2, z=3.3, t=4.4), vector.Planar),
# has all spatial coordinates (3D or 4D)
isinstance(vector.obj(x=1.1, y=2.2, z=3.3, t=4.4), vector.Spatial),
# has temporal coordinates (4D)
isinstance(vector.obj(x=1.1, y=2.2, z=3.3, t=4.4), vector.Lorentz),
# azimuthal coordinate type
isinstance(vector.obj(x=1.1, y=2.2, z=3.3, t=4.4).azimuthal, vector.AzimuthalXY),
# longitudinal coordinate type
isinstance(
vector.obj(x=1.1, y=2.2, z=3.3, t=4.4).longitudinal, vector.LongitudinalZ
),
# temporal coordinate type
isinstance(vector.obj(x=1.1, y=2.2, z=3.3, t=4.4).temporal, vector.TemporalT),
)
2D向量的允许关键字参数有
x
和y
用于笛卡尔方位坐标px
和py
用于动量rho
和phi
用于极坐标方位pt
和phi
用于动量
对于3D向量,您需要上述参数和
z
用于笛卡尔纵向坐标pz
用于动量theta
用于球极角(从 $0$ 到 $\pi$,包括)eta
用于伪快度,这是一种球极角
对于4D向量,您需要上述参数和
t
用于笛卡尔时间坐标E
或energy
用于四维动量tau
用于“固有时间”(向量的静止坐标系中的时间坐标)M
或mass
用于四维动量
由于动量向量除了几何名称外还有动量同义词,任何动量同义词都会使整个向量成为动量向量。
如果您想通过关键字参数绕过维度和坐标系推断(例如,用于静态类型),则可以使用专用构造函数
vector.VectorObject2D.from_xy(1.1, 2.2)
vector.MomentumObject3D.from_rhophiz(1.1, 2.2, 3.3)
vector.VectorObject4D.from_xyetatau(1.1, 2.2, 3.3, 4.4)
以及所有可能的方位、纵向和时间坐标的组合,几何和动量风味。
SymPy 向量
注意:SymPy 向量的操作仅在向量为正时间线型时与数值向量(Python、NumPy 和 Awkward 后端)100% 兼容,即如果
t**2 > x**2 + y**2 + z**2
。空间线型和负时间线型情况有不同的符号约定。
您可以直接使用 VectorSympy
和 MomentumSympy
类来构建对象类型向量
import sympy
x, y, z, t, px, py, pz, eta, tau = sympy.symbols(
"x y z t px py pz eta tau",
real=True, # see sympy assumptions to add more restrictions on the symbols
)
vector.VectorSympy2D(x=x, y=y)
vector.MomentumSympy3D(px=px, py=py, pz=pz)
vector.VectorSympy4D(x=x, y=y, eta=eta, tau=tau)
每个类都是如此。
# Test instance type for any level of granularity.
(
# is a vector or array of vectors
isinstance(vector.VectorSympy2D(x=x, y=y), vector.Vector),
# is 2D (not 3D or 4D)
isinstance(vector.VectorSympy2D(x=x, y=y), vector.Vector2D),
# is a sympy vector (not an array)
isinstance(vector.VectorSympy2D(x=x, y=y), vector.VectorSympy),
# has momentum synonyms
isinstance(vector.MomentumSympy2D(px=px, py=py), vector.Momentum),
# has transverse plane (2D, 3D, or 4D)
isinstance(vector.VectorSympy4D(x=x, y=y, z=z, t=t), vector.Planar),
# has all spatial coordinates (3D or 4D)
isinstance(vector.VectorSympy4D(x=x, y=y, z=z, t=t), vector.Spatial),
# has temporal coordinates (4D)
isinstance(vector.VectorSympy4D(x=x, y=y, z=z, t=t), vector.Lorentz),
# azimuthal coordinate type
isinstance(vector.VectorSympy4D(x=x, y=y, z=z, t=t).azimuthal, vector.AzimuthalXY),
# longitudinal coordinate type
isinstance(
vector.VectorSympy4D(x=x, y=y, z=z, t=t).longitudinal, vector.LongitudinalZ
),
# temporal coordinate type
isinstance(vector.VectorSympy4D(x=x, y=y, z=z, t=t).temporal, vector.TemporalT),
)
由于 VectorSympy2D
、VectorSympy3D
、VectorSympy4D
和它们的动量等效操作 SymPy 表达式,因此所有正常的 SymPy 方法和函数都适用于结果、坐标和向量。
sympy.init_session() # latex printing
v1 = vector.VectorSympy2D(x=x, y=y)
sympy.Eq(v1.rho, sympy.sqrt(x**2 + y**2))
v2 = vector.VectorSympy4D(x=x, y=y, z=z, t=t)
v2.to_rhophithetatau().tau
values = {x: 3, y: 2, z: 1, t: 10} # t**2 > x**2 + y**2 + z**2
v2.is_timelike()
v2.is_timelike().subs(values)
v2.to_rhophithetatau().tau.subs(values).evalf()
v2.boost(v2.to_beta3())
v2.boost(v2.to_beta3()).t
v2.boost(v2.to_beta3()).t.simplify()
v2.boost(v2.to_beta3()).t.subs(values)
v2.boost(v2.to_beta3()).t.subs(values).evalf()
适用于 vector.obj
构造的所有关键字参数和规则也适用于 vector.VectorSympyND
和 vector.MomentumObjectND
对象。
向量 NumPy 数组
您可以直接使用 VectorNumpy
类来构建对象类型向量
# NumPy-like arguments (literally passed through to NumPy)
vector.VectorNumpy2D(
[(1.1, 2.1), (1.2, 2.2), (1.3, 2.3), (1.4, 2.4), (1.5, 2.5)],
dtype=[("x", float), ("y", float)],
)
# Pandas-like arguments (dict from names to column arrays)
vector.VectorNumpy2D({"x": [1.1, 1.2, 1.3, 1.4, 1.5], "y": [2.1, 2.2, 2.3, 2.4, 2.5]})
# As with objects, the coordinate system and dimension is taken from the names of the fields.
vector.VectorNumpy4D(
{
"x": [1.1, 1.2, 1.3, 1.4, 1.5],
"y": [2.1, 2.2, 2.3, 2.4, 2.5],
"z": [3.1, 3.2, 3.3, 3.4, 3.5],
"t": [4.1, 4.2, 4.3, 4.4, 4.5],
}
)
每个类都是如此。
或者,您可以使用单个包装函数来构建所有可能的 NumPy 类型向量组合
# NumPy-like arguments (literally passed through to NumPy)
vector.array(
[(1.1, 2.1), (1.2, 2.2), (1.3, 2.3), (1.4, 2.4), (1.5, 2.5)],
dtype=[("x", float), ("y", float)],
)
# Pandas-like arguments (dict from names to column arrays)
vector.array({"x": [1.1, 1.2, 1.3, 1.4, 1.5], "y": [2.1, 2.2, 2.3, 2.4, 2.5]})
# As with objects, the coordinate system and dimension is taken from the names of the fields.
vector.array(
{
"x": [1.1, 1.2, 1.3, 1.4, 1.5],
"y": [2.1, 2.2, 2.3, 2.4, 2.5],
"z": [3.1, 3.2, 3.3, 3.4, 3.5],
"t": [4.1, 4.2, 4.3, 4.4, 4.5],
}
)
vector.array(
{
"pt": [1.1, 1.2, 1.3, 1.4, 1.5],
"phi": [2.1, 2.2, 2.3, 2.4, 2.5],
"eta": [3.1, 3.2, 3.3, 3.4, 3.5],
"M": [4.1, 4.2, 4.3, 4.4, 4.5],
}
)
现有的 NumPy 数组可以视为向量数组,但需要是一个具有可识别字段名的 结构化数组。
np.arange(0, 24, 0.1).view( # NumPy array
[
("x", float),
("y", float),
("z", float),
("t", float),
] # interpret groups of four values as named fields
).view(
vector.VectorNumpy4D
) # give it vector properties and methods
由于 VectorNumpy2D
、VectorNumpy3D
、VectorNumpy4D
和它们的动量等效是 NumPy 数组子类,因此所有正常的 NumPy 方法和函数都适用于它们。
np.arange(0, 24, 0.1).view(
[("x", float), ("y", float), ("z", float), ("t", float)]
).view(vector.VectorNumpy4D).reshape(6, 5, 2)
适用于 vector.obj
构造的所有关键字参数和规则也适用于 vector.arr
dtypes。
即使在构造时使用了动量同义词,dtype 中也使用几何名称。
vector.arr({"px": [1, 2, 3, 4], "py": [1.1, 2.2, 3.3, 4.4], "pz": [0.1, 0.2, 0.3, 0.4]})
向量 Awkward Arrays
Awkward Arrays 是比 NumPy 允许的更复杂的数据结构数组,例如变长列表、嵌套记录、缺失数据甚至异构数据(多个数据类型:谨慎使用)。
vector.awk
函数的行为与 ak.Array 构造函数完全相同,只是它创建向量数组。
vector.awk(
[
[{"x": 1, "y": 1.1, "z": 0.1}, {"x": 2, "y": 2.2, "z": 0.2}],
[],
[{"x": 3, "y": 3.3, "z": 0.3}],
[
{"x": 4, "y": 4.4, "z": 0.4},
{"x": 5, "y": 5.5, "z": 0.5},
{"x": 6, "y": 6.6, "z": 0.6},
],
]
)
如果您希望将名为 "Vector2D
", "Vector3D
", "Vector4D
", "Momentum2D
", "Momentum3D
" 或 "Momentum4D
" 的任何记录解释为向量,请全局注册这些行为。
vector.register_awkward()
ak.Array(
[
[{"x": 1, "y": 1.1, "z": 0.1}, {"x": 2, "y": 2.2, "z": 0.2}],
[],
[{"x": 3, "y": 3.3, "z": 0.3}],
[
{"x": 4, "y": 4.4, "z": 0.4},
{"x": 5, "y": 5.5, "z": 0.5},
{"x": 6, "y": 6.6, "z": 0.6},
],
],
with_name="Vector3D",
)
所有适用于 vector.obj
构造的参数和规则也适用于 vector.awk
字段名称。
最后,可以子类化 VectorAwkward
混合类以创建自定义向量类。尴尬的行为类和投影必须命名为 *Array
。例如,coffea
使用以下名称 - TwoVectorArray
,ThreeVectorArray
,PolarTwoVectorArray
,SphericalThreeVectorArray
,...
向量属性
任何几何坐标都可以从任何坐标系中的向量中计算得出;它们将根据需要提供或计算。
vector.obj(x=3, y=4).rho
vector.obj(rho=5, phi=0.9273).x
vector.obj(rho=5, phi=0.9273).y
vector.obj(x=1, y=2, z=3).theta
vector.obj(x=1, y=2, z=3).eta
有些属性不是坐标,而是由它们派生出来的。
vector.obj(x=1, y=2, z=3).costheta
vector.obj(x=1, y=2, z=3).mag # spatial magnitude
vector.obj(x=1, y=2, z=3).mag2 # spatial magnitude squared
这些属性被提供,因为它们可以在不同的坐标系中更快或更稳定地计算。例如,模量忽略了极坐标中的 phi
。
vector.obj(rho=3, phi=0.123456789, z=4).mag2
动量向量除了动量同义词之外,还具有几何属性。
vector.obj(px=3, py=4).rho
vector.obj(px=3, py=4).pt
vector.obj(x=1, y=2, z=3, E=4).tau
vector.obj(x=1, y=2, z=3, E=4).mass
关键在于:向量数组返回坐标数组。
vector.arr(
{
"x": [1.0, 2.0, 3.0, 4.0, 5.0],
"y": [1.1, 2.2, 3.3, 4.4, 5.5],
"z": [0.1, 0.2, 0.3, 0.4, 0.5],
}
).theta
vector.awk(
[
[{"x": 1, "y": 1.1, "z": 0.1}, {"x": 2, "y": 2.2, "z": 0.2}],
[],
[{"x": 3, "y": 3.3, "z": 0.3}],
[{"x": 4, "y": 4.4, "z": 0.4}, {"x": 5, "y": 5.5, "z": 0.5}],
]
).theta
# Make a large, random NumPy array of 3D momentum vectors.
array = (
np.random.normal(0, 1, 150)
.view([(x, float) for x in ("x", "y", "z")])
.view(vector.MomentumNumpy3D)
.reshape(5, 5, 2)
)
# Get the transverse momentum of each one.
array.pt
# The array and its components have the same shape.
array.shape
array.pt.shape
# Make a large, random Awkward Array of 3D momentum vectors.
array = vector.awk(
[
[
{x: np.random.normal(0, 1) for x in ("px", "py", "pz")}
for inner in range(np.random.poisson(1.5))
]
for outer in range(50)
]
)
# Get the transverse momentum of each one, in the same nested structure.
array.pt
# The array and its components have the same list lengths (and can therefore be used together in subsequent calculations).
ak.num(array)
ak.num(array.pt)
向量方法
向量方法需要参数(括号内),这些参数可以是标量或其他向量,具体取决于计算。
vector.obj(x=3, y=4).rotateZ(0.1)
vector.obj(rho=5, phi=0.4).rotateZ(0.1)
# Broadcasts a scalar rotation angle of 0.5 to all elements of the NumPy array.
print(
vector.arr({"rho": [1, 2, 3, 4, 5], "phi": [0.1, 0.2, 0.3, 0.4, 0.5]}).rotateZ(0.5)
)
# Matches each rotation angle to an element of the NumPy array.
print(
vector.arr({"rho": [1, 2, 3, 4, 5], "phi": [0.1, 0.2, 0.3, 0.4, 0.5]}).rotateZ(
np.array([0.1, 0.2, 0.3, 0.4, 0.5])
)
)
# Broadcasts a scalar rotation angle of 0.5 to all elements of the Awkward Array.
print(
vector.awk(
[[{"rho": 1, "phi": 0.1}, {"rho": 2, "phi": 0.2}], [], [{"rho": 3, "phi": 0.3}]]
).rotateZ(0.5)
)
# Broadcasts a rotation angle of 0.1 to both elements of the first list, 0.2 to the empty list, and 0.3 to the only element of the last list.
print(
vector.awk(
[[{"rho": 1, "phi": 0.1}, {"rho": 2, "phi": 0.2}], [], [{"rho": 3, "phi": 0.3}]]
).rotateZ([0.1, 0.2, 0.3])
)
# Matches each rotation angle to an element of the Awkward Array.
print(
vector.awk(
[[{"rho": 1, "phi": 0.1}, {"rho": 2, "phi": 0.2}], [], [{"rho": 3, "phi": 0.3}]]
).rotateZ([[0.1, 0.2], [], [0.3]])
)
一些方法等同于二元运算符。
vector.obj(x=3, y=4).scale(10)
vector.obj(x=3, y=4) * 10
10 * vector.obj(x=3, y=4)
vector.obj(rho=5, phi=0.5) * 10
一些方法涉及多个向量。
vector.obj(x=1, y=2).add(vector.obj(x=5, y=5))
vector.obj(x=1, y=2) + vector.obj(x=5, y=5)
vector.obj(x=1, y=2).dot(vector.obj(x=5, y=5))
vector.obj(x=1, y=2) @ vector.obj(x=5, y=5)
向量可以使用不同的坐标系。需要转换,但为了速度和数值稳定性而尽量减少。
# both are Cartesian, dot product is exact
vector.obj(x=3, y=4) @ vector.obj(x=6, y=8)
# one is polar, dot product is approximate
vector.obj(rho=5, phi=0.9273) @ vector.obj(x=6, y=8)
# one is polar, dot product is approximate
vector.obj(x=3, y=4) @ vector.obj(rho=10, phi=0.9273)
# both are polar, a formula that depends on phi differences is used
vector.obj(rho=5, phi=0.9273) @ vector.obj(rho=10, phi=0.9273)
在 Python 中,一些“运算符”实际上是内置函数,例如 abs
。
abs(vector.obj(x=3, y=4))
注意,abs
返回
- 2D 向量的
rho
- 3D 向量的
mag
- 4D 向量的
tau
(mass
)
当您想要特定维度上的模量时,请使用命名属性;当您想要任何维度上的模量时,请使用 abs
。
向量可以来自不同的后端。适用于 Python 数字、NumPy 数组和 Awkward 数组的常规广播规则适用。
vector.arr({"x": [1, 2, 3, 4, 5], "y": [0.1, 0.2, 0.3, 0.4, 0.5]}) + vector.obj(
x=10, y=5
)
(
vector.awk(
[ # an Awkward Array of vectors
[{"x": 1, "y": 1.1}, {"x": 2, "y": 2.2}],
[],
[{"x": 3, "y": 3.3}],
[{"x": 4, "y": 4.4}, {"x": 5, "y": 5.5}],
]
)
+ vector.obj(x=10, y=5) # and a single vector object
)
(
vector.awk(
[ # an Awkward Array of vectors
[{"x": 1, "y": 1.1}, {"x": 2, "y": 2.2}],
[],
[{"x": 3, "y": 3.3}],
[{"x": 4, "y": 4.4}, {"x": 5, "y": 5.5}],
]
)
+ vector.arr(
{"x": [4, 3, 2, 1], "y": [0.1, 0.1, 0.1, 0.1]}
) # and a NumPy array of vectors
)
一些操作是为 2D 或 3D 向量定义的,但可以在更高维度的向量上使用,因为额外的分量可以被忽略或不受影响。
# deltaphi is a planar operation (defined on the transverse plane)
vector.obj(rho=1, phi=0.5).deltaphi(vector.obj(rho=2, phi=0.3))
# but we can use it on 3D vectors
vector.obj(rho=1, phi=0.5, z=10).deltaphi(vector.obj(rho=2, phi=0.3, theta=1.4))
# and 4D vectors
vector.obj(rho=1, phi=0.5, z=10, t=100).deltaphi(
vector.obj(rho=2, phi=0.3, theta=1.4, tau=1000)
)
# and mixed dimensionality
vector.obj(rho=1, phi=0.5).deltaphi(vector.obj(rho=2, phi=0.3, theta=1.4, tau=1000))
这对于给 4D 向量赋予 3D 向量的所有功能特别有用。
vector.obj(x=1, y=2, z=3).rotateX(np.pi / 4)
vector.obj(x=1, y=2, z=3, tau=10).rotateX(np.pi / 4)
vector.obj(pt=1, phi=1.3, eta=2).deltaR(vector.obj(pt=2, phi=0.3, eta=1))
vector.obj(pt=1, phi=1.3, eta=2, mass=5).deltaR(
vector.obj(pt=2, phi=0.3, eta=1, mass=10)
)
对于一些操作(如 +
、-
、==
、!=
等)- 向量的维度应该相等。这可以通过使用 like
方法、to_{coordinate_name}
方法、to_Vector*D
方法来实现。这些 to_Vector*D
方法为用户提供更大的灵活性,即,可以将新坐标值作为命名参数传递给方法。
v1 = vector.obj(x=1, y=2, z=3)
v2 = vector.obj(x=1, y=2)
v1 - v2.like(v1) # transforms v2 to v1's coordinate system (imputes z=0)
v1.like(v2) - v2 # transforms v1 to v2's coordinate system (removes z)
v1 - v2.to_xyz() # transforms v2 to xyz coordinates (imputes z=0)
v1.to_xy() - v2 # transforms v1 to xy coordinates (removes z)
v1 - v2.to_Vector3D(z=3) # transforms v2 to 3D (imputes z=3)
v1.to_Vector2D() - v2 # transforms v1 to 2D (removes z)
类似地,对于一些向量方法,输入向量的维度会进行严格的类型检查。
例如,叉积仅定义于 3D 和 7D 向量;因此,在 4D 向量上运行该方法将引发错误。
vector.obj(x=0.1, y=0.2, z=0.3).cross(vector.obj(x=0.4, y=0.5, z=0.6))
属性和方法(当前)列表如下
平面(2D、3D、4D)
x
(px
)y
(py
)rho
(pt
):二维模量rho2
(pt2
):二维模量平方phi
deltaphi(vector)
:phi 的差异(有符号,并校正为 $-\pi$ 至 $\pi$)rotateZ(angle)
transform2D(obj)
:obj 必须通过obj["xx"]
、obj["xy"]
、obj["yx"]
、obj["yy"]
提供组件is_parallel(vector, tolerance=1e-5)
:只有当它们指向同一方向时才为真is_antiparallel(vector, tolerance=1e-5)
:只有当它们指向相反方向时才为真is_perpendicular(vector, tolerance=1e-5)
空间(3D、4D)
z
(pz
)theta
eta
costheta
cottheta
mag
(p
):三维模量,不包括时间分量mag2
(p2
):三维模长的平方cross
:叉积(严格三维)deltaangle(vector)
:角度差(总是非负)deltaeta(vector)
:eta
差(有符号)deltaR(vector)
:$\Delta R = \sqrt{\Delta\phi^2 + \Delta\eta^2}$deltaR2(vector)
:上述的平方rotateX(angle)
rotateY(angle)
rotate_axis(axis, angle)
:忽略axis
的模长,但必须至少为3Drotate_euler(phi, theta, psi, order="zxz")
:参数顺序与ROOT::Math::EulerAngles相同,且order="zxz"
与ROOT的约定一致rotate_nautical(yaw, pitch, roll)
rotate_quaternion(u, i, j, k)
:再次,约定与ROOT::Math::Quaternion相同。transform3D(obj)
:obj
必须通过obj["xx"]
、obj["xy"]
等提供组件is_parallel(vector, tolerance=1e-5)
:只有当它们指向同一方向时才为真is_antiparallel(vector, tolerance=1e-5)
:只有当它们指向相反方向时才为真is_perpendicular(vector, tolerance=1e-5)
洛伦兹(仅4D)
t
(E
、energy
):遵循ROOT::Math::LorentzVector的行为,将时空矢量视为负t
和负tau
,并截断方向错误的时空中矢量t2
(E2
、energy2
)tau
(M
、mass
):参见上面的注释tau2
(M2
、mass2
)beta
:介于$0$(包含)和$1$(不包含,除非矢量分量是无穷大)之间的标量deltaRapidityPhi
:$\Delta R_{\mbox{rapidity}} = \Delta\phi^2 + \Delta \mbox{rapidity}^2$deltaRapidityPhi2
:上述的平方gamma
:介于$1$(包含)和$\infty$之间的标量rapidity
:介于$0$(包含)和$\infty$之间的标量boost_p4(four_vector)
:使用另一个4D矢量作为差值来改变坐标系boost_beta(three_vector)
:使用3D beta矢量(所有分量介于$-1$和$+1$之间)来改变坐标系boost(vector)
:使用给定vector
的维度来确定行为boostX(beta=None, gamma=None)
:提供beta
或gamma
,但不能同时提供boostY(beta=None, gamma=None)
:提供beta
或gamma
,但不能同时提供boostZ(beta=None, gamma=None)
:提供beta
或gamma
,但不能同时提供transform4D(obj)
:obj
必须通过obj["xx"]
、obj["xy"]
等提供组件to_beta3()
:将four_vector
(用于boost_p4
)转换为three_vector
(用于boost_beta3
)is_timelike(tolerance=0)
is_spacelike(tolerance=0)
is_lightlike(tolerance=1e-5)
:注意不同的容忍度
所有维度的数字
unit()
:注意括号dot(vector)
:也可以使用@
运算符add(vector)
:也可以使用+
运算符subtract(vector)
:也可以使用-
运算符scale(factor)
:也可以使用*
运算符equal(vector)
:也可以使用==
运算符,但考虑使用isclose
not_equal(vector)
:也可以使用!=
运算符,但考虑使用isclose
sum()
:也可以使用numpy.sum
或awkward.sum
,仅适用于NumPy和Awkward矢量count_nonzero()
:也可以使用numpy.count_nonzero
或awkward.count_nonzero
,仅适用于NumPy和Awkward矢量count()
:也可以使用awkward.count
,仅适用于Awkward矢量isclose(vector, rtol=1e-5, atol=1e-8, equal_nan=False)
:类似于np.isclose;数组还有allclose方法to_VectorND(coordinates)
/to_ND(coordinates)
:将N
替换为所需的矢量维度to_{coordinate-names}
:例如 -to_rhophietatau
like(other)
:将矢量投影到other
的维度上,例如 -two_d_vector.like(three_d_vector)
使用Numba编译您的Python
Numba 是一个用于 NumPy 和 Python 中数学相关子集的即时(JIT)编译器。它允许您在不离开 Python 环境的情况下编写快速代码。Numba 的缺点是它只能编译涉及它所识别的对象和函数的代码块。
Vector 库包括扩展,以告知 Numba 关于矢量对象、矢量 NumPy 数组和矢量 Awkward Arrays。截至编写时,由于 numba/numba#6148,矢量 NumPy 数组的实现尚不完整。
例如,考虑以下函数
@nb.njit
def compute_mass(v1, v2):
return (v1 + v2).mass
compute_mass(vector.obj(px=1, py=2, pz=3, E=4), vector.obj(px=-1, py=-2, pz=-3, E=4))
当两个 MomentumObject4D
对象作为参数传递时,Numba 会识别它们,并将 Python 对象替换为低级结构。当它编译函数时,它会识别 +
为 4D add
函数,并识别 .mass
为结果的 tau
成分。
尽管这表明 Numba 可以操作矢量对象,但仅编译少数几个向量的计算并没有性能优势(而且可能存在劣势)。优势在于涉及大量向量的数组中。
# This is still not a large number. You want millions.
array = vector.awk(
[
[
dict(
{x: np.random.normal(0, 1) for x in ("px", "py", "pz")},
E=np.random.normal(10, 1),
)
for inner in range(np.random.poisson(1.5))
]
for outer in range(50)
]
)
@nb.njit
def compute_masses(array):
out = np.empty(len(array), np.float64)
for i, event in enumerate(array):
total = vector.obj(px=0.0, py=0.0, pz=0.0, E=0.0)
for vec in event:
total = total + vec
out[i] = total.mass
return out
compute_masses(array)
扩展 Awkward 混合子类
目前,可以通过子类化矢量混合子类来扩展矢量功能。尽管现有的机制运作良好,但它仍在不断改进。
例如,可以通过以下方式扩展 MomentumAwkward
类
behavior = vector.backends.awkward.behavior
@ak.mixin_class(behavior)
class TwoVector(vector.backends.awkward.MomentumAwkward2D):
pass
@ak.mixin_class(behavior)
class ThreeVector(vector.backends.awkward.MomentumAwkward3D):
pass
# required for transforming vectors
# the class names must always end with "Array"
TwoVectorArray.ProjectionClass2D = TwoVectorArray # noqa: F821
TwoVectorArray.ProjectionClass3D = ThreeVectorArray # noqa: F821
TwoVectorArray.MomentumClass = TwoVectorArray # noqa: F821
ThreeVectorArray.ProjectionClass2D = TwoVectorArray # noqa: F821
ThreeVectorArray.ProjectionClass3D = ThreeVectorArray # noqa: F821
ThreeVectorArray.MomentumClass = ThreeVectorArray # noqa: F821
vec = ak.zip(
{
"pt": [[1, 2], [], [3], [4]],
"phi": [[1.2, 1.4], [], [1.6], [3.4]],
},
with_name="TwoVector",
behavior=behavior,
)
vec
二元运算符不是由 awkward 自动注册的,但可以使用矢量方法在子类化的矢量上执行操作。
vec.add(vec)
类似地,新方法可以内部使用其他矢量方法。
@ak.mixin_class(behavior)
class LorentzVector(vector.backends.awkward.MomentumAwkward4D):
@ak.mixin_class_method(np.divide, {numbers.Number})
def divide(self, factor):
return self.scale(1 / factor)
# required for transforming vectors
# the class names must always end with "Array"
LorentzVectorArray.ProjectionClass2D = TwoVectorArray # noqa: F821
LorentzVectorArray.ProjectionClass3D = ThreeVectorArray # noqa: F821
LorentzVectorArray.ProjectionClass4D = LorentzVectorArray # noqa: F821
LorentzVectorArray.MomentumClass = LorentzVectorArray # noqa: F821
vec = ak.zip(
{
"pt": [[1, 2], [], [3], [4]],
"eta": [[1.2, 1.4], [], [1.6], [3.4]],
"phi": [[0.3, 0.4], [], [0.5], [0.6]],
"energy": [[50, 51], [], [52], [60]],
},
with_name="LorentzVector",
behavior=behavior,
)
vec / 2
vec.like(vector.obj(x=1, y=2))
vec.like(vector.obj(x=1, y=2, z=3))
还可以在向量的行为字典中手动添加二元运算,以启用二元运算。
_binary_dispatch_cls = {
"TwoVector": TwoVector,
"ThreeVector": ThreeVector,
"LorentzVector": LorentzVector,
}
_rank = [TwoVector, ThreeVector, LorentzVector]
for lhs, lhs_to in _binary_dispatch_cls.items():
for rhs, rhs_to in _binary_dispatch_cls.items():
out_to = min(lhs_to, rhs_to, key=_rank.index)
behavior[(np.add, lhs, rhs)] = out_to.add
behavior[(np.subtract, lhs, rhs)] = out_to.subtract
vec + vec
vec.to_2D() + vec.to_2D()
最后,而不是手动注册超类 ufunc,可以使用 copy_behaviors
实用函数复制新子类的行为项
behavior.update(ak._util.copy_behaviors("Vector2D", "TwoVector", behavior))
behavior.update(ak._util.copy_behaviors("Vector3D", "ThreeVector", behavior))
behavior.update(ak._util.copy_behaviors("Momentum4D", "LorentzVector", behavior))
vec + vec
vec.to_2D() + vec.to_2D()
关于向量的讨论
- 2024 年 7 月 3 日 - 新的 SymPy 向量后端:统一实验物理学家和理论物理学家 - PyHEP 2024(虚拟)
- 2023 年 10 月 9 日 - Vector 的最新动态?首个重大版本已发布! - PyHEP 2023(虚拟) 🎥
- 2022 年 9 月 13 日 - 使用 Vector 构造 HEP 向量和分析 HEP 数据 - PyHEP 2022(虚拟) 🎥
- 2022 年 7 月 20 日 - 分析 Grand Challenge / HEP 科学 Python 生态系统 - DANCE/CoDaS@Snowmass 2022 计算和数据科学软件培训
- 2022 年 4 月 25 日 - 基础库(uproot、awkward、hist、mplhep) - IRIS-HEP AGC 工具 2022 工作坊 🎥
- 2021 年 11 月 3 日 - 数据处理:uproot、awkward 和 vector - IRIS-HEP AGC 工具 2021 工作坊 🎥
截至 2023 年 11 月 17 日的状态
vector 的首个重大版本已发布,该包已达到稳定状态。工作由 GitHub 上创建的错误报告和功能请求引领。它只能通过您的反馈来改进!
贡献者 ✨
感谢这些优秀的人们 (emoji key)
Jim Pivarski 🚧 💻 📖 |
亨利·施莱纳 🚧 💻 📖 |
埃杜阿多·罗德里格斯 🚧 💻 📖 |
N!no 📖 |
彼得·法克德尔 📖 |
卢克·克雷茨科 💻 |
尼古拉斯·史密斯 🤔 |
约纳斯·埃斯勒 🤔 |
本项目遵循所有贡献者规范。欢迎任何形式的贡献!有关设置开发环境的更多信息,请参阅CONTRIBUTING.md。
致谢
该库主要是由吉姆·皮瓦尔斯基、亨利·施莱纳、萨兰什·乔普拉和埃杜阿多·罗德里格斯开发的。
本工作的支持来自国家科学基金会合作协议OAC-1836650和PHY-2323298(IRIS-HEP)以及OAC-1450377(DIANA/HEP)。在此材料中表达的意见、发现、结论或建议是作者的观点,并不一定反映国家科学基金会的观点。
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分布
构建分布
vector-1.5.1.tar.gz的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | 41ec731fb67ea35af2075eb3a4d6c83ef93b580dade63010821cbc00f1b98961 |
|
MD5 | a5426fff7e539b9647bd141a7eb948d2 |
|
BLAKE2b-256 | 18ddc59c3baae9b0e0324144353cde08842888c1e7b889bcebec056f667630bd |
vector-1.5.1-py3-none-any.whl的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | 79ca6e12140841cc5611f9e855e3245af88da0c69e7f0a6a5dc81ba83a83eda8 |
|
MD5 | e5aac74006f4a4cdfeb09e23023d4062 |
|
BLAKE2b-256 | 75a1f0a457e4fb66d55331240ca15b386840d0ed1da07a5d2906fe94ffd3b9d5 |