diff --git a/corsika/detail/framework/core/Cascade.inl b/corsika/detail/framework/core/Cascade.inl
index 8cd5b2e39f3f87e303ee51aecf9de64ecdda9131..0e9161259de194737b19c46504645b79233c5b3d 100644
--- a/corsika/detail/framework/core/Cascade.inl
+++ b/corsika/detail/framework/core/Cascade.inl
@@ -10,6 +10,8 @@
 
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
+#include <corsika/framework/process/ContinuousProcessStepLength.hpp>
+#include <corsika/framework/process/ContinuousProcessIndex.hpp>
 #include <corsika/framework/random/ExponentialDistribution.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
 #include <corsika/framework/random/UniformRealDistribution.hpp>
@@ -118,7 +120,10 @@ namespace corsika {
                                                                           next_interact);
 
     // determine the maximum geometric step length
-    LengthType const continuous_max_dist = sequence_.getMaxStepLength(vParticle, step);
+    ContinuousProcessStepLength const continuousMaxStep =
+        sequence_.getMaxStepLength(vParticle, step);
+    LengthType const continuous_max_dist = continuousMaxStep;
+    ContinuousProcessIndex const limitingId = continuousMaxStep;
 
     // take minimum of geometry, interaction, decay for next step
     auto const min_distance =
