From c38635469d52640288615e1ca1265d20815de468 Mon Sep 17 00:00:00 2001
From: Maximilian Reininghaus <maximilian.reininghaus@kit.edu>
Date: Thu, 14 Feb 2019 17:13:47 +0100
Subject: [PATCH] first try

---
 Environment/VolumeTreeNode.h                  |  1 +
 Framework/Cascade/Cascade.h                   | 59 ++++++-----
 Processes/TrackingLine/TrackingLine.cc        | 67 -------------
 Processes/TrackingLine/TrackingLine.h         | 97 ++++++++++++++++++-
 Processes/TrackingLine/testTrackingLine.cc    |  2 +-
 .../TrackingLine/testTrackingLineStack.cc     | 37 -------
 6 files changed, 130 insertions(+), 133 deletions(-)
 delete mode 100644 Processes/TrackingLine/testTrackingLineStack.cc

diff --git a/Environment/VolumeTreeNode.h b/Environment/VolumeTreeNode.h
index 3331c41bf..e125b243d 100644
--- a/Environment/VolumeTreeNode.h
+++ b/Environment/VolumeTreeNode.h
@@ -13,6 +13,7 @@
 #define _include_VolumeTreeNode_H
 
 #include <corsika/geometry/Volume.h>
+#include <corsika/environment/IMediumModel.h>
 #include <memory>
 #include <vector>
 
diff --git a/Framework/Cascade/Cascade.h b/Framework/Cascade/Cascade.h
index 2d55e9030..4bddb9c57 100644
--- a/Framework/Cascade/Cascade.h
+++ b/Framework/Cascade/Cascade.h
@@ -14,9 +14,9 @@
 
 #include <corsika/environment/Environment.h>
 #include <corsika/process/ProcessReturn.h>
+#include <corsika/random/ExponentialDistribution.h>
 #include <corsika/random/RNGManager.h>
 #include <corsika/random/UniformRealDistribution.h>
-#include <corsika/random/ExponentialDistribution.h>
 #include <corsika/setup/SetupTrajectory.h>
 #include <corsika/units/PhysicalUnits.h>
 
