From 9e9d3cfc8632f9b812532790adbe3539e38477ea Mon Sep 17 00:00:00 2001
From: Maximilian Reininghaus <maximilian.reininghaus@kit.edu>
Date: Thu, 25 Apr 2019 19:11:59 -0300
Subject: [PATCH] implemented UrQMD::GetCrossSection

---
 Processes/UrQMD/UrQMD.cc     | 84 ++++++++++++++++++++++++++----------
 Processes/UrQMD/UrQMD.h      |  4 +-
 Processes/UrQMD/init.f       |  3 +-
 Processes/UrQMD/testUrQMD.cc |  5 ++-
 4 files changed, 69 insertions(+), 27 deletions(-)

diff --git a/Processes/UrQMD/UrQMD.cc b/Processes/UrQMD/UrQMD.cc
index 2f48668b7..452714fd8 100644
--- a/Processes/UrQMD/UrQMD.cc
+++ b/Processes/UrQMD/UrQMD.cc
@@ -21,45 +21,83 @@ using SetupParticle = corsika::setup::Stack::StackIterator;
 using SetupProjectile = corsika::setup::StackView::StackIterator;
 using SetupTrack = corsika::setup::Trajectory;
 
-CrossSectionType UrQMD::GetCrossSection(
-    corsika::particles::Code projectileID, corsika::particles::Code targetID,
-    corsika::units::si::HEPEnergyType projectileEnergy) const {
+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,
+                                  corsika::units::si::HEPEnergyType vProjectileEnergyLab)
+                                  const {
   using namespace units::si;
-  return 10_mb; // TODO: implement
+
+  // TODO: energy cuts, return 0 for non-hadrons
+
+  auto const projectileCode = vProjectile.GetPID();
+
+  // the following is a translation of ptsigtot() into C++
+  if (projectileCode != particles::Code::Nucleus &&
+      !IsNucleus(vTargetCode)) { // both particles are "special"
+    auto const mProj = particles::GetMass(projectileCode);
+    auto const mTar = particles::GetMass(vTargetCode);
+    double sqrtS = sqrt(detail::static_pow<2>(mProj) + detail::static_pow<2>(mTar) +
+                        2 * vProjectileEnergyLab * mTar) *
+                   (1 / 1_GeV);
+
+    // we must set some UrQMD globals first...
+    auto const [ityp, iso3] = ConvertToUrQMD(projectileCode);
+    inputs_.spityp[0] = ityp;
+    inputs_.spiso3[0] = iso3;
+
+    auto const [itypTar, iso3Tar] = ConvertToUrQMD(vTargetCode);
+    inputs_.spityp[1] = itypTar;
+    inputs_.spiso3[1] = iso3Tar;
+
+    int one = 1;
+    int two = 2;
+    return sigtot_(one, two, sqrtS) * 1_mb;
+  } else {
+    int const Ap =
+        (projectileCode == particles::Code::Nucleus) ? vProjectile.GetNuclearA() : 1;
+    int const At = IsNucleus(vTargetCode) ? particles::GetNucleusA(vTargetCode) : 1;
+
+    double const maxImpact = nucrad_(Ap) + nucrad_(At) + 2 * options_.CTParam[30 - 1];
+    return 10_mb * M_PI * detail::static_pow<2>(maxImpact);
+    // is a constant cross-section really reasonable?
+  }
 }
 
