From 91d6b637c24267f9a899d9333b31c8c453eec77a Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Mon, 10 Dec 2018 08:32:18 +0100
Subject: [PATCH 1/3] switch on -O3 for Release build

---
 CMakeLists.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2a5cae812..11d785415 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,9 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
     "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
 endif()
 
+#set(CMAKE_CXX_FLAGS "-Wall -Wextra")
+set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+set(CMAKE_CXX_FLAGS_RELEASE "-O3")
 
 # unit testing coverage, does not work yet
 #include (CodeCoverage)
-- 
GitLab


From 15fbf4144c629ddc25bae63d8f9180b3d4d8d257 Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Tue, 11 Dec 2018 09:50:24 +0100
Subject: [PATCH 2/3] this mostly resolves it

---
 Documentation/Examples/cascade_example.cc     |  18 +--
 Framework/Cascade/Cascade.h                   |  48 ++++++--
 Framework/Cascade/testCascade.cc              |  43 ++++---
 Framework/ProcessSequence/BaseProcess.h       |  19 ++-
 Framework/ProcessSequence/DiscreteProcess.h   |   6 +
 Framework/ProcessSequence/ProcessReturn.h     |   3 +-
 Framework/ProcessSequence/ProcessSequence.h   | 110 +++++++++++++++---
 .../ProcessSequence/testProcessSequence.cc    |  24 ++++
 Framework/StackInterface/Stack.h              |   3 +
 Processes/StackInspector/StackInspector.cc    |   5 +-
 Processes/StackInspector/StackInspector.h     |   2 +-
 Stack/SuperStupidStack/SuperStupidStack.h     |   2 +-
 12 files changed, 231 insertions(+), 52 deletions(-)

diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc
index c22fa23bb..09ae4815c 100644
--- a/Documentation/Examples/cascade_example.cc
+++ b/Documentation/Examples/cascade_example.cc
@@ -36,13 +36,12 @@ using namespace std;
 
 static int fCount = 0;
 