@@ -142,7 +147,8 @@ namespace corsika {
     vParticle.setTime(vParticle.getTime() + step.getDuration());
 
     // apply all continuous processes on particle + track
-    if (sequence_.doContinuous(vParticle, step) == ProcessReturn::ParticleAbsorbed) {
+    if (sequence_.doContinuous(vParticle, step, limitingId) ==
+        ProcessReturn::ParticleAbsorbed) {
       CORSIKA_LOG_DEBUG("Cascade: delete absorbed particle PID={} E={} GeV",
                         vParticle.getPID(), vParticle.getEnergy() / 1_GeV);
       if (!vParticle.isErased()) vParticle.erase();
diff --git a/corsika/detail/framework/geometry/FourVector.inl b/corsika/detail/framework/geometry/FourVector.inl
index 6c0a039e5466ef46d2d3014b7e91a6f0621c922c..135790bfcfa83efaf1a78f218228d0c2557f5853 100644
--- a/corsika/detail/framework/geometry/FourVector.inl
+++ b/corsika/detail/framework/geometry/FourVector.inl
@@ -95,7 +95,7 @@ namespace corsika {
 
   template <typename TTimeType, typename TSpaceVecType>
   typename FourVector<TTimeType, TSpaceVecType>::norm_type
-      FourVector<TTimeType, TSpaceVecType>::operator*(FourVector const& b) {
+  FourVector<TTimeType, TSpaceVecType>::operator*(FourVector const& b) {
     if constexpr (std::is_same<time_type, decltype(std::declval<space_type>() / meter *
                                                    second)>::value)
       return timeLike_ * b.timeLike_ * constants::cSquared - spaceLike_.norm();
diff --git a/corsika/detail/framework/geometry/Plane.inl b/corsika/detail/framework/geometry/Plane.inl
index e158e04d36a59bbec08e1b3e2b7e6aebc76ee7ab..d32167cf138254a3325b4fe9503dd4884bdbde79 100644
--- a/corsika/detail/framework/geometry/Plane.inl
+++ b/corsika/detail/framework/geometry/Plane.inl
@@ -12,6 +12,8 @@
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/Vector.hpp>
 
+#include <sstream>
+
 namespace corsika {
 
   inline bool Plane::isAbove(Point const& vP) const {
@@ -26,4 +28,10 @@ namespace corsika {
 
   inline Plane::DimLessVec const& Plane::getNormal() const { return normal_; }
 
+  inline std::string Plane::asString() const {
+    std::ostringstream txt;
+    txt << "center=" << center_ << ", normal=" << normal_;
+    return txt.str();
+  }
+
 } // namespace corsika
diff --git a/corsika/detail/framework/geometry/Point.inl b/corsika/detail/framework/geometry/Point.inl
index 6c550c1ce716deb8e3004f775a81b9bebb182d75..45c6900f58ff152400e9cc44c7419aee8efbcf01 100644
--- a/corsika/detail/framework/geometry/Point.inl
+++ b/corsika/detail/framework/geometry/Point.inl
@@ -95,4 +95,10 @@ namespace corsika {
     return Vector<length_d>(cs, getCoordinates() - pB.getCoordinates(cs));
   }
 
+  inline std::ostream& operator<<(std::ostream& os, corsika::Point const& p) {
+    auto const& qv = p.getCoordinates();
+    os << qv << " (ref:" << fmt::ptr(p.getCoordinateSystem()) << ")";
+    return os;
+  }
+
 } // namespace corsika
diff --git a/corsika/detail/framework/geometry/QuantityVector.inl b/corsika/detail/framework/geometry/QuantityVector.inl
index 9df35aab4827ecf034697b9554498eb45f7fb428..6ba02e4f8d4bd8e8cec5231d47ffb23d87931430 100644
--- a/corsika/detail/framework/geometry/QuantityVector.inl
+++ b/corsika/detail/framework/geometry/QuantityVector.inl
@@ -145,7 +145,7 @@ namespace corsika {
 
   template <typename TDimension>
   inline std::ostream& operator<<(std::ostream& os,
-                                  corsika::QuantityVector<TDimension> const qv) {
+                                  corsika::QuantityVector<TDimension> const& qv) {
     using quantity_type = phys::units::quantity<TDimension, double>;
 
     os << '(' << qv.eigenVector_(0) << ' ' << qv.eigenVector_(1) << ' '
diff --git a/corsika/detail/framework/geometry/Vector.inl b/corsika/detail/framework/geometry/Vector.inl
index cbfd597b3e556fc04c03b0829b4f949bcb459ae8..ff968693f8542ef2f95629c4d7ca7050b406a549 100644
--- a/corsika/detail/framework/geometry/Vector.inl
+++ b/corsika/detail/framework/geometry/Vector.inl
@@ -228,4 +228,12 @@ namespace corsika {
                                                   bareResult);
   }
 
+  template <typename TDimension>
+  inline std::ostream& operator<<(std::ostream& os,
+                                  corsika::Vector<TDimension> const& v) {
+    auto const& qv = v.getComponents();
+    os << qv << " (ref:" << fmt::ptr(v.getCoordinateSystem()) << ")";
+    return os;
+  }
+
 } // namespace corsika
diff --git a/corsika/detail/framework/process/ProcessSequence.inl b/corsika/detail/framework/process/ProcessSequence.inl
index 7759270ee0b0cfe0fc416d2c5923b3b9dc1498e3..19056ad6c696c8c74268742e7f1447bdca0be856 100644
--- a/corsika/detail/framework/process/ProcessSequence.inl
+++ b/corsika/detail/framework/process/ProcessSequence.inl
@@ -12,6 +12,8 @@
 #include <corsika/framework/process/BaseProcess.hpp>
 #include <corsika/framework/process/BoundaryCrossingProcess.hpp>
 #include <corsika/framework/process/ContinuousProcess.hpp>
+#include <corsika/framework/process/ContinuousProcessStepLength.hpp>
+#include <corsika/framework/process/ContinuousProcessIndex.hpp>
 #include <corsika/framework/process/DecayProcess.hpp>
 #include <corsika/framework/process/InteractionProcess.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
@@ -24,11 +26,14 @@
 
 namespace corsika {
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TParticle>
-  ProcessReturn ProcessSequence<TProcess1, TProcess2>::doBoundaryCrossing(
-      TParticle& particle, typename TParticle::node_type const& from,
-      typename TParticle::node_type const& to) {
+  ProcessReturn ProcessSequence<
+      TProcess1, TProcess2, IndexStart, IndexProcess1,
+      IndexProcess2>::doBoundaryCrossing(TParticle& particle,
+                                         typename TParticle::node_type const& from,
+                                         typename TParticle::node_type const& to) {
     ProcessReturn ret = ProcessReturn::Ok;
 
     if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process1_type>,
@@ -46,25 +51,38 @@ namespace corsika {
     return ret;
   }
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TParticle, typename TTrack>
-  ProcessReturn ProcessSequence<TProcess1, TProcess2>::doContinuous(TParticle& particle,
-                                                                    TTrack& vT) {
+  ProcessReturn
+  ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1, IndexProcess2>::
+      doContinuous(TParticle& particle, TTrack& vT,
+                   [[maybe_unused]] ContinuousProcessIndex const limitId) {
     ProcessReturn ret = ProcessReturn::Ok;
-    if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>, process1_type> ||
-                  t1ProcSeq) {
-      ret |= A_.doContinuous(particle, vT);
+    if constexpr (t1ProcSeq) {
+      ret |= A_.doContinuous(particle, vT, limitId);
+    } else if constexpr (is_continuous_process_v<process1_type>) {
+      ret |=
+          A_.doContinuous(particle, vT, limitId == ContinuousProcessIndex(IndexProcess1));
     }
-    if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>, process2_type> ||
-                  t2ProcSeq) {
-      if (!isAbsorbed(ret)) { ret |= B_.doContinuous(particle, vT); }
+
+    if constexpr (t2ProcSeq) {
+      if (!isAbsorbed(ret)) { ret |= B_.doContinuous(particle, vT, limitId); }
+    } else if constexpr (is_continuous_process_v<process2_type>) {
+      if (!isAbsorbed(ret)) {
+        ret |= B_.doContinuous(particle, vT,
+                               limitId == ContinuousProcessIndex(IndexProcess2));
+      }
     }
+
     return ret;
   }
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TSecondaries>
-  void ProcessSequence<TProcess1, TProcess2>::doSecondaries(TSecondaries& vS) {
+  void ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                       IndexProcess2>::doSecondaries(TSecondaries& vS) {
     if constexpr (std::is_base_of_v<SecondariesProcess<process1_type>, process1_type> ||
                   t1ProcSeq) {
       A_.doSecondaries(vS);
@@ -75,8 +93,10 @@ namespace corsika {
     }
   }
 
-  template <typename TProcess1, typename TProcess2>
-  bool ProcessSequence<TProcess1, TProcess2>::checkStep() {
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
+  bool ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                       IndexProcess2>::checkStep() {
     bool ret = false;
     if constexpr (std::is_base_of_v<StackProcess<process1_type>, process1_type> ||
                   (t1ProcSeq && !t1SwitchProcSeq)) {
@@ -89,9 +109,11 @@ namespace corsika {
     return ret;
   }
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TStack>
-  void ProcessSequence<TProcess1, TProcess2>::doStack(TStack& stack) {
+  void ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                       IndexProcess2>::doStack(TStack& stack) {
     if constexpr (std::is_base_of_v<StackProcess<process1_type>, process1_type> ||
                   (t1ProcSeq && !t1SwitchProcSeq)) {
       if (A_.checkStep()) { A_.doStack(stack); }
@@ -102,30 +124,52 @@ namespace corsika {
     }
   }
 
-  template <typename TProcess1, typename TProcess2>
+  /**
+   * Calculate the maximum allowed length of the next tracking step, based on all
+   * ContinuousProcess-es
+   *
+   * The maximum allowed step length is the minimum of the allowed track lenght over all
+   * ContinuousProcess-es in the ProcessSequence.
+   *
+   * \return: ContinuousProcessStepLength which contains the step length itself in
+   *          LengthType, and a unique identifier of the related ContinuousProcess.
+   **/
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TParticle, typename TTrack>
-  LengthType ProcessSequence<TProcess1, TProcess2>::getMaxStepLength(TParticle& particle,
-                                                                     TTrack& vTrack) {
-    LengthType max_length = // if no other process in the sequence implements it
-        std::numeric_limits<double>::infinity() * meter;
+  ContinuousProcessStepLength
+  ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                  IndexProcess2>::getMaxStepLength(TParticle& particle, TTrack& vTrack) {
+    // if no other process in the sequence implements it
+    ContinuousProcessStepLength max_length(std::numeric_limits<double>::infinity() *
+                                           meter);
 
-    if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>, process1_type> ||
-                  t1ProcSeq) {
-      LengthType const len = A_.getMaxStepLength(particle, vTrack);
-      max_length = std::min(max_length, len);
+    if constexpr (t1ProcSeq) {
+      ContinuousProcessStepLength const step = A_.getMaxStepLength(particle, vTrack);
+      max_length = std::min(max_length, step);
+    } else if constexpr (is_continuous_process_v<process1_type>) {
+      ContinuousProcessStepLength const step(A_.getMaxStepLength(particle, vTrack),
+                                             ContinuousProcessIndex(IndexProcess1));
+      max_length = std::min(max_length, step);
     }
-    if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>, process2_type> ||
-                  t2ProcSeq) {
-      LengthType const len = B_.getMaxStepLength(particle, vTrack);
-      max_length = std::min(max_length, len);
+    //      return ContinuousProcessStepLength(std::min(max_length, len), IndexProcess1);
+    if constexpr (t2ProcSeq) {
+      ContinuousProcessStepLength const step = B_.getMaxStepLength(particle, vTrack);
+      max_length = std::min(max_length, step);
+    } else if constexpr (is_continuous_process_v<process2_type>) {
+      ContinuousProcessStepLength const step(B_.getMaxStepLength(particle, vTrack),
+                                             ContinuousProcessIndex(IndexProcess2));
+      max_length = std::min(max_length, step);
     }
     return max_length;
   }
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TParticle>
-  InverseGrammageType ProcessSequence<TProcess1, TProcess2>::getInverseInteractionLength(
-      TParticle&& particle) {
+  InverseGrammageType
+  ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                  IndexProcess2>::getInverseInteractionLength(TParticle&& particle) {
 
     InverseGrammageType tot = 0 * meter * meter / gram; // default value
 
@@ -140,11 +184,14 @@ namespace corsika {
     return tot;
   }
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TSecondaryView>
-  inline ProcessReturn ProcessSequence<TProcess1, TProcess2>::selectInteraction(
-      TSecondaryView& view, [[maybe_unused]] InverseGrammageType lambda_inv_select,
-      [[maybe_unused]] InverseGrammageType lambda_inv_sum) {
+  inline ProcessReturn
+  ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1, IndexProcess2>::
+      selectInteraction(TSecondaryView& view,
+                        [[maybe_unused]] InverseGrammageType lambda_inv_select,
+                        [[maybe_unused]] InverseGrammageType lambda_inv_sum) {
 
     // TODO: add check for lambda_inv_select>lambda_inv_tot
 
@@ -182,10 +229,12 @@ namespace corsika {
     return ProcessReturn::Ok;
   }
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   template <typename TParticle>
-  inline InverseTimeType ProcessSequence<TProcess1, TProcess2>::getInverseLifetime(
-      TParticle&& particle) {
+  inline InverseTimeType
+  ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                  IndexProcess2>::getInverseLifetime(TParticle&& particle) {
 
     InverseTimeType tot = 0 / second; // default value
 
@@ -200,12 +249,15 @@ namespace corsika {
     return tot;
   }
 
-  template <typename TProcess1, typename TProcess2>
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
   // select decay process
   template <typename TSecondaryView>
-  inline ProcessReturn ProcessSequence<TProcess1, TProcess2>::selectDecay(
-      TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select,
-      [[maybe_unused]] InverseTimeType decay_inv_sum) {
+  inline ProcessReturn ProcessSequence<
+      TProcess1, TProcess2, IndexStart, IndexProcess1,
+      IndexProcess2>::selectDecay(TSecondaryView& view,
+                                  [[maybe_unused]] InverseTimeType decay_inv_select,
+                                  [[maybe_unused]] InverseTimeType decay_inv_sum) {
 
     // TODO: add check for decay_inv_select>decay_inv_tot
 
diff --git a/corsika/detail/framework/process/SwitchProcessSequence.inl b/corsika/detail/framework/process/SwitchProcessSequence.inl
index 62d33995afefe53aa3865df31969413d18a63a99..2eadc8782bf164ee7074c97db4f35d37db2abbd9 100644
--- a/corsika/detail/framework/process/SwitchProcessSequence.inl
+++ b/corsika/detail/framework/process/SwitchProcessSequence.inl
@@ -12,6 +12,8 @@
 #include <corsika/framework/process/ProcessTraits.hpp>
 #include <corsika/framework/process/BoundaryCrossingProcess.hpp>
 #include <corsika/framework/process/ContinuousProcess.hpp>
+#include <corsika/framework/process/ContinuousProcessStepLength.hpp>
+#include <corsika/framework/process/ContinuousProcessIndex.hpp>
 #include <corsika/framework/process/DecayProcess.hpp>
 #include <corsika/framework/process/InteractionProcess.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
@@ -25,10 +27,14 @@
 
 namespace corsika {
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   template <typename TParticle, typename TVTNType>
-  ProcessReturn SwitchProcessSequence<TProcess1, TProcess2, TSelect>::doBoundaryCrossing(
-      TParticle& particle, TVTNType const& from, TVTNType const& to) {
+  ProcessReturn
+  SwitchProcessSequence<TProcess1, TProcess2, TSelect, IndexStart, IndexProcess1,
+                        IndexProcess2>::doBoundaryCrossing(TParticle& particle,
+                                                           TVTNType const& from,
+                                                           TVTNType const& to) {
     switch (select_(particle)) {
       case SwitchResult::First: {
         if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process1_type>,
@@ -50,24 +56,27 @@ namespace corsika {
     return ProcessReturn::Ok;
   }
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   template <typename TParticle, typename TTrack>
-  inline ProcessReturn SwitchProcessSequence<TProcess1, TProcess2, TSelect>::doContinuous(
-      TParticle& particle, TTrack& vT) {
+  inline ProcessReturn SwitchProcessSequence<
+      TProcess1, TProcess2, TSelect, IndexStart, IndexProcess1,
+      IndexProcess2>::doContinuous(TParticle& particle, TTrack& vT,
+                                   ContinuousProcessIndex const idLimit) {
     switch (select_(particle)) {
       case SwitchResult::First: {
-        if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>,
-                                        process1_type> ||
-                      t1ProcSeq) {
-          return A_.doContinuous(particle, vT);
+        if constexpr (t1ProcSeq) { return A_.doContinuous(particle, vT, idLimit); }
+        if constexpr (is_continuous_process_v<process1_type>) {
+          return A_.doContinuous(particle, vT,
+                                 idLimit == ContinuousProcessIndex(IndexProcess1));
         }
         break;
       }
       case SwitchResult::Second: {
-        if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>,
-                                        process2_type> ||
-                      t2ProcSeq) {
-          return B_.doContinuous(particle, vT);
+        if constexpr (t2ProcSeq) { return B_.doContinuous(particle, vT, idLimit); }
+        if constexpr (is_continuous_process_v<process2_type>) {
+          return B_.doContinuous(particle, vT,
+                                 idLimit == ContinuousProcessIndex(IndexProcess2));
         }
         break;
       }
@@ -75,10 +84,12 @@ namespace corsika {
     return ProcessReturn::Ok;
   }
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   template <typename TSecondaries>
-  inline void SwitchProcessSequence<TProcess1, TProcess2, TSelect>::doSecondaries(
-      TSecondaries& vS) {
+  inline void
+  SwitchProcessSequence<TProcess1, TProcess2, TSelect, IndexStart, IndexProcess1,
+                        IndexProcess2>::doSecondaries(TSecondaries& vS) {
     const auto& particle = vS.parent();
     switch (select_(particle)) {
       case SwitchResult::First: {
@@ -100,39 +111,42 @@ namespace corsika {
     }
   }
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   template <typename TParticle, typename TTrack>
-  inline LengthType SwitchProcessSequence<TProcess1, TProcess2,
-                                          TSelect>::getMaxStepLength(TParticle& particle,
-                                                                     TTrack& vTrack) {
+  inline ContinuousProcessStepLength
+  SwitchProcessSequence<TProcess1, TProcess2, TSelect, IndexStart, IndexProcess1,
+                        IndexProcess2>::getMaxStepLength(TParticle& particle,
+                                                         TTrack& vTrack) {
     switch (select_(particle)) {
       case SwitchResult::First: {
-        if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>,
-                                        process1_type> ||
-                      t1ProcSeq) {
-          return A_.getMaxStepLength(particle, vTrack);
+        if constexpr (t1ProcSeq) { return A_.getMaxStepLength(particle, vTrack); }
+        if constexpr (is_continuous_process_v<process1_type>) {
+          return ContinuousProcessStepLength(A_.getMaxStepLength(particle, vTrack),
+                                             ContinuousProcessIndex(IndexProcess1));
         }
         break;
       }
       case SwitchResult::Second: {
-        if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>,
-                                        process2_type> ||
-                      t2ProcSeq) {
-          return B_.getMaxStepLength(particle, vTrack);
+        if constexpr (t2ProcSeq) { return B_.getMaxStepLength(particle, vTrack); }
+        if constexpr (is_continuous_process_v<process2_type>) {
+          return ContinuousProcessStepLength(B_.getMaxStepLength(particle, vTrack),
+                                             ContinuousProcessIndex(IndexProcess2));
         }
         break;
       }
     }
 
     // if no other process in the sequence implements it
-    return std::numeric_limits<double>::infinity() * meter;
+    return ContinuousProcessStepLength(std::numeric_limits<double>::infinity() * meter);
   }
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   template <typename TParticle>
-  inline InverseGrammageType
-  SwitchProcessSequence<TProcess1, TProcess2, TSelect>::getInverseInteractionLength(
-      TParticle&& particle) {
+  inline InverseGrammageType SwitchProcessSequence<
+      TProcess1, TProcess2, TSelect, IndexStart, IndexProcess1,
+      IndexProcess2>::getInverseInteractionLength(TParticle&& particle) {
 
     switch (select_(particle)) {
       case SwitchResult::First: {
@@ -155,12 +169,14 @@ namespace corsika {
     return 0 * meter * meter / gram; // default value
   }
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   template <typename TSecondaryView>
-  inline ProcessReturn
-  SwitchProcessSequence<TProcess1, TProcess2, TSelect>::selectInteraction(
-      TSecondaryView& view, [[maybe_unused]] InverseGrammageType lambda_inv_select,
-      [[maybe_unused]] InverseGrammageType lambda_inv_sum) {
+  inline ProcessReturn SwitchProcessSequence<TProcess1, TProcess2, TSelect, IndexStart,
+                                             IndexProcess1, IndexProcess2>::
+      selectInteraction(TSecondaryView& view,
+                        [[maybe_unused]] InverseGrammageType lambda_inv_select,
+                        [[maybe_unused]] InverseGrammageType lambda_inv_sum) {
     switch (select_(view.parent())) {
       case SwitchResult::First: {
         if constexpr (t1ProcSeq) {
@@ -203,11 +219,12 @@ namespace corsika {
     return ProcessReturn::Ok;
   }
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   template <typename TParticle>
   inline InverseTimeType
-  SwitchProcessSequence<TProcess1, TProcess2, TSelect>::getInverseLifetime(
-      TParticle&& particle) {
+  SwitchProcessSequence<TProcess1, TProcess2, TSelect, IndexStart, IndexProcess1,
+                        IndexProcess2>::getInverseLifetime(TParticle&& particle) {
 
     switch (select_(particle)) {
       case SwitchResult::First: {
@@ -229,12 +246,15 @@ namespace corsika {
     return 0 / second; // default value
   }
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect, int IndexStart,
+            int IndexProcess1, int IndexProcess2>
   // select decay process
   template <typename TSecondaryView>
-  inline ProcessReturn SwitchProcessSequence<TProcess1, TProcess2, TSelect>::selectDecay(
-      TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select,
-      [[maybe_unused]] InverseTimeType decay_inv_sum) {
+  inline ProcessReturn SwitchProcessSequence<
+      TProcess1, TProcess2, TSelect, IndexStart, IndexProcess1,
+      IndexProcess2>::selectDecay(TSecondaryView& view,
+                                  [[maybe_unused]] InverseTimeType decay_inv_select,
+                                  [[maybe_unused]] InverseTimeType decay_inv_sum) {
     switch (select_(view.parent())) {
       case SwitchResult::First: {
         if constexpr (t1ProcSeq) {
@@ -277,11 +297,23 @@ namespace corsika {
     return ProcessReturn::Ok;
   }
 
+  /*
+  /// traits marker to identify objectas ProcessSequence
+  template <typename TProcess1, typename TProcess2, typename TSelect>
+  struct is_process_sequence<ProcessSequence<typename std::decay_t<TProcess1>,
+                                                   typename std::decay_t<TProcess2>,
+                                                   typename std::decay_t<TSelect>>>
+      : std::true_type {};
+  */
   /// traits marker to identify objectas ProcessSequence
   template <typename TProcess1, typename TProcess2, typename TSelect>
   struct is_process_sequence<SwitchProcessSequence<TProcess1, TProcess2, TSelect>>
       : std::true_type {};
 
+  template <typename TProcess1, typename TProcess2, typename TSelect>
+  struct is_process_sequence<SwitchProcessSequence<TProcess1, TProcess2, TSelect>&>
+      : std::true_type {};
+
   /// traits marker to identify objectas SwitchProcessSequence
   template <typename TProcess1, typename TProcess2, typename TSelect>
   struct is_switch_process_sequence<SwitchProcessSequence<TProcess1, TProcess2, TSelect>>
diff --git a/corsika/detail/media/WeightProvider.inl b/corsika/detail/media/WeightProvider.inl
index af9849aa3ca75b9bdaeefc661d56232f1ab895f4..c075b236350127c9978fb7c08d87ed035292e5a8 100644
--- a/corsika/detail/media/WeightProvider.inl
+++ b/corsika/detail/media/WeightProvider.inl
@@ -20,7 +20,7 @@ namespace corsika {
 
   template <class AConstIterator, class BConstIterator>
   typename WeightProviderIterator<AConstIterator, BConstIterator>::value_type
-      WeightProviderIterator<AConstIterator, BConstIterator>::operator*() const {
+  WeightProviderIterator<AConstIterator, BConstIterator>::operator*() const {
     return ((*aIter_) * (*bIter_)).magnitude();
   }
 
diff --git a/corsika/detail/modules/LongitudinalProfile.inl b/corsika/detail/modules/LongitudinalProfile.inl
index d18813c26f08a7fc42dfaa0042579943b3185d69..df6bb471dbb04c4dfeff3a9c62cc86f3501f2ec1 100644
--- a/corsika/detail/modules/LongitudinalProfile.inl
+++ b/corsika/detail/modules/LongitudinalProfile.inl
@@ -27,7 +27,7 @@ namespace corsika {
 
   template <typename TParticle, typename TTrack>
   ProcessReturn LongitudinalProfile::doContinuous(TParticle const& vP,
-                                                  TTrack const& vTrack) {
+                                                  TTrack const& vTrack, bool const) {
     auto const pid = vP.getPID();
 
     GrammageType const grammageStart = shower_axis_.getProjectedX(vTrack.getPosition(0));
diff --git a/corsika/detail/modules/ObservationPlane.inl b/corsika/detail/modules/ObservationPlane.inl
index e266a357f3c89351d6126de767bc09978717a34f..74c29b336dc26a3837b036db5bf3af895feb96f4 100644
--- a/corsika/detail/modules/ObservationPlane.inl
+++ b/corsika/detail/modules/ObservationPlane.inl
@@ -7,6 +7,8 @@
  */
 
 #include <corsika/modules/ObservationPlane.hpp>
+#include <corsika/framework/core/Logging.hpp>
+#include <corsika/setup/SetupTrajectory.hpp>
 
 #include <fstream>
 
@@ -26,27 +28,22 @@ namespace corsika {
   }
 
   ProcessReturn ObservationPlane::doContinuous(
-      corsika::setup::Stack::particle_type& particle,
-      corsika::setup::Trajectory& trajectory) {
-    TimeType const timeOfIntersection =
-        (plane_.getCenter() - trajectory.getPosition(0)).dot(plane_.getNormal()) /
-        trajectory.getVelocity(0).dot(plane_.getNormal());
+      corsika::setup::Stack::particle_type& particle, corsika::setup::Trajectory&,
+      bool const stepLimit) {
 
-    if (timeOfIntersection < TimeType::zero()) { return ProcessReturn::Ok; }
+    /*
+       The current step did not yet reach the ObservationPlane, do nothing now and wait:
+     */
+    if (!stepLimit) { return ProcessReturn::Ok; }
 
-    if (plane_.isAbove(trajectory.getPosition(0)) ==
-        plane_.isAbove(trajectory.getPosition(1))) {
-      return ProcessReturn::Ok;
-    }
-
-    const auto energy = particle.getEnergy();
-    auto const displacement = trajectory.getPosition(1) - plane_.getCenter();
+    HEPEnergyType const energy = particle.getEnergy();
+    Point const pointOfIntersection = particle.getPosition();
+    Vector const displacement = pointOfIntersection - plane_.getCenter();
 
     outputStream_ << static_cast<int>(get_PDG(particle.getPID())) << ' ' << energy / 1_eV
                   << ' ' << displacement.dot(xAxis_) / 1_m << ' '
                   << displacement.dot(yAxis_) / 1_m
-                  << (trajectory.getPosition(1) - plane_.getCenter()).getNorm() / 1_m
-                  << std::endl;
+                  << (pointOfIntersection - plane_.getCenter()).getNorm() / 1_m << '\n';
 
     if (deleteOnHit_) {
       count_ground_++;
@@ -59,84 +56,37 @@ namespace corsika {
   }
 
   LengthType ObservationPlane::getMaxStepLength(
-      corsika::setup::Stack::particle_type const& vParticle,
+      corsika::setup::Stack::particle_type const& particle,
       corsika::setup::Trajectory const& trajectory) {
 
-    int chargeNumber;
-    if (is_nucleus(vParticle.getPID())) {
-      chargeNumber = vParticle.getNuclearZ();
-    } else {
-      chargeNumber = get_charge_number(vParticle.getPID());
-    }
-    auto const* currentLogicalVolumeNode = vParticle.getNode();
-    auto magneticfield = currentLogicalVolumeNode->getModelProperties().getMagneticField(
-        vParticle.getPosition());
-    auto direction = trajectory.getVelocity(0).normalized();
-
-    if (chargeNumber != 0 &&
-        abs(plane_.getNormal().dot(
-            trajectory.getLine().getVelocity().cross(magneticfield))) *
-                1_s / 1_m / 1_T >
-            1e-6) {
-      auto const* currentLogicalVolumeNode = vParticle.getNode();
-      auto magneticfield =
-          currentLogicalVolumeNode->getModelProperties().getMagneticField(
-              vParticle.getPosition());
-      auto k =
-          chargeNumber * constants::c * 1_eV / (vParticle.getMomentum().getNorm() * 1_V);
-
-      if (direction.dot(plane_.getNormal()) * direction.dot(plane_.getNormal()) -
-              (plane_.getNormal().dot(trajectory.getPosition(0) - plane_.getCenter()) *
-               plane_.getNormal().dot(direction.cross(magneticfield)) * 2 * k) <
-          0) {
-        return std::numeric_limits<double>::infinity() * 1_m;
-      }
-
-      LengthType MaxStepLength1 =
-          (sqrt(direction.dot(plane_.getNormal()) * direction.dot(plane_.getNormal()) -
-                (plane_.getNormal().dot(trajectory.getPosition(0) - plane_.getCenter()) *
-                 plane_.getNormal().dot(direction.cross(magneticfield)) * 2 * k)) -
-           direction.dot(plane_.getNormal()) / direction.getNorm()) /
-          (plane_.getNormal().dot(direction.cross(magneticfield)) * k);
-
-      LengthType MaxStepLength2 =
-          (-sqrt(direction.dot(plane_.getNormal()) * direction.dot(plane_.getNormal()) -
-                 (plane_.getNormal().dot(trajectory.getPosition(0) - plane_.getCenter()) *
-                  plane_.getNormal().dot(direction.cross(magneticfield)) * 2 * k)) -
-           direction.dot(plane_.getNormal()) / direction.getNorm()) /
-          (plane_.getNormal().dot(direction.cross(magneticfield)) * k);
-
-      if (MaxStepLength1 <= 0_m && MaxStepLength2 <= 0_m) {
-        return std::numeric_limits<double>::infinity() * 1_m;
-      } else if (MaxStepLength1 <= 0_m || MaxStepLength2 < MaxStepLength1) {
-        std::cout << " steplength to obs plane 2: " << MaxStepLength2 << std::endl;
-        return MaxStepLength2 *
-               (direction + direction.cross(magneticfield) * MaxStepLength2 * k / 2)
-                   .getNorm() *
-               1.001;
-      } else if (MaxStepLength2 <= 0_m || MaxStepLength1 < MaxStepLength2) {
-        std::cout << " steplength to obs plane 1: " << MaxStepLength1 << std::endl;
-        return MaxStepLength1 *
-               (direction + direction.cross(magneticfield) * MaxStepLength2 * k / 2)
-                   .getNorm() *
-               1.001;
-      }
-    }
+    auto const& volumeNode = particle.getNode();
+
+    typedef typename std::remove_const_t<
+        std::remove_reference_t<decltype(volumeNode->getModelProperties())>>
+        medium_type;
+
+    Intersections const intersection =
+        setup::Tracking::intersect<corsika::setup::Stack::particle_type, medium_type>(
+            particle, plane_, volumeNode->getModelProperties());
 
-    TimeType const timeOfIntersection =
-        (plane_.getCenter() - trajectory.getPosition(0)).dot(plane_.getNormal()) /
-        trajectory.getVelocity(0).dot(plane_.getNormal());
+    TimeType const timeOfIntersection = intersection.getEntry();
+
+    CORSIKA_LOG_TRACE("particle={}, pos={}, dir={}, plane={}, timeOfIntersection={}",
+                      particle.asString(), particle.getPosition(),
+                      particle.getDirection(), plane_.asString(), timeOfIntersection);
 
     if (timeOfIntersection < TimeType::zero()) {
       return std::numeric_limits<double>::infinity() * 1_m;
     }
+    if (timeOfIntersection > trajectory.getDuration()) {
+      return std::numeric_limits<double>::infinity() * 1_m;
+    }
 
     double const fractionOfIntersection = timeOfIntersection / trajectory.getDuration();
 
     auto const pointOfIntersection = trajectory.getPosition(fractionOfIntersection);
-    auto dist = (trajectory.getPosition(0) - pointOfIntersection).getNorm() * 1.0001;
-    CORSIKA_LOG_TRACE("ObservationPlane w/o magnetic field: getMaxStepLength l={} m",
-                      dist / 1_m);
+    auto dist = (trajectory.getPosition(0) - pointOfIntersection).getNorm();
+    CORSIKA_LOG_TRACE("ObservationPlane: getMaxStepLength l={} m", dist / 1_m);
     return dist;
   }
 
diff --git a/corsika/detail/modules/ParticleCut.inl b/corsika/detail/modules/ParticleCut.inl
index 7a22b4d719beddef778acab9861b65ba7578217f..3fd882225fec411ced5ef823dff9b35fcea0ef56 100644
--- a/corsika/detail/modules/ParticleCut.inl
+++ b/corsika/detail/modules/ParticleCut.inl
@@ -145,7 +145,7 @@ namespace corsika {
   }
 
   ProcessReturn ParticleCut::doContinuous(corsika::setup::Stack::particle_type& particle,
-                                          corsika::setup::Trajectory const&) {
+                                          corsika::setup::Trajectory const&, bool const) {
     CORSIKA_LOG_TRACE("ParticleCut::DoContinuous");
     if (checkCutParticle(particle)) {
       CORSIKA_LOG_TRACE("removing during continuous");
diff --git a/corsika/detail/modules/TrackWriter.inl b/corsika/detail/modules/TrackWriter.inl
index 27b47cf6571c23975842fdec279e582ed30ce775..c6f72edf437b4d49cf728cf3ab16b358176f78f9 100644
--- a/corsika/detail/modules/TrackWriter.inl
+++ b/corsika/detail/modules/TrackWriter.inl
@@ -31,7 +31,8 @@ namespace corsika {
   }
 
   template <typename TParticle, typename TTrack>
-  ProcessReturn TrackWriter::doContinuous(const TParticle& vP, const TTrack& vT) {
+  ProcessReturn TrackWriter::doContinuous(const TParticle& vP, const TTrack& vT,
+                                          bool const) {
     auto const start = vT.getPosition(0).getCoordinates();
     auto const delta = vT.getPosition(1).getCoordinates() - start;
     auto const pdg = static_cast<int>(get_PDG(vP.getPID()));
diff --git a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl
index 89fe81c7bee6316b97c9cd78322dfef247eade3d..cbabb0892dc3c4880c74d910ddef99ce7036736c 100644
--- a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl
+++ b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl
@@ -140,7 +140,7 @@ namespace corsika {
   }
 
   ProcessReturn BetheBlochPDG::doContinuous(setup::Stack::particle_type& p,
-                                            setup::Trajectory const& t) {
+                                            setup::Trajectory const& t, bool const) {
     if (p.getChargeNumber() == 0) return ProcessReturn::Ok;
 
     GrammageType const dX =
@@ -174,7 +174,7 @@ namespace corsika {
     // slightly smaller than emCut since, either this Step is limited
     // by energy_lim, then the particle is stopped in a very short
     // range (before doing anythin else) and is then removed
-    // instantly. The exact position where it reaches emCut is not
+    // instantly. The exact 3D position where it reaches emCut is not very
     // important, the important fact is that its E_kin is zero
     // afterwards.
     //
diff --git a/corsika/detail/modules/proposal/ContinuousProcess.inl b/corsika/detail/modules/proposal/ContinuousProcess.inl
index 8bfbd705b8bb0dfc19d1e7efe79252aa5a6a69be..26f604c998efa2360d4da94adab53e9fac4d28b9 100644
--- a/corsika/detail/modules/proposal/ContinuousProcess.inl
+++ b/corsika/detail/modules/proposal/ContinuousProcess.inl
@@ -88,7 +88,7 @@ namespace corsika::proposal {
 
   template <>
   ProcessReturn ContinuousProcess::doContinuous(setup::Stack::particle_type& vP,
-                                                setup::Trajectory const& vT) {
+                                                setup::Trajectory const& vT, bool const) {
 
     if (!canInteract(vP.getPID())) return ProcessReturn::Ok;
     if (vT.getLength() == 0_m) return ProcessReturn::Ok;
diff --git a/corsika/detail/modules/tracking/TrackingStraight.inl b/corsika/detail/modules/tracking/TrackingStraight.inl
index 2c284b4d01dddc3be3322dc305a84f6f836bd5e5..5869601a566d959ffac3432424b5fb9eaa4929cf 100644
--- a/corsika/detail/modules/tracking/TrackingStraight.inl
+++ b/corsika/detail/modules/tracking/TrackingStraight.inl
@@ -92,6 +92,8 @@ namespace corsika::tracking_line {
     auto const n = plane.getNormal();
     auto const c = n.dot(velocity);
 
+    CORSIKA_LOG_TRACE("c={}, delta={}, momentum={}", c, delta, particle.getMomentum());
+
     return Intersections(c.magnitude() == 0
                              ? std::numeric_limits<TimeType::value_type>::infinity() * 1_s
                              : n.dot(delta) / c);
diff --git a/corsika/framework/core/Logging.hpp b/corsika/framework/core/Logging.hpp
index 4d4c43a7ba2e4f7e9d2c90e87a905d542b554df8..29ef3e13c55470f95d933f4bcb6e998cdef68fef 100644
--- a/corsika/framework/core/Logging.hpp
+++ b/corsika/framework/core/Logging.hpp
@@ -35,9 +35,9 @@
 // if this is a Debug build, include debug messages in objects
 #ifdef DEBUG
 // trace is the highest level of logging (ALL messages will be printed)
-#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
+#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
 #else // otherwise, remove everything but "error" and worse messages
-#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
+#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
 #endif
 
 #include <spdlog/fmt/ostr.h> // will output whenerver a streaming operator is found
diff --git a/corsika/framework/geometry/Plane.hpp b/corsika/framework/geometry/Plane.hpp
index 9b2eacade48f5d9913d5b5311f1ae595cbcde039..7218e6b3564e857946669743be61c6519f467f12 100644
--- a/corsika/framework/geometry/Plane.hpp
+++ b/corsika/framework/geometry/Plane.hpp
@@ -12,6 +12,8 @@
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/Vector.hpp>
 
+#include <string>
+
 namespace corsika {
 
   class Plane {
@@ -32,6 +34,8 @@ namespace corsika {
 
     DimLessVec const& getNormal() const;
 
+    std::string asString() const;
+
   public:
     Point const center_;
     DimLessVec const normal_;
diff --git a/corsika/framework/geometry/QuantityVector.hpp b/corsika/framework/geometry/QuantityVector.hpp
index 235237afe59b8ffbf19413e625e7bdd1178a18e8..eb6c2f11e2679d434e2dbf617875254a60af621f 100644
--- a/corsika/framework/geometry/QuantityVector.hpp
+++ b/corsika/framework/geometry/QuantityVector.hpp
@@ -101,7 +101,7 @@ namespace corsika {
     template <typename T>
     friend class corsika::Vector;
     template <typename TDim>
-    friend std::ostream& operator<<(std::ostream& os, QuantityVector<TDim> qv);
+    friend std::ostream& operator<<(std::ostream& os, QuantityVector<TDim> const& qv);
 
   protected:
     Eigen::Vector3d
@@ -114,7 +114,7 @@ namespace corsika {
 
   template <typename TDimension>
   inline std::ostream& operator<<(std::ostream& os,
-                                  corsika::QuantityVector<TDimension> const qv);
+                                  corsika::QuantityVector<TDimension> const& qv);
 
 } // namespace corsika
 
diff --git a/corsika/framework/process/BaseProcess.hpp b/corsika/framework/process/BaseProcess.hpp
index e91651d12ea99cafd40718ae288a869852a5cf35..b8c96a54faa504a84c79272ce23f67534b6950b8 100644
--- a/corsika/framework/process/BaseProcess.hpp
+++ b/corsika/framework/process/BaseProcess.hpp
@@ -8,6 +8,10 @@
 
 #pragma once
 
+#include <corsika/framework/process/ProcessTraits.hpp>
+
+#include <type_traits>
+
 namespace corsika {
 
   class TDerived; // fwd decl
@@ -39,8 +43,28 @@ namespace corsika {
     const TDerived& ref() const { return static_cast<const TDerived&>(*this); }
 
   public:
+    //! Default number of processes ist just one, obviously
+    static unsigned int constexpr getNumberOfProcesses() { return 1; }
+
     // Base processor type for use in other template classes
     using process_type = TDerived;
   };
 
+  /**
+   * ProcessTraits specialization
+   **/
+  template <typename TProcess>
+  struct is_process<
+      TProcess,
+      std::enable_if_t<std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess>>,
+                                         typename std::decay_t<TProcess>>>>
+      : std::true_type {};
+
+  template <typename TProcess, int N>
+  struct count_processes<TProcess, N,
+                         typename std::enable_if_t<is_process_v<TProcess> &&
+                                                   !is_process_sequence_v<TProcess>>> {
+    static unsigned int constexpr count = N + 1;
+  };
+
 } // namespace corsika
diff --git a/corsika/framework/process/ContinuousProcess.hpp b/corsika/framework/process/ContinuousProcess.hpp
index 1343c082272a8e0e49830e53c164f985abe5e860..51d73d332fbe00ea3c5845608a0c582f224d5b4c 100644
--- a/corsika/framework/process/ContinuousProcess.hpp
+++ b/corsika/framework/process/ContinuousProcess.hpp
@@ -8,8 +8,10 @@
 
 #pragma once
 
+#include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/process/BaseProcess.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
+#include <corsika/framework/process/ProcessTraits.hpp>
 
 namespace corsika {
 
@@ -28,13 +30,41 @@ namespace corsika {
   protected:
   public:
     // here starts the interface part
-    // -> enforce TDerived to implement DoContinuous...
+    /**
+     * Applies the effects of this ContinuousProcess on a Particle on a Track.
+     *
+     * Note, the stepLimit is a flag, if this particular process was responsible for the
+     * track-length limit. This can be used by the process to trigger activity.
+     *
+     * \todo -> enforce TDerived to implement doContinuous...
+     **/
     template <typename TParticle, typename TTrack>
-    ProcessReturn doContinuous(TParticle&, TTrack const&) const;
+    ProcessReturn doContinuous(TParticle&, TTrack const&, bool const stepLimit) const;
 
-    // -> enforce TDerived to implement MaxStepLength...
+    /**
+     * Calculates/returns a possible step length limitation of this continuousprocess.
+     *
+     *
+     * \todo -> enforce TDerived to implement getMaxStepLength...
+     **/
     template <typename TParticle, typename TTrack>
     LengthType getMaxStepLength(TParticle const& p, TTrack const& track) const;
   };
 
+  /**
+   * ProcessTraits specialization
+   **/
+  template <typename TProcess>
+  struct is_continuous_process<
+      TProcess, std::enable_if_t<
+                    std::is_base_of_v<ContinuousProcess<typename std::decay_t<TProcess>>,
+                                      typename std::decay_t<TProcess>>>>
+      : std::true_type {};
+
+  template <typename TProcess, int N>
+  struct count_continuous<TProcess, N,
+                          typename std::enable_if_t<is_continuous_process_v<TProcess>>> {
+    enum { count = N + 1 };
+  };
+
 } // namespace corsika
diff --git a/corsika/framework/process/ContinuousProcessIndex.hpp b/corsika/framework/process/ContinuousProcessIndex.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc2617d2bb6ed5366431d1369480ef9abf593426
--- /dev/null
+++ b/corsika/framework/process/ContinuousProcessIndex.hpp
@@ -0,0 +1,32 @@
+/*
+ * (c) Copyright 2021 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * 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.
+ */
+
+#pragma once
+
+namespace corsika {
+
+  /**
+   * To index individual processes (continuous processes) inside a
+   * ProcessSequence.
+   *
+   **/
+
+  class ContinuousProcessIndex {
+  public:
+    ContinuousProcessIndex(int const id)
+        : id_(id) {}
+    void setIndex(int const id) { id_ = id; }
+    int getIndex() const { return id_; }
+    bool operator==(ContinuousProcessIndex const v) const { return id_ == v.id_; }
+    bool operator!=(ContinuousProcessIndex const v) const { return id_ != v.id_; }
+
+  private:
+    int id_;
+  };
+
+} // namespace corsika
diff --git a/corsika/framework/process/ContinuousProcessStepLength.hpp b/corsika/framework/process/ContinuousProcessStepLength.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..32b921857aaf6762c584ac5bf68b6885c019e038
--- /dev/null
+++ b/corsika/framework/process/ContinuousProcessStepLength.hpp
@@ -0,0 +1,43 @@
+/*
+ * (c) Copyright 2021 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/process/ContinuousProcessIndex.hpp>
+
+namespace corsika {
+
+  /**
+   * To store step length in LengthType and unique index in ProcessSequence of shortest
+   * step ContinuousProcess.
+   *
+   **/
+
+  class ContinuousProcessStepLength {
+  public:
+    ContinuousProcessStepLength(LengthType const step)
+        : step_(step)
+        , id_(0) {}
+    ContinuousProcessStepLength(LengthType const step, ContinuousProcessIndex const id)
+        : step_(step)
+        , id_(id) {}
+    void setLength(LengthType const step) { step_ = step; }
+    LengthType getLength() const { return step_; }
+    void setIndex(ContinuousProcessIndex const id) { id_ = id; }
+    ContinuousProcessIndex getIndex() const { return id_; }
+    operator ContinuousProcessIndex() const { return id_; }
+    operator LengthType() const { return step_; }
+    bool operator<(ContinuousProcessStepLength const& r) const { return step_ < r.step_; }
+
+  private:
+    LengthType step_;
+    ContinuousProcessIndex id_;
+  };
+
+} // namespace corsika
diff --git a/corsika/framework/process/ProcessSequence.hpp b/corsika/framework/process/ProcessSequence.hpp
index 70337e1099d09cd4945d7f557f2a1661dedc0d0b..d909d07151c4d15a1bdf040af11ce46e8a930f24 100644
--- a/corsika/framework/process/ProcessSequence.hpp
+++ b/corsika/framework/process/ProcessSequence.hpp
@@ -16,6 +16,8 @@
 #include <corsika/framework/process/ProcessTraits.hpp>
 #include <corsika/framework/process/BoundaryCrossingProcess.hpp>
 #include <corsika/framework/process/ContinuousProcess.hpp>
+#include <corsika/framework/process/ContinuousProcessIndex.hpp>
+#include <corsika/framework/process/ContinuousProcessStepLength.hpp>
 #include <corsika/framework/process/DecayProcess.hpp>
 #include <corsika/framework/process/InteractionProcess.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
@@ -26,6 +28,21 @@
 
 namespace corsika {
 
+  template <typename TProcess, int N>
+  struct count_continuous<TProcess, N,
+                          typename std::enable_if_t<is_process_sequence_v<TProcess>>> {
+    static unsigned int constexpr count =
+        N + std::decay_t<TProcess>::getNumberOfProcesses();
+  };
+
+  template <typename TProcess, int N>
+  struct count_processes<TProcess, N,
+                         typename std::enable_if_t<is_process_v<TProcess> &&
+                                                   is_process_sequence_v<TProcess>>> {
+    static unsigned int constexpr count =
+        N + std::decay_t<TProcess>::getNumberOfProcesses();
+  };
+
   /**
    *
    *  Definition of a static process list/sequence
@@ -39,13 +56,21 @@ namespace corsika {
    *  they are just classes. This allows us to handle both, rvalue as
    *  well as lvalue Processes in the ProcessSequence.
    *
-   *  The sequence, and the processes use CRTP.
+   *  (The sequence, and the processes use the CRTP, curiously recurring template
+   *  pattern).
    *
-   *  \todo There are several FIXME's in the ProcessSequence.inl due to
-   *  outstanding migration of SecondaryView::parent()
+   * Template parameters:
+   *  - TProcess1 is of type BaseProcess, either a dedicatd process, or a ProcessSequence
+   *  - TProcess2 is of type BaseProcess, either a dedicatd process, or a ProcessSequence
+   *  - ProcessIndexOffset, IndexOfProcess1, IndexOfProcess2 are to count and index each
+   *ContinuousProcess in the entire process-chain
    **/
 
-  template <typename TProcess1, typename TProcess2 = NullModel>
+  template <typename TProcess1, typename TProcess2 = NullModel,
+            int ProcessIndexOffset = 0,
+            int IndexOfProcess1 = count_processes<
+                TProcess1, count_processes<TProcess2, ProcessIndexOffset>::count>::count,
+            int IndexOfProcess2 = count_processes<TProcess2, ProcessIndexOffset>::count>
   class ProcessSequence : public BaseProcess<ProcessSequence<TProcess1, TProcess2>> {
 
     using process1_type = typename std::decay_t<TProcess1>;
@@ -58,16 +83,13 @@ namespace corsika {
     static bool constexpr t2SwitchProcSeq = is_switch_process_sequence_v<process2_type>;
 
     // make sure only BaseProcess types TProcess1/2 are passed
-    static_assert(std::is_base_of_v<BaseProcess<process1_type>, process1_type>,
+    static_assert(is_process_v<process1_type>,
                   "can only use process derived from BaseProcess in "
                   "ProcessSequence, for Process 1");
-    static_assert(std::is_base_of_v<BaseProcess<process2_type>, process2_type>,
+    static_assert(is_process_v<process2_type>,
                   "can only use process derived from BaseProcess in "
                   "ProcessSequence, for Process 2");
 
-    TProcess1 A_; /// process/list A, this is a reference, if possible
-    TProcess2 B_; /// process/list B, this is a reference, if possible
-
   public:
     // resource management
     ProcessSequence() = delete; // only initialized objects
@@ -96,7 +118,8 @@ namespace corsika {
                                      typename TParticle::node_type const& to);
 
     template <typename TParticle, typename TTrack>
-    inline ProcessReturn doContinuous(TParticle& particle, TTrack& vT);
+    inline ProcessReturn doContinuous(TParticle& particle, TTrack& vT,
+                                      ContinuousProcessIndex const limitID);
 
     template <typename TSecondaries>
     inline void doSecondaries(TSecondaries& vS);
@@ -117,8 +140,19 @@ namespace corsika {
     template <typename TStack>
     inline void doStack(TStack& stack);
 
+    /**
+     * Determines the step-length limitation caused by ContinuousProcess-es in this
+     ProcessSequence.
+     *
+     * Returns a ContinuousProcessStepLength object, which contains both: the actual
+     * length (LengthType) as well as the index of the ContinuousProcess inside the
+     * ProcessSequence (for identification).
+
+     **/
+
     template <typename TParticle, typename TTrack>
-    inline LengthType getMaxStepLength(TParticle& particle, TTrack& vTrack);
+    inline ContinuousProcessStepLength getMaxStepLength(TParticle& particle,
+                                                        TTrack& vTrack);
 
     template <typename TParticle>
     inline GrammageType getInteractionLength(TParticle&& particle) {
@@ -147,6 +181,17 @@ namespace corsika {
     inline ProcessReturn selectDecay(
         TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select,
         [[maybe_unused]] InverseTimeType decay_inv_sum = InverseTimeType::zero());
+
+    /**
+     * static counter to uniquely index (count) all ContinuousProcess in switch sequence.
+     **/
+    static unsigned int constexpr getNumberOfProcesses() { return numberOfProcesses_; }
+
+  private:
+    TProcess1 A_; /// process/list A, this is a reference, if possible
+    TProcess2 B_; /// process/list B, this is a reference, if possible
+
+    static unsigned int constexpr numberOfProcesses_ = IndexOfProcess1; // static counter
   };
 
   /**
@@ -170,12 +215,12 @@ namespace corsika {
    *
    * \param vA needs to derive from BaseProcess or ProcessSequence
    * \param vB paramter-pack, needs to derive BaseProcess or ProcessSequence
+   *
    **/
 
   template <typename... TProcesses, typename TProcess1>
   inline typename std::enable_if_t<
-      std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>,
-                        typename std::decay_t<TProcess1>>,
+      is_process_v<typename std::decay_t<TProcess1>>,
       ProcessSequence<TProcess1, decltype(make_sequence(std::declval<TProcesses>()...))>>
   make_sequence(TProcess1&& vA, TProcesses&&... vBs) {
     return ProcessSequence<TProcess1,
@@ -192,12 +237,9 @@ namespace corsika {
    * \param vB needs to derive BaseProcess or ProcessSequence
    **/
   template <typename TProcess1, typename TProcess2>
-  inline typename std::enable_if_t<
-      std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>,
-                        typename std::decay_t<TProcess1>> &&
-          std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>,
-                            typename std::decay_t<TProcess2>>,
-      ProcessSequence<TProcess1, TProcess2>>
+  inline typename std::enable_if_t<is_process_v<typename std::decay_t<TProcess1>> &&
+                                       is_process_v<typename std::decay_t<TProcess2>>,
+                                   ProcessSequence<TProcess1, TProcess2>>
   make_sequence(TProcess1&& vA, TProcess2&& vB) {
     return ProcessSequence<TProcess1, TProcess2>(vA, vB);
   }
@@ -211,10 +253,8 @@ namespace corsika {
    * \param vA needs to derive from BaseProcess or ProcessSequence
    **/
   template <typename TProcess>
-  inline typename std::enable_if_t<
-      std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess>>,
-                        typename std::decay_t<TProcess>>,
-      ProcessSequence<TProcess, NullModel>>
+  inline typename std::enable_if_t<is_process_v<typename std::decay_t<TProcess>>,
+                                   ProcessSequence<TProcess, NullModel>>
   make_sequence(TProcess&& vA) {
     return ProcessSequence<TProcess, NullModel>(vA, NullModel());
   }
@@ -226,11 +266,7 @@ namespace corsika {
   struct is_process_sequence<ProcessSequence<TProcess1, TProcess2>> : std::true_type {
     // only switch on for BaseProcesses
     template <typename std::enable_if_t<
-        std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>,
-                          typename std::decay_t<TProcess1>> &&
-            std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>,
-                              typename std::decay_t<TProcess2>>,
-        int>>
+        is_process_v<TProcess1> && is_process_v<TProcess2>, int>>
     is_process_sequence() {}
   };
 
diff --git a/corsika/framework/process/ProcessTraits.hpp b/corsika/framework/process/ProcessTraits.hpp
index 7b303d2d3ce3a9ce1363d2433e08832e80032f46..b08318093e7be4147e5408661b16c8feb1c3921e 100644
--- a/corsika/framework/process/ProcessTraits.hpp
+++ b/corsika/framework/process/ProcessTraits.hpp
@@ -16,6 +16,24 @@
 
 namespace corsika {
 
+  /**
+   * A traits marker to identify BaseProcess, thus any type of process
+   */
+  template <typename TProcess, typename Enable = void>
+  struct is_process : std::false_type {};
+
+  template <typename TProcess>
+  bool constexpr is_process_v = is_process<TProcess>::value;
+
+  /**
+   * A traits marker to identify ContinuousProcess
+   */
+  template <typename TProcess, typename Enable = void>
+  struct is_continuous_process : std::false_type {};
+
+  template <typename TProcess>
+  bool constexpr is_continuous_process_v = is_continuous_process<TProcess>::value;
+
   /**
    *  A traits marker to track which BaseProcess is also a ProcessSequence
    **/
@@ -44,4 +62,20 @@ namespace corsika {
   template <typename TClass>
   bool constexpr contains_stack_process_v = contains_stack_process<TClass>::value;
 
+  /**
+   * traits class to count ContinuousProcess-es, general version
+   **/
+  template <typename TProcess, int N = 0, typename Enable = void>
+  struct count_continuous {
+    static unsigned int constexpr count = N;
+  };
+
+  /**
+   * traits class to count any type of Process, general version
+   **/
+  template <typename TProcess, int N = 0, typename Enable = void>
+  struct count_processes {
+    static unsigned int constexpr count = N;
+  };
+
 } // namespace corsika
diff --git a/corsika/framework/process/SwitchProcessSequence.hpp b/corsika/framework/process/SwitchProcessSequence.hpp
index dab419ae5a5c66fda13eee9c0247c697e0cdcfd1..dcf4b214ec84f58bd69a44cf9cd47c2ae3f02a36 100644
--- a/corsika/framework/process/SwitchProcessSequence.hpp
+++ b/corsika/framework/process/SwitchProcessSequence.hpp
@@ -16,6 +16,7 @@
 #include <corsika/framework/process/ProcessTraits.hpp>
 #include <corsika/framework/process/BoundaryCrossingProcess.hpp>
 #include <corsika/framework/process/ContinuousProcess.hpp>
+#include <corsika/framework/process/ContinuousProcessIndex.hpp>
 #include <corsika/framework/process/DecayProcess.hpp>
 #include <corsika/framework/process/InteractionProcess.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
@@ -57,10 +58,19 @@ namespace corsika {
      since this makes no sense. The StackProcess acts on an entire
      particle stack and not on indiviidual particles.
 
+     Template parameters:
+      - TProcess1 is of type BaseProcess, either a dedicatd process, or a ProcessSequence
+      - TProcess2 is of type BaseProcess, either a dedicatd process, or a ProcessSequence
+      - IndexFirstProcess, IndexOfProcess1, IndexOfProcess2 are to count and index each
+  ContinuousProcess in the entire process-chain
+
      See also class \sa ProcessSequence
   **/
 
-  template <typename TProcess1, typename TProcess2, typename TSelect>
+  template <typename TProcess1, typename TProcess2, typename TSelect,
+            int IndexFirstProcess = 0,
+            int IndexOfProcess1 = count_processes<TProcess1, IndexFirstProcess>::count,
+            int IndexOfProcess2 = count_processes<TProcess2, IndexOfProcess1>::count>
   class SwitchProcessSequence
       : public BaseProcess<SwitchProcessSequence<TProcess1, TProcess2, TSelect>> {
 
@@ -71,10 +81,10 @@ namespace corsika {
     static bool constexpr t2ProcSeq = is_process_sequence_v<process2_type>;
 
     // make sure only BaseProcess types TProcess1/2 are passed
-    static_assert(std::is_base_of_v<BaseProcess<process1_type>, process1_type>,
+    static_assert(is_process_v<process1_type>,
                   "can only use process derived from BaseProcess in "
                   "SwitchProcessSequence, for Process 1");
-    static_assert(std::is_base_of_v<BaseProcess<process2_type>, process2_type>,
+    static_assert(is_process_v<process2_type>,
                   "can only use process derived from BaseProcess in "
                   "SwitchProcessSequence, for Process 2");
 
@@ -122,13 +132,15 @@ namespace corsika {
                                      TVTNType const& to);
 
     template <typename TParticle, typename TTrack>
-    inline ProcessReturn doContinuous(TParticle& particle, TTrack& vT);
+    inline ProcessReturn doContinuous(TParticle& particle, TTrack& vT,
+                                      ContinuousProcessIndex const limitId);
 
     template <typename TSecondaries>
     inline void doSecondaries(TSecondaries& vS);
 
     template <typename TParticle, typename TTrack>
-    inline LengthType getMaxStepLength(TParticle& particle, TTrack& vTrack);
+    inline ContinuousProcessStepLength getMaxStepLength(TParticle& particle,
+                                                        TTrack& vTrack);
 
     template <typename TParticle>
     inline GrammageType getInteractionLength(TParticle&& particle) {
@@ -158,12 +170,19 @@ namespace corsika {
         TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select,
         [[maybe_unused]] InverseTimeType decay_inv_sum = InverseTimeType::zero());
 
+    /**
+     * static counter to uniquely index (count) all ContinuousProcess in switch sequence.
+     **/
+    static unsigned int constexpr getNumberOfProcesses() { return numberOfProcesses_; }
+
   private:
     TSelect select_; /// selector functor to switch between branch a and b, this is a
                      /// reference, if possible
 
     TProcess1 A_; /// process branch a, this is a reference, if possible
     TProcess2 B_; /// process branch b, this is a reference, if possible
+
+    static unsigned int constexpr numberOfProcesses_ = IndexOfProcess2; // static counter
   };
 
   /**
@@ -178,12 +197,9 @@ namespace corsika {
    **/
 
   template <typename TProcess1, typename TProcess2, typename TSelect>
-  inline typename std::enable_if_t<
-      std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>,
-                        typename std::decay_t<TProcess1>> &&
-          std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>,
-                            typename std::decay_t<TProcess2>>,
-      SwitchProcessSequence<TProcess1, TProcess2, TSelect>>
+  inline typename std::enable_if_t<is_process_v<typename std::decay_t<TProcess1>> &&
+                                       is_process_v<typename std::decay_t<TProcess2>>,
+                                   SwitchProcessSequence<TProcess1, TProcess2, TSelect>>
   make_select(TProcess1&& vA, TProcess2&& vB, TSelect selector) {
     return SwitchProcessSequence<TProcess1, TProcess2, TSelect>(vA, vB, selector);
   }
diff --git a/corsika/modules/LongitudinalProfile.hpp b/corsika/modules/LongitudinalProfile.hpp
index baaa5046824c142694097a18ba662ba97647799c..b06e2ef852541342f474881a0209a154cf85602e 100644
--- a/corsika/modules/LongitudinalProfile.hpp
+++ b/corsika/modules/LongitudinalProfile.hpp
@@ -41,7 +41,9 @@ namespace corsika {
                         GrammageType dX = 10_g / square(1_cm)); // profile binning);
 
     template <typename TParticle, typename TTrack>
-    ProcessReturn doContinuous(TParticle const&, TTrack const&);
+    ProcessReturn doContinuous(
+        TParticle const&, TTrack const&,
+        bool const flagLimit = false); // not needed for LongitudinalProfile
 
     template <typename TParticle, typename TTrack>
     LengthType getMaxStepLength(TParticle const&, TTrack const&) {
diff --git a/corsika/modules/ObservationPlane.hpp b/corsika/modules/ObservationPlane.hpp
index 7effcd93b6abfda4ae1cc8b2adca07b38cb6cdc6..8276c0d1235f44539bfc17468f20aff5eda902b5 100644
--- a/corsika/modules/ObservationPlane.hpp
+++ b/corsika/modules/ObservationPlane.hpp
@@ -31,7 +31,8 @@ namespace corsika {
                      bool = true);
 
     ProcessReturn doContinuous(corsika::setup::Stack::particle_type& vParticle,
-                               corsika::setup::Trajectory& vTrajectory);
+                               corsika::setup::Trajectory& vTrajectory,
+                               bool const stepLimit);
 
     LengthType getMaxStepLength(corsika::setup::Stack::particle_type const&,
                                 corsika::setup::Trajectory const& vTrajectory);
diff --git a/corsika/modules/ParticleCut.hpp b/corsika/modules/ParticleCut.hpp
index 1678c528edbc9815bc9c1388bcd81d9c32748615..9842dd034530d7528e1359e63983d8adc85b25f0 100644
--- a/corsika/modules/ParticleCut.hpp
+++ b/corsika/modules/ParticleCut.hpp
@@ -50,8 +50,10 @@ namespace corsika {
                 bool const em, bool const inv);
 
     void doSecondaries(corsika::setup::StackView&);
-    ProcessReturn doContinuous(corsika::setup::Stack::particle_type& vParticle,
-                               corsika::setup::Trajectory const& vTrajectory);
+    ProcessReturn doContinuous(
+        corsika::setup::Stack::particle_type& vParticle,
+        corsika::setup::Trajectory const& vTrajectory,
+        const bool limitFlag = false); // this is not used for ParticleCut
     LengthType getMaxStepLength(corsika::setup::Stack::particle_type const&,
                                 corsika::setup::Trajectory const&) {
       return meter * std::numeric_limits<double>::infinity();
diff --git a/corsika/modules/TrackWriter.hpp b/corsika/modules/TrackWriter.hpp
index c437bc7d15dfe4ada3ef269e874cccf2ce5a36a7..5bf9856b389fe80774ea629b27a4b4dc10f33c85 100644
--- a/corsika/modules/TrackWriter.hpp
+++ b/corsika/modules/TrackWriter.hpp
@@ -22,7 +22,7 @@ namespace corsika {
     TrackWriter(std::string const& filename);
 
     template <typename TParticle, typename TTrack>
-    ProcessReturn doContinuous(TParticle const&, TTrack const&);
+    ProcessReturn doContinuous(TParticle const&, TTrack const&, bool const limitFlag);
 
     template <typename TParticle, typename TTrack>
     LengthType getMaxStepLength(TParticle const&, TTrack const&);
diff --git a/corsika/modules/energy_loss/BetheBlochPDG.hpp b/corsika/modules/energy_loss/BetheBlochPDG.hpp
index f8e8759376a3833bd3f7df438b2dbe4132c5e3c8..582a0c4e03046cc738105d32d2cfcdd7e94964a9 100644
--- a/corsika/modules/energy_loss/BetheBlochPDG.hpp
+++ b/corsika/modules/energy_loss/BetheBlochPDG.hpp
@@ -43,7 +43,17 @@ namespace corsika {
   public:
     BetheBlochPDG(ShowerAxis const& showerAxis);
 
-    ProcessReturn doContinuous(setup::Stack::particle_type&, setup::Trajectory const&);
+    /** clang-format-off
+     * Interface function of ContinuousProcess.
+     *
+     * \param particle The particle to process in its current state
+     * \param track The trajectory in space of this particle, on which doContinuous should
+     *        act
+     * \param limitFlag flag to identify, if BetheBlochPDG::getMaxStepLength is the
+     *        globally limiting factor (or not)
+     clang-format-on **/
+    ProcessReturn doContinuous(setup::Stack::particle_type& particle,
+                               setup::Trajectory const& track, bool const limitFlag);
     LengthType getMaxStepLength(setup::Stack::particle_type const&,
                                 setup::Trajectory const&)
         const; //! limited by the energy threshold! By default the limit is the particle
diff --git a/corsika/modules/proposal/ContinuousProcess.hpp b/corsika/modules/proposal/ContinuousProcess.hpp
index 3b8976f3ac6bfe7a6d5251740782e4ca8fec89bc..0efbf12ecd6100ae3e6cc7e9bc777cacb2f2dfcb 100644
--- a/corsika/modules/proposal/ContinuousProcess.hpp
+++ b/corsika/modules/proposal/ContinuousProcess.hpp
@@ -67,8 +67,11 @@ namespace corsika::proposal {
     //! If the particle if below the given energy threshold where it will be
     //! considered stochastically, it will be absorbed.
     //!
+    //! \param limitFlag is true, if the track was actually limited by
+    //! proposal::ContinuousProcess::getMaxStepLength
+    //!
     template <typename TParticle, typename TTrack>
-    ProcessReturn doContinuous(TParticle&, TTrack const&);
+    ProcessReturn doContinuous(TParticle&, TTrack const& track, bool const limitFlag);
 
     //!
     //! Calculates maximal step length of process.
diff --git a/examples/em_shower.cpp b/examples/em_shower.cpp
index 2afddc84ee9744909d4378eb3cf2456267655308..e4d8b3cc432a1852f96dbababca6a0c024fc037b 100644
--- a/examples/em_shower.cpp
+++ b/examples/em_shower.cpp
@@ -141,11 +141,10 @@ int main(int argc, char** argv) {
 
   // setup processes, decays and interactions
 
-  // PROPOSAL processs proposal{...};
   ParticleCut cut(10_GeV, 10_GeV, 100_PeV, 100_PeV, true);
-  corsika::proposal::Interaction proposal(env);
-  corsika::proposal::ContinuousProcess em_continuous(env);
-  InteractionCounter proposalCounted(proposal);
+  corsika::proposal::Interaction emCascade(env);
+  corsika::proposal::ContinuousProcess emContinuous(env);
+  InteractionCounter emCascadeCounted(emCascade);
 
   TrackWriter trackWriter("tracks.dat");
 
@@ -156,7 +155,7 @@ int main(int argc, char** argv) {
   ObservationPlane observationLevel(obsPlane, DirectionVector(rootCS, {1., 0., 0.}),
                                     "particles.dat");
 
-  auto sequence = make_sequence(proposalCounted, em_continuous, longprof, cut,
+  auto sequence = make_sequence(emCascadeCounted, emContinuous, longprof, cut,
                                 observationLevel, trackWriter);
   // define air shower object, run simulation
   setup::Tracking tracking;
@@ -169,18 +168,18 @@ int main(int argc, char** argv) {
   EAS.run();
 
   cut.showResults();
-  em_continuous.showResults();
+  emContinuous.showResults();
   observationLevel.showResults();
   const HEPEnergyType Efinal = cut.getCutEnergy() + cut.getInvEnergy() +
-                               cut.getEmEnergy() + em_continuous.getEnergyLost() +
+                               cut.getEmEnergy() + emContinuous.getEnergyLost() +
                                observationLevel.getEnergyGround();
   cout << "total cut energy (GeV): " << Efinal / 1_GeV << endl
        << "relative difference (%): " << (Efinal / E0 - 1) * 100 << endl;
   observationLevel.reset();
   cut.reset();
-  em_continuous.reset();
+  emContinuous.reset();
 
-  auto const hists = proposalCounted.getHistogram();
+  auto const hists = emCascadeCounted.getHistogram();
   save_hist(hists.labHist(), "inthist_lab_emShower.npz", true);
   save_hist(hists.CMSHist(), "inthist_cms_emShower.npz", true);
   longprof.save("longprof_emShower.txt");
diff --git a/examples/particle_list_example.cpp b/examples/particle_list_example.cpp
index 4b8d1d75770743d92e7ad2051ce05bb25d1156c9..8a10d9f094fcc5e4838778e2bc5526347b2bfba0 100644
--- a/examples/particle_list_example.cpp
+++ b/examples/particle_list_example.cpp
@@ -35,37 +35,39 @@ using namespace std;
 int main() {
 
   logging::set_level(logging::level::info);
-  corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v");
+  corsika_logger->set_pattern("[%n:%^%-8l%$] %v");
 
   logging::info(
+      "\n"
       "------------------------------------------\n"
-      "particles in CORSIKA\n"
-      "------------------------------------------\n"
-      "Name                | "
+      "        particles in CORSIKA\n"
+      "------------------------------------------\n");
+  int const width = 20 + 10 + 10 + 10 + 15 + 15 + 17;
+  logging::info(
+      "Name                 | "
       "PDG-id     | "
       "SIBYLL-id  | "
       "QGSJETII-id| "
       "PDG-mass (GeV)   | "
-      "SIBYLL-mass (GeV)|\n"
-      "{:-}",
-      "", 104);
+      "SIBYLL-mass (GeV)|");
+  logging::info("{:->{}}", ' ', width);
   for (auto p : get_all_particles()) {
     if (!is_nucleus(p)) {
       corsika::sibyll::SibyllCode sib_id = corsika::sibyll::convertToSibyll(p);
       auto const sib_mass = (sib_id != corsika::sibyll::SibyllCode::Unknown
                                  ? to_string(corsika::sibyll::getSibyllMass(p) / 1_GeV)
-                                 : "--");
+                                 : "");
       auto const qgs_id = corsika::qgsjetII::convertToQgsjetII(p);
-      logging::info("{:20} | {:10} | {:10} | {:10.5} | {:18.5}", p,
+      logging::info("{:20} | {:10} | {:10} | {:10} | {:>15.5} | {:>15.5} |", p,
                     static_cast<int>(get_PDG(p)),
                     (sib_id != corsika::sibyll::SibyllCode::Unknown
                          ? to_string(static_cast<int>(sib_id))
-                         : "--"),
+                         : ""),
                     (qgs_id != corsika::qgsjetII::QgsjetIICode::Unknown
                          ? to_string(static_cast<int>(qgs_id))
-                         : "--"),
+                         : ""),
                     get_mass(p) / 1_GeV, sib_mass);
     }
   }
-  logging::info("{:-104}", "");
+  logging::info("{:->{}}", ' ', width);
 }
diff --git a/examples/staticsequence_example.cpp b/examples/staticsequence_example.cpp
index d7b9e06b5051d8b8a721b87bba5c9407f3090a70..3f6c5aff75c72ec9058773fabbb6347e0db15274 100644
--- a/examples/staticsequence_example.cpp
+++ b/examples/staticsequence_example.cpp
@@ -24,7 +24,7 @@ class Process1 : public ContinuousProcess<Process1> {
 public:
   Process1() {}
   template <typename D, typename T>
-  ProcessReturn doContinuous(D& d, T&) const {
+  ProcessReturn doContinuous(D& d, T&, bool const) const {
     for (int i = 0; i < nData; ++i) d.p[i] += 1;
     return ProcessReturn::Ok;
   }
@@ -35,7 +35,7 @@ public:
   Process2() {}
 
   template <typename D, typename T>
-  inline ProcessReturn doContinuous(D& d, T&) const {
+  inline ProcessReturn doContinuous(D& d, T&, bool const) const {
     for (int i = 0; i < nData; ++i) d.p[i] -= 0.1 * i;
     return ProcessReturn::Ok;
   }
@@ -46,7 +46,7 @@ public:
   Process3() {}
 
   template <typename D, typename T>
-  inline ProcessReturn doContinuous(D&, T&) const {
+  inline ProcessReturn doContinuous(D&, T&, bool const) const {
     return ProcessReturn::Ok;
   }
 };
@@ -56,7 +56,7 @@ public:
   Process4(const double v)
       : fV(v) {}
   template <typename D, typename T>
-  inline ProcessReturn doContinuous(D& d, T&) const {
+  inline ProcessReturn doContinuous(D& d, T&, bool const) const {
     for (int i = 0; i < nData; ++i) d.p[i] *= fV;
     return ProcessReturn::Ok;
   }
@@ -90,7 +90,7 @@ void modular() {
 
   const int nEv = 10;
   for (int iEv = 0; iEv < nEv; ++iEv) {
-    sequence.doContinuous(particle, track);
+    sequence.doContinuous(particle, track, ContinuousProcessIndex(0));
     for (int i = 0; i < nData; ++i) {
       check[i] += 1. - 0.1 * i;
       check[i] *= 1.5;
diff --git a/examples/vertical_EAS.cpp b/examples/vertical_EAS.cpp
index f012440e82deb19c3ab2b5220622c0255da9dbc5..04ddbb2221c9c753e7dbe9550dc07b9a3e45a77e 100644
--- a/examples/vertical_EAS.cpp
+++ b/examples/vertical_EAS.cpp
@@ -91,8 +91,8 @@ using MyExtraEnv = MediumPropertyModel<UniformMagneticField<T>>;
 
 int main(int argc, char** argv) {
 
-  corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v");
-  logging::set_level(logging::level::info);
+  corsika_logger->set_pattern("[%n:%^%-8l%$] %s:%#: %v");
+  logging::set_level(logging::level::trace);
 
   CORSIKA_LOG_INFO("vertical_EAS");
 
@@ -222,9 +222,9 @@ int main(int argc, char** argv) {
   decaySibyll.printDecayConfig();
 
   ParticleCut cut{60_GeV, 60_GeV, 60_GeV, 60_GeV, true};
-  corsika::proposal::Interaction proposal(env);
-  corsika::proposal::ContinuousProcess em_continuous(env);
-  InteractionCounter proposalCounted(proposal);
+  corsika::proposal::Interaction emCascade(env);
+  corsika::proposal::ContinuousProcess emContinuous(env);
+  InteractionCounter emCascadeCounted(emCascade);
 
   OnShellCheck reset_particle_mass(1.e-3, 1.e-1, false);
   TrackWriter trackWriter("tracks.dat");
@@ -254,9 +254,9 @@ int main(int argc, char** argv) {
   auto hadronSequence = make_select(
       urqmdCounted, make_sequence(sibyllNucCounted, sibyllCounted), EnergySwitch(55_GeV));
   auto decaySequence = make_sequence(decayPythia, decaySibyll);
-  auto sequence = make_sequence(stackInspect, hadronSequence, reset_particle_mass,
-                                decaySequence, proposalCounted, em_continuous, cut,
-                                trackWriter, observationLevel, longprof);
+  auto sequence =
+      make_sequence(stackInspect, hadronSequence, reset_particle_mass, decaySequence,
+                    emContinuous, cut, trackWriter, observationLevel, longprof);
 
   // define air shower object, run simulation
   setup::Tracking tracking;
@@ -268,19 +268,19 @@ int main(int argc, char** argv) {
   EAS.run();
 
   cut.showResults();
-  em_continuous.showResults();
+  emContinuous.showResults();
   observationLevel.showResults();
   const HEPEnergyType Efinal = cut.getCutEnergy() + cut.getInvEnergy() +
-                               cut.getEmEnergy() + em_continuous.getEnergyLost() +
+                               cut.getEmEnergy() + emContinuous.getEnergyLost() +
                                observationLevel.getEnergyGround();
   cout << "total cut energy (GeV): " << Efinal / 1_GeV << endl
        << "relative difference (%): " << (Efinal / E0 - 1) * 100 << endl;
   observationLevel.reset();
   cut.reset();
-  em_continuous.reset();
+  emContinuous.reset();
 
   auto const hists = sibyllCounted.getHistogram() + sibyllNucCounted.getHistogram() +
-                     urqmdCounted.getHistogram() + proposalCounted.getHistogram();
+                     urqmdCounted.getHistogram();
 
   save_hist(hists.labHist(), "inthist_lab_verticalEAS.npz", true);
   save_hist(hists.CMSHist(), "inthist_cms_verticalEAS.npz", true);
diff --git a/modules/conex b/modules/conex
index 73e3d1fa850d2d3602a15b3b948ac1789fbc968d..820f042b6a055276d465437c74160ef7c199b646 160000
--- a/modules/conex
+++ b/modules/conex
@@ -1 +1 @@
-Subproject commit 73e3d1fa850d2d3602a15b3b948ac1789fbc968d
+Subproject commit 820f042b6a055276d465437c74160ef7c199b646
diff --git a/modules/data b/modules/data
index afe83dc19c1464deb176f38c3ddab80a64e081f4..8b76a9ca2599cd0ce1f204b17362eb06bbcf5277 160000
--- a/modules/data
+++ b/modules/data
@@ -1 +1 @@
-Subproject commit afe83dc19c1464deb176f38c3ddab80a64e081f4
+Subproject commit 8b76a9ca2599cd0ce1f204b17362eb06bbcf5277
diff --git a/tests/framework/testGeometry.cpp b/tests/framework/testGeometry.cpp
index a39201c04de97d13ccc24343cd5b4a0148a2c5a5..e8847ee5e824242344147f46afeb37dfe0eb3708 100644
--- a/tests/framework/testGeometry.cpp
+++ b/tests/framework/testGeometry.cpp
@@ -26,18 +26,20 @@ using namespace corsika::testing;
 
 double constexpr absMargin = 1.0e-8;
 
-TEST_CASE("transformations between CoordinateSystems") {
+TEST_CASE("Geometry CoordinateSystems") {
 
   logging::set_level(logging::level::info);
-  corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v");
+  corsika_logger->set_pattern("[%n:%^%-8l%$] %v");
 
   CoordinateSystemPtr rootCS = get_root_CoordinateSystem();
 
   QuantityVector<length_d> const coordinates{0_m, 0_m, 0_m};
   Point p1(rootCS, coordinates);
+  CORSIKA_LOG_INFO("Point p1={}", p1);
 
   QuantityVector<magnetic_flux_density_d> components{1. * tesla, 0. * tesla, 0. * tesla};
   Vector<magnetic_flux_density_d> v1(rootCS, components);
+  CORSIKA_LOG_INFO("Vector<magnetic_flux_density_d> v1={}", v1);
 
   CHECK((p1.getCoordinates() - coordinates).getNorm().magnitude() ==
         Approx(0).margin(absMargin));
@@ -46,6 +48,7 @@ TEST_CASE("transformations between CoordinateSystems") {
 
   SECTION("translations") {
     QuantityVector<length_d> const translationVector{0_m, 4_m, 0_m};
+    CORSIKA_LOG_INFO("QuantityVector<length_d> translationVector={}", translationVector);
 
     CoordinateSystemPtr translatedCS = make_translation(rootCS, translationVector);
 
@@ -184,7 +187,7 @@ TEST_CASE("transformations between CoordinateSystems") {
   }
 }
 
-TEST_CASE("CoordinateSystem hirarchy") {
+TEST_CASE("Geometry CoordinateSystem-hirarchy") {
 
   CoordinateSystemPtr rootCS = get_root_CoordinateSystem();
 
@@ -232,7 +235,7 @@ TEST_CASE("CoordinateSystem hirarchy") {
   CHECK((p1 - p6).getNorm().magnitude() == Approx(0).margin(absMargin));
 }
 
-TEST_CASE("Sphere") {
+TEST_CASE("Geometry Sphere") {
   CoordinateSystemPtr const& rootCS = get_root_CoordinateSystem();
   Point center(rootCS, {0_m, 3_m, 4_m});
   Sphere sphere(center, 5_m);
@@ -251,7 +254,7 @@ TEST_CASE("Sphere") {
   }
 }
 
-TEST_CASE("Trajectories") {
+TEST_CASE("Geometry Trajectories") {
   CoordinateSystemPtr rootCS = get_root_CoordinateSystem();
   Point r0(rootCS, {0_m, 0_m, 0_m});
 
diff --git a/tests/framework/testProcessSequence.cpp b/tests/framework/testProcessSequence.cpp
index ac80847cabbd24913175b44a6a78e62af7e9db2c..d2612bb8860497c34aa1550b1eb227ba2d108c68 100644
--- a/tests/framework/testProcessSequence.cpp
+++ b/tests/framework/testProcessSequence.cpp
@@ -9,6 +9,8 @@
 #include <corsika/framework/process/ProcessSequence.hpp>
 #include <corsika/framework/process/SwitchProcessSequence.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/process/ProcessTraits.hpp>
+#include <corsika/framework/process/ContinuousProcessStepLength.hpp>
 
 #include <catch2/catch.hpp>
 
@@ -17,10 +19,12 @@
 #include <iostream>
 #include <typeinfo>
 
+#include <boost/type_index.hpp>
+
 using namespace corsika;
 using namespace std;
 
-static const int nData = 10;
+static int const nData = 10;
 
 int globalCount = 0; // simple counter
 
@@ -31,68 +35,110 @@ int checkCont = 0;     // use this as a bit field
 
 class ContinuousProcess1 : public ContinuousProcess<ContinuousProcess1> {
 public:
-  ContinuousProcess1(const int v)
-      : v_(v) {
+  ContinuousProcess1(int const v, LengthType const step)
+      : v_(v)
+      , step_(step) {
 
     cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
     globalCount++;
   }
 
+  void setStep(LengthType const v) { step_ = v; }
+
   template <typename D, typename T>
-  inline ProcessReturn doContinuous(D& d, T&) const {
+  inline ProcessReturn doContinuous(D& d, T&, bool const flag) const {
+    flag_ = flag;
     cout << "ContinuousProcess1::DoContinuous" << endl;
     checkCont |= 1;
     for (int i = 0; i < nData; ++i) d.data_[i] += 0.933;
     return ProcessReturn::Ok;
   }
 
+  template <typename TParticle, typename TTrack>
+  inline LengthType getMaxStepLength(TParticle&, TTrack&) {
+    return step_;
+  }
+
+  bool getFlag() const { return flag_; }
+  void resetFlag() { flag_ = false; }
+
 private:
   int v_ = 0;
+  LengthType step_ = 0_m;
+  mutable bool flag_ = false;
 };
 
 class ContinuousProcess2 : public ContinuousProcess<ContinuousProcess2> {
 public:
-  ContinuousProcess2(const int v)
-      : v_(v) {
+  ContinuousProcess2(int const v, LengthType const step)
+      : v_(v)
+      , step_(step) {
     cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
     globalCount++;
   }
 
+  void setStep(LengthType const v) { step_ = v; }
+
   template <typename D, typename T>
-  inline ProcessReturn doContinuous(D& d, T&) const {
+  inline ProcessReturn doContinuous(D& d, T&, bool const flag) const {
+    flag_ = flag;
     cout << "ContinuousProcess2::DoContinuous" << endl;
     checkCont |= 2;
     for (int i = 0; i < nData; ++i) d.data_[i] += 0.111;
     return ProcessReturn::Ok;
   }
 
+  template <typename TParticle, typename TTrack>
+  inline LengthType getMaxStepLength(TParticle&, TTrack&) {
+    return step_;
+  }
+
+  bool getFlag() const { return flag_; }
+  void resetFlag() { flag_ = false; }
+
 private:
   int v_ = 0;
+  LengthType step_ = 0_m;
+  mutable bool flag_ = false;
 };
 
 class ContinuousProcess3 : public ContinuousProcess<ContinuousProcess3> {
 public:
-  ContinuousProcess3(const int v)
-      : v_(v) {
+  ContinuousProcess3(int const v, LengthType const step)
+      : v_(v)
+      , step_(step) {
     cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
     globalCount++;
   }
 
+  void setStep(LengthType const v) { step_ = v; }
+
   template <typename D, typename T>
-  inline ProcessReturn doContinuous(D& d, T&) const {
+  inline ProcessReturn doContinuous(D& d, T&, bool const flag) const {
+    flag_ = flag;
     cout << "ContinuousProcess3::DoContinuous" << endl;
     checkCont |= 4;
     for (int i = 0; i < nData; ++i) d.data_[i] += 0.333;
     return ProcessReturn::Ok;
   }
 
+  template <typename TParticle, typename TTrack>
+  inline LengthType getMaxStepLength(TParticle&, TTrack&) {
+    return step_;
+  }
+
+  bool getFlag() const { return flag_; }
+  void resetFlag() { flag_ = false; }
+
 private:
   int v_ = 0;
+  LengthType step_ = 0_m;
+  mutable bool flag_ = false;
 };
 
 class Process1 : public InteractionProcess<Process1> {
 public:
-  Process1(const int v)
+  Process1(int const v)
       : v_(v) {
     cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
     globalCount++;
@@ -115,7 +161,7 @@ private:
 
 class Process2 : public InteractionProcess<Process2> {
 public:
-  Process2(const int v)
+  Process2(int const v)
       : v_(v) {
     cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
     globalCount++;
@@ -139,7 +185,7 @@ private:
 
 class Process3 : public InteractionProcess<Process3> {
 public:
-  Process3(const int v)
+  Process3(int const v)
       : v_(v) {
     cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
     globalCount++;
@@ -163,14 +209,14 @@ private:
 
 class Process4 : public BaseProcess<Process4> {
 public:
-  Process4(const int v)
+  Process4(int const v)
       : v_(v) {
     cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
     globalCount++;
   }
 
   template <typename D, typename T>
-  inline ProcessReturn doContinuous(D& d, T&) const {
+  inline ProcessReturn doContinuous(D& d, T&, bool const) const {
     std::cout << "Base::doContinuous" << std::endl;
     checkCont |= 8;
     for (int i = 0; i < nData; ++i) { d.data_[i] /= 1.2; }
@@ -187,7 +233,7 @@ private:
 
 class Decay1 : public DecayProcess<Decay1> {
 public:
-  Decay1(const int) {
+  Decay1(int const) {
     cout << "Decay1()" << endl;
     globalCount++;
   }
@@ -204,7 +250,7 @@ public:
 
 class Decay2 : public DecayProcess<Decay2> {
 public:
-  Decay2(const int) {
+  Decay2(int const) {
     cout << "Decay2()" << endl;
     globalCount++;
   }
@@ -221,7 +267,7 @@ public:
 
 class Stack1 : public StackProcess<Stack1> {
 public:
-  Stack1(const int n)
+  Stack1(int const n)
       : StackProcess(n) {}
   template <typename TStack>
   ProcessReturn doStack(TStack&) {
@@ -234,12 +280,16 @@ private:
   int count_ = 0;
 };
 
+// The stack is non-existent for this example
 struct DummyStack {};
+// our data object (particle) is a simple arrary of doubles
 struct DummyData {
   double data_[nData] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 };
+// there is no real trajectory/track
 struct DummyTrajectory {};
-
+// since there is no stack, there is also no view. This is a simplistic dummy object
+// sufficient here.
 struct DummyView {
   DummyView(DummyData& p)
       : p_(p) {}
@@ -247,10 +297,22 @@ struct DummyView {
   DummyData& parent() { return p_; }
 };
 
-TEST_CASE("Process Sequence", "[Process Sequence]") {
+TEST_CASE("ProcessSequence General", "ProcessSequence") {
 
   logging::set_level(logging::level::info);
-  corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v");
+  corsika_logger->set_pattern("[%n:%^%-8l%$]: %v");
+
+  SECTION("BaseProcess") {
+
+    Process1 m1(0);
+    const Process4 m4(3);
+
+    CHECK(is_process_v<Process1>);
+    CHECK_FALSE(is_process_v<DummyData>);
+    CHECK(is_process_v<decltype(m4)>);
+    CHECK(is_process_v<decltype(Decay1(1))>);
+    CHECK(is_process_v<decltype(ContinuousProcess3{3, 3_m})>);
+  }
 
   SECTION("Check construction") {
     globalCount = 0;
@@ -264,10 +326,15 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     CHECK(globalCount == 4);
 
     auto sequence1 = make_sequence(m1, m2, m3, m4);
-    CHECK(is_process_sequence_v<decltype(sequence1)> == true);
-    CHECK(is_process_sequence_v<decltype(m2)> == false);
-    CHECK(is_switch_process_sequence_v<decltype(sequence1)> == false);
-    CHECK(is_switch_process_sequence_v<decltype(m2)> == false);
+    CHECK(is_process_v<decltype(sequence1)>);
+    CHECK(is_process_v<decltype(m2)>);
+    CHECK(is_process_sequence_v<decltype(sequence1)>);
+    CHECK_FALSE(is_process_sequence_v<decltype(m2)>);
+    CHECK_FALSE(is_switch_process_sequence_v<decltype(sequence1)>);
+    CHECK_FALSE(is_switch_process_sequence_v<decltype(m2)>);
+
+    CHECK_FALSE(is_process_sequence_v<decltype(Decay1(7))>);
+    CHECK_FALSE(is_switch_process_sequence_v<decltype(Decay1(7))>);
 
     auto sequence2 = make_sequence(m1, m2, m3);
     CHECK(is_process_sequence_v<decltype(sequence2)> == true);
@@ -278,7 +345,7 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
 
   SECTION("interaction length") {
     globalCount = 0;
-    ContinuousProcess1 cp1(0);
+    ContinuousProcess1 cp1(0, 1_m);
     Process2 m2(1);
     Process3 m3(2);
 
@@ -296,7 +363,7 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
 
   SECTION("lifetime") {
     globalCount = 0;
-    ContinuousProcess1 cp1(0);
+    ContinuousProcess1 cp1(0, 1_m);
     Process2 m2(1);
     Process3 m3(2);
     Decay1 d3(3);
@@ -313,30 +380,61 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     globalCount = 0;
   }
 
-  SECTION("sectionTwo") {
+  SECTION("ContinousProcess") {
     globalCount = 0;
-    ContinuousProcess1 cp1(0); // += 0.933
-    ContinuousProcess2 cp2(1); // += 0.111
-    Process2 m2(2);            //  /= 1.1
-    Process3 m3(3);            //  *= 1.01
+    ContinuousProcess1 cp1(0, 1_m);   // += 0.933
+    ContinuousProcess2 cp2(1, 1.1_m); // += 0.111
+    Process2 m2(2);                   //  /= 1.1
+    Process3 m3(3);                   //  *= 1.01
 
     auto sequence2 = make_sequence(cp1, m2, m3, cp2);
 
+    std::cout << boost::typeindex::type_id<decltype(sequence2)>().pretty_name()
+              << std::endl;
+
     DummyData particle;
     DummyTrajectory track;
 
+    cp1.resetFlag();
+    cp2.resetFlag();
+
+    ContinuousProcessStepLength const step1 = sequence2.getMaxStepLength(particle, track);
+    CHECK(LengthType(step1) == 1_m);
+    sequence2.doContinuous(particle, track, step1);
+    CHECK(cp1.getFlag());
+    CHECK_FALSE(cp2.getFlag());
+    CORSIKA_LOG_INFO("step1, l={}, i={}", LengthType(step1),
+                     ContinuousProcessIndex(step1).getIndex());
+
+    cp1.resetFlag();
+    cp2.resetFlag();
+
+    cp1.setStep(10_m);
+    ContinuousProcessStepLength const step2 = sequence2.getMaxStepLength(particle, track);
+    CHECK(LengthType(step2) == 1.1_m);
+    CHECK(ContinuousProcessIndex(step1) != ContinuousProcessIndex(step2));
+    sequence2.doContinuous(particle, track, step2);
+    CHECK_FALSE(cp1.getFlag());
+    CHECK(cp2.getFlag());
+    CORSIKA_LOG_INFO("step2, l={}, i={}", LengthType(step2),
+                     ContinuousProcessIndex(step2).getIndex());
+
     cout << "-->init sequence2" << endl;
     globalCount = 0;
-    cout << "-->docont" << endl;
+    cout << "-->docontinuous" << endl;
 
     // validation data
     double test_data[nData] = {0};
 
-    const int nLoop = 5;
+    // reset
+    particle = DummyData();
+    track = DummyTrajectory();
+
+    int const nLoop = 5;
     cout << "Running loop with n=" << nLoop << endl;
     for (int iLoop = 0; iLoop < nLoop; ++iLoop) {
       for (int i = 0; i < nData; ++i) { test_data[i] += 0.933 + 0.111; }
-      sequence2.doContinuous(particle, track);
+      sequence2.doContinuous(particle, track, ContinuousProcessIndex(1));
     }
     for (int i = 0; i < nData; i++) {
       cout << "data_[" << i << "]=" << particle.data_[i] << endl;
@@ -355,14 +453,14 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
 
     DummyStack stack;
 
-    const int nLoop = 20;
+    int const nLoop = 20;
     for (int i = 0; i < nLoop; ++i) { sequence1.doStack(stack); }
 
     CHECK(s1.getCount() == 20);
     CHECK(s2.getCount() == 10);
 
-    ContinuousProcess2 cp2(1); // += 0.111
-    Process2 m2(2);            //  /= 1.1
+    ContinuousProcess2 cp2(1, 2_m); // += 0.111
+    Process2 m2(2);                 //  /= 1.1
     auto sequence2 = make_sequence(cp2, m2);
     auto sequence3 = make_sequence(cp2, m2, s1);
 
@@ -373,39 +471,64 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
   }
 }
 
-TEST_CASE("Switch Process Sequence", "[Process Sequence]") {
+TEST_CASE("SwitchProcessSequence", "ProcessSequence") {
 
   logging::set_level(logging::level::info);
-  corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v");
+  corsika_logger->set_pattern("[%n:%^%-8l%$]: %v");
+
+  /**
+   * In this example switching is done only by "data_[0]>0", where
+   * data in an arrray of doubles, DummyData.
+   */
+
+  struct SwitchSelect {
+    SwitchResult operator()(DummyData const& p) const {
+      if (p.data_[0] > 0) return SwitchResult::First;
+      return SwitchResult::Second;
+    }
+  };
+  SwitchSelect select1;
+
+  auto cp1 = ContinuousProcess1(0, 1_m);
+  auto cp2 = ContinuousProcess2(0, 2_m);
+  auto cp3 = ContinuousProcess3(0, 3_m);
+
+  auto sequence1 = make_sequence(Process1(0), cp2, Decay1(0));
+  auto sequence2 = make_sequence(cp3, Process2(0), Decay2(0));
+
+  auto sequence3 = make_sequence(cp1, Process3(0),
+                                 SwitchProcessSequence(sequence1, sequence2, select1));
 
   SECTION("Check construction") {
 
-    struct TestSelect {
-      SwitchResult operator()(const DummyData& p) const {
-        std::cout << "TestSelect data=" << p.data_[0] << std::endl;
-        if (p.data_[0] > 0) return SwitchResult::First;
-        return SwitchResult::Second;
-      }
-    };
-    TestSelect select1;
+    auto sequence_alt =
+        make_sequence(cp1, Process3(0),
+                      make_select(make_sequence(Process1(0), cp2, Decay1(0)),
+                                  make_sequence(cp3, Process2(0), Decay2(0)), select1));
 
-    auto sequence1 = make_sequence(Process1(0), ContinuousProcess2(0), Decay1(0));
-    auto sequence2 = make_sequence(ContinuousProcess3(0), Process2(0), Decay2(0));
+    auto switch_seq = SwitchProcessSequence(sequence1, sequence2, select1);
+    CHECK(is_process_sequence_v<decltype(switch_seq)>);
+    CHECK(is_switch_process_sequence_v<decltype(switch_seq)>);
+    // CHECK(is_switch_process_sequence_v<decltype(&switch_seq)>);
+    CHECK(is_switch_process_sequence_v<decltype(
+              SwitchProcessSequence(sequence1, sequence2, select1))>);
 
-    auto sequence3 = make_sequence(ContinuousProcess1(0), Process3(0),
-                                   SwitchProcessSequence(sequence1, sequence2, select1));
+    CHECK(is_process_sequence_v<decltype(sequence3)>);
+    CHECK_FALSE(is_switch_process_sequence_v<decltype(sequence3)>);
 
-    auto sequence_alt = make_sequence(
-        ContinuousProcess1(0), Process3(0),
-        make_select(make_sequence(Process1(0), ContinuousProcess2(0), Decay1(0)),
-                    make_sequence(ContinuousProcess3(0), Process2(0), Decay2(0)),
-                    select1));
+    CHECK(is_process_sequence_v<decltype(
+              SwitchProcessSequence(sequence1, sequence2, select1))>);
+    CHECK(is_switch_process_sequence_v<decltype(
+              SwitchProcessSequence(sequence1, sequence2, select1))>);
 
     // check that same process sequence can be build in different ways
     CHECK(typeid(sequence3) == typeid(sequence_alt));
-    CHECK(is_process_sequence_v<decltype(sequence3)> == true);
+    CHECK(is_process_sequence_v<decltype(sequence3)>);
     CHECK(is_process_sequence_v<decltype(
-              SwitchProcessSequence(sequence1, sequence2, select1))> == true);
+              SwitchProcessSequence(sequence1, sequence2, select1))>);
+  }
+
+  SECTION("Check interfaces") {
 
     DummyData particle;
     DummyTrajectory track;
@@ -416,7 +539,7 @@ TEST_CASE("Switch Process Sequence", "[Process Sequence]") {
     checkSec = 0;
     checkCont = 0;
     particle.data_[0] = 100; // data positive
-    sequence3.doContinuous(particle, track);
+    sequence3.doContinuous(particle, track, ContinuousProcessIndex(1));
     CHECK(checkInteract == 0);
     CHECK(checkDecay == 0);
     CHECK(checkCont == 0b011);
@@ -427,7 +550,7 @@ TEST_CASE("Switch Process Sequence", "[Process Sequence]") {
     checkSec = 0;
     checkCont = 0;
     particle.data_[0] = -100; // data negative
-    sequence_alt.doContinuous(particle, track);
+    sequence3.doContinuous(particle, track, ContinuousProcessIndex(1));
     CHECK(checkInteract == 0);
     CHECK(checkDecay == 0);
     CHECK(checkCont == 0b101);
@@ -478,4 +601,168 @@ TEST_CASE("Switch Process Sequence", "[Process Sequence]") {
     CHECK(checkCont == 0);
     CHECK(checkSec == 0);
   }
+
+  SECTION("Check ContinuousProcesses in SwitchProcessSequence") {
+
+    DummyData particle;
+    DummyTrajectory track;
+
+    particle.data_[0] =
+        100; // data positive, selects particular branch on SwitchProcessSequence
+
+    cp1.setStep(10_m);
+    cp2.setStep(15_m);
+    cp3.setStep(100_m);
+
+    cp1.resetFlag();
+    cp2.resetFlag();
+    cp3.resetFlag();
+
+    ContinuousProcessStepLength const step1 = sequence3.getMaxStepLength(particle, track);
+    CHECK(LengthType(step1) == 10_m);
+    sequence3.doContinuous(particle, track, step1);
+    CHECK(cp1.getFlag());
+    CHECK_FALSE(cp2.getFlag());
+    CHECK_FALSE(cp3.getFlag());
+    CORSIKA_LOG_INFO("step1, l={}, i={}", LengthType(step1),
+                     ContinuousProcessIndex(step1).getIndex());
+
+    particle.data_[0] =
+        100; // data positive, selects particular branch on SwitchProcessSequence
+
+    cp1.setStep(50_m);
+    cp2.setStep(15_m);
+    cp3.setStep(100_m);
+
+    cp1.resetFlag();
+    cp2.resetFlag();
+    cp3.resetFlag();
+
+    ContinuousProcessStepLength const step2 = sequence3.getMaxStepLength(particle, track);
+    CHECK(LengthType(step2) == 15_m);
+    sequence3.doContinuous(particle, track, step2);
+    CHECK_FALSE(cp1.getFlag());
+    CHECK(cp2.getFlag());
+    CHECK_FALSE(cp3.getFlag());
+    CORSIKA_LOG_INFO("step2, len_cont={}, indexLimit={} type={}", LengthType(step2),
+                     ContinuousProcessIndex(step2).getIndex(),
+                     boost::typeindex::type_id<decltype(sequence3)>().pretty_name());
+
+    particle.data_[0] =
+        -100; // data positive, selects particular branch on SwitchProcessSequence
+
+    cp1.setStep(11_m);
+    cp2.setStep(15_m);
+    cp3.setStep(100_m);
+
+    cp1.resetFlag();
+    cp2.resetFlag();
+    cp3.resetFlag();
+
+    ContinuousProcessStepLength const step3 = sequence3.getMaxStepLength(particle, track);
+    CHECK(LengthType(step3) == 11_m);
+    sequence3.doContinuous(particle, track, step3);
+    CHECK(cp1.getFlag());
+    CHECK_FALSE(cp2.getFlag());
+    CHECK_FALSE(cp3.getFlag());
+    CORSIKA_LOG_INFO("step3, len_cont={}, indexLimit={} type={}", LengthType(step3),
+                     ContinuousProcessIndex(step3).getIndex(),
+                     boost::typeindex::type_id<decltype(sequence3)>().pretty_name());
+
+    particle.data_[0] =
+        -100; // data positive, selects particular branch on SwitchProcessSequence
+
+    cp1.setStep(11_m);
+    cp2.setStep(15_m);
+    cp3.setStep(2_m);
+
+    cp1.resetFlag();
+    cp2.resetFlag();
+    cp3.resetFlag();
+
+    ContinuousProcessStepLength const step4 = sequence3.getMaxStepLength(particle, track);
+    CHECK(LengthType(step4) == 2_m);
+    sequence3.doContinuous(particle, track, step4);
+    CHECK_FALSE(cp1.getFlag());
+    CHECK_FALSE(cp2.getFlag());
+    CHECK(cp3.getFlag());
+    CORSIKA_LOG_INFO("step4, len_cont={}, indexLimit={} type={}", LengthType(step4),
+                     ContinuousProcessIndex(step4).getIndex(),
+                     boost::typeindex::type_id<decltype(sequence3)>().pretty_name());
+  }
+}
+
+TEST_CASE("ProcessSequence Indexing", "ProcessSequence") {
+
+  logging::set_level(logging::level::info);
+  corsika_logger->set_pattern("[%n:%^%-8l%$]: %v");
+
+  SECTION("Indexing") {
+
+    int const n0 = count_continuous<Decay2>::count;
+    int const n1 = count_continuous<ContinuousProcess3>::count;
+    int const n2 = count_continuous<ContinuousProcess2,
+                                    count_continuous<ContinuousProcess3>::count>::count;
+    int const n1_b =
+        count_continuous<Process2, count_continuous<ContinuousProcess3>::count>::count;
+    int const n1_c =
+        count_continuous<ContinuousProcess3, count_continuous<Process2>::count>::count;
+    int const n12 =
+        count_continuous<ContinuousProcess2,
+                         count_continuous<ContinuousProcess3, 10>::count>::count;
+    int const n11_b =
+        count_continuous<Process1,
+                         count_continuous<ContinuousProcess3, 10>::count>::count;
+    int const n11_c = count_continuous<ContinuousProcess3,
+                                       count_continuous<Process1, 10>::count>::count;
+
+    CHECK(n0 == 0);
+    CHECK(n1 == 1);
+    CHECK(n1_b == 1);
+    CHECK(n1_c == 1);
+    CHECK(n2 == 2);
+    CHECK(n11_b == 11);
+    CHECK(n11_c == 11);
+    CHECK(n12 == 12);
+
+    std::cout << count_continuous<ContinuousProcess3>::count << std::endl;
+    std::cout << count_continuous<Process3>::count << std::endl;
+
+    struct SwitchSelect {
+      SwitchResult operator()(DummyData const& p) const {
+        std::cout << "SwitchSelect data=" << p.data_[0] << std::endl;
+        if (p.data_[0] > 0) return SwitchResult::First;
+        return SwitchResult::Second;
+      }
+    };
+
+    auto sequence1 = make_sequence(Process1(0), ContinuousProcess2(0, 2_m), Decay1(0));
+    auto sequence2 = make_sequence(ContinuousProcess3(0, 3_m), Process2(0), Decay2(0),
+                                   ContinuousProcess1(0, 1_m));
+
+    SwitchSelect select1;
+    auto switch_seq = SwitchProcessSequence(sequence1, sequence2, select1);
+
+    auto sequence3 = make_sequence(ContinuousProcess1(0, 1_m), Process3(0), switch_seq);
+    auto sequence4 = make_sequence(ContinuousProcess1(0, 1_m), Process3(0),
+                                   SwitchProcessSequence(sequence1, sequence2, select1));
+
+    int const switch_seq_n = count_continuous<decltype(switch_seq)>::count;
+    int const sequence3_n = count_continuous<decltype(sequence3)>::count;
+
+    CHECK(decltype(sequence1)::getNumberOfProcesses() == 3);
+    CHECK(count_continuous<decltype(sequence1)>::count == 3);
+    CHECK(count_continuous<decltype(sequence2)>::count == 4);
+    CHECK(switch_seq_n == 7);
+    CHECK(sequence3_n == 9);
+    CHECK(count_continuous<decltype(sequence4)>::count == 9);
+
+    std::cout << "switch_seq "
+              << boost::typeindex::type_id<decltype(switch_seq)>().pretty_name()
+              << std::endl;
+
+    std::cout << "sequence3 "
+              << boost::typeindex::type_id<decltype(sequence3)>().pretty_name()
+              << std::endl;
+  }
 }
diff --git a/tests/modules/testObservationPlane.cpp b/tests/modules/testObservationPlane.cpp
index 9b9be4656d447b76552d63ae8e6b83657effa3d2..90a12288bd0b24c4c3021adaf66630fd1265d688 100644
--- a/tests/modules/testObservationPlane.cpp
+++ b/tests/modules/testObservationPlane.cpp
@@ -23,10 +23,10 @@
 
 using namespace corsika;
 
-TEST_CASE("ContinuousProcess interface", "[proccesses][observation_plane]") {
+TEST_CASE("ObservationPlane", "[proccesses][observation_plane]") {
 
-  logging::set_level(logging::level::info);
-  corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v");
+  logging::set_level(logging::level::trace);
+  corsika_logger->set_pattern("[%n:%^%-8l%$]: %v");
 
   auto [env, csPtr, nodePtr] = setup::testing::setup_environment(Code::Oxygen);
   auto const& cs = *csPtr;
@@ -34,48 +34,64 @@ TEST_CASE("ContinuousProcess interface", "[proccesses][observation_plane]") {
   [[maybe_unused]] auto const& node_dummy = nodePtr;
 
   /*
-    Test with downward going 1_GeV neutrino, starting at 0,1_m,10m
+    Test with 1_GeV neutrino, starting at 0,0,0 travelling into +x direction (see
+    setup_stack).
 
-    ObservationPlane has origin at 0,0,0
+    ObservationPlane has origin at 10,0,0 and a normal in x-direction
    */
   auto [stack, viewPtr] =
       setup::testing::setup_stack(Code::NuE, 0, 0, 1_GeV, nodePtr, cs);
   [[maybe_unused]] setup::StackView& view = *viewPtr;
   auto particle = stack->getNextParticle();
 
+  // dummy track. Not used for calculation!
   Point const start(cs, {0_m, 1_m, 10_m});
   VelocityVector vec(cs, 0_m / second, 0_m / second, -constants::c);
   Line line(start, vec);
-
-  setup::Trajectory track =
+  setup::Trajectory no_used_track =
       setup::testing::make_track<setup::Trajectory>(line, 12_m / constants::c);
 
-  particle.setPosition(Point(cs, {1_m, 1_m, 10_m})); // moving already along -z
-
   SECTION("horizontal plane") {
 
-    Plane const obsPlane(Point(cs, {0_m, 0_m, 0_m}), DirectionVector(cs, {0., 0., 1.}));
-    ObservationPlane obs(obsPlane, DirectionVector(cs, {1., 0., 0.}), "particles.dat",
+    Plane const obsPlane(Point(cs, {10_m, 0_m, 0_m}), DirectionVector(cs, {1., 0., 0.}));
+    ObservationPlane obs(obsPlane, DirectionVector(cs, {0., 1., 0.}), "particles.dat",
                          true);
 
-    LengthType const length = obs.getMaxStepLength(particle, track);
-    ProcessReturn const ret = obs.doContinuous(particle, track);
+    LengthType const length = obs.getMaxStepLength(particle, no_used_track);
+    ProcessReturn const ret = obs.doContinuous(particle, no_used_track, true);
 
     CHECK(length / 10_m == Approx(1).margin(1e-4));
     CHECK(ret == ProcessReturn::ParticleAbsorbed);
   }
 
-  SECTION("inclined plane") {}
-
   SECTION("transparent plane") {
-    Plane const obsPlane(Point(cs, {0_m, 0_m, 0_m}), DirectionVector(cs, {0., 0., 1.}));
-    ObservationPlane obs(obsPlane, DirectionVector(cs, {1., 0., 0.}), "particles.dat",
+    Plane const obsPlane(Point(cs, {1_m, 0_m, 0_m}), DirectionVector(cs, {1., 0., 0.}));
+    ObservationPlane obs(obsPlane, DirectionVector(cs, {0., 0., 1.}), "particles.dat",
                          false);
 
-    LengthType const length = obs.getMaxStepLength(particle, track);
-    ProcessReturn const ret = obs.doContinuous(particle, track);
+    LengthType const length = obs.getMaxStepLength(particle, no_used_track);
+    ProcessReturn const ret = obs.doContinuous(particle, no_used_track, true);
 
-    CHECK(length / 10_m == Approx(1).margin(1e-4));
+    CHECK(length / 1_m == Approx(1).margin(1e-4));
     CHECK(ret == ProcessReturn::Ok);
   }
+
+  SECTION("inclined plane, inclined particle") {
+
+    MomentumVector const pnew = MomentumVector(cs, {1_GeV, 0.5_GeV, -0.4_GeV});
+    HEPEnergyType const enew = sqrt(pnew.dot(pnew));
+    particle.setMomentum(pnew);
+    particle.setEnergy(enew);
+
+    Plane const obsPlane(Point(cs, {10_m, 5_m, 5_m}),
+                         DirectionVector(cs, {1, 0.1, -0.05}));
+    ObservationPlane obs(obsPlane, DirectionVector(cs, {0., 1., 0.}), "particles.dat",
+                         true);
+
+    LengthType const length = obs.getMaxStepLength(particle, no_used_track);
+    ProcessReturn const ret = obs.doContinuous(particle, no_used_track, true);
+
+    CHECK(length / 10_m == Approx(1.1375).margin(1e-4));
+    CHECK(ret == ProcessReturn::ParticleAbsorbed);
+  }
 }
diff --git a/tests/modules/testParticleCut.cpp b/tests/modules/testParticleCut.cpp
index 0dede160e563c6abab6a9a3fb2b1f0318f3dc1c7..ef12f58e8489341ad64adcfd0d67194c064514cb 100644
--- a/tests/modules/testParticleCut.cpp
+++ b/tests/modules/testParticleCut.cpp
@@ -14,6 +14,7 @@
 #include <corsika/framework/geometry/Vector.hpp>
 #include <corsika/framework/utility/CorsikaFenv.hpp>
 #include <corsika/media/Environment.hpp>
+#include <corsika/framework/process/ContinuousProcessIndex.hpp>
 
 #include <SetupTestStack.hpp>
 #include <SetupTestTrajectory.hpp>