Users should be able to get along reading just this summary for orientation, and looking at the header files to see the details of methods and signatures, The Formulas and Definitions document provides exact definitions where needed.
This is a set of classes and methods implementing the physicist's familiar 3-vector, 4-vector, rotation and Lorentz transformation concepts.
Layer | Classes | Concepts |
---|---|---|
Support | EulerAngles AxisAngles |
Euler angles and Axis/angle structure |
PhysicsVectors 3-space |
SpaceVector UnitVector |
<3-D vectors, and vectors of unit length |
4-space | LorentzVector | 4-vectors in Minkowski space |
Transformations 3-space |
Rotation RotationX RotationY RotationZ |
Rotations of 3-vectors and simpler rotations about a coordinate axis |
4-space | LorentzTransformation LorentzBoost LorentzBoostX LorentzBoostY LorentzBoostZ |
Lorentz Transformations, pure Lorentz Boosts, and simpler boosts along a coordinate axis |
SpaceVectors may be expressed, and components obtained or set,
in cartesian, polar, or
cylindrical coordinates.
Methods include dot and cross products,
unit vectors and magnitudes,
angles between vectors, and rotations and boosts.
There are also functions of particular use to HEP, like pseudo-rapidity,
projections, and transverse part of a
SpaceVector,
and kinetic methods on 4-vectors
such as invariantMass()
of pairs or containers of particles.
This package may be obtained from:
fsgi02.fnal.gov
)
in directories rooted at
To use classes, for example SpaceVector and Rotation, include the header file in the following way:
#include "PhysicsVectors/SpaceVector.h" #include "PhysicsVectors/Rotation.h"For convenience the package provides a single overall header which itself draws in all class definitions:
#include "PhysicsVectors/PhysicsVectors.h"
For each class we define in this package, the methods for construction and for setting or obtaining data obey certain conventions. These use the idea of the components of an object.
Float8 r, theta, phi; SpaceVector v ( r, theta, DEGREES, phi, DEGREES ); // Components can be expressed as r, theta, phi -- Float8 alpha = v.theta(); v.theta() = .5; // Changes phi to .5 radians, keeping r, theta fixed
set()
which sets all components at once.
For each form of components there is
a signature of set()
matching the signature of
that form of constructor.
v.set( 5, 60, DEGREES, 12 ); // Components can be expressed as r, phi, z. // v, which was constructed earlier, is set to these // values of cylindrical coordinates instead.
==
and ==
have
obvious meanings, in terms of exact equality.
However, when working with actual vectors, it is useful to have a looser
criterion for practical equality.
And boolean methods such as isOrthogonal()
are more certainly useful if they allow for some tolerance.
The methods in the PhysicsVectors package
support checking for
equality within a given relative tolerance using these rules:
==
comparision is supplemented by
an isNear()
method, which takes an object of the same class and returns a bool
result (true
or false
). For example,
SpaceVector v1, v2; if ( v1.isNear(v2) ) { /* do whatever */ }
tolerance
.
Normally this would be omitted, in which case it defaults to a universal
tolerance
which will be 100 times the machine epsilon.
Components | Meaning |
---|---|
x, y, z | Cartesian Coordinates |
r, theta, phi | (Spherical) polar coordinates |
rho, phi, z | Cylindrical coordinates |
Scalar x, y, z, r, theta, phi, rho; SpaceVector v1( x, y, z ); SpaceVector v2( r, theta, RADIANS, phi, RADIANS ); SpaceVector v3( rho, phi, RADIANS, z ); Scalar c1, c2, c3, r, pa, aa, rho; c1 = v.x(); c2 = v.y(); c3 = v.z(); c1 = v.r(); pa = v.theta(); aa = v.phi(); c1 = v.rho(); aa = v.phi(); c3 = v.z(); // only rho() is new v.x() = c1; v.y() = c2; v.z() = c3; v.r() = r; v.theta() = pa; v.phi() = aa; v.rho() = rho;Notice the funny-looking keyword
RADIANS
in the example.
This is an
argument which
serves to distinguish one signature of constructor from another.
Instead of RADIANS
you can substitute
DEGREES
or
(when supplying theta) ETA
.
UnitVector is a class that inherits from SpaceVector, but some methods of SpaceVector which don't make sense for unit vectors are made private to flag their use as an error at compile time. UnitVectors may be constructed from a non-zero SpaceVector, or by supplying the polar (theta, phi).
Scalar theta, phi; UnitVector u1( theta DEGREES, phi, RADIANS );
v1 = v2 + c*v3; v1 = v2 - v3*c; v1 = v2 - v3/c; v1 *= c; v1 += v2; v1 -= v2;UnitVectors do not form a vector space; they may be multiplied by a Scalar or added tegether, but the result is an ordinary SpaceVector.
There are methods representing the usual binary 3-vector operations: Dot and cross products. There are also logical tests for whether vectors are parallel or orthogonal.
Scalar v1.dot(v2) SpaceVector v1.cross(v2) Scalar v1.diff2(v2) // squared difference bool v1.isNear(v2) bool v1.parallel(v2) bool v1.orthogonal(v2)The boolean methods test for near-alignment with a relative tolerance rather than perfect alignment.
The SpaceVector class provides a variety of methods returning numerical properties of a single vector:
Scalar v.mag(), Scalar v.mag2() Scalar v.beta(), Scalar v.gamma() SpaceVector v.unit()There are also methods returning properties of a vector, or performing operations on two vectors, with respect to some reference direction. Typically the physicist wants these properties relative to the Z direction. We call these ``z-implied'' methods: The reference direction is usually omitted, and the Z axis is assumed. This example shows a signature using a reference direction only in the most commonly used case: The angle between a vecotr and a direction.
Scalar v.perp() Scalar v.perp2() Scalar v.angle() v.angle(dir) Scalar v.cosTheta() Scalar v.cos2Theta() Scalar v.eta() Scalar v.rapidity() SpaceVector v.project() SpaceVector v.perpPart() Scalar v.azimAngle(v2) Scalar v.polarAngle(v2)See the Formulas and Definitions document for precise meanings of these methods, particularly rapidity and angular decomposition.
SpaceVector v.rotated.(Scalar phi, Scalar theta, Scalar psi); SpaceVector v.rotated.(UnitVector dir, Scalar delta); SpaceVector v.rotatedX.(Scalar delta); SpaceVector v.rotatedY.(Scalar delta); SpaceVector v.rotatedZ.(Scalar delta); v.applyRotation.(Scalar phi, Scalar theta, Scalar psi); v.applyRotation.(UnitVector dir, Scalar delta); v.applyRotationX.(Scalar delta); v.applyRotationY.(Scalar delta); v.applyRotationZ.(Scalar delta);
Components | Meaning |
---|---|
x, y, z, t t, x, y, z |
Cartesian Coordinates (time component must be a Tcomponent and may be placed first or last) |
v, t t, v |
SpaceVector and time component (supplied as a Tcomponent or as a Scalar |
t | Time component only (for particle at rest) |
When constructing or setting a LorentzVector from four cartesian components, one could be confused as to whether to supply (x, y, z, t) or (t, x, y, z). To eliminate possible accidents, the signature for such methods takes three Scalars x, y, and z, and an instance of Tcomponent for t.
LorentzVector w ( 1, 3, 5, Tcomponent(40) ); // Preferred LorentzVector w ( Tcomponent(40), 1, 3, 5 ); // Also accepted LorentzVector w ( 40, 1, 3, 5 ); // Nope. No such signature.Constructors for are also provided taking a SpaceVector and a time component, or just a time component for a particle at rest. Access is supported for these forms of components.
LorentzVector w(SpaceVector v, Tcomponent t); LorentzVector w(SpaceVector v, Scalar t); // OK LorentzVector w(Tcomponent t); // (0,0,0,t) LorentzVector w(Scalar t); // (0,0,0,t) // OK Scalar x = w.x(); Scalar x = w.y(); Scalar z = w.z(); Scalar t = w.t(); SpaceVector v = w.v(); v = w.getV(); w.set(Tcomponent t, Scalar x, Scalar y, Scalar z); w.set(Scalar x, Scalar y, Scalar z, Tcomponent t); w.x() = x; w.y() = y; w.z() = z; w.t() = t;As shown, in cases where no ambiguity would result, a Scalar value of t may be used in place of the Tcomponent.
w1 = w2 + c*w3; w1 = w2 - w3*c; w1 = w2 - w3/c; w1 *= c; w1 += w2; w1 -= w2; w2 = -w1;The dot product is supported; by default, a (- - - +) metric applies. That is, if w is timelike, w.dot(w) will be positive.
LorentzVector w, w1; Scalar x = w.dot(w1); /* Metric-dependant */ Scalar x = w.diff2(w1); /* Metric-dependant */ Scalar x = w.delta2Euclidean(w1); bool b = w.isNear(w1); bool b = w.isNearCM(w1); bool b = w.isParallel(w1);Notice that
isNearCM()
, a Lorentz-invariant test for
near-equality in the center-of-mass
frame--applicable only to timelike LorentzVectors--is provided along with the
Euclidean-norm method isNear()
.
The mathematical meanings of near-equivalence and isParallel
are
listed in the Formulas and Definitions document.
There are three special boolean methods isTimelike()
,
isLightlike()
, and isSpacelike()
,
and {\tt isTimelike()},
which test whether the squared norm w.dot(w)
is positive, zero, or negative.
The isLightlike()
method implies a check for equality,
and therefore uses a tolerance as described in the section about
isNear().
Several other simple property methods are provided as well:
LorentzVector w; bool b = w.isSpacelike(); b = w.isLightlike(); b = w.isTimelike(); Scalar x = w.mag2(); /* w.dot(w) -- Metric-dependant */ Scalar w.plus(); Scalar w.minus(); /* t + z and t - z */ Scalar w. euclideanNorm2(); Scalar w.euclideanNorm()
These methods all return results independent of the choice of metric.
There are kinematic functions relating to the boost it would take to bring a particle at rest into having some specified LorentzVector as its 4-momentum. These return the relativistic beta, gamma, and boostVector, the SpaceVector which when used as a boost would make this transformation.
There are also methods to extract the rest mass, and the invariant mass of a pair or a list of \LV s.
Pseudorapidity and rapidity are computed with respect to some reference direction, which defaults to the Z direction; see the Formulas and Definitions document for precise meanings.
Scalar restMass2() Scalar restMass() LorentzVector rest4Vector() /* ( 0, 0, 0, restMass() ) */ SpaceVector boostVector() Scalar eta() Scalar rapidity() Scalar w1.invariantMass(w2) Scalar w1.invariantMass2(w2) SpaceVector w1.findBoostToCM(w2) /* boost to joint CM frame */These important concepts are also provided for standard containers of LorentzVectors:
list<LorentzVector> w_list; Float8 m = w_list.invariantMass();
The class has methods that rotate the 4-vector itself
(v.applyRotation()
and v.applyBoost()
)
as well as methods that
return a new 4-vector leaving the original unchanged
(v2 = v.rotated()
and
v2 = v.boosted()
.
Rotation about one of the coordinate axes, or boosts along a coordinate axis, are special cases; methods are provided to take advantage of the simpler form of these operations.
LorentzVector w, w2; UnitVector dir; w2 = w.boosted(UnitVector dir, Scalar beta); w2 = w.boosted(SpaceVector v); w2 = w.boostedX(beta); w2 = w.boostedY(beta); w2 = w.boostedZ(beta); Scalar phi; w2 = w.rotated(UnitVector dir, phi); w2 = w.rotatedX(phi); w2 = w.rotatedY(phi); w2 = w.rotatedZ(phi);
A Rotation can be represented by a real, orthogonal matrix with determinant +1. Combining two Rotations is represented by multiplying their matrices.
The value of a Rotation may be obtained in any of those forms, and also in the form of individual components of the matrix representing the Rotation.
Components | Meaning |
---|---|
phi, theta, psi | Individual Euler Angles |
eulerAngles | A struct holding the three Euler Angles |
axis, delta | axis and angle of rotation about that axis |
axisAngle | A struct holding a UnitVector axis and angle of rotation |
colX, colY, colZ | three orthogonal UnitVectors |
As is the case for vectors, methods are supplied to set one "component" of a Rotation keeping the remaing ones fixed. But here by "component" we mean one argument to a possible constructor of Rotation, keeping the other arguments in that constructor fixed.
The default constructor sets the \Rotation\ to the identity rotation. The package also provides a static constant Rotation::IDENTITY.
Rotation r0 (); ASSERT (r0 == Rotation::IDENTITY); Rotation r1 ( SpaceVector(1,2,3), .02 ); // axis and delta Rotation r2 ( PI/4, PI/3, PI/6 ); // Euler angles phi, theta, psi EulerAngles ex (phi, theta, psi); Rotation r4 (ex); UnitVector v = r1.axis(); // unit vector Scalar angle = r1.delta(); // Angle of rotation about an axis Scalar psi = r1.psi(); // Euler psi (==angle psi around axis) Scalar theta = r1.theta(); // Will always be <= 90 degrees Scalar phi = r1.phi(); r.setDelta(Scalar delta); // change delta, keep axis fixed r.setPsi(Scalar psi); // change psi, keep phi, theta fixedIn addition to the forms of components, you can obtain, but cannot individually change, the values of a row or a element of the matrix representation of a Rotation.
Rotation r1; Scalar elem = r1.xx(); elem = r1.tz(); UnitVector u1 = r1.rowY(); u1 = r1.rowT();
Inversion of a Rotation, represented by inverting the orthogonal matrix representation, is provided by the inverse() method. Note that r1.inverse() produces a result of the inverse of r1; it does not change r1 itself. To invert a Rotation in place, use r1.invert().
Equality (and dictionary ordering) comparison is supported. The isNear mechanism is also supported among rotations; see the Formulas and Definitions document for a precise definition.
Rotation r1, r2, r3; r3 = r2 * r1; r2 = r1.inverse(); r3 = r2 * r1; ASSERT ( r3.isNear(Rotation::IDENTITY));
Rotation r1; SpaceVector v1, v2; v2 = r1(v1);The application of a Rotation to a SpaceVector may be viewed as left multiplying the vector representation by the matrix representing that rotation.
Similarly, a Rotation applied to a UnitVector produces a UnitVector, and a Rotation applied to a LorentzVector produces a LorentzVector. And a Rotation may be applied an EBvector, rotating each component to yield a new EBvector.
The * multiplication notation is not used. Multiplication of a rotation by by a vector on its left is not permitted.
A Rotation may be applied in bulk to each element of a container of SpaceVectors, UnitVectors, LorentzVectors, or EBvectors. A new container is returned, each of whose elements is the corresponding vector in the original, rotated by the specified Rotation.
The container may be any of the standard container types.
Rotation r1; listv_list; list vprime_list = r1(v_list);
Aside from the simpler constructors (and correspondingly simpler {\tt set()} methods), all methods and signatures available for Rotation are available RotationX, RotationY, and RotationZ. Of course, the implementations will take advantage of the simpler forms, to do much less work.
RotationX rx1 (.25); // delta is specified in radians, the axis is X SpaceVector v1, v2; v2 = rx1(v1);These specialized rotation objects are defined in Rotation.h. Multiplying two rotations--combining two specialized rotations of different types will give a general \Rotation.
A few words of orientation: We always work with c = 1, and never consider "tachyonic" transformations. And in defining Lorentz Transformations we have use the same "active" viewpoint as was used in defining rotations: Space (or in this case, spacetime) is "rotated" by some amount, rather than saying that the new coordinate system is "rotated" by some amount relative to the old.
A pure boost by beta in the X direction can be represented by a matrix
gamma 0 0 beta*gamma 0 1 0 0 0 0 1 0 beta*gamma 0 0 gamma
However, many (probably most) HEP applications use pure boosts, and not mixed combinations of rotations and boosts. Since the operations with a LorentzTransformation known to be a pure boost can be accomplished with less work than for the general case, this package supports a class LorentzBoost representing a pure boost in some direction.
LorentzBoost is on the same footing as Rotation: Each represents three of the six degrees of freedom of a general LorentzTransformation. Other than constructors and component access, the same set of methods apply to LorentzBoost as to the more general LorentzTransformation. In particular, LorentzBoosts, Rotations, and LorentzTransformations may be multiplied by one another, with the obvious form of results: Boost times boost remains a pure boost, rotation times rotation remains a pure rotation, and all other combinations result in a general LorentzTransformation.
The package also provides additional classes, representing pure boosts along the X, Y, and Z axes. {\tt LorentzBoostX}, {\tt LorentzBoostY}, {\tt LorentzBoostZ} have internal representations which are more compact that that for a general \LB, and the forms of their constructors are simpler.
Again, aside from the simpler constructors and access methods, all methods and signatures available for LorentzBoost and LorentzTransformation are available for these classes, but implementations will take advantage of the simpler forms.
All these boost objects are defined in LorentzTransformation.h.
Components | Meaning |
---|---|
direction, beta | Boost by beta (|beta| < 1) along direction |
boostVector | Pure boost velocity (taking c=1) |
UnitVector dir; SpaceVector bv; LorentzBoost t1 ( dir, -.04); LorentzBoost t2 ( bv ); // bv.mag2() must be < 1The default constructor sets the LorentzBoost to the identity transformation, which is equivalent to using a boost vector of zero.
A LorentzTransformation can be constructed as a pure rotation or a pure boost, or by combining the two (in either order). It can also be constructed by supplying four LorentzVectors obeying appropriate conditions.
Components | Meaning |
---|---|
boostVector, rotation | Apply rotation, then boost the result |
boostVector, rotation | Apply boost, then rotate the result |
col1, col2, col3, col4 | Four orthosymplectic Lorentzvectors |
Rotation r1; SpaceVector bv; LorentzTransformation t3 ( r1 ); LorentzTransformation t4 ( bv ); LorentzTransformation t5 ( bv, r1 ); // t5 = t4*t3 LorentzTransformation t6 ( bv, r1 ); // t6 = t3*t4 LorentzVector lam1, lam2, lam3, lam4; LorentzTransformation t7 (lam1, lam2, lam3, lam4);You may, as for
t4
in the example,
construct a general LorentzTransformation (instead of a LorentzBoost)
from just its boost vector. Since LorentzBoost supports all the functionality
that LorentzTransformation does, the only case where this is reasonable is if
you anticipate the need
to change the value of t4
to a general transformation later.
w1.dot(w2) = w1.dot(w3) = w1.dot(w4) = 0 w2.dot(w3) = w2.dot(w4) = 0 w3.dot(w4) = 0 w1.dot(w1) = w2.dot(w2) = w3.dot(w3) = -1 w4.dot(w4) = 1
There are methods to get and/or modify components of a LorentzBoost:
LorentzBoost lb; SpaceVector v; UnitVector u; Float8 bet; bet = lb.beta(); lb.beta() = bet; u = lb.direction(); lb.direction() = u; v = lb.boostVector(); lb.boostVector() = v;In addition, all the access methods available for a general LorentzTransformation are available for LorentzBoost (and for Rotation as well), although most of these are trivial in one respect or another.
Every LorentzTransformation can be expressed as a pure boost along some direction, followed by a pure rotation (or by a rotation followed by a boost) and methods are provided to decompose the transformation in this way.
Rotation r1; LorentzTransformation t1; LorentzBoost b1; t1.decompose(&r1, &b1); // T = R*B t1.decompose(&b1, &r1); // T = B*RFinally, one can get (but not change) the rows, columns, or individual components of the representation matrix for a LorentzTransformation:
LorentzTransformation t1; Scalar u; LorentzVector v; v = t1.row1(); v = t1.row2(); v = t1.row3(); v = t1.row4(); v = t1.col1(); v = t1.col2(); v = t1.col3(); v = t1.col4(); u = t1.xx(); u = t1.yz(); u = t1.tz(); u = t1.tt();
Equality (and dictionary ordering) comparison is supported. The isNear() mechanism is also supported among LorentzTransformations; see the Formulas and Definitions document for a precise definition of when two Lorentz transformations are considered to be near one another.
Inversion of a LorentzTransformation, represented by inverting the matrix representation, is provided by the inverse() method. t1.inverse() returns a result of the inverse of t1; it does not change t1 itself. t1.invert() inverts t1 in place.
LorentzTransformation t1, t2, t3; t3 = t2 * t1; t2 = t1.inverse(); t3 = t2 * t1; ASSERT ( t3.isNear(LorentzTransformation::IDENTITY));
LorentzTransformation t1; LorentzVector w1, w2; w2 = t1(w1);The application of a LorentzTransformation to a LorentzVector may be viewed as left multiplying the vector representation by the matrix representing that transformation.
An LorentzTransformation may also be applied to an EBvector. This is mathematically defined as applying the transformation to the field tensor F and reading off the new E and B from that transformed tensor. This of course mixes E and B.
LorentzTransfromation t1; EBvector eb1, eb2; eb2 = t1(eb1);
A LorentzTransformation may be applied in bulk to each element of a container of LorentzVectors or EBvectors. A new container is returned, each of whose elements is the corresponding vector in the original, transformed by the specified Lorentz transformation.
LorentzTransformation t1; listw_list; list wprime_list; wprime_list = t1(w_list);
The container may be any of the standard container types, or for that matter any container having the same iterator semantics.