diff --git a/Framework/Utilities/COMBoost.cc b/Framework/Utilities/COMBoost.cc
index 5d8b00857b66afb73c7cbbe922b65e87c57e767a..a12b533bbc0ef756737920b750a5c00a9556a58f 100644
--- a/Framework/Utilities/COMBoost.cc
+++ b/Framework/Utilities/COMBoost.cc
@@ -10,41 +10,53 @@
  */
 
 #include <corsika/geometry/CoordinateSystem.h>
+#include <corsika/geometry/FourVector.h>
 #include <corsika/geometry/Vector.h>
 #include <corsika/units/PhysicalUnits.h>
 #include <corsika/utl/COMBoost.h>
 
 using namespace corsika::utl;
 using namespace corsika::units::si;
+using namespace corsika::geometry;
+
+//! sign function without branches
+template <typename T>
+static int sgn(T val) {
+  return (T(0) < val) - (val < T(0));
+}
 
-template <typename FourVector>
-COMBoost<FourVector>::COMBoost(const FourVector& Pprojectile,
-                               const HEPMassType massTarget)
-    : fRotation(Eigen::Matrix3d::Identity())
-    , fCS(Pprojectile.GetSpaceLikeComponents().GetCoordinateSystem()) {
-  // calculate matrix for rotating pProjectile to z-axis first
+COMBoost::COMBoost(FourVector<HEPEnergyType, Vector<hepmomentum_d>> const& Pprojectile,
+                   const HEPMassType massTarget)
+    : fCS(Pprojectile.GetSpaceLikeComponents().GetCoordinateSystem()) {
   auto const pProjectile = Pprojectile.GetSpaceLikeComponents();
   auto const pProjNorm = pProjectile.norm();
   auto const a = (pProjectile / pProjNorm).GetComponents().eVector;
+  auto const a1 = a(0), a2 = a(1);
 
-  if (a(0) == 0 && a(1) == 0) {
-    if (a(2) < 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:
+  auto const s = sgn(a(2));
+  auto const c = 1 / (1 + s * a(2));
 
-      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 A, B;
 
-    Eigen::Matrix3d vHat;
-    vHat << 0, -v(2), v(1), v(2), 0, -v(0), -v(1), v(0), 0;
+  if (s > 0) {
+    A << 1, 0, -a1,                     // comment to prevent clang-format
+        0, 1, -a2,                      // .
+        a1, a2, 1;                      // .
+    B << -a1 * a1 * c, -a1 * a2 * c, 0, // .
+        -a1 * a2 * c, -a2 * a2 * c, 0,  // .
+        0, 0, -(a1 * a1 + a2 * a2) * c; // .
 
-    fRotation += vHat + vHat * vHat / (1 + a.dot(b));
+  } else {
+    A << 1, 0, a1,                      // comment to prevent clang-format
+        0, -1, -a2,                     // .
+        a1, a2, -1;                     // .
+    B << -a1 * a1 * c, -a1 * a2 * c, 0, // .
+        +a1 * a2 * c, +a2 * a2 * c, 0,  // .
+        0, 0, (a1 * a1 + a2 * a2) * c;  // .
   }
 
+  fRotation = A + B;
+
   // calculate boost
   double const beta = pProjNorm / (Pprojectile.GetTimeLikeComponent() + massTarget);
 
@@ -54,68 +66,13 @@ COMBoost<FourVector>::COMBoost(const FourVector& Pprojectile,
   double const sinhEta = -beta * coshEta;
 
   std::cout << "COMBoost (1-beta)=" << 1 - beta << " gamma=" << coshEta << std::endl;
+  std::cout << "  det = " << fRotation.determinant() - 1 << std::endl;
 
   fBoost << coshEta, sinhEta, sinhEta, coshEta;
 
   fInverseBoost << coshEta, -sinhEta, -sinhEta, coshEta;
 }
 
-template <typename FourVector>
-FourVector COMBoost<FourVector>::toCoM(const FourVector& p) const {
-  auto pComponents = p.GetSpaceLikeComponents().GetComponents(fCS);
-  Eigen::Vector3d eVecRotated = fRotation * pComponents.eVector;
-  Eigen::Vector2d lab;
-
-  lab << (p.GetTimeLikeComponent() * (1 / 1_GeV)),
-      (eVecRotated(2) * (1 / 1_GeV).magnitude());
-
-  auto const boostedZ = fBoost * lab;
-  auto const E_CoM = boostedZ(0) * 1_GeV;
-
-  eVecRotated(2) = boostedZ(1) * (1_GeV).magnitude();
-
-  return FourVector(E_CoM, corsika::geometry::Vector<hepmomentum_d>(fCS, eVecRotated));
-}
-
-template <typename FourVector>
-FourVector COMBoost<FourVector>::fromCoM(const FourVector& p) const {
-  Eigen::Vector2d com;
-  com << (p.GetTimeLikeComponent() * (1 / 1_GeV)),
-      (p.GetSpaceLikeComponents().GetComponents().eVector(2) * (1 / 1_GeV).magnitude());
-
-  std::cout << "COMBoost::fromCoM Ecm=" << p.GetTimeLikeComponent() / 1_GeV << " GeV, "
-            << " pcm=" << p.GetSpaceLikeComponents().GetComponents().squaredNorm() / 1_GeV
-            << " GeV" << std::endl;
-
-  auto const boostedZ = fInverseBoost * com;
-  auto const E_lab = boostedZ(0) * 1_GeV;
-
-  auto pLab = p.GetSpaceLikeComponents().GetComponents();
-  pLab.eVector(2) = boostedZ(1) * (1_GeV).magnitude();
-  pLab.eVector = fRotation.transpose() * pLab.eVector;
-
-  std::cout << "COMBoost::fromCoM --> Elab=" << E_lab / 1_GeV << "GeV, "
-            << " pcm=" << pLab.squaredNorm() / 1_GeV << "GeV" << std::endl;
-
-  return FourVector(E_lab, corsika::geometry::Vector(fCS, pLab));
-}
-
 /*
   Here we instantiate all physically meaningful versions of COMBoost
  */
-
-#include <corsika/geometry/FourVector.h>
-
-namespace corsika::utl {
-
-  using corsika::geometry::FourVector;
-  using corsika::geometry::Vector;
-  using namespace corsika::units;
-
-  // for normal HEP energy/momentum units in [GeV]
-  template class COMBoost<FourVector<HEPEnergyType, Vector<hepmomentum_d>>>;
-  // template class COMBoost<FourVector<HEPEnergyType&, Vector<hepmomentum_d>&>>;
-
-  // template class COMBoost<FourVector<TimeType, Vector<length_d>>>;
-  // template class COMBoost<FourVector<TimeType&, Vector<length_d>&>>;
-} // namespace corsika::utl
diff --git a/Framework/Utilities/COMBoost.h b/Framework/Utilities/COMBoost.h
index eebc8358ad5f5891587c3ee9bda036e7c6b98784..57867769dc420c77630ebe3d446f0834999dd988 100644
--- a/Framework/Utilities/COMBoost.h
+++ b/Framework/Utilities/COMBoost.h
@@ -13,6 +13,7 @@
 #define _include_corsika_utilties_comboost_h_
 
 #include <corsika/geometry/CoordinateSystem.h>
+#include <corsika/geometry/FourVector.h>
 #include <corsika/units/PhysicalUnits.h>
 
 #include <Eigen/Dense>
@@ -24,7 +25,6 @@ namespace corsika::utl {
      referenence frames, using FourVectors.
    */
 
-  template <typename FourVector>
   class COMBoost {
     Eigen::Matrix3d fRotation;
     Eigen::Matrix2d fBoost, fInverseBoost;
@@ -32,14 +32,66 @@ namespace corsika::utl {
 
   public:
     //! construct a COMBoost given four-vector of prjectile and mass of target
-    COMBoost(const FourVector& Pprojectile,
-             const corsika::units::si::HEPEnergyType massTarget);
+    COMBoost(
+        const corsika::geometry::FourVector<
+            corsika::units::si::HEPEnergyType,
+            corsika::geometry::Vector<corsika::units::si::hepmomentum_d>>& Pprojectile,
+        const corsika::units::si::HEPEnergyType massTarget);
+
+    auto const& GetRotationMatrix() const { return fRotation; }
 
     //! transforms a 4-momentum from lab frame to the center-of-mass frame
-    FourVector toCoM(const FourVector& p) const;
+    template <typename FourVector>
+    FourVector toCoM(const FourVector& p) const {
+      using namespace corsika::units::si;
+      auto pComponents = p.GetSpaceLikeComponents().GetComponents(fCS);
+      Eigen::Vector3d eVecRotated = fRotation * pComponents.eVector;
+      Eigen::Vector2d lab;
+
+      lab << (p.GetTimeLikeComponent() * (1 / 1_GeV)),
+          (eVecRotated(2) * (1 / 1_GeV).magnitude());
+
+      auto const boostedZ = fBoost * lab;
+      auto const E_CoM = boostedZ(0) * 1_GeV;
+
+      eVecRotated(2) = boostedZ(1) * (1_GeV).magnitude();
+
+      return FourVector(E_CoM,
+                        corsika::geometry::Vector<hepmomentum_d>(fCS, eVecRotated));
+    }
 
     //! transforms a 4-momentum from the center-of-mass frame back to lab frame
-    FourVector fromCoM(const FourVector& pCoM) const;
+    template <typename FourVector>
+    FourVector fromCoM(const FourVector& p) const {
+      using namespace corsika::units::si;
+      Eigen::Vector2d com;
+      com << (p.GetTimeLikeComponent() * (1 / 1_GeV)),
+          (p.GetSpaceLikeComponents().GetComponents().eVector(2) *
+           (1 / 1_GeV).magnitude());
+
+      auto const plab = p.GetSpaceLikeComponents().GetComponents();
+      std::cout << "COMBoost::fromCoM Ecm=" << p.GetTimeLikeComponent() / 1_GeV
+                << " GeV, "
+                << " pcm = " << plab / 1_GeV << " (norm = " << plab.norm() / 1_GeV
+                << " GeV), invariant mass = " << p.GetNorm() / 1_GeV << " GeV"
+                << std::endl;
+
+      auto const boostedZ = fInverseBoost * com;
+      auto const E_lab = boostedZ(0) * 1_GeV;
+
+      auto pLab = p.GetSpaceLikeComponents().GetComponents();
+      pLab.eVector(2) = boostedZ(1) * (1_GeV).magnitude();
+      pLab.eVector = fRotation.transpose() * pLab.eVector;
+
+      FourVector f(E_lab, corsika::geometry::Vector(fCS, pLab));
+
+      std::cout << "COMBoost::fromCoM --> Elab=" << E_lab / 1_GeV << "GeV, "
+                << " pcm = " << pLab / 1_GeV << " (norm =" << pLab.norm() / 1_GeV
+                << " GeV), invariant mass = " << f.GetNorm() / 1_GeV << " GeV"
+                << std::endl;
+
+      return f;
+    }
   };
 } // namespace corsika::utl
 
diff --git a/Framework/Utilities/testCOMBoost.cc b/Framework/Utilities/testCOMBoost.cc
index 501db86435b535f14b47e6f072cbf885878e8293..159f97a7e598fe269d566fa11f53e36bab3cb24a 100644
--- a/Framework/Utilities/testCOMBoost.cc
+++ b/Framework/Utilities/testCOMBoost.cc
@@ -18,6 +18,9 @@
 #include <corsika/geometry/Vector.h>
 #include <corsika/units/PhysicalUnits.h>
 #include <corsika/utl/COMBoost.h>
+
+#include <Eigen/Dense>
+
 #include <iostream>
 
 using namespace corsika::geometry;
@@ -28,21 +31,103 @@ using corsika::units::constants::cSquared;
 
 double constexpr absMargin = 1e-6;
 
-TEST_CASE("boosts") {
-  CoordinateSystem& rootCS =
+CoordinateSystem const& rootCS =
       RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
-
-  // helper function for energy-momentum
+      
+ // helper function for energy-momentum
   // relativistic energy
-  auto energy = [](HEPMassType m, Vector<hepmomentum_d> const& p) {
+  auto const energy = [](HEPMassType m, Vector<hepmomentum_d> const& p) {
     return sqrt(m * m + p.squaredNorm());
   };
 
   // helper function for mandelstam-s
-  auto s = [](HEPEnergyType E, QuantityVector<hepmomentum_d> const& p) {
+  auto const s = [](HEPEnergyType E, QuantityVector<hepmomentum_d> const& p) {
     return E * E - p.squaredNorm();
   };
 
+
+TEST_CASE("rotation") {
+    // define projectile kinematics in lab frame
+    HEPMassType const projectileMass = 1_GeV;
+    HEPMassType const targetMass = 1.0e300_eV;
+    Vector<hepmomentum_d> pProjectileLab{rootCS, {0_GeV, 0_PeV, 1_GeV}};
+    HEPEnergyType const eProjectileLab = energy(projectileMass, pProjectileLab);
+    const FourVector PprojLab(eProjectileLab, pProjectileLab);
+    
+    Eigen::Vector3d e1, e2, e3;
+        e1 << 1, 0, 0;
+        e2 << 0, 1, 0;
+        e3 << 0, 0, 1;
+
+    // define boost to com frame
+    SECTION("pos. z-axis") {
+        COMBoost boost({eProjectileLab, {rootCS, {0_GeV, 0_GeV, 1_GeV}}}, targetMass);
+        auto const& rot = boost.GetRotationMatrix();
+        
+        CHECK((rot * e3 - e3).norm() == Approx(0).margin(absMargin));
+        CHECK((rot * e1).norm() == Approx(1));
+        CHECK((rot * e2).norm() == Approx(1));
+        CHECK((rot * e3).norm() == Approx(1));
+        CHECK(rot.determinant() == Approx(1));
+    }
+    
+    SECTION("y-axis in upper half") {
+        COMBoost boost({eProjectileLab, {rootCS, {0_GeV, 1_GeV, 1_meV}}}, targetMass);
+        auto const& rot = boost.GetRotationMatrix();
+        
+        CHECK((rot * e2 - e3).norm() == Approx(0).margin(absMargin));
+        CHECK((rot * e1).norm() == Approx(1));
+        CHECK((rot * e2).norm() == Approx(1));
+        CHECK((rot * e3).norm() == Approx(1));
+        CHECK(rot.determinant() == Approx(1));
+    }
+    
+    SECTION("x-axis in upper half") {
+        COMBoost boost({eProjectileLab, {rootCS, {1_GeV, 0_GeV, 1_meV}}}, targetMass);
+        auto const& rot = boost.GetRotationMatrix();
+                
+        CHECK((rot * e1 - e3).norm() == Approx(0).margin(absMargin));
+        CHECK((rot * e1).norm() == Approx(1));
+        CHECK((rot * e2).norm() == Approx(1));
+        CHECK((rot * e3).norm() == Approx(1));
+        CHECK(rot.determinant() == Approx(1));
+    }
+    
+    SECTION("neg. z-axis") {
+        COMBoost boost({eProjectileLab, {rootCS, {0_GeV, 0_GeV, -1_GeV}}}, targetMass);
+        auto const& rot = boost.GetRotationMatrix();
+        
+        CHECK((rot * (-e3) - e3).norm() == Approx(0).margin(absMargin));
+        CHECK((rot * e1).norm() == Approx(1));
+        CHECK((rot * e2).norm() == Approx(1));
+        CHECK((rot * e3).norm() == Approx(1));
+        CHECK(rot.determinant() == Approx(1));
+    }
+    
+    SECTION("x-axis lower half") {
+        COMBoost boost({eProjectileLab, {rootCS, {1_GeV, 0_GeV, -1_meV}}}, targetMass);
+        auto const& rot = boost.GetRotationMatrix();
+        
+        CHECK((rot * e1 - e3).norm() == Approx(0).margin(absMargin));
+        CHECK((rot * e1).norm() == Approx(1));
+        CHECK((rot * e2).norm() == Approx(1));
+        CHECK((rot * e3).norm() == Approx(1));
+        CHECK(rot.determinant() == Approx(1));
+    }
+    
+    SECTION("y-axis lower half") {
+        COMBoost boost({eProjectileLab, {rootCS, {0_GeV, 1_GeV, -1_meV}}}, targetMass);
+        auto const& rot = boost.GetRotationMatrix();
+        
+        CHECK((rot * e2 - e3).norm() == Approx(0).margin(absMargin));
+        CHECK((rot * e1).norm() == Approx(1));
+        CHECK((rot * e2).norm() == Approx(1));
+        CHECK((rot * e3).norm() == Approx(1));
+        CHECK(rot.determinant() == Approx(1));
+    }
+}
+
+TEST_CASE("boosts") {
   // define target kinematics in lab frame
   HEPMassType const targetMass = 1_GeV;
   Vector<hepmomentum_d> pTargetLab{rootCS, {0_eV, 0_eV, 0_eV}};