From d36ec1ca9161e2385a7c6f227a31bc2b4143f319 Mon Sep 17 00:00:00 2001
From: Maximilian Reininghaus <maximilian.reininghaus@tu-dortmund.de>
Date: Sat, 27 Apr 2019 22:19:23 -0300
Subject: [PATCH] infinite interaction length for non-hadrons

---
 Processes/UrQMD/UrQMD.cc     | 36 +++++++++++++++++++++++++++++-------
 Processes/UrQMD/UrQMD.h      |  6 ++++--
 Processes/UrQMD/testUrQMD.cc | 14 ++++++--------
 3 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/Processes/UrQMD/UrQMD.cc b/Processes/UrQMD/UrQMD.cc
index 9a88c8588..1f7e44215 100644
--- a/Processes/UrQMD/UrQMD.cc
+++ b/Processes/UrQMD/UrQMD.cc
@@ -7,6 +7,7 @@
 #include <corsika/setup/SetupTrajectory.h>
 #include <corsika/units/PhysicalUnits.h>
 
+#include <algorithm>
 #include <functional>
 #include <iostream>
 #include <random>
@@ -23,10 +24,8 @@ using SetupTrack = corsika::setup::Trajectory;
 
 template <typename TParticle> // need template here, as this is called both with
                               // SetupParticle as well as SetupProjectile
-                              CrossSectionType UrQMD::GetCrossSection(
-                                  TParticle const& vProjectile,
-                                  corsika::particles::Code vTargetCode)
-                                  const {
+CrossSectionType UrQMD::GetCrossSection(TParticle const& vProjectile,
+                                        corsika::particles::Code vTargetCode) const {
   using namespace units::si;
 
   // TODO: energy cuts, return 0 for non-hadrons
@@ -39,9 +38,10 @@ template <typename TParticle> // need template here, as this is called both with
       !IsNucleus(vTargetCode)) { // both particles are "special"
     auto const mProj = particles::GetMass(projectileCode);
     auto const mTar = particles::GetMass(vTargetCode);
-    double sqrtS = sqrt(units::si::detail::static_pow<2>(mProj) + units::si::detail::static_pow<2>(mTar) +
-                        2 * projectileEnergyLab * mTar) *
-                   (1 / 1_GeV);
+    double sqrtS =
+        sqrt(units::si::detail::static_pow<2>(mProj) +
+             units::si::detail::static_pow<2>(mTar) + 2 * projectileEnergyLab * mTar) *
+        (1 / 1_GeV);
 
     // we must set some UrQMD globals first...
     auto const [ityp, iso3] = ConvertToUrQMD(projectileCode);
@@ -66,7 +66,29 @@ template <typename TParticle> // need template here, as this is called both with
   }
 }
 
+bool UrQMD::CanInteract(particles::Code vCode) const {
+  // According to the manual, UrQMD can use all mesons, baryons and nucleons
+  // which are modeled also as input particles. I think it is safer to accept
+  // only the usual long-lived species as input.
+  // TODO: Charmed mesons should be added to the list, too
+
+  static particles::Code const validProjectileCodes[] = {
+      particles::Code::Nucleus, particles::Code::Proton,      particles::Code::AntiProton,
+      particles::Code::Neutron, particles::Code::AntiNeutron, particles::Code::PiPlus,
+      particles::Code::PiMinus, particles::Code::KPlus,       particles::Code::KMinus,
+      particles::Code::K0,      particles::Code::K0Bar};
+
+  return std::find(std::cbegin(validProjectileCodes), std::cend(validProjectileCodes),
+                   vCode) != std::cend(validProjectileCodes);
+}
+
 GrammageType UrQMD::GetInteractionLength(SetupParticle& vParticle, SetupTrack&) const {
+  if (!CanInteract(vParticle.GetPID())) {
+    // we could do the canInteract check in GetCrossSection, too but if
+    // we do it here we have the advantage of avoiding the loop
+    return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm);
+  }
+
   auto const& mediumComposition =
       vParticle.GetNode()->GetModelProperties().GetNuclearComposition();
   using namespace std::placeholders;
diff --git a/Processes/UrQMD/UrQMD.h b/Processes/UrQMD/UrQMD.h
index 798d86d7a..0b34e2e14 100644
--- a/Processes/UrQMD/UrQMD.h
+++ b/Processes/UrQMD/UrQMD.h
@@ -19,12 +19,14 @@ namespace corsika::process::UrQMD {
         corsika::setup::Stack::StackIterator&, corsika::setup::Trajectory&) const;
 
     template <typename TParticle>
-    corsika::units::si::CrossSectionType GetCrossSection(
-        TParticle const&, corsika::particles::Code) const;
+    corsika::units::si::CrossSectionType GetCrossSection(TParticle const&,
+                                                         corsika::particles::Code) const;
 
     corsika::process::EProcessReturn DoInteraction(
         corsika::setup::StackView::StackIterator&);
 
+    bool CanInteract(particles::Code) const;
+
   private:
     corsika::random::RNG& fRNG =
         corsika::random::RNGManager::GetInstance().GetRandomStream("UrQMD");
diff --git a/Processes/UrQMD/testUrQMD.cc b/Processes/UrQMD/testUrQMD.cc
index f65838d32..0a9af8749 100644
--- a/Processes/UrQMD/testUrQMD.cc
+++ b/Processes/UrQMD/testUrQMD.cc
@@ -42,10 +42,8 @@ using namespace corsika::units::si;
 template <typename TStackView>
 auto sumCharge(TStackView const& view) {
   int totalCharge = 0;
-  
-  for (auto const& p : view) {
-    totalCharge += particles::GetChargeNumber(p.GetPID());
-  }
+
+  for (auto const& p : view) { totalCharge += particles::GetChargeNumber(p.GetPID()); }
 
   return totalCharge;
 }
@@ -165,7 +163,7 @@ TEST_CASE("UrQMD") {
     auto [stackPtr, secViewPtr] = setupStack(A, Z, 400_GeV, nodePtr, *csPtr);
 
     // must be assigned to variable, cannot be used as rvalue?!
-    auto projectile =    secViewPtr     ->GetProjectile();
+    auto projectile = secViewPtr->GetProjectile();
     [[maybe_unused]] process::EProcessReturn const ret = urqmd.DoInteraction(projectile);
 
     REQUIRE(sumCharge(*secViewPtr) ==
@@ -175,14 +173,14 @@ TEST_CASE("UrQMD") {
   SECTION("\"special\" projectile") {
     auto [env, csPtr, nodePtr] = setupEnvironment(particles::Code::Oxygen);
     auto [stackPtr, secViewPtr] =
-        setupStack(particles::Code::PiPlus, 400_GeV, nodePtr, *csPtr);
+        setupStack(particles::Code::K0, 400_GeV, nodePtr, *csPtr);
 
     // must be assigned to variable, cannot be used as rvalue?!
-    auto projectile = secViewPtr->GetProjectile(); 
+    auto projectile = secViewPtr->GetProjectile();
     [[maybe_unused]] process::EProcessReturn const ret = urqmd.DoInteraction(projectile);
 
     REQUIRE(sumCharge(*secViewPtr) ==
-            particles::GetChargeNumber(particles::Code::PiPlus) +
+            particles::GetChargeNumber(particles::Code::K0) +
                 particles::GetChargeNumber(particles::Code::Oxygen));
   }
 }
-- 
GitLab