-GrammageType UrQMD::GetInteractionLength(SetupParticle& particle, SetupTrack&) const {
+GrammageType UrQMD::GetInteractionLength(SetupParticle& vParticle, SetupTrack&) const {
   auto const& mediumComposition =
-      particle.GetNode()->GetModelProperties().GetNuclearComposition();
+      vParticle.GetNode()->GetModelProperties().GetNuclearComposition();
   using namespace std::placeholders;
 
-  CrossSectionType const weightedProdCrossSection =
-      mediumComposition.WeightedSum(std::bind(
-          &UrQMD::GetCrossSection, this, particle.GetPID(), _1, particle.GetEnergy()));
+  CrossSectionType const weightedProdCrossSection = mediumComposition.WeightedSum(
+      std::bind(&UrQMD::GetCrossSection<decltype(vParticle)>, this, vParticle, _1,
+                vParticle.GetEnergy()));
 
   return mediumComposition.GetAverageMassNumber() * units::constants::u /
          weightedProdCrossSection;
 }
 
-corsika::process::EProcessReturn UrQMD::DoInteraction(SetupProjectile& projectile) {
+corsika::process::EProcessReturn UrQMD::DoInteraction(SetupProjectile& vProjectile) {
   using namespace units::si;
 
-  auto const projectileCode = projectile.GetPID();
-  auto const projectileEnergyLab = projectile.GetEnergy();
-  auto const& projectileMomentumLab = projectile.GetMomentum();
-  auto const& projectilePosition = projectile.GetPosition();
-  auto const projectileTime = projectile.GetTime();
+  auto const projectileCode = vProjectile.GetPID();
+  auto const projectileEnergyLab = vProjectile.GetEnergy();
+  auto const& projectileMomentumLab = vProjectile.GetMomentum();
+  auto const& projectilePosition = vProjectile.GetPosition();
+  auto const projectileTime = vProjectile.GetTime();
 
   // sample target particle
   auto const& mediumComposition =
-      projectile.GetNode()->GetModelProperties().GetNuclearComposition();
+      vProjectile.GetNode()->GetModelProperties().GetNuclearComposition();
   auto const componentCrossSections = std::invoke([&]() {
     auto const& components = mediumComposition.GetComponents();
     std::vector<CrossSectionType> crossSections;
     crossSections.reserve(components.size());
 
     for (auto const c : components) {
-      crossSections.push_back(GetCrossSection(projectileCode, c, projectileEnergyLab));
+      crossSections.push_back(GetCrossSection(vProjectile, c, projectileEnergyLab));
     }
 
     return crossSections;
@@ -79,8 +117,8 @@ corsika::process::EProcessReturn UrQMD::DoInteraction(SetupProjectile& projectil
     // is this everything?
     inputs_.prspflg = 0;
 
-    sys_.Ap = projectile.GetNuclearA();
-    sys_.Zp = projectile.GetNuclearZ();
+    sys_.Ap = vProjectile.GetNuclearA();
+    sys_.Zp = vProjectile.GetNuclearZ();
 
     rsys_.bdist = nucrad_(targetA) + nucrad_(sys_.Ap) + 2 * options_.CTParam[30 - 1];
 
@@ -97,7 +135,7 @@ corsika::process::EProcessReturn UrQMD::DoInteraction(SetupProjectile& projectil
     inputs_.spiso3[0] = iso3;
   }
 
-  rsys_.ebeam = (projectileEnergyLab - projectile.GetMass()) * (1 / 1_GeV);
+  rsys_.ebeam = (projectileEnergyLab - vProjectile.GetMass()) * (1 / 1_GeV);
 
   // initilazation regarding target
   if (particles::IsNucleus(targetCode)) {
@@ -113,7 +151,7 @@ corsika::process::EProcessReturn UrQMD::DoInteraction(SetupProjectile& projectil
     inputs_.spiso3[1] = iso3;
   }
 
-  int iflb = 0; // flag for retrying interaction in case of elastic scattering
+  int iflb = 0; // flag for retrying interaction in case of empty event, 0 means retry
   urqmd_(iflb);
 
   // now retrieve secondaries from UrQMD
@@ -132,7 +170,7 @@ corsika::process::EProcessReturn UrQMD::DoInteraction(SetupProjectile& projectil
     momentum.rebase(originalCS); // transform back into standard lab frame
     std::cout << i << " " << code << " " << momentum.GetComponents() << std::endl;
 
-    projectile.AddSecondary(
+    vProjectile.AddSecondary(
         std::tuple<particles::Code, HEPEnergyType, stack::MomentumVector, geometry::Point,
                    TimeType>{code, energy, momentum, projectilePosition, projectileTime});
   }
@@ -140,7 +178,7 @@ corsika::process::EProcessReturn UrQMD::DoInteraction(SetupProjectile& projectil
   std::cout << "UrQMD generated " << sys_.npart << " secondaries!" << std::endl;
 
   if (sys_.npart > 0) // delete only in case of inelastic collision, otherwise keep
-    projectile.Delete();
+    vProjectile.Delete();
 
   return process::EProcessReturn::eOk;
 }
diff --git a/Processes/UrQMD/UrQMD.h b/Processes/UrQMD/UrQMD.h
index ca3b4b398..c32082a83 100644
--- a/Processes/UrQMD/UrQMD.h
+++ b/Processes/UrQMD/UrQMD.h
@@ -18,8 +18,9 @@ namespace corsika::process::UrQMD {
     corsika::units::si::GrammageType GetInteractionLength(
         corsika::setup::Stack::StackIterator&, corsika::setup::Trajectory&) const;
 
+    template <typename TParticle>
     corsika::units::si::CrossSectionType GetCrossSection(
-        corsika::particles::Code, corsika::particles::Code,
+        TParticle const&, corsika::particles::Code,
         corsika::units::si::HEPEnergyType) const;
 
     corsika::process::EProcessReturn DoInteraction(
@@ -55,6 +56,7 @@ namespace corsika::process::UrQMD {
   double nucrad_(int const&);
   void urqmd_(int&);
   int pdgid_(int&, int&);
+  double sigtot_(int&, int&, double&);
 
   // defined in coms.f
   extern struct {
diff --git a/Processes/UrQMD/init.f b/Processes/UrQMD/init.f
index d934f7f74..76afc9dfa 100644
--- a/Processes/UrQMD/init.f
+++ b/Processes/UrQMD/init.f
@@ -338,11 +338,12 @@ c determine impact parameter
          if(CTOption(5).eq.0) then
             bimp=bdist
          elseif(CTOption(5).eq.1) then
+C M.R. we don't truncate bdist here, logic happens in CORSIKA
 c hjd1
 c           if(bdist.gt.(nucrad(Ap)+nucrad(At)+2*CTParam(30)))
 c    &           bdist=nucrad(Ap)+nucrad(At)+2*CTParam(30)
 c hjd1
-c ! M.R. 2019-04-24: updated sampling procedure from UrQMD 3.4
+C M.R. 2019-04-24: updated sampling procedure from UrQMD 3.4
             bimp=sqrt(bmin**2 + ranf(0) * (bdist**2 - bmin**2)) 
      
 cdh         if (bimp<bmin) goto 215
diff --git a/Processes/UrQMD/testUrQMD.cc b/Processes/UrQMD/testUrQMD.cc
index 6cddf3e92..fec1f3ea0 100644
--- a/Processes/UrQMD/testUrQMD.cc
+++ b/Processes/UrQMD/testUrQMD.cc
@@ -41,9 +41,10 @@ auto sumCharge(TStack& stack) {
   int totalCharge = 0;
   int count = 0;
   for (auto& p : stack) {
-    count++;
+    std::cout << count++ << " ";
     totalCharge += particles::GetChargeNumber(p.GetPID());
-    std::cout << p.GetPID() << " " << particles::GetChargeNumber(p.GetPID()) << std::endl;
+    std::cout << p.GetPID() << " " << particles::GetChargeNumber(p.GetPID()) << ' '
+              << p.GetMomentum().GetComponents() << std::endl;
   }
 
   std::cout << count << " particles on stack" << std::endl;
-- 
GitLab