From 007fbbb3ce051124da2e946f445a5b80c24cfff6 Mon Sep 17 00:00:00 2001
From: Maximilian Reininghaus <maximilian.reininghaus@tu-dortmund.de>
Date: Sat, 29 Dec 2018 00:20:17 +0100
Subject: [PATCH] rotation in COMBoost for (0,0,-z) case

---
 Framework/Utilities/COMBoost.cc     | 18 ++++---
 Framework/Utilities/testCOMBoost.cc | 79 +++++++++++++++--------------
 2 files changed, 54 insertions(+), 43 deletions(-)

diff --git a/Framework/Utilities/COMBoost.cc b/Framework/Utilities/COMBoost.cc
index 4e8a9688..42d5995d 100644
--- a/Framework/Utilities/COMBoost.cc
+++ b/Framework/Utilities/COMBoost.cc
@@ -18,17 +18,23 @@ COMBoost::COMBoost(EnergyType eProjectile, COMBoost::MomentumVector const& pProj
     : fRotation(Eigen::Matrix3d::Identity())
     , fCS(pProjectile.GetCoordinateSystem()) {
   // calculate matrix for rotating pProjectile to z-axis first
-  // TODO: handle the case when pProjectile ~ (0, 0, -1)
   auto const pProjNorm = pProjectile.norm();
   auto const a = (pProjectile / pProjNorm).GetComponents().eVector;
 
-  Eigen::Vector3d const b{0, 0, 1};
-  auto const v = a.cross(b);
+  if (a(0) == 0 && a(1) == 0) {
+    // if pProjectile ~ (0, 0, -1), the standard formula for the rotation matrix breaks
+    // down but we can easily define a suitable rotation manually. We just need some SO(3)
+    // matrix that reverses the z-axis and I like this one:
+    fRotation << 1, 0, 0, 0, -1, 0, 0, 0, -1;
+  } else {
+    Eigen::Vector3d const b{0, 0, 1};
+    auto const v = a.cross(b);
 
-  Eigen::Matrix3d vHat;
-  vHat << 0, -v(2), v(1), v(2), 0, -v(0), -v(1), v(0), 0;
+    Eigen::Matrix3d vHat;
+    vHat << 0, -v(2), v(1), v(2), 0, -v(0), -v(1), v(0), 0;
 
-  fRotation += vHat + vHat * vHat / (1 + a.dot(b));
+    fRotation += vHat + vHat * vHat / (1 + a.dot(b));
+  }
 
   // calculate boost
   double const x = pProjNorm * units::constants::c /
diff --git a/Framework/Utilities/testCOMBoost.cc b/Framework/Utilities/testCOMBoost.cc
index faac8c6d..3af25856 100644
--- a/Framework/Utilities/testCOMBoost.cc
+++ b/Framework/Utilities/testCOMBoost.cc
@@ -41,41 +41,46 @@ TEST_CASE("boosts") {
 
   // define projectile kinematics in lab frame
   MassType const projectileMass = 1._GeV / cSquared;
-  Vector<momentum_d> pProjectileLab{rootCS, {0_GeV / c, 1_PeV / c, 0_GeV / c}};
-  EnergyType const eProjectileLab = energy(projectileMass, pProjectileLab);
-
-  // define target kinematics in lab frame
-  MassType const targetMass = 1_GeV / cSquared;
-  Vector<momentum_d> pTargetLab{rootCS, {0_Ns, 0_Ns, 0_Ns}};
-  EnergyType const eTargetLab = energy(targetMass, pTargetLab);
-
-  // define boost to com frame
-  COMBoost boost(eProjectileLab, pProjectileLab, targetMass);
-
-  // boost projecticle
-  auto const [eProjectileCoM, pProjectileCoM] =
-      boost.toCoM(eProjectileLab, pProjectileLab);
-
-  // boost target
-  auto const [eTargetCoM, pTargetCoM] = boost.toCoM(eTargetLab, pTargetLab);
-
-  // sum of momenta in CoM, should be 0
-  auto const sumPCoM = pProjectileCoM + pTargetCoM;
-  CHECK(sumPCoM[2] / (1_GeV / c) == Approx(0).margin(absMargin));
-
-  // mandelstam-s should be invariant under transformation
-  CHECK(s(eProjectileLab + eTargetLab,
-          pProjectileLab.GetComponents() + pTargetLab.GetComponents()) /
-            (1_GeV / c) / (1_GeV / c) ==
-        Approx(s(eProjectileCoM + eTargetCoM, pProjectileCoM + pTargetCoM) / (1_GeV / c) /
-               (1_GeV / c)));
-
-  // boost back...
-  auto const [eProjectileBack, pProjectileBack] =
-      boost.fromCoM(eProjectileCoM, pProjectileCoM);
-
-  // ...should yield original values before the boosts
-  CHECK(eProjectileBack / eProjectileLab == Approx(1));
-  CHECK((pProjectileBack - pProjectileLab).norm() / pProjectileLab.norm() ==
-        Approx(0).margin(absMargin));
+  std::vector<Vector<momentum_d>> labProjectiles{
+      {rootCS, {0_GeV / c, 1_PeV / c, 0_GeV / c}},   // standard case
+      {rootCS, {0_GeV / c, 0_GeV / c, -1_GeV / c}}}; // "special" case
+
+  for (auto const& pProjectileLab : labProjectiles) {
+    EnergyType const eProjectileLab = energy(projectileMass, pProjectileLab);
+
+    // define target kinematics in lab frame
+    MassType const targetMass = 1_GeV / cSquared;
+    Vector<momentum_d> pTargetLab{rootCS, {0_Ns, 0_Ns, 0_Ns}};
+    EnergyType const eTargetLab = energy(targetMass, pTargetLab);
+
+    // define boost to com frame
+    COMBoost boost(eProjectileLab, pProjectileLab, targetMass);
+
+    // boost projecticle
+    auto const [eProjectileCoM, pProjectileCoM] =
+        boost.toCoM(eProjectileLab, pProjectileLab);
+
+    // boost target
+    auto const [eTargetCoM, pTargetCoM] = boost.toCoM(eTargetLab, pTargetLab);
+
+    // sum of momenta in CoM, should be 0
+    auto const sumPCoM = pProjectileCoM + pTargetCoM;
+    CHECK(sumPCoM[2] / (1_GeV / c) == Approx(0).margin(absMargin));
+
+    // mandelstam-s should be invariant under transformation
+    CHECK(s(eProjectileLab + eTargetLab,
+            pProjectileLab.GetComponents() + pTargetLab.GetComponents()) /
+              (1_GeV / c) / (1_GeV / c) ==
+          Approx(s(eProjectileCoM + eTargetCoM, pProjectileCoM + pTargetCoM) /
+                 (1_GeV / c) / (1_GeV / c)));
+
+    // boost back...
+    auto const [eProjectileBack, pProjectileBack] =
+        boost.fromCoM(eProjectileCoM, pProjectileCoM);
+
+    // ...should yield original values before the boosts
+    CHECK(eProjectileBack / eProjectileLab == Approx(1));
+    CHECK((pProjectileBack - pProjectileLab).norm() / pProjectileLab.norm() ==
+          Approx(0).margin(absMargin));
+  }
 }
-- 
GitLab