-class ProcessSplit : public corsika::process::BaseProcess<ProcessSplit> {
+class ProcessSplit : public corsika::process::DiscreteProcess<ProcessSplit> {
 public:
   ProcessSplit() {}
 
   template <typename Particle, typename Track>
-  double MinStepLength(Particle& p, Track&) const {
-
+  double GetInteractionLength(Particle& p, Track&) const {
     // beam particles for sibyll : 1, 2, 3 for p, pi, k
     // read from cross section code table
     int kBeam = 1;
@@ -81,17 +80,20 @@ public:
     std::cout << "ProcessSplit: "
               << "interaction length (g/cm2): " << int_length << std::endl;
     // add exponential sampling
-    int a = 0;
-    const double next_step = -int_length * log(s_rndm_(a));
     /*
       what are the units of the output? slant depth or 3space length?
 
     */
-    std::cout << "ProcessSplit: "
-              << "next step (g/cm2): " << next_step << std::endl;
-    return next_step;
+    return int_length;
+    //
+    //int a = 0;
+    //const double next_step = -int_length * log(s_rndm_(a));
+    //std::cout << "ProcessSplit: "
+    //        << "next step (g/cm2): " << next_step << std::endl;
+    //return next_step;
   }
 
+
   template <typename Particle, typename Track, typename Stack>
   EProcessReturn DoContinuous(Particle&, Track&, Stack&) const {
     // corsika::utls::ignore(p);
diff --git a/Framework/Cascade/Cascade.h b/Framework/Cascade/Cascade.h
index 592372f5d..a1e6ff8a2 100644
--- a/Framework/Cascade/Cascade.h
+++ b/Framework/Cascade/Cascade.h
@@ -14,11 +14,12 @@
 
 #include <corsika/process/ProcessReturn.h>
 #include <corsika/units/PhysicalUnits.h>
+#include <corsika/setup/SetupTrajectory.h>
+#include <corsika/random/RNGManager.h>
 
 #include <type_traits>
 
-#include <corsika/setup/SetupTrajectory.h>
-
+using namespace corsika;
 using namespace corsika::units::si;
 
 namespace corsika::cascade {
@@ -50,24 +51,53 @@ namespace corsika::cascade {
         }
         // do cascade equations, which can put new particles on Stack,
         // thus, the double loop
-        // DoCascadeEquations(); //
+        // DoCascadeEquations();
       }
     }
 
-    void Step(Particle& particle) {
+    void Step(Particle& particle) {      
+      
       corsika::setup::Trajectory step = fTracking.GetTrack(particle);
-      fProcesseList.MinStepLength(particle, step);
-
+      const double total_inv_lambda = fProcesseList.GetTotalInverseInteractionLength(particle, step);
+      
+      // sample random exponential step length
+      // ....
+      static corsika::random::RNG& rmng =
+	corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
+      const double sample_step = rmng() / (double)rmng.max();
+      const double next_step = -log(sample_step) / total_inv_lambda;
+
+      const double min_step = fProcesseList.MinStepLength(particle, step);
+      // convert next_step from grammage to length
+      // Environment::GetDistance(step, next_step);
+      // ....
+      
+      // update step with actual min(min_step, next_step)
+      // ....
+      
       /// here the particle is actually moved along the trajectory to new position:
       // std::visit(corsika::setup::ParticleUpdate<Particle>{particle}, step);
       particle.SetPosition(step.GetPosition(1));
-
+      
       corsika::process::EProcessReturn status =
           fProcesseList.DoContinuous(particle, step, fStack);
+      
       if (status == corsika::process::EProcessReturn::eParticleAbsorbed) {
-        fStack.Delete(particle); // TODO: check if this is really needed
+        // fStack.Delete(particle); // TODO: check if this is really needed
       } else {
-        fProcesseList.DoDiscrete(particle, fStack);
+
+	// check if min_step < random_step  ->  skip discrete if rndm>min_step/random_step
+	if (min_step<next_step) {
+	  const double p_next = min_step/next_step;
+	  const double sample_skip = rmng() / (double)rmng.max();
+	  if (sample_skip>p_next) {
+	    return;// corsika::process::EProcessReturn::eOk;
+	  }
+	}
+	const double sample_process = rmng() / (double)rmng.max();
+	double inv_lambda_count = 0;
+	fProcesseList.SelectDiscrete(particle, fStack, total_inv_lambda,
+				     sample_process, inv_lambda_count);
       }
     }
 
diff --git a/Framework/Cascade/testCascade.cc b/Framework/Cascade/testCascade.cc
index a218cb788..f315cc292 100644
--- a/Framework/Cascade/testCascade.cc
+++ b/Framework/Cascade/testCascade.cc
@@ -17,6 +17,8 @@
 
 #include <corsika/stack/super_stupid/SuperStupidStack.h>
 
+#include <corsika/particles/ParticleProperties.h>
+
 #include <corsika/geometry/Point.h>
 #include <corsika/geometry/RootCoordinateSystem.h>
 #include <corsika/geometry/Vector.h>
@@ -42,15 +44,18 @@ static int fCount = 0;
 class ProcessSplit : public corsika::process::BaseProcess<ProcessSplit> {
 public:
   ProcessSplit() {}
-
-  template <typename Particle>
-  void MinStepLength(Particle&, setup::Trajectory&) const {}
-
-  template <typename Particle, typename Stack>
-  EProcessReturn DoContinuous(Particle&, setup::Trajectory&, Stack&) const {
+  
+  template <typename Particle, typename T>
+  double MinStepLength(Particle&, T&) const { return 1; }
+  
+  template <typename Particle, typename T>
+  double GetInteractionLength(Particle&, T&) const { return 1; }
+  
+  template <typename Particle, typename T, typename Stack>
+  EProcessReturn DoContinuous(Particle&, T&, Stack&) const {
     return EProcessReturn::eOk;
   }
-
+  
   template <typename Particle, typename Stack>
   void DoDiscrete(Particle& p, Stack& s) const {
     EnergyType E = p.GetEnergy();
@@ -60,7 +65,9 @@ public:
     } else {
       p.SetEnergy(E / 2);
       auto pnew = s.NewParticle();
-      // s.Copy(p, pnew);
+      // s.Copy(p, pnew); fix that .... todo
+      pnew.SetPID(p.GetPID());
+      pnew.SetTime(p.GetTime());
       pnew.SetEnergy(E / 2);
       pnew.SetPosition(p.GetPosition());
       pnew.SetMomentum(p.GetMomentum());
@@ -76,27 +83,34 @@ private:
 
 TEST_CASE("Cascade", "[Cascade]") {
 
-  tracking_line::TrackingLine<setup::Stack> tracking;
+  corsika::random::RNGManager& rmng = corsika::random::RNGManager::GetInstance();
+  ;
+  const std::string str_name = "s_rndm";
+  rmng.RegisterRandomStream(str_name);
 
+  tracking_line::TrackingLine<setup::Stack> tracking;
+  
   stack_inspector::StackInspector<setup::Stack> p0(true);
   ProcessSplit p1;
   const auto sequence = p0 + p1;
   setup::Stack stack;
-
+  
   corsika::cascade::Cascade EAS(tracking, sequence, stack);
-
   CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();
-
+  
   stack.Clear();
   auto particle = stack.NewParticle();
   EnergyType E0 = 100_GeV;
+  particle.SetPID(particles::Code::Electron);
   particle.SetEnergy(E0);
   particle.SetPosition(Point(rootCS, {0_m, 0_m, 10_km}));
   particle.SetMomentum(corsika::stack::super_stupid::MomentumVector(
       rootCS, {0 * newton * second, 0 * newton * second, -1 * newton * second}));
+  particle.SetTime(0_ns);
   EAS.Init();
   EAS.Run();
-
+  
+  /*
   SECTION("sectionTwo") {
     for (int i = 0; i < 0; ++i) {
       stack.Clear();
@@ -105,8 +119,9 @@ TEST_CASE("Cascade", "[Cascade]") {
       particle.SetEnergy(E0);
       EAS.Init();
       EAS.Run();
-
+      
       // cout << "Result: E0=" << E0 / 1_GeV << "GeV, count=" << p1.GetCount() << endl;
     }
   }
+  */
 }
diff --git a/Framework/ProcessSequence/BaseProcess.h b/Framework/ProcessSequence/BaseProcess.h
index 34dcb198e..b17305d5a 100644
--- a/Framework/ProcessSequence/BaseProcess.h
+++ b/Framework/ProcessSequence/BaseProcess.h
@@ -29,14 +29,27 @@ namespace corsika::process {
   struct BaseProcess {
     derived& GetRef() { return static_cast<derived&>(*this); }
     const derived& GetRef() const { return static_cast<const derived&>(*this); }
-
+    
     template <typename Particle, typename Stack>
     inline EProcessReturn DoDiscrete(Particle&, Stack&) const; // {}
-
+    
     template <typename Particle, typename Track, typename Stack>
     inline EProcessReturn DoContinuous(Particle&, Track&, Stack&) const; // {}
-  };
 
+    template <typename Particle, typename Track>
+      inline double GetInverseInteractionLength(Particle& p, Track& t) const {
+      return 1./GetRef().GetInteractionLength(p, t);
+    }
+};
+  
+  /*
+  template<template<typename, typename> class T, typename A, typename B>
+    typename BaseProcess< T<A, B> >::is_process_sequence 
+    {
+      static const bool value = true;
+    };
+  */
+  
   /*
   template <typename T>
   struct is_base {
diff --git a/Framework/ProcessSequence/DiscreteProcess.h b/Framework/ProcessSequence/DiscreteProcess.h
index a540c92c7..d0464e4eb 100644
--- a/Framework/ProcessSequence/DiscreteProcess.h
+++ b/Framework/ProcessSequence/DiscreteProcess.h
@@ -37,6 +37,12 @@ namespace corsika::process {
     // -> enforce derived to implement DoDiscrete...
     template <typename Particle, typename Stack>
     inline EProcessReturn DoDiscrete(Particle&, Stack&) const; // {}
+
+    template <typename Particle, typename Track>
+    inline double GetInverseInteractionLength(Particle& p, Track& t) const {
+      return 1./GetRef().GetInteractionLength(p, t);
+    }
+    
   };
 
 } // namespace corsika::process
diff --git a/Framework/ProcessSequence/ProcessReturn.h b/Framework/ProcessSequence/ProcessReturn.h
index 82cc816c5..039a56222 100644
--- a/Framework/ProcessSequence/ProcessReturn.h
+++ b/Framework/ProcessSequence/ProcessReturn.h
@@ -23,7 +23,8 @@ namespace corsika::process {
   enum class EProcessReturn {
     eOk = 1,
     eParticleAbsorbed = 2,
-  };
+    eInteracted = 3,
+    };
 } // namespace corsika::process
 
 #endif
diff --git a/Framework/ProcessSequence/ProcessSequence.h b/Framework/ProcessSequence/ProcessSequence.h
index 54ac90e7a..a24356d8e 100644
--- a/Framework/ProcessSequence/ProcessSequence.h
+++ b/Framework/ProcessSequence/ProcessSequence.h
@@ -17,6 +17,9 @@
 #include <corsika/process/DiscreteProcess.h>
 #include <corsika/process/ProcessReturn.h>
 
+#include <limits>
+#include <cmath>
+
 //#include <corsika/setup/SetupTrajectory.h>
 // using corsika::setup::Trajectory;
 //#include <variant>
@@ -25,7 +28,7 @@
 
 namespace corsika::process {
 
-  /* namespace detail { */
+  // namespace detail {
 
   /*   /\* template<typename TT1, typename TT2, typename Type = void> *\/ */
   /*   /\*   struct CallHello { *\/ */
@@ -41,7 +44,7 @@ namespace corsika::process {
   /*   /\* 	static void Call(const TT1&, const TT2&) { *\/ */
   /*   /\* 	  std::cout << "special" << std::endl; *\/ */
   /*   /\* 	}	 *\/ */
-  /*   /\*   }; *\/ */
+  /*          }; */
 
   /*   template<typename T1, typename T2, typename Particle, typename Trajectory, typename
    * Stack> //, typename Type = void> */
@@ -121,7 +124,7 @@ namespace corsika::process {
   /*     } */
   /*   }; */
   /*   *\/ */
-  /* } // end namespace detail */
+  //} // end namespace detail
 
   /**
      \class ProcessSequence
@@ -134,8 +137,24 @@ namespace corsika::process {
      https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
    */
 
+  //template <typename T1, typename T2>
+  //class ProcessSequence : public BaseProcess<ProcessSequence<T1, T2> >;
+
+  // this is a marker to track which BaseProcess is also a ProcessSequence
+    template <typename T>
+    struct is_process_sequence {
+      static const bool value = false;
+    };
+    
+
   template <typename T1, typename T2>
   class ProcessSequence : public BaseProcess<ProcessSequence<T1, T2> > {
+    
+    /*    template <>
+      struct BaseProcess<ProcessSequence<T1, T2> >::is_process_sequence<true> {
+      static const bool value = true;
+      };*/
+    
   public:
     const T1& A;
     const T2& B;
@@ -162,20 +181,38 @@ namespace corsika::process {
     }
 
     template <typename Particle, typename Track>
-    inline void MinStepLength(Particle& p, Track& track) const {
-      A.MinStepLength(p, track);
-      B.MinStepLength(p, track);
+    inline double MinStepLength(Particle& p, Track& track) const {
+      double min_length = std::numeric_limits<double>::infinity();
+      if constexpr (!std::is_base_of<DiscreteProcess<T1>, T1>::value) {
+	  min_length = std::min(min_length, A.MinStepLength(p,track));
+	}
+      if constexpr (!std::is_base_of<DiscreteProcess<T2>, T2>::value) {
+	  min_length = std::min(min_length, B.MinStepLength(p,track));
+	}
+      return min_length;
+    }
+
+    template <typename Particle, typename Track>
+    inline double GetTotalInteractionLength(Particle& p, Track& t) const {
+      return 1. / GetInverseInteractionLength(p, t);
+    }
+
+    template <typename Particle, typename Track>
+    inline double GetTotalInverseInteractionLength(Particle& p, Track& t) const {
+      return GetInverseInteractionLength(p, t);
     }
 
-    /*
     template <typename Particle, typename Track>
-    inline Track Transport(Particle& p, double& length) const {
-      A.Transport(p, length); // todo: maybe check (?) if there is more than one Transport
-                              // process implemented??
-      return B.Transport(
-          p, length); // need to do this also to decide which Track to return!!!!
+    inline double GetInverseInteractionLength(Particle& p, Track& t) const {
+      double tot = 0;
+      if constexpr (!std::is_base_of<ContinuousProcess<T1>, T1>::value) {
+        tot += A.GetInverseInteractionLength(p, t);
+      }
+      if constexpr (!std::is_base_of<ContinuousProcess<T2>, T2>::value) {
+        tot += B.GetInverseInteractionLength(p, t);
+      }
+      return tot;
     }
-    */
 
     template <typename Particle, typename Stack>
     inline EProcessReturn DoDiscrete(Particle& p, Stack& s) const {
@@ -188,6 +225,47 @@ namespace corsika::process {
       return EProcessReturn::eOk;
     }
 
+    template <typename Particle, typename Stack>
+      inline EProcessReturn SelectDiscrete(Particle& p, Stack& s,
+					   const double lambda_inv_tot,
+					   const double rndm_select,
+					   double& lambda_inv_count) const {
+      if constexpr (is_process_sequence<T1>::value) {
+	  // if A is a process sequence --> check inside
+	  const EProcessReturn ret = A.SelectDiscrete(p, s, lambda_inv_count, rndm_select, lambda_inv_count);
+	  // if A did suceed, stop routine
+	  if (ret != EProcessReturn::eOk) {
+	    return ret;
+	  }
+	} else if constexpr (!std::is_base_of<ContinuousProcess<T1>, T1>::value) {
+	  // if this is not a ContinuousProcess --> evaluate probability
+	  lambda_inv_count += A.GetInverseInteractionLength(p, s);
+	  // check if we should execute THIS process and then EXIT
+	  if (rndm_select<lambda_inv_count/lambda_inv_tot) {
+	    A.DoDiscrete(p, s);
+	    return EProcessReturn::eInteracted;
+	  }
+	} // end branch A
+      
+      if constexpr (is_process_sequence<T2>::value) {
+	  // if A is a process sequence --> check inside
+	  const EProcessReturn ret = B.SelectDiscrete(p, s, lambda_inv_count, rndm_select, lambda_inv_count);
+	  // if A did suceed, stop routine
+	  if (ret != EProcessReturn::eOk) {
+	    return ret;
+	  }
+	} else if constexpr (!std::is_base_of<ContinuousProcess<T2>, T2>::value) {
+	  // if this is not a ContinuousProcess --> evaluate probability
+	  lambda_inv_count += B.GetInverseInteractionLength(p, s);
+	  // check if we should execute THIS process and then EXIT
+	  if (rndm_select<lambda_inv_count/lambda_inv_tot) {
+	    B.DoDiscrete(p, s);
+	    return EProcessReturn::eInteracted;
+	  }
+	} // end branch A
+      return EProcessReturn::eOk;
+    }
+
     /// TODO the const_cast is not nice, think about the constness here
     inline void Init() const {
       const_cast<T1*>(&A)->Init();
@@ -289,6 +367,12 @@ namespace corsika::process {
     }
   */
 
+        template<template<typename, typename> class T, typename A, typename B>
+      struct is_process_sequence< T<A,B> > 
+    {
+      static const bool value = true;
+    };
+
 } // namespace corsika::process
 
 #endif
diff --git a/Framework/ProcessSequence/testProcessSequence.cc b/Framework/ProcessSequence/testProcessSequence.cc
index 7094cacb9..008201b7e 100644
--- a/Framework/ProcessSequence/testProcessSequence.cc
+++ b/Framework/ProcessSequence/testProcessSequence.cc
@@ -100,6 +100,11 @@ public:
     cout << "Process2::DoDiscrete" << endl;
     return EProcessReturn::eOk;
   }
+  template <typename Particle, typename Track>
+  inline double GetInteractionLength(Particle&, Track&) const {
+    cout << "Process2::GetInteractionLength" << endl;
+    return 3;
+  }
 };
 
 class Process3 : public DiscreteProcess<Process3> {
@@ -118,6 +123,11 @@ public:
     cout << "Process3::DoDiscrete" << endl;
     return EProcessReturn::eOk;
   }
+  template <typename Particle, typename Track>
+  inline double GetInteractionLength(Particle&, Track&) const {
+    cout << "Process3::GetInteractionLength" << endl;
+    return 1.;
+  }
 };
 
 class Process4 : public BaseProcess<Process4> {
@@ -169,6 +179,20 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     // REQUIRE_THROWS(sequence_wrong.Init());
   }
 
+  SECTION("interaction length") {
+    ContinuousProcess1 cp1(0);
+    Process2 m2(1);
+    Process3 m3(2);
+
+    DummyStack s;
+    DummyTrajectory t;
+
+    const auto sequence2 = cp1 + m2 + m3;
+    double tot = sequence2.GetTotalInteractionLength(s, t);
+    double tot_inv = sequence2.GetTotalInverseInteractionLength(s, t);
+    cout << "lambda_tot=" << tot << " lambda_tot_inv=" << tot_inv << endl;
+  }
+  
   SECTION("sectionTwo") {
 
     ContinuousProcess1 cp1(0);
diff --git a/Framework/StackInterface/Stack.h b/Framework/StackInterface/Stack.h
index b4660144d..e71880ccf 100644
--- a/Framework/StackInterface/Stack.h
+++ b/Framework/StackInterface/Stack.h
@@ -67,6 +67,9 @@ namespace corsika::stack {
       IncrementSize();
       return StackIterator(*this, GetSize() - 1);
     }
+    void Copy(StackIterator& a, StackIterator& b) {
+      Copy(a.GetIndex(), b.GetIndex());
+    }
     /// delete this particle
     void Delete(StackIterator& p) {
       if (GetSize() == 0) { /*error*/
diff --git a/Processes/StackInspector/StackInspector.cc b/Processes/StackInspector/StackInspector.cc
index b0acefc4a..abf47afd1 100644
--- a/Processes/StackInspector/StackInspector.cc
+++ b/Processes/StackInspector/StackInspector.cc
@@ -17,6 +17,7 @@
 
 #include <corsika/setup/SetupTrajectory.h>
 
+#include <limits>
 #include <iostream>
 using namespace std;
 
@@ -56,8 +57,8 @@ process::EProcessReturn StackInspector<Stack>::DoContinuous(Particle&, setup::Tr
 }
 
 template <typename Stack>
-void StackInspector<Stack>::MinStepLength(Particle&, setup::Trajectory&) const {
-  // return 0;
+double StackInspector<Stack>::MinStepLength(Particle&, setup::Trajectory&) const {
+  return std::numeric_limits<double>::infinity();
 }
 
 template <typename Stack>
diff --git a/Processes/StackInspector/StackInspector.h b/Processes/StackInspector/StackInspector.h
index 7b68d92d3..38d5cfc01 100644
--- a/Processes/StackInspector/StackInspector.h
+++ b/Processes/StackInspector/StackInspector.h
@@ -36,7 +36,7 @@ namespace corsika::process {
       EProcessReturn DoContinuous(Particle&, corsika::setup::Trajectory&, Stack& s) const;
 
       //      template <typename Particle>
-      void MinStepLength(Particle&, corsika::setup::Trajectory&) const;
+      double MinStepLength(Particle&, corsika::setup::Trajectory&) const;
 
     private:
       bool fReport;
diff --git a/Stack/SuperStupidStack/SuperStupidStack.h b/Stack/SuperStupidStack/SuperStupidStack.h
index d1c8bc2b3..8c7993442 100644
--- a/Stack/SuperStupidStack/SuperStupidStack.h
+++ b/Stack/SuperStupidStack/SuperStupidStack.h
@@ -128,7 +128,7 @@ namespace corsika::stack {
       void Swap(const int i1, const int i2) {
         std::swap(fDataPID[i2], fDataPID[i1]);
         std::swap(fDataE[i2], fDataE[i1]);
-        std::swap(fMomentum[i2], fMomentum[i1]); // should be Momentum !!!!
+        std::swap(fMomentum[i2], fMomentum[i1]);
         std::swap(fPosition[i2], fPosition[i1]);
         std::swap(fTime[i2], fTime[i1]);
       }
-- 
GitLab


From beca7928b9cf8ff25332931076ba1a0274a396f1 Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Wed, 12 Dec 2018 00:55:05 +0100
Subject: [PATCH 3/3] added new test section, final work

---
 Documentation/Examples/cascade_example.cc     |  19 +-
 Framework/Cascade/Cascade.h                   |  97 ++++--
 Framework/Cascade/testCascade.cc              |  30 +-
 Framework/ProcessSequence/BaseProcess.h       |  16 +-
 Framework/ProcessSequence/CMakeLists.txt      |   3 +-
 Framework/ProcessSequence/DecayProcess.h      |  51 +++
 Framework/ProcessSequence/DiscreteProcess.h   |   8 +-
 .../ProcessSequence/InteractionProcess.h      |  51 +++
 Framework/ProcessSequence/ProcessReturn.h     |   3 +-
 Framework/ProcessSequence/ProcessSequence.h   | 296 ++++++++----------
 .../ProcessSequence/testProcessSequence.cc    |  59 +++-
 Framework/StackInterface/Stack.h              |   4 +-
 Processes/StackInspector/StackInspector.cc    |   4 +-
 Processes/StackInspector/StackInspector.h     |   2 +-
 14 files changed, 398 insertions(+), 245 deletions(-)
 create mode 100644 Framework/ProcessSequence/DecayProcess.h
 create mode 100644 Framework/ProcessSequence/InteractionProcess.h

diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc
index 09ae4815c..d7e673ee5 100644
--- a/Documentation/Examples/cascade_example.cc
+++ b/Documentation/Examples/cascade_example.cc
@@ -36,7 +36,7 @@ using namespace std;
 
 static int fCount = 0;
 
-class ProcessSplit : public corsika::process::DiscreteProcess<ProcessSplit> {
+class ProcessSplit : public corsika::process::InteractionProcess<ProcessSplit> {
 public:
   ProcessSplit() {}
 
@@ -86,14 +86,13 @@ public:
     */
     return int_length;
     //
-    //int a = 0;
-    //const double next_step = -int_length * log(s_rndm_(a));
-    //std::cout << "ProcessSplit: "
+    // int a = 0;
+    // const double next_step = -int_length * log(s_rndm_(a));
+    // std::cout << "ProcessSplit: "
     //        << "next step (g/cm2): " << next_step << std::endl;
-    //return next_step;
+    // return next_step;
   }
 
-
   template <typename Particle, typename Track, typename Stack>
   EProcessReturn DoContinuous(Particle&, Track&, Stack&) const {
     // corsika::utls::ignore(p);
@@ -101,8 +100,8 @@ public:
   }
 
   template <typename Particle, typename Stack>
-  void DoDiscrete(Particle& p, Stack& s) const {
-    cout << "DoDiscrete: " << p.GetPID() << " interaction? "
+  void DoInteraction(Particle& p, Stack& s) const {
+    cout << "DoInteraction: " << p.GetPID() << " interaction? "
          << process::sibyll::CanInteract(p.GetPID()) << endl;
     if (process::sibyll::CanInteract(p.GetPID())) {
 
@@ -127,11 +126,11 @@ public:
       int kTarget = 1; // p.GetPID();
 
       std::cout << "ProcessSplit: "
-                << " DoDiscrete: E(GeV):" << E / 1_GeV << " Ecm(GeV): " << Ecm / 1_GeV
+                << " DoInteraction: E(GeV):" << E / 1_GeV << " Ecm(GeV): " << Ecm / 1_GeV
                 << std::endl;
       if (E < 8.5_GeV || Ecm < 10_GeV) {
         std::cout << "ProcessSplit: "
-                  << " DoDiscrete: dropping particle.." << std::endl;
+                  << " DoInteraction: dropping particle.." << std::endl;
         p.Delete();
         fCount++;
       } else {
diff --git a/Framework/Cascade/Cascade.h b/Framework/Cascade/Cascade.h
index a1e6ff8a2..7cd9d077d 100644
--- a/Framework/Cascade/Cascade.h
+++ b/Framework/Cascade/Cascade.h
@@ -13,9 +13,9 @@
 #define _include_corsika_cascade_Cascade_h_
 
 #include <corsika/process/ProcessReturn.h>
-#include <corsika/units/PhysicalUnits.h>
-#include <corsika/setup/SetupTrajectory.h>
 #include <corsika/random/RNGManager.h>
+#include <corsika/setup/SetupTrajectory.h>
+#include <corsika/units/PhysicalUnits.h>
 
 #include <type_traits>
 
@@ -55,49 +55,88 @@ namespace corsika::cascade {
       }
     }
 
-    void Step(Particle& particle) {      
-      
+    void Step(Particle& particle) {
+
+      // get access to random number generator
+      static corsika::random::RNG& rmng =
+          corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
+
+      // determine geometric tracking
       corsika::setup::Trajectory step = fTracking.GetTrack(particle);
-      const double total_inv_lambda = fProcesseList.GetTotalInverseInteractionLength(particle, step);
-      
+
+      // determine combined total interaction length (inverse)
+      const double total_inv_lambda =
+          fProcesseList.GetTotalInverseInteractionLength(particle, step);
+
       // sample random exponential step length
-      // ....
-      static corsika::random::RNG& rmng =
-	corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
       const double sample_step = rmng() / (double)rmng.max();
-      const double next_step = -log(sample_step) / total_inv_lambda;
+      const double next_interact = -log(sample_step) / total_inv_lambda;
+      std::cout << "total_inv_lambda=" << total_inv_lambda
+                << ", next_interact=" << next_interact << std::endl;
+
+      // determine the maximum geometric step length
+      const double distance_max = fProcesseList.MaxStepLength(particle, step);
+      std::cout << "distance_max=" << distance_max << std::endl;
+
+      // determine combined total inverse decay time
+      const double total_inv_lifetime = fProcesseList.GetTotalInverseLifetime(particle);
 
-      const double min_step = fProcesseList.MinStepLength(particle, step);
-      // convert next_step from grammage to length
+      // sample random exponential decay time
+      const double sample_decay = rmng() / (double)rmng.max();
+      const double next_decay = -log(sample_decay) / total_inv_lifetime;
+      std::cout << "total_inv_lifetime=" << total_inv_lifetime
+                << ", next_decay=" << next_decay << std::endl;
+
+      // convert next_step from grammage to length [m]
       // Environment::GetDistance(step, next_step);
+      const double distance_interact = next_interact;
       // ....
-      
-      // update step with actual min(min_step, next_step)
+
+      // convert next_decay from time to length [m]
+      // Environment::GetDistance(step, next_decay);
+      const double distance_decay = next_decay;
       // ....
-      
+
+      // take minimum of geometry, interaction, decay for next step
+      const double distance_decay_interact = std::min(next_decay, next_interact);
+      const double distance_next = std::min(distance_decay_interact, distance_max);
+
       /// here the particle is actually moved along the trajectory to new position:
       // std::visit(corsika::setup::ParticleUpdate<Particle>{particle}, step);
       particle.SetPosition(step.GetPosition(1));
-      
+      // .... also update time, momentum, direction, ...
+
+      // apply all continuous processes on particle + track
       corsika::process::EProcessReturn status =
           fProcesseList.DoContinuous(particle, step, fStack);
-      
+
       if (status == corsika::process::EProcessReturn::eParticleAbsorbed) {
         // fStack.Delete(particle); // TODO: check if this is really needed
       } else {
 
-	// check if min_step < random_step  ->  skip discrete if rndm>min_step/random_step
-	if (min_step<next_step) {
-	  const double p_next = min_step/next_step;
-	  const double sample_skip = rmng() / (double)rmng.max();
-	  if (sample_skip>p_next) {
-	    return;// corsika::process::EProcessReturn::eOk;
-	  }
-	}
-	const double sample_process = rmng() / (double)rmng.max();
-	double inv_lambda_count = 0;
-	fProcesseList.SelectDiscrete(particle, fStack, total_inv_lambda,
-				     sample_process, inv_lambda_count);
+        std::cout << "select process " << (distance_decay_interact < distance_max)
+                  << std::endl;
+        // check if geometry limits step, then quit this step
+        if (distance_decay_interact < distance_max) {
+          // check weather decay or interaction limits this step
+          if (distance_decay > distance_interact) {
+            std::cout << "collide" << std::endl;
+            const double actual_inv_length =
+                fProcesseList.GetTotalInverseInteractionLength(particle, step);
+            const double sample_process = rmng() / (double)rmng.max();
+            double inv_lambda_count = 0;
+            fProcesseList.SelectInteraction(particle, fStack, actual_inv_length,
+                                            sample_process, inv_lambda_count);
+          } else {
+            std::cout << "decay" << std::endl;
+            const double actual_decay_time =
+                fProcesseList.GetTotalInverseLifetime(particle);
+            const double sample_process = rmng() / (double)rmng.max();
+            double inv_decay_count = 0;
+            fProcesseList.SelectDecay(particle, fStack, actual_decay_time, sample_process,
+                                      inv_decay_count);
+          }
+        }
       }
     }
 
diff --git a/Framework/Cascade/testCascade.cc b/Framework/Cascade/testCascade.cc
index f315cc292..6502dff5c 100644
--- a/Framework/Cascade/testCascade.cc
+++ b/Framework/Cascade/testCascade.cc
@@ -41,23 +41,17 @@ using namespace std;
 
 static int fCount = 0;
 
-class ProcessSplit : public corsika::process::BaseProcess<ProcessSplit> {
+class ProcessSplit : public corsika::process::ContinuousProcess<ProcessSplit> {
 public:
   ProcessSplit() {}
-  
-  template <typename Particle, typename T>
-  double MinStepLength(Particle&, T&) const { return 1; }
-  
+
   template <typename Particle, typename T>
-  double GetInteractionLength(Particle&, T&) const { return 1; }
-  
-  template <typename Particle, typename T, typename Stack>
-  EProcessReturn DoContinuous(Particle&, T&, Stack&) const {
-    return EProcessReturn::eOk;
+  double MaxStepLength(Particle&, T&) const {
+    return 1;
   }
-  
-  template <typename Particle, typename Stack>
-  void DoDiscrete(Particle& p, Stack& s) const {
+
+  template <typename Particle, typename T, typename Stack>
+  void DoContinuous(Particle& p, T&, Stack& s) const {
     EnergyType E = p.GetEnergy();
     if (E < 85_MeV) {
       p.Delete();
@@ -89,15 +83,15 @@ TEST_CASE("Cascade", "[Cascade]") {
   rmng.RegisterRandomStream(str_name);
 
   tracking_line::TrackingLine<setup::Stack> tracking;
-  
+
   stack_inspector::StackInspector<setup::Stack> p0(true);
   ProcessSplit p1;
   const auto sequence = p0 + p1;
   setup::Stack stack;
-  
+
   corsika::cascade::Cascade EAS(tracking, sequence, stack);
   CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();
-  
+
   stack.Clear();
   auto particle = stack.NewParticle();
   EnergyType E0 = 100_GeV;
@@ -109,7 +103,7 @@ TEST_CASE("Cascade", "[Cascade]") {
   particle.SetTime(0_ns);
   EAS.Init();
   EAS.Run();
-  
+
   /*
   SECTION("sectionTwo") {
     for (int i = 0; i < 0; ++i) {
@@ -119,7 +113,7 @@ TEST_CASE("Cascade", "[Cascade]") {
       particle.SetEnergy(E0);
       EAS.Init();
       EAS.Run();
-      
+
       // cout << "Result: E0=" << E0 / 1_GeV << "GeV, count=" << p1.GetCount() << endl;
     }
   }
diff --git a/Framework/ProcessSequence/BaseProcess.h b/Framework/ProcessSequence/BaseProcess.h
index b17305d5a..9cc29196b 100644
--- a/Framework/ProcessSequence/BaseProcess.h
+++ b/Framework/ProcessSequence/BaseProcess.h
@@ -29,27 +29,29 @@ namespace corsika::process {
   struct BaseProcess {
     derived& GetRef() { return static_cast<derived&>(*this); }
     const derived& GetRef() const { return static_cast<const derived&>(*this); }
-    
+    /*
     template <typename Particle, typename Stack>
     inline EProcessReturn DoDiscrete(Particle&, Stack&) const; // {}
-    
+
     template <typename Particle, typename Track, typename Stack>
     inline EProcessReturn DoContinuous(Particle&, Track&, Stack&) const; // {}
-
+    */
+    /*
     template <typename Particle, typename Track>
       inline double GetInverseInteractionLength(Particle& p, Track& t) const {
       return 1./GetRef().GetInteractionLength(p, t);
     }
-};
-  
+    */
+  };
+
   /*
   template<template<typename, typename> class T, typename A, typename B>
-    typename BaseProcess< T<A, B> >::is_process_sequence 
+    typename BaseProcess< T<A, B> >::is_process_sequence
     {
       static const bool value = true;
     };
   */
-  
+
   /*
   template <typename T>
   struct is_base {
diff --git a/Framework/ProcessSequence/CMakeLists.txt b/Framework/ProcessSequence/CMakeLists.txt
index c1f5a4586..6c3e5ff8c 100644
--- a/Framework/ProcessSequence/CMakeLists.txt
+++ b/Framework/ProcessSequence/CMakeLists.txt
@@ -12,7 +12,8 @@ set (
   CORSIKAprocesssequence_HEADERS
   BaseProcess.h
   ContinuousProcess.h
-  DiscreteProcess.h
+  InteractionProcess.h
+  DecayProcess.h
   ProcessSequence.h
   ProcessReturn.h
   )
diff --git a/Framework/ProcessSequence/DecayProcess.h b/Framework/ProcessSequence/DecayProcess.h
new file mode 100644
index 000000000..8a49803ed
--- /dev/null
+++ b/Framework/ProcessSequence/DecayProcess.h
@@ -0,0 +1,51 @@
+
+/**
+ * (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_corsika_decayprocess_h_
+#define _include_corsika_decayprocess_h_
+
+#include <corsika/process/ProcessReturn.h> // for convenience
+#include <corsika/setup/SetupTrajectory.h>
+
+namespace corsika::process {
+
+  /**
+     \class DecayProcess
+
+     The structural base type of a process object in a
+     ProcessSequence. Both, the ProcessSequence and all its elements
+     are of type DecayProcess<T>
+
+   */
+
+  template <typename derived>
+  struct DecayProcess {
+
+    derived& GetRef() { return static_cast<derived&>(*this); }
+    const derived& GetRef() const { return static_cast<const derived&>(*this); }
+
+    /// here starts the interface-definition part
+    // -> enforce derived to implement DoDecay...
+    template <typename Particle, typename Stack>
+    inline EProcessReturn DoDecay(Particle&, Stack&) const;
+
+    template <typename Particle>
+    inline double GetLifetime(Particle& p) const;
+
+    template <typename Particle>
+    inline double GetInverseLifetime(Particle& p) const {
+      return 1. / GetRef().GetLifetime(p);
+    }
+  };
+
+} // namespace corsika::process
+
+#endif
diff --git a/Framework/ProcessSequence/DiscreteProcess.h b/Framework/ProcessSequence/DiscreteProcess.h
index d0464e4eb..7ce50810f 100644
--- a/Framework/ProcessSequence/DiscreteProcess.h
+++ b/Framework/ProcessSequence/DiscreteProcess.h
@@ -36,13 +36,15 @@ namespace corsika::process {
     /// here starts the interface-definition part
     // -> enforce derived to implement DoDiscrete...
     template <typename Particle, typename Stack>
-    inline EProcessReturn DoDiscrete(Particle&, Stack&) const; // {}
+    inline EProcessReturn DoDiscrete(Particle&, Stack&) const;
+
+    template <typename Particle, typename Track>
+    inline double GetInteractionLength(Particle& p, Track& t) const;
 
     template <typename Particle, typename Track>
     inline double GetInverseInteractionLength(Particle& p, Track& t) const {
-      return 1./GetRef().GetInteractionLength(p, t);
+      return 1. / GetRef().GetInteractionLength(p, t);
     }
-    
   };
 
 } // namespace corsika::process
diff --git a/Framework/ProcessSequence/InteractionProcess.h b/Framework/ProcessSequence/InteractionProcess.h
new file mode 100644
index 000000000..40264e606
--- /dev/null
+++ b/Framework/ProcessSequence/InteractionProcess.h
@@ -0,0 +1,51 @@
+
+/**
+ * (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_corsika_interactionprocess_h_
+#define _include_corsika_interactionprocess_h_
+
+#include <corsika/process/ProcessReturn.h> // for convenience
+#include <corsika/setup/SetupTrajectory.h>
+
+namespace corsika::process {
+
+  /**
+     \class InteractionProcess
+
+     The structural base type of a process object in a
+     ProcessSequence. Both, the ProcessSequence and all its elements
+     are of type InteractionProcess<T>
+
+   */
+
+  template <typename derived>
+  struct InteractionProcess {
+
+    derived& GetRef() { return static_cast<derived&>(*this); }
+    const derived& GetRef() const { return static_cast<const derived&>(*this); }
+
+    /// here starts the interface-definition part
+    // -> enforce derived to implement DoInteraction...
+    template <typename Particle, typename Stack>
+    inline EProcessReturn DoInteraction(Particle&, Stack&) const;
+
+    template <typename Particle, typename Track>
+    inline double GetInteractionLength(Particle& p, Track& t) const;
+
+    template <typename Particle, typename Track>
+    inline double GetInverseInteractionLength(Particle& p, Track& t) const {
+      return 1. / GetRef().GetInteractionLength(p, t);
+    }
+  };
+
+} // namespace corsika::process
+
+#endif
diff --git a/Framework/ProcessSequence/ProcessReturn.h b/Framework/ProcessSequence/ProcessReturn.h
index 039a56222..afd75d690 100644
--- a/Framework/ProcessSequence/ProcessReturn.h
+++ b/Framework/ProcessSequence/ProcessReturn.h
@@ -24,7 +24,8 @@ namespace corsika::process {
     eOk = 1,
     eParticleAbsorbed = 2,
     eInteracted = 3,
-    };
+    eDecayed = 4,
+  };
 } // namespace corsika::process
 
 #endif
diff --git a/Framework/ProcessSequence/ProcessSequence.h b/Framework/ProcessSequence/ProcessSequence.h
index a24356d8e..8517d4345 100644
--- a/Framework/ProcessSequence/ProcessSequence.h
+++ b/Framework/ProcessSequence/ProcessSequence.h
@@ -14,11 +14,13 @@
 
 #include <corsika/process/BaseProcess.h>
 #include <corsika/process/ContinuousProcess.h>
-#include <corsika/process/DiscreteProcess.h>
+#include <corsika/process/DecayProcess.h>
+//#include <corsika/process/DiscreteProcess.h>
+#include <corsika/process/InteractionProcess.h>
 #include <corsika/process/ProcessReturn.h>
 
-#include <limits>
 #include <cmath>
+#include <limits>
 
 //#include <corsika/setup/SetupTrajectory.h>
 // using corsika::setup::Trajectory;
@@ -137,24 +139,15 @@ namespace corsika::process {
      https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
    */
 
-  //template <typename T1, typename T2>
-  //class ProcessSequence : public BaseProcess<ProcessSequence<T1, T2> >;
-
   // this is a marker to track which BaseProcess is also a ProcessSequence
-    template <typename T>
-    struct is_process_sequence {
-      static const bool value = false;
-    };
-    
+  template <typename T>
+  struct is_process_sequence {
+    static const bool value = false;
+  };
 
   template <typename T1, typename T2>
   class ProcessSequence : public BaseProcess<ProcessSequence<T1, T2> > {
-    
-    /*    template <>
-      struct BaseProcess<ProcessSequence<T1, T2> >::is_process_sequence<true> {
-      static const bool value = true;
-      };*/
-    
+
   public:
     const T1& A;
     const T2& B;
@@ -169,27 +162,29 @@ namespace corsika::process {
     template <typename Particle, typename Track, typename Stack>
     inline EProcessReturn DoContinuous(Particle& p, Track& t, Stack& s) const {
       EProcessReturn ret = EProcessReturn::eOk;
-      if constexpr (!std::is_base_of<DiscreteProcess<T1>, T1>::value) {
-        // A.DoContinuous(std::forward<Particle>(p), t, std::forward<Stack>(s));
+      if constexpr (std::is_base_of<ContinuousProcess<T1>, T1>::value ||
+                    is_process_sequence<T1>::value) {
         A.DoContinuous(p, t, s);
       }
-      if constexpr (!std::is_base_of<DiscreteProcess<T2>, T2>::value) {
-        // B.DoContinuous(std::forward<Particle>(p), t, std::forward<Stack>(s));
+      if constexpr (std::is_base_of<ContinuousProcess<T2>, T2>::value ||
+                    is_process_sequence<T2>::value) {
         B.DoContinuous(p, t, s);
       }
       return ret;
     }
 
     template <typename Particle, typename Track>
-    inline double MinStepLength(Particle& p, Track& track) const {
-      double min_length = std::numeric_limits<double>::infinity();
-      if constexpr (!std::is_base_of<DiscreteProcess<T1>, T1>::value) {
-	  min_length = std::min(min_length, A.MinStepLength(p,track));
-	}
-      if constexpr (!std::is_base_of<DiscreteProcess<T2>, T2>::value) {
-	  min_length = std::min(min_length, B.MinStepLength(p,track));
-	}
-      return min_length;
+    inline double MaxStepLength(Particle& p, Track& track) const {
+      double max_length = std::numeric_limits<double>::infinity();
+      if constexpr (std::is_base_of<ContinuousProcess<T1>, T1>::value ||
+                    is_process_sequence<T1>::value) {
+        max_length = std::min(max_length, A.MaxStepLength(p, track));
+      }
+      if constexpr (std::is_base_of<ContinuousProcess<T2>, T2>::value ||
+                    is_process_sequence<T2>::value) {
+        max_length = std::min(max_length, B.MaxStepLength(p, track));
+      }
+      return max_length;
     }
 
     template <typename Particle, typename Track>
@@ -205,64 +200,116 @@ namespace corsika::process {
     template <typename Particle, typename Track>
     inline double GetInverseInteractionLength(Particle& p, Track& t) const {
       double tot = 0;
-      if constexpr (!std::is_base_of<ContinuousProcess<T1>, T1>::value) {
+      if constexpr (std::is_base_of<InteractionProcess<T1>, T1>::value ||
+                    is_process_sequence<T1>::value) {
         tot += A.GetInverseInteractionLength(p, t);
       }
-      if constexpr (!std::is_base_of<ContinuousProcess<T2>, T2>::value) {
+      if constexpr (std::is_base_of<InteractionProcess<T2>, T2>::value ||
+                    is_process_sequence<T2>::value) {
         tot += B.GetInverseInteractionLength(p, t);
       }
       return tot;
     }
 
     template <typename Particle, typename Stack>
-    inline EProcessReturn DoDiscrete(Particle& p, Stack& s) const {
-      if constexpr (!std::is_base_of<ContinuousProcess<T1>, T1>::value) {
-        A.DoDiscrete(p, s);
+    inline EProcessReturn SelectInteraction(Particle& p, Stack& s,
+                                            const double lambda_inv_tot,
+                                            const double rndm_select,
+                                            double& lambda_inv_count) const {
+      if constexpr (is_process_sequence<T1>::value) {
+        // if A is a process sequence --> check inside
+        const EProcessReturn ret =
+            A.SelectInteraction(p, s, lambda_inv_count, rndm_select, lambda_inv_count);
+        // if A did succeed, stop routine
+        if (ret != EProcessReturn::eOk) { return ret; }
+      } else if constexpr (std::is_base_of<InteractionProcess<T1>, T1>::value) {
+        // if this is not a ContinuousProcess --> evaluate probability
+        lambda_inv_count += A.GetInverseInteractionLength(p, s);
+        // check if we should execute THIS process and then EXIT
+        if (rndm_select < lambda_inv_count / lambda_inv_tot) {
+          A.DoInteraction(p, s);
+          return EProcessReturn::eInteracted;
+        }
+      } // end branch A
+
+      if constexpr (is_process_sequence<T2>::value) {
+        // if A is a process sequence --> check inside
+        const EProcessReturn ret =
+            B.SelectInteraction(p, s, lambda_inv_count, rndm_select, lambda_inv_count);
+        // if A did succeed, stop routine
+        if (ret != EProcessReturn::eOk) { return ret; }
+      } else if constexpr (std::is_base_of<InteractionProcess<T2>, T2>::value) {
+        // if this is not a ContinuousProcess --> evaluate probability
+        lambda_inv_count += B.GetInverseInteractionLength(p, s);
+        // check if we should execute THIS process and then EXIT
+        if (rndm_select < lambda_inv_count / lambda_inv_tot) {
+          B.DoInteraction(p, s);
+          return EProcessReturn::eInteracted;
+        }
+      } // end branch A
+      return EProcessReturn::eOk;
+    }
+
+    template <typename Particle>
+    inline double GetTotalLifetime(Particle& p) const {
+      return 1. / GetInverseLifetime(p);
+    }
+
+    template <typename Particle>
+    inline double GetTotalInverseLifetime(Particle& p) const {
+      return GetInverseLifetime(p);
+    }
+
+    template <typename Particle>
+    inline double GetInverseLifetime(Particle& p) const {
+      double tot = 0;
+      if constexpr (std::is_base_of<DecayProcess<T1>, T1>::value ||
+                    is_process_sequence<T1>::value) {
+        tot += A.GetInverseLifetime(p);
       }
-      if constexpr (!std::is_base_of<ContinuousProcess<T2>, T2>::value) {
-        B.DoDiscrete(p, s);
+      if constexpr (std::is_base_of<DecayProcess<T2>, T2>::value ||
+                    is_process_sequence<T2>::value) {
+        tot += B.GetInverseLifetime(p);
       }
-      return EProcessReturn::eOk;
+      return tot;
     }
 
+    // select decay process
     template <typename Particle, typename Stack>
-      inline EProcessReturn SelectDiscrete(Particle& p, Stack& s,
-					   const double lambda_inv_tot,
-					   const double rndm_select,
-					   double& lambda_inv_count) const {
+    inline EProcessReturn SelectDecay(Particle& p, Stack& s, const double decay_inv_tot,
+                                      const double rndm_select,
+                                      double& decay_inv_count) const {
       if constexpr (is_process_sequence<T1>::value) {
-	  // if A is a process sequence --> check inside
-	  const EProcessReturn ret = A.SelectDiscrete(p, s, lambda_inv_count, rndm_select, lambda_inv_count);
-	  // if A did suceed, stop routine
-	  if (ret != EProcessReturn::eOk) {
-	    return ret;
-	  }
-	} else if constexpr (!std::is_base_of<ContinuousProcess<T1>, T1>::value) {
-	  // if this is not a ContinuousProcess --> evaluate probability
-	  lambda_inv_count += A.GetInverseInteractionLength(p, s);
-	  // check if we should execute THIS process and then EXIT
-	  if (rndm_select<lambda_inv_count/lambda_inv_tot) {
-	    A.DoDiscrete(p, s);
-	    return EProcessReturn::eInteracted;
-	  }
-	} // end branch A
-      
+        // if A is a process sequence --> check inside
+        const EProcessReturn ret =
+            A.SelectDecay(p, s, decay_inv_count, rndm_select, decay_inv_count);
+        // if A did succeed, stop routine
+        if (ret != EProcessReturn::eOk) { return ret; }
+      } else if constexpr (std::is_base_of<DecayProcess<T1>, T1>::value) {
+        // if this is not a ContinuousProcess --> evaluate probability
+        decay_inv_count += A.GetInverseLifetime(p);
+        // check if we should execute THIS process and then EXIT
+        if (rndm_select < decay_inv_count / decay_inv_tot) {
+          A.DoDecay(p, s);
+          return EProcessReturn::eDecayed;
+        }
+      } // end branch A
+
       if constexpr (is_process_sequence<T2>::value) {
-	  // if A is a process sequence --> check inside
-	  const EProcessReturn ret = B.SelectDiscrete(p, s, lambda_inv_count, rndm_select, lambda_inv_count);
-	  // if A did suceed, stop routine
-	  if (ret != EProcessReturn::eOk) {
-	    return ret;
-	  }
-	} else if constexpr (!std::is_base_of<ContinuousProcess<T2>, T2>::value) {
-	  // if this is not a ContinuousProcess --> evaluate probability
-	  lambda_inv_count += B.GetInverseInteractionLength(p, s);
-	  // check if we should execute THIS process and then EXIT
-	  if (rndm_select<lambda_inv_count/lambda_inv_tot) {
-	    B.DoDiscrete(p, s);
-	    return EProcessReturn::eInteracted;
-	  }
-	} // end branch A
+        // if A is a process sequence --> check inside
+        const EProcessReturn ret =
+            B.SelectDecay(p, s, decay_inv_count, rndm_select, decay_inv_count);
+        // if A did succeed, stop routine
+        if (ret != EProcessReturn::eOk) { return ret; }
+      } else if constexpr (std::is_base_of<DecayProcess<T2>, T2>::value) {
+        // if this is not a ContinuousProcess --> evaluate probability
+        decay_inv_count += B.GetInverseLifetime(p);
+        // check if we should execute THIS process and then EXIT
+        if (rndm_select < decay_inv_count / decay_inv_tot) {
+          B.DoDecay(p, s);
+          return EProcessReturn::eDecayed;
+        }
+      } // end branch B
       return EProcessReturn::eOk;
     }
 
@@ -273,8 +320,8 @@ namespace corsika::process {
     }
   };
 
-  /// the +operator assembles many BaseProcess, ContinuousProcess, and
-  /// DiscreteProcess objects into a ProcessSequence, all combinatorics
+  /// the + operator assembles many BaseProcess, ContinuousProcess, and
+  /// InteractionProcess objects into a ProcessSequence, all combinatorics
   /// must be allowed, this is why we define a macro to define all
   /// combinations here:
 
@@ -285,93 +332,26 @@ namespace corsika::process {
   }
 
   OPSEQ(BaseProcess, BaseProcess)
-  OPSEQ(BaseProcess, DiscreteProcess)
+  OPSEQ(BaseProcess, InteractionProcess)
   OPSEQ(BaseProcess, ContinuousProcess)
+  OPSEQ(BaseProcess, DecayProcess)
   OPSEQ(ContinuousProcess, BaseProcess)
-  OPSEQ(ContinuousProcess, DiscreteProcess)
+  OPSEQ(ContinuousProcess, InteractionProcess)
   OPSEQ(ContinuousProcess, ContinuousProcess)
-  OPSEQ(DiscreteProcess, BaseProcess)
-  OPSEQ(DiscreteProcess, DiscreteProcess)
-  OPSEQ(DiscreteProcess, ContinuousProcess)
-
-  /*
-    template <typename T1>
-    struct depth_lhs
-    {
-    static const int num = 0;
-    };
-
-
-
-    // terminating condition
-    template <typename T1, typename T2>
-    struct depth_lhs< Sequence<T1,T2> >
-    {
-    // try to expand the left node (T1) which might be a Sequence type
-    static const int num = 1 + depth_lhs<T1>::num;
-    };
-  */
-
-  /*
-    template <typename T1>
-    struct mat_ptrs
-    {
-    static const int num = 0;
-
-    inline static void
-    get_ptrs(const Process** ptrs, const T1& X)
-    {
-    ptrs[0] = reinterpret_cast<const Process*>(&X);
-    }
-    };
-
-
-    template <typename T1, typename T2>
-    struct mat_ptrs< Sequence<T1,T2> >
-    {
-    static const int num = 1 + mat_ptrs<T1>::num;
-
-    inline static void
-    get_ptrs(const Process** in_ptrs, const Sequence<T1,T2>& X)
-    {
-    // traverse the left node
-    mat_ptrs<T1>::get_ptrs(in_ptrs, X.A);
-    // get address of the matrix on the right node
-    in_ptrs[num] = reinterpret_cast<const Process*>(&X.B);
-    }
-    };
-  */
-
-  /*
-    template<typename T1, typename T2>
-    const Process&
-    Process::operator=(const Sequence<T1,T2>& X)
-    {
-    int N = 1 + depth_lhs< Sequence<T1,T2> >::num;
-    const Process* ptrs[N];
-    mat_ptrs< Sequence<T1,T2> >::get_ptrs(ptrs, X);
-    int r = ptrs[0]->rows;
-    int c = ptrs[0]->cols;
-    // ... check that all matrices have the same size ...
-    set_size(r, c);
-    for(int j=0; j<r*c; ++j)
-    {
-    double sum = ptrs[0]->data[j];
-    for(int i=1; i<N; ++i)
-    {
-    sum += ptrs[i]->data[j];
-    }
-    data[j] = sum;
-    }
-    return *this;
-    }
-  */
-
-        template<template<typename, typename> class T, typename A, typename B>
-      struct is_process_sequence< T<A,B> > 
-    {
-      static const bool value = true;
-    };
+  OPSEQ(ContinuousProcess, DecayProcess)
+  OPSEQ(InteractionProcess, BaseProcess)
+  OPSEQ(InteractionProcess, InteractionProcess)
+  OPSEQ(InteractionProcess, ContinuousProcess)
+  OPSEQ(InteractionProcess, DecayProcess)
+  OPSEQ(DecayProcess, BaseProcess)
+  OPSEQ(DecayProcess, InteractionProcess)
+  OPSEQ(DecayProcess, ContinuousProcess)
+  OPSEQ(DecayProcess, DecayProcess)
+
+  template <template <typename, typename> class T, typename A, typename B>
+  struct is_process_sequence<T<A, B> > {
+    static const bool value = true;
+  };
 
 } // namespace corsika::process
 
diff --git a/Framework/ProcessSequence/testProcessSequence.cc b/Framework/ProcessSequence/testProcessSequence.cc
index 008201b7e..af9bfeead 100644
--- a/Framework/ProcessSequence/testProcessSequence.cc
+++ b/Framework/ProcessSequence/testProcessSequence.cc
@@ -66,7 +66,7 @@ public:
   }
 };
 
-class Process1 : public DiscreteProcess<Process1> {
+class Process1 : public InteractionProcess<Process1> {
 public:
   Process1(const int v)
       : fV(v) {}
@@ -76,7 +76,7 @@ public:
     globalCount++;
   }
   template <typename D, typename S>
-  inline EProcessReturn DoDiscrete(D& d, S&) const {
+  inline EProcessReturn DoInteraction(D& d, S&) const {
     for (int i = 0; i < nData; ++i) d.p[i] += 1 + i;
     return EProcessReturn::eOk;
   }
@@ -84,7 +84,7 @@ public:
   int fV;
 };
 
-class Process2 : public DiscreteProcess<Process2> {
+class Process2 : public InteractionProcess<Process2> {
   int fV = 0;
 
 public:
@@ -96,8 +96,8 @@ public:
     globalCount++;
   }
   template <typename Particle, typename Stack>
-  inline EProcessReturn DoDiscrete(Particle&, Stack&) const {
-    cout << "Process2::DoDiscrete" << endl;
+  inline EProcessReturn DoInteraction(Particle&, Stack&) const {
+    cout << "Process2::DoInteraction" << endl;
     return EProcessReturn::eOk;
   }
   template <typename Particle, typename Track>
@@ -107,7 +107,7 @@ public:
   }
 };
 
-class Process3 : public DiscreteProcess<Process3> {
+class Process3 : public InteractionProcess<Process3> {
   int fV = 0;
 
 public:
@@ -119,8 +119,8 @@ public:
     globalCount++;
   }
   template <typename Particle, typename Stack>
-  inline EProcessReturn DoDiscrete(Particle&, Stack&) const {
-    cout << "Process3::DoDiscrete" << endl;
+  inline EProcessReturn DoInteraction(Particle&, Stack&) const {
+    cout << "Process3::DoInteraction" << endl;
     return EProcessReturn::eOk;
   }
   template <typename Particle, typename Track>
@@ -148,7 +148,28 @@ public:
   }
   // inline double MinStepLength(D& d) {
   template <typename Particle, typename Stack>
-  EProcessReturn DoDiscrete(Particle&, Stack&) const {
+  EProcessReturn DoInteraction(Particle&, Stack&) const {
+    return EProcessReturn::eOk;
+  }
+};
+
+class Decay1 : public DecayProcess<Decay1> {
+  int fV = 0;
+
+public:
+  Decay1(const int v)
+      : fV(v) {}
+  void Init() {
+    cout << "Decay1::Init" << endl;
+    assert(globalCount == fV);
+    globalCount++;
+  }
+  template <typename Particle>
+  double GetLifetime(Particle&) const {
+    return 1;
+  }
+  template <typename Particle, typename Stack>
+  EProcessReturn DoDecay(Particle&, Stack&) const {
     return EProcessReturn::eOk;
   }
 };
@@ -192,7 +213,21 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     double tot_inv = sequence2.GetTotalInverseInteractionLength(s, t);
     cout << "lambda_tot=" << tot << " lambda_tot_inv=" << tot_inv << endl;
   }
-  
+
+  SECTION("lifetime") {
+    ContinuousProcess1 cp1(0);
+    Process2 m2(1);
+    Process3 m3(2);
+    Decay1 d3(2);
+
+    DummyStack s;
+
+    const auto sequence2 = cp1 + m2 + m3 + d3;
+    double tot = sequence2.GetTotalLifetime(s);
+    double tot_inv = sequence2.GetTotalInverseLifetime(s);
+    cout << "lambda_tot=" << tot << " lambda_tot_inv=" << tot_inv << endl;
+  }
+
   SECTION("sectionTwo") {
 
     ContinuousProcess1 cp1(0);
@@ -213,14 +248,14 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
 
     sequence2.DoContinuous(p, t, s);
     cout << "-->dodisc" << endl;
-    sequence2.DoDiscrete(p, s);
+    // sequence2.DoInteraction(p, s);
     cout << "-->done" << endl;
 
     const int nLoop = 5;
     cout << "Running loop with n=" << nLoop << endl;
     for (int i = 0; i < nLoop; ++i) {
       sequence2.DoContinuous(p, t, s);
-      sequence2.DoDiscrete(p, s);
+      // sequence2.DoInteraction(p, s);
     }
     for (int i = 0; i < nData; i++) { cout << "data[" << i << "]=" << p.p[i] << endl; }
     cout << "done" << endl;
diff --git a/Framework/StackInterface/Stack.h b/Framework/StackInterface/Stack.h
index e71880ccf..f47c15d3d 100644
--- a/Framework/StackInterface/Stack.h
+++ b/Framework/StackInterface/Stack.h
@@ -67,9 +67,7 @@ namespace corsika::stack {
       IncrementSize();
       return StackIterator(*this, GetSize() - 1);
     }
-    void Copy(StackIterator& a, StackIterator& b) {
-      Copy(a.GetIndex(), b.GetIndex());
-    }
+    void Copy(StackIterator& a, StackIterator& b) { Copy(a.GetIndex(), b.GetIndex()); }
     /// delete this particle
     void Delete(StackIterator& p) {
       if (GetSize() == 0) { /*error*/
diff --git a/Processes/StackInspector/StackInspector.cc b/Processes/StackInspector/StackInspector.cc
index abf47afd1..1076803b8 100644
--- a/Processes/StackInspector/StackInspector.cc
+++ b/Processes/StackInspector/StackInspector.cc
@@ -17,8 +17,8 @@
 
 #include <corsika/setup/SetupTrajectory.h>
 
-#include <limits>
 #include <iostream>
+#include <limits>
 using namespace std;
 
 using namespace corsika;
@@ -57,7 +57,7 @@ process::EProcessReturn StackInspector<Stack>::DoContinuous(Particle&, setup::Tr
 }
 
 template <typename Stack>
-double StackInspector<Stack>::MinStepLength(Particle&, setup::Trajectory&) const {
+double StackInspector<Stack>::MaxStepLength(Particle&, setup::Trajectory&) const {
   return std::numeric_limits<double>::infinity();
 }
 
diff --git a/Processes/StackInspector/StackInspector.h b/Processes/StackInspector/StackInspector.h
index 38d5cfc01..58b9ec5eb 100644
--- a/Processes/StackInspector/StackInspector.h
+++ b/Processes/StackInspector/StackInspector.h
@@ -36,7 +36,7 @@ namespace corsika::process {
       EProcessReturn DoContinuous(Particle&, corsika::setup::Trajectory&, Stack& s) const;
 
       //      template <typename Particle>
-      double MinStepLength(Particle&, corsika::setup::Trajectory&) const;
+      double MaxStepLength(Particle&, corsika::setup::Trajectory&) const;
 
     private:
       bool fReport;
-- 
GitLab