From 7ba0023b3b7698a2d12f3531a297e2b364ca22e1 Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Wed, 16 Jan 2019 09:15:19 +0100
Subject: [PATCH] debuggin crash in COM at high energies

---
 Documentation/Examples/cascade_example.cc |  2 +-
 Framework/Geometry/FourVector.h           | 16 ++---
 Framework/Utilities/COMBoost.cc           | 75 ++++++++++++++++-------
 Framework/Utilities/COMBoost.h            | 24 ++++----
 Framework/Utilities/testCOMBoost.cc       | 29 +++++----
 Processes/Sibyll/Interaction.h            | 60 ++++++++++--------
 6 files changed, 128 insertions(+), 78 deletions(-)

diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc
index e978949c..e49a41e3 100644
--- a/Documentation/Examples/cascade_example.cc
+++ b/Documentation/Examples/cascade_example.cc
@@ -245,7 +245,7 @@ int main() {
   // setup particle stack, and add primary particle
   setup::Stack stack;
   stack.Clear();
-  const HEPEnergyType E0 = 100_TeV;
+  const HEPEnergyType E0 = 1000_TeV;
   double theta = 0.;
   double phi = 0.;
   {
diff --git a/Framework/Geometry/FourVector.h b/Framework/Geometry/FourVector.h
index bb848758..93f29dcf 100644
--- a/Framework/Geometry/FourVector.h
+++ b/Framework/Geometry/FourVector.h
@@ -33,7 +33,7 @@ namespace corsika::geometry {
   public:
     using SpaceType = typename std::decay<SpaceVecType>::type::Quantity;
 
-    /// check the types and the physical units here:
+    //! check the types and the physical units here:
     static_assert(
         std::is_same<typename std::decay<TimeType>::type, SpaceType>::value ||
             std::is_same<typename std::decay<TimeType>::type,
@@ -47,7 +47,9 @@ namespace corsika::geometry {
         : fTimeLike(eT)
         , fSpaceLike(eS) {}
 
-    TimeType GetTime() { return fTimeLike; }
+    TimeType GetTimeLikeComponent() const { return fTimeLike; }
+    SpaceVecType& GetSpaceLikeComponents() { return fSpaceLike; }
+    const SpaceVecType& GetSpaceLikeComponents() const { return fSpaceLike; }
 
     auto GetNormSqr() const { return GetTimeSquared() - fSpaceLike.squaredNorm(); }
 
@@ -55,15 +57,15 @@ namespace corsika::geometry {
 
     bool IsTimelike() const {
       return GetTimeSquared() < fSpaceLike.squaredNorm();
-    } /// Norm2 < 0
+    } //! Norm2 < 0
 
     bool IsSpacelike() const {
       return GetTimeSquared() > fSpaceLike.squaredNorm();
-    } /// Norm2 > 0
+    } //! Norm2 > 0
 
     bool IsPhotonlike() const {
       return GetTimeSquared() == fSpaceLike.squaredNorm();
-    } /// Norm2 == 0
+    } //! Norm2 == 0
 
     FourVector& operator+=(const FourVector& b) {
       fTimeLike += b.fTimeLike;
@@ -129,11 +131,11 @@ namespace corsika::geometry {
     }
 
   protected:
-    /// the data members
+    //! the data members
     TimeType fTimeLike;
     SpaceVecType fSpaceLike;
 
-    /// the friends: math operators
+    //! the friends: math operators
     template <typename T, typename U>
     friend FourVector<typename std::decay<T>::type, typename std::decay<U>::type>
     operator+(const FourVector<T, U>&, const FourVector<T, U>&);
diff --git a/Framework/Utilities/COMBoost.cc b/Framework/Utilities/COMBoost.cc
index 1bf8f839..3e9aafb8 100644
--- a/Framework/Utilities/COMBoost.cc
+++ b/Framework/Utilities/COMBoost.cc
@@ -8,16 +8,20 @@
  * the license.
  */
 
+#include <corsika/geometry/CoordinateSystem.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;
 
-COMBoost::COMBoost(HEPEnergyType eProjectile, COMBoost::MomentumVector const& pProjectile,
-                   HEPMassType mTarget)
+template <typename FourVector>
+COMBoost<FourVector>::COMBoost(const FourVector& Pprojectile, const FourVector& Ptarget)
     : fRotation(Eigen::Matrix3d::Identity())
-    , fCS(pProjectile.GetCoordinateSystem()) {
+    , fCS(Pprojectile.GetSpaceLikeComponents().GetCoordinateSystem()) {
   // calculate matrix for rotating pProjectile to z-axis first
+  auto const pProjectile = Pprojectile.GetSpaceLikeComponents();
   auto const pProjNorm = pProjectile.norm();
   auto const a = (pProjectile / pProjNorm).GetComponents().eVector;
 
@@ -37,47 +41,76 @@ COMBoost::COMBoost(HEPEnergyType eProjectile, COMBoost::MomentumVector const& pP
   }
 
   // calculate boost
-  double const x = pProjNorm / (eProjectile + mTarget);
+  double const beta =
+      pProjNorm / (Pprojectile.GetTimeLikeComponent() + Ptarget.GetTimeLikeComponent());
 
-  /* Accurracy matters here, x = 1 - epsilon for ultra-relativistic boosts */
-  double const coshEta = 1 / std::sqrt((1 + x) * (1 - x));
-  //~ double const coshEta = 1 / std::sqrt((1-x*x));
-  double const sinhEta = -x * coshEta;
+  /* Accurracy matters here, beta = 1 - epsilon for ultra-relativistic boosts */
+  double const coshEta = 1 / std::sqrt((1 + beta) * (1 - beta));
+  //~ double const coshEta = 1 / std::sqrt((1-beta*beta));
+  double const sinhEta = -beta * coshEta;
 
+  std::cout << "COMBoost (1-beta)=" << 1-beta << " gamma=" << coshEta << std::endl;
+  
   fBoost << coshEta, sinhEta, sinhEta, coshEta;
 
   fInverseBoost << coshEta, -sinhEta, -sinhEta, coshEta;
 }
 
-std::tuple<HEPEnergyType, corsika::geometry::QuantityVector<hepmomentum_d>>
-COMBoost::toCoM(HEPEnergyType E, COMBoost::MomentumVector p) const {
-  corsika::geometry::QuantityVector<hepmomentum_d> pComponents = p.GetComponents(fCS);
+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 << (E * (1 / 1_GeV)), (eVecRotated(2) * (1 / 1_GeV).magnitude());
+  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 std::make_tuple(E_CoM,
-                         corsika::geometry::QuantityVector<hepmomentum_d>{eVecRotated});
+  return FourVector(E_CoM, corsika::geometry::Vector<hepmomentum_d>(fCS, eVecRotated));
 }
 
-std::tuple<HEPEnergyType, COMBoost::MomentumVector> COMBoost::fromCoM(
-    HEPEnergyType E,
-    corsika::geometry::QuantityVector<units::si::hepmomentum_d> pCoM) const {
+template <typename FourVector>
+FourVector COMBoost<FourVector>::fromCoM(const FourVector& p) const {
   Eigen::Vector2d com;
-  com << (E * (1 / 1_GeV)), (pCoM.eVector(2) * (1 / 1_GeV).magnitude());
+  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() / 1_GeV << "GeV" << std::endl;
+  
   auto const boostedZ = fInverseBoost * com;
-  auto const E_CoM = boostedZ(0) * 1_GeV;
+  auto const E_lab = boostedZ(0) * 1_GeV;
 
-  auto pLab = pCoM;
+  auto pLab = p.GetSpaceLikeComponents().GetComponents();
   pLab.eVector(2) = boostedZ(1) * (1_GeV).magnitude();
   pLab.eVector = fRotation.transpose() * pLab.eVector;
 
-  return std::make_tuple(E_CoM, MomentumVector(fCS, pLab));
+  std::cout << "COMBoost::fromCoM --> Elab=" << E_lab / 1_GeV << "GeV, "
+	    << " pcm=" << pLab / 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 fa57d8f3..08dfe75a 100644
--- a/Framework/Utilities/COMBoost.h
+++ b/Framework/Utilities/COMBoost.h
@@ -12,33 +12,31 @@
 #define _include_corsika_utilties_comboost_h_
 
 #include <corsika/geometry/CoordinateSystem.h>
-#include <corsika/geometry/QuantityVector.h>
-#include <corsika/geometry/Vector.h>
-#include <corsika/units/PhysicalUnits.h>
+
 #include <Eigen/Dense>
-#include <tuple>
 
 namespace corsika::utl {
+
+  /**
+     This utility class handles Lorentz boost between different
+     referenence frames, using FourVectors.
+   */
+
+  template <typename FourVector>
   class COMBoost {
     Eigen::Matrix3d fRotation;
     Eigen::Matrix2d fBoost, fInverseBoost;
     corsika::geometry::CoordinateSystem const& fCS;
-    using MomentumVector = corsika::geometry::Vector<units::si::hepmomentum_d>;
 
   public:
     //! construct a COMBoost given energy and momentum of projectile and mass of target
-    COMBoost(units::si::HEPEnergyType eProjectile, MomentumVector const& pProjectile,
-             units::si::HEPMassType mTarget);
+    COMBoost(const FourVector& Pprojectile, const FourVector& Ptarget);
 
     //! transforms a 4-momentum from lab frame to the center-of-mass frame
-    std::tuple<units::si::HEPEnergyType,
-               geometry::QuantityVector<units::si::hepmomentum_d>>
-    toCoM(units::si::HEPEnergyType E, MomentumVector p) const;
+    FourVector toCoM(const FourVector& p) const;
 
     //! transforms a 4-momentum from the center-of-mass frame back to lab frame
-    std::tuple<units::si::HEPEnergyType, MomentumVector> fromCoM(
-        units::si::HEPEnergyType E,
-        geometry::QuantityVector<units::si::hepmomentum_d> pCoM) const;
+    FourVector fromCoM(const FourVector& pCoM) const;
   };
 } // namespace corsika::utl
 
diff --git a/Framework/Utilities/testCOMBoost.cc b/Framework/Utilities/testCOMBoost.cc
index 6b3b9505..bbc6c295 100644
--- a/Framework/Utilities/testCOMBoost.cc
+++ b/Framework/Utilities/testCOMBoost.cc
@@ -12,7 +12,9 @@
                           // cpp file
 #include <catch2/catch.hpp>
 
+#include <corsika/geometry/FourVector.h>
 #include <corsika/geometry/RootCoordinateSystem.h>
+#include <corsika/geometry/Vector.h>
 #include <corsika/units/PhysicalUnits.h>
 #include <corsika/utl/COMBoost.h>
 #include <iostream>
@@ -43,6 +45,7 @@ TEST_CASE("boosts") {
   HEPMassType const projectileMass = 1._GeV;
   Vector<hepmomentum_d> pProjectileLab{rootCS, {0_GeV, 1_PeV, 0_GeV}};
   HEPEnergyType const eProjectileLab = energy(projectileMass, pProjectileLab);
+  const FourVector PprojLab(eProjectileLab, pProjectileLab);
 
   // define target kinematics in lab frame
   HEPMassType const targetMass = 1_GeV;
@@ -50,32 +53,34 @@ TEST_CASE("boosts") {
   HEPEnergyType const eTargetLab = energy(targetMass, pTargetLab);
 
   // define boost to com frame
-  COMBoost boost(eProjectileLab, pProjectileLab, targetMass);
+  COMBoost boost(PprojLab, FourVector(targetMass, pTargetLab));
 
   // boost projecticle
-  auto const [eProjectileCoM, pProjectileCoM] =
-      boost.toCoM(eProjectileLab, pProjectileLab);
+  auto const PprojCoM = boost.toCoM(PprojLab);
 
   // boost target
-  auto const [eTargetCoM, pTargetCoM] = boost.toCoM(eTargetLab, pTargetLab);
+  auto const PtargCoM = boost.toCoM(FourVector(targetMass, pTargetLab));
 
   // sum of momenta in CoM, should be 0
-  auto const sumPCoM = pProjectileCoM + pTargetCoM;
-  CHECK(sumPCoM[2] / 1_GeV == Approx(0).margin(absMargin));
+  auto const sumPCoM =
+      PprojCoM.GetSpaceLikeComponents() + PtargCoM.GetSpaceLikeComponents();
+  CHECK(sumPCoM.norm() / 1_GeV == Approx(0).margin(absMargin));
 
   // mandelstam-s should be invariant under transformation
   CHECK(s(eProjectileLab + eTargetLab,
           pProjectileLab.GetComponents() + pTargetLab.GetComponents()) /
             1_GeV / 1_GeV ==
-        Approx(s(eProjectileCoM + eTargetCoM, pProjectileCoM + pTargetCoM) / 1_GeV /
-               1_GeV));
+        Approx(s(PprojCoM.GetTimeLikeComponent() + PtargCoM.GetTimeLikeComponent(),
+                 PprojCoM.GetSpaceLikeComponents().GetComponents() +
+                     PtargCoM.GetSpaceLikeComponents().GetComponents()) /
+               1_GeV / 1_GeV));
 
   // boost back...
-  auto const [eProjectileBack, pProjectileBack] =
-      boost.fromCoM(eProjectileCoM, pProjectileCoM);
+  auto const PprojBack = boost.fromCoM(PprojCoM);
 
   // ...should yield original values before the boosts
-  CHECK(eProjectileBack / eProjectileLab == Approx(1));
-  CHECK((pProjectileBack - pProjectileLab).norm() / pProjectileLab.norm() ==
+  CHECK(PprojBack.GetTimeLikeComponent() / PprojLab.GetTimeLikeComponent() == Approx(1));
+  CHECK((PprojBack.GetSpaceLikeComponents() - PprojLab.GetSpaceLikeComponents()).norm() /
+            PprojLab.GetSpaceLikeComponents().norm() ==
         Approx(0).margin(absMargin));
 }
diff --git a/Processes/Sibyll/Interaction.h b/Processes/Sibyll/Interaction.h
index f35b244f..91702692 100644
--- a/Processes/Sibyll/Interaction.h
+++ b/Processes/Sibyll/Interaction.h
@@ -16,6 +16,7 @@
 
 #include <corsika/environment/Environment.h>
 #include <corsika/environment/NuclearComposition.h>
+#include <corsika/geometry/FourVector.h>
 #include <corsika/particles/ParticleProperties.h>
 #include <corsika/process/sibyll/ParticleConversion.h>
 #include <corsika/process/sibyll/SibStack.h>
@@ -97,11 +98,11 @@ namespace corsika::process::sibyll {
                                               corsika::particles::Neutron::GetMass());
 
       // FOR NOW: assume target is at rest
-      MomentumVector pTarget(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
+      MomentumVector pTarget(rootCS, {0_GeV, 0_GeV, 0_GeV});
 
       // total momentum and energy
       HEPEnergyType Elab = p.GetEnergy() + nucleon_mass;
-      MomentumVector pTotLab(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
+      MomentumVector pTotLab(rootCS, {0_GeV, 0_GeV, 0_GeV});
       pTotLab += p.GetMomentum();
       pTotLab += pTarget;
       auto const pTotLabNorm = pTotLab.norm();
@@ -165,6 +166,11 @@ namespace corsika::process::sibyll {
       return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm);
     }
 
+    /**
+       In this function SIBYLL is called to produce one event. The
+       event is copied (and boosted) into the shower lab frame. 
+     */
+    
     template <typename Particle, typename Stack>
     corsika::process::EProcessReturn DoInteraction(Particle& p, Stack& s) {
 
@@ -178,7 +184,8 @@ namespace corsika::process::sibyll {
       const auto corsikaBeamId = p.GetPID();
       cout << "ProcessSibyll: "
            << "DoInteraction: " << corsikaBeamId << " interaction? "
-           << process::sibyll::CanInteract(corsikaBeamId) << endl;
+           << process::sibyll::CanInteract(corsikaBeamId)
+	   << endl;
       if (process::sibyll::CanInteract(corsikaBeamId)) {
         const CoordinateSystem& rootCS =
             RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
@@ -194,16 +201,12 @@ namespace corsika::process::sibyll {
         // FOR NOW: target is always at rest
         const auto eTargetLab = 0_GeV + nucleon_mass;
         const auto pTargetLab = MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV);
-
+	const FourVector PtargLab(eTargetLab, pTargetLab);
+  
         // define projectile
-        auto const pProjectileLab = p.GetMomentum();
         HEPEnergyType const eProjectileLab = p.GetEnergy();
-
-        // define target kinematics in lab frame
-        HEPMassType const targetMass = nucleon_mass;
-        // define boost to and from CoM frame
-        // CoM frame definition in Sibyll projectile: +z
-        COMBoost const boost(eProjectileLab, pProjectileLab, targetMass);
+        auto const pProjectileLab = p.GetMomentum();
+        const FourVector PprojLab(eProjectileLab, pProjectileLab);
 
         cout << "Interaction: ebeam lab: " << eProjectileLab / 1_GeV << endl
              << "Interaction: pbeam lab: " << pProjectileLab.GetComponents() / 1_GeV
@@ -212,18 +215,26 @@ namespace corsika::process::sibyll {
              << "Interaction: ptarget lab: " << pTargetLab.GetComponents() / 1_GeV
              << endl;
 
+        // define target kinematics in lab frame
+        // define boost to and from CoM frame
+        // CoM frame definition in Sibyll projectile: +z
+        COMBoost const boost(PprojLab, PtargLab);
+
         // just for show:
         // boost projecticle
-        auto const [eProjectileCoM, pProjectileCoM] =
-            boost.toCoM(eProjectileLab, pProjectileLab);
+        auto const PprojCoM = boost.toCoM(PprojLab);
 
         // boost target
-        auto const [eTargetCoM, pTargetCoM] = boost.toCoM(eTargetLab, pTargetLab);
+        auto const PtargCoM = boost.toCoM(PtargLab);
 
-        cout << "Interaction: ebeam CoM: " << eProjectileCoM / 1_GeV << endl
-             << "Interaction: pbeam CoM: " << pProjectileCoM / 1_GeV << endl;
-        cout << "Interaction: etarget CoM: " << eTargetCoM / 1_GeV << endl
-             << "Interaction: ptarget CoM: " << pTargetCoM / 1_GeV << endl;
+        cout << "Interaction: ebeam CoM: " << PprojCoM.GetTimeLikeComponent() / 1_GeV
+             << endl
+             << "Interaction: pbeam CoM: "
+             << PprojCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl;
+        cout << "Interaction: etarget CoM: " << PtargCoM.GetTimeLikeComponent() / 1_GeV
+             << endl
+             << "Interaction: ptarget CoM: "
+             << PtargCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl;
 
         cout << "Interaction: position of interaction: " << pOrig.GetCoordinates()
              << endl;
@@ -246,7 +257,7 @@ namespace corsika::process::sibyll {
 #warning reading interaction cross section again, should not be necessary
         auto const& compVec = mediumComposition.GetComponents();
         std::vector<si::CrossSectionType> cross_section_of_components(
-            mediumComposition.GetComponents().size());
+								      compVec.size());
 
         for (size_t i = 0; i < compVec.size(); ++i) {
           auto const targetId = compVec[i];
@@ -279,7 +290,8 @@ namespace corsika::process::sibyll {
                   << " Ecm(GeV): " << Ecm / 1_GeV << std::endl;
         if (eProjectileLab < 8.5_GeV || Ecm < 10_GeV) {
           std::cout << "Interaction: "
-                    << " DoInteraction: should have dropped particle.." << std::endl;
+                    << " DoInteraction: should have dropped particle.. "
+		    << "THIS IS AN ERROR" << std::endl;
           // p.Delete(); delete later... different process
         } else {
           fCount++;
@@ -310,15 +322,15 @@ namespace corsika::process::sibyll {
             if (psib.HasDecayed()) continue;
 
             // transform energy to lab. frame
-            auto const pCoM = psib.GetMomentum().GetComponents();
+            auto const pCoM = psib.GetMomentum();
             HEPEnergyType const eCoM = psib.GetEnergy();
-            auto const [eLab, pLab] = boost.fromCoM(eCoM, pCoM);
+            auto const Plab = boost.fromCoM(FourVector(eCoM, pCoM));
 
             // add to corsika stack
             auto pnew = s.NewParticle();
             pnew.SetPID(process::sibyll::ConvertFromSibyll(psib.GetPID()));
-            pnew.SetEnergy(eLab);
-            pnew.SetMomentum(pLab);
+            pnew.SetEnergy(Plab.GetTimeLikeComponent());
+            pnew.SetMomentum(Plab.GetSpaceLikeComponents());
             pnew.SetPosition(pOrig);
             pnew.SetTime(tOrig);
 
-- 
GitLab