@@ -37,7 +37,7 @@ namespace corsika::cascade {
    * plugged into the cascade simulation.
    *
    * <b>Tracking</b> must be a class according to the
-   * TrackingInterface providing the functions: 
+   * TrackingInterface providing the functions:
    * <code>auto GetTrack(Particle const& p)</auto>,
    * with the return type <code>geometry::Trajectory<corsika::geometry::Line>
    * </code>
@@ -77,19 +77,19 @@ namespace corsika::cascade {
       fProcessSequence.Init();
       fStack.Init();
     }
-    
+
     /**
      * set the nodes for all particles on the stack according to their numerical
      * position
      */
     void SetNodes() {
-        std::for_each(fStack.begin(), fStack.end(), [&](auto& p) {
-            auto const* numericalNode =
+      std::for_each(fStack.begin(), fStack.end(), [&](auto& p) {
+        auto const* numericalNode =
             fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition());
-            p.SetNode(numericalNode);
-            
-            std::cout << "initial node " << p.GetNode() << std::endl; 
-        });
+        p.SetNode(numericalNode);
+
+        std::cout << "initial node " << p.GetNode() << std::endl;
+      });
     }
 
     /**
@@ -98,11 +98,12 @@ namespace corsika::cascade {
      */
     void Run() {
       SetNodes();
-      
-      while (!fStack.IsEmpty()) {
-        while (!fStack.IsEmpty()) {
+
+      while (!fStack.IsEmpty() && countSteps < maxSteps) {
+        while (!fStack.IsEmpty() && countSteps < maxSteps) {
           auto pNext = fStack.GetNextParticle();
           Step(pNext);
+          countSteps++;
         }
         // do cascade equations, which can put new particles on Stack,
         // thus, the double loop
@@ -125,7 +126,7 @@ namespace corsika::cascade {
       using namespace corsika::units::si;
 
       // determine geometric tracking
-      corsika::setup::Trajectory step = fTracking.GetTrack(particle);
+      auto [step, geomMaxLength, nextVol] = fTracking.GetTrack(particle);
 
       // determine combined total interaction length (inverse)
       InverseGrammageType const total_inv_lambda =
@@ -139,12 +140,13 @@ namespace corsika::cascade {
                 << ", next_interact=" << next_interact << std::endl;
 
       auto const* currentLogicalNode = particle.GetNode();
-      
+
       auto const* currentNumericalNode =
-        fEnvironment.GetUniverse()->GetContainingNode(particle.GetPosition());
-        
-      std::cout << "nodes: " << currentLogicalNode << " " << currentNumericalNode << std::endl;
-        
+          fEnvironment.GetUniverse()->GetContainingNode(particle.GetPosition());
+
+      std::cout << "nodes: " << currentLogicalNode << " " << currentNumericalNode
+                << std::endl;
+
       if (currentNumericalNode != currentLogicalNode) {
         throw std::runtime_error("numerical and logical nodes don't match");
       }
@@ -155,7 +157,8 @@ namespace corsika::cascade {
 
       // convert next_step from grammage to length
       LengthType const distance_interact =
-          currentLogicalNode->GetModelProperties().ArclengthFromGrammage(step, next_interact);
+          currentLogicalNode->GetModelProperties().ArclengthFromGrammage(step,
+                                                                         next_interact);
 
       // determine the maximum geometric step length
       LengthType const distance_max = fProcessSequence.MaxStepLength(particle, step);
@@ -178,7 +181,7 @@ namespace corsika::cascade {
 
       // take minimum of geometry, interaction, decay for next step
       auto const min_distance =
-          std::min({distance_interact, distance_decay, distance_max});
+          std::min({distance_interact, distance_decay, distance_max, geomMaxLength});
 
       std::cout << " move particle by : " << min_distance << std::endl;
 
@@ -191,7 +194,8 @@ namespace corsika::cascade {
 
       // particle.GetNode(); // previous VolumeNode
       //~ particle.SetNode(
-          //~ currentLogicalNode); // NOTE @Max : here we need to distinguish: IF particle step is
+      //~ currentLogicalNode); // NOTE @Max : here we need to distinguish: IF particle
+      //step is
       // limited by tracking (via fTracking.GetTrack()), THEN we need
       // to check/update VolumeNodes. In all other cases it is
       // guaranteed that we are still in the same volume
@@ -208,11 +212,9 @@ namespace corsika::cascade {
       }
 
       std::cout << "sth. happening before geometric limit ? "
-                << ((min_distance < distance_max) ? "yes" : "no") << std::endl;
-
-      if (min_distance < distance_max) { // interaction to happen within geometric limit
-        // check whether decay or interaction limits this step
+                << ((min_distance < geomMaxLength) ? "yes" : "no") << std::endl;
 
+      if (min_distance < geomMaxLength) { // interaction to happen within geometric limit
         if (min_distance == distance_interact) {
           std::cout << "collide" << std::endl;
 
@@ -225,7 +227,7 @@ namespace corsika::cascade {
           InverseGrammageType inv_lambda_count = 0. * meter * meter / gram;
           fProcessSequence.SelectInteraction(particle, step, fStack, sample_process,
                                              inv_lambda_count);
-        } else {
+        } else if (min_distance == distance_decay) {
           std::cout << "decay" << std::endl;
           InverseTimeType const actual_decay_time =
               fProcessSequence.GetTotalInverseLifetime(particle);
@@ -235,7 +237,12 @@ namespace corsika::cascade {
           const auto sample_process = uniDist(fRNG);
           InverseTimeType inv_decay_count = 0 / second;
           fProcessSequence.SelectDecay(particle, fStack, sample_process, inv_decay_count);
+        } else { // step-length limitation within volume
+          std::cout << "step-length limitation" << std::endl;
         }
+      } else { // boundary crossing
+        std::cout << "boundary crossing! next node = " << nextVol << std::endl;
+        particle.SetNode(nextVol);
       }
     }
 
diff --git a/Processes/TrackingLine/TrackingLine.cc b/Processes/TrackingLine/TrackingLine.cc
index 36a267a92..2c610c9c2 100644
--- a/Processes/TrackingLine/TrackingLine.cc
+++ b/Processes/TrackingLine/TrackingLine.cc
@@ -62,73 +62,6 @@ namespace corsika::process::tracking_line {
       corsika::environment::Environment const& pEnv)
       : fEnvironment(pEnv) {}
 
-  template <class Stack, class Trajectory>
-  Trajectory TrackingLine<Stack, Trajectory>::GetTrack(Particle const& p) {
-    using std::cout;
-    using std::endl;
-    using namespace corsika::units::si;
-    using namespace corsika::geometry;
-    geometry::Vector<SpeedType::dimension_type> const velocity =
-        p.GetMomentum() / p.GetEnergy() * corsika::units::constants::c;
-
-    auto const currentPosition = p.GetPosition();
-    std::cout << "TrackingLine pid: " << p.GetPID() << " , E = " << p.GetEnergy() / 1_GeV
-              << " GeV" << std::endl;
-    std::cout << "TrackingLine pos: " << currentPosition.GetCoordinates() << std::endl;
-    std::cout << "TrackingLine   E: " << p.GetEnergy() / 1_GeV << " GeV" << std::endl;
-    std::cout << "TrackingLine   p: " << p.GetMomentum().GetComponents() / 1_GeV
-              << " GeV " << std::endl;
-    std::cout << "TrackingLine   v: " << velocity.GetComponents() << std::endl;
-
-    // to do: include effect of magnetic field
-    geometry::Line line(currentPosition, velocity);
-
-    auto const* currentVolumeNode =
-        fEnvironment.GetUniverse()->GetContainingNode(currentPosition);
-    auto const& children = currentVolumeNode->GetChildNodes();
-    auto const& excluded = currentVolumeNode->GetExcludedNodes();
-
-    std::vector<TimeType> intersectionTimes;
-
-    auto addIfIntersects = [&](auto& vtn) {
-      auto const& volume = vtn.GetVolume();
-      auto const& sphere = dynamic_cast<geometry::Sphere const&>(
-          volume); // for the moment we are a bit bold here and assume
-      // everything is a sphere, crashes with exception if not
-
-      if (auto opt = TimeOfIntersection(line, sphere); opt.has_value()) {
-        auto const [t1, t2] = *opt;
-        if (t1.magnitude() >= 0)
-          intersectionTimes.push_back(t1);
-        else if (t2.magnitude() >= 0)
-          intersectionTimes.push_back(t2);
-      }
-    };
-
-    for (auto const& child : children) { addIfIntersects(*child); }
-
-    for (auto const* child : excluded) { addIfIntersects(*child); }
-
-    addIfIntersects(*currentVolumeNode);
-
-    auto const minIter =
-        std::min_element(intersectionTimes.cbegin(), intersectionTimes.cend());
-
-    TimeType min;
-
-    if (minIter == intersectionTimes.cend()) {
-      min = 1_s; // todo: do sth. more reasonable as soon as tracking is able
-      // to handle the numerics properly
-      //~ throw std::runtime_error("no intersection with anything!");
-    } else {
-      min = *minIter;
-    }
-
-    std::cout << " t-intersect: " << min << std::endl;
-
-    return Trajectory(line, min);
-  }
-
 } // namespace corsika::process::tracking_line
 
 #include <corsika/setup/SetupStack.h>
diff --git a/Processes/TrackingLine/TrackingLine.h b/Processes/TrackingLine/TrackingLine.h
index bd0aff7f2..a6d749d82 100644
--- a/Processes/TrackingLine/TrackingLine.h
+++ b/Processes/TrackingLine/TrackingLine.h
@@ -12,9 +12,12 @@
 #ifndef _include_corsika_processes_TrackingLine_h_
 #define _include_corsika_processes_TrackingLine_h_
 
+#include <corsika/environment/Environment.h>
+#include <corsika/environment/VolumeTreeNode.h>
 #include <corsika/units/PhysicalUnits.h>
-#include <map> // for std::pair
 #include <optional>
+#include <type_traits>
+#include <utility>
 
 namespace corsika::environment {
   class Environment;
@@ -42,7 +45,97 @@ namespace corsika::process {
 
       TrackingLine(corsika::environment::Environment const& pEnv);
 
-      Trajectory GetTrack(Particle const& p);
+      auto GetTrack(Particle const& p) {
+        using std::cout;
+        using std::endl;
+        using namespace corsika::units::si;
+        using namespace corsika::geometry;
+        geometry::Vector<SpeedType::dimension_type> const velocity =
+            p.GetMomentum() / p.GetEnergy() * corsika::units::constants::c;
+
+        auto const currentPosition = p.GetPosition();
+        std::cout << "TrackingLine pid: " << p.GetPID()
+                  << " , E = " << p.GetEnergy() / 1_GeV << " GeV" << std::endl;
+        std::cout << "TrackingLine pos: " << currentPosition.GetCoordinates()
+                  << std::endl;
+        std::cout << "TrackingLine   E: " << p.GetEnergy() / 1_GeV << " GeV" << std::endl;
+        std::cout << "TrackingLine   p: " << p.GetMomentum().GetComponents() / 1_GeV
+                  << " GeV " << std::endl;
+        std::cout << "TrackingLine   v: " << velocity.GetComponents() << std::endl;
+
+        // to do: include effect of magnetic field
+        geometry::Line line(currentPosition, velocity);
+
+        auto const* currentLogicalVolumeNode = p.GetNode();
+        //~ auto const* currentNumericalVolumeNode =
+        //~ fEnvironment.GetUniverse()->GetContainingNode(currentPosition);
+        auto const numericallyInside =
+            currentLogicalVolumeNode->GetVolume().Contains(currentPosition);
+
+        auto const& children = currentLogicalVolumeNode->GetChildNodes();
+        auto const& excluded = currentLogicalVolumeNode->GetExcludedNodes();
+
+        std::vector<std::pair<TimeType, environment::BaseNodeType const*>> intersections;
+
+        auto addIfIntersects = [&](auto const& vtn, auto const& nextNode) {
+          static_assert(std::is_same_v<decltype(vtn), decltype(nextNode)>);
+          auto const& volume = vtn.GetVolume();
+          auto const& sphere = dynamic_cast<geometry::Sphere const&>(
+              volume); // for the moment we are a bit bold here and assume
+          // everything is a sphere, crashes with exception if not
+
+          if (auto opt = TimeOfIntersection(line, sphere); opt.has_value()) {
+            auto const [t1, t2] = *opt;
+            std::cout << "intersection times: " << t1 / 1_s << "; " << t2 / 1_s
+                      << std::endl;
+            if (t1.magnitude() > 0)
+              intersections.emplace_back(t1, &nextNode);
+            else if (t2.magnitude() > 0)
+              intersections.emplace_back(t2, &nextNode);
+          }
+        };
+
+        for (auto const& child : children) { addIfIntersects(*child, *child); }
+
+        for (auto const* ex : excluded) { addIfIntersects(*ex, *ex); }
+
+        if (numericallyInside) {
+          addIfIntersects(
+              *currentLogicalVolumeNode,
+              *currentLogicalVolumeNode
+                   ->GetParent()); // todo: add parent node to vector, not current!
+        } else {
+          auto const& sphere = dynamic_cast<geometry::Sphere const&>(
+              currentLogicalVolumeNode->GetVolume());
+          // for the moment we are a bit bold here and assume
+          // everything is a sphere, crashes with exception if not
+          auto const [t1, t2] = *TimeOfIntersection(line, sphere);
+
+          if (t1 > 0_s) {
+            assert(t2 > 0_s);
+            intersections.emplace_back(t2, currentLogicalVolumeNode->GetParent());
+          }
+        }
+
+        auto const minIter = std::min_element(
+            intersections.cbegin(), intersections.cend(),
+            [](auto const& a, auto const& b) { return a.first < b.first; });
+
+        TimeType min;
+
+        if (minIter == intersections.cend()) {
+          min = 1_s; // todo: do sth. more reasonable as soon as tracking is able
+          // to handle the numerics properly
+          throw std::runtime_error("no intersection with anything!");
+        } else {
+          min = minIter->first;
+        }
+
+        std::cout << " t-intersect: " << min << std::endl;
+
+        return std::make_tuple(Trajectory(line, min), velocity.norm() * min,
+                               minIter->second);
+      }
     };
 
   } // namespace tracking_line
diff --git a/Processes/TrackingLine/testTrackingLine.cc b/Processes/TrackingLine/testTrackingLine.cc
index d0c225999..19efb14f3 100644
--- a/Processes/TrackingLine/testTrackingLine.cc
+++ b/Processes/TrackingLine/testTrackingLine.cc
@@ -85,7 +85,7 @@ TEST_CASE("TrackingLine") {
                                                             0_m / second, 1_m / second);
     Line line(origin, v);
 
-    auto const traj = tracking.GetTrack(p);
+    auto const [traj, geomMaxLength, nextVol] = tracking.GetTrack(p);
 
     REQUIRE((traj.GetPosition(1.) - Point(cs, 0_m, 0_m, radius))
                 .GetComponents(cs)
diff --git a/Processes/TrackingLine/testTrackingLineStack.cc b/Processes/TrackingLine/testTrackingLineStack.cc
deleted file mode 100644
index 4c2192388..000000000
--- a/Processes/TrackingLine/testTrackingLineStack.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-
-/*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
- *
- * See file AUTHORS for a list of contributors.
- *
- * This software is distributed under the terms of the GNU General Public
- * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
- * the license.
- */
-
-#ifndef _include_process_trackinling_teststack_h_
-#define _include_process_trackinling_teststack_h_
-
-typedef corsika::units::si::hepmomentum_d MOMENTUM;
-
-struct DummyParticle {
-  HEPEnergyType fEnergy;
-  Vector<MOMENTUM> fMomentum;
-  Point fPosition;
-
-  DummyParticle(HEPEnergyType pEnergy, Vector<MOMENTUM> pMomentum, Point pPosition)
-      : fEnergy(pEnergy)
-      , fMomentum(pMomentum)
-      , fPosition(pPosition) {}
-
-  auto GetEnergy() const { return fEnergy; }
-  auto GetMomentum() const { return fMomentum; }
-  auto GetPosition() const { return fPosition; }
-  auto GetPID() const { return corsika::particles::Code::Unknown; }
-};
-
-struct DummyStack {
-  using ParticleType = DummyParticle;
-};
-
-#endif
-- 
GitLab