diff --git a/Documentation/Examples/staticsequence_example.cc b/Documentation/Examples/staticsequence_example.cc
index 1038e06370c5b1af4d7a2572169139a7d0c96ae5..306c3567ed210daed7787a4f3a7fbdd896aa9e55 100644
--- a/Documentation/Examples/staticsequence_example.cc
+++ b/Documentation/Examples/staticsequence_example.cc
@@ -25,43 +25,43 @@ using namespace std;
 
 const int nData = 10;
 
-class Process1 : public BaseProcess {
+class Process1 : public ContinuousProcess<Process1> {
 public:
   Process1() {}
-  template <typename D, typename T, typename S>
-  EProcessReturn DoContinuous(D& d, T&, S&) const {
+  template <typename D, typename T>
+  EProcessReturn DoContinuous(D& d, T&) const {
     for (int i = 0; i < nData; ++i) d.p[i] += 1;
     return EProcessReturn::eOk;
   }
 };
 
-class Process2 : public BaseProcess {
+class Process2 : public ContinuousProcess<Process2> {
 public:
   Process2() {}
 
-  template <typename D, typename T, typename S>
-  inline EProcessReturn DoContinuous(D& d, T&, S&) const {
+  template <typename D, typename T>
+  inline EProcessReturn DoContinuous(D& d, T&) const {
     for (int i = 0; i < nData; ++i) d.p[i] -= 0.1 * i;
     return EProcessReturn::eOk;
   }
 };
 
-class Process3 : public BaseProcess {
+class Process3 : public ContinuousProcess<Process3> {
 public:
   Process3() {}
 
-  template <typename D, typename T, typename S>
-  inline EProcessReturn DoContinuous(D&, T&, S&) const {
+  template <typename D, typename T>
+  inline EProcessReturn DoContinuous(D&, T&) const {
     return EProcessReturn::eOk;
   }
 };
 
-class Process4 : public BaseProcess {
+class Process4 : public ContinuousProcess<Process4> {
 public:
   Process4(const double v)
       : fV(v) {}
-  template <typename D, typename T, typename S>
-  inline EProcessReturn DoContinuous(D& d, T&, S&) const {
+  template <typename D, typename T>
+  inline EProcessReturn DoContinuous(D& d, T&) const {
     for (int i = 0; i < nData; ++i) d.p[i] *= fV;
     return EProcessReturn::eOk;
   }
diff --git a/Framework/ProcessSequence/BaseProcess.h b/Framework/ProcessSequence/BaseProcess.h
index f559a77c3b4f3a0dcc5facae289b0393f4f85a2e..e397d70b26358aaaba514f6ef3941844f1788187 100644
--- a/Framework/ProcessSequence/BaseProcess.h
+++ b/Framework/ProcessSequence/BaseProcess.h
@@ -23,6 +23,13 @@ namespace corsika::process {
    */
 
   struct BaseProcess {
+    static constexpr bool is_boundary_crossing = false;
+    static constexpr bool is_continuous = false;
+    static constexpr bool is_decay = false;
+    static constexpr bool is_interaction = false;
+    static constexpr bool is_secondaries = false;
+    static constexpr bool is_stack = false;
+
     void Init() {} // override this in derived
   };
 
diff --git a/Framework/ProcessSequence/BoundaryCrossingProcess.h b/Framework/ProcessSequence/BoundaryCrossingProcess.h
index 5b7f6ec62f7192112334d86005280a763ad0e929..48618c695390bbcca939b3de25446533bcf1e40c 100644
--- a/Framework/ProcessSequence/BoundaryCrossingProcess.h
+++ b/Framework/ProcessSequence/BoundaryCrossingProcess.h
@@ -20,6 +20,7 @@ namespace corsika::process {
 
   template <typename TDerived>
   struct BoundaryCrossingProcess : BaseProcess {
+    static constexpr bool is_boundary_crossing = true;
 
     /**
      * This method is called when a particle crosses the boundary between the nodes
diff --git a/Framework/ProcessSequence/CMakeLists.txt b/Framework/ProcessSequence/CMakeLists.txt
index a6c2a1701fccba3090b5376a2856090a97a3ae7e..8d2774a944dd6209f9f5ee3328a25776ef6dd192 100644
--- a/Framework/ProcessSequence/CMakeLists.txt
+++ b/Framework/ProcessSequence/CMakeLists.txt
@@ -17,6 +17,7 @@ set (
   StackProcess.h
   DecayProcess.h
   ProcessSequence.h
+  ConditionalProcessSequence.h
   ProcessReturn.h
   )
 
@@ -47,9 +48,17 @@ target_link_libraries (
 CORSIKA_ADD_TEST (testProcessSequence)
 target_link_libraries (
   testProcessSequence
-  ProcessSwitch
   CORSIKAsetup
   CORSIKAgeometry
   CORSIKAprocesssequence
   CORSIKAtesting
   )
+
+  CORSIKA_ADD_TEST (testConditionalProcessSequence)
+  target_link_libraries (
+    testConditionalProcessSequence
+    CORSIKAsetup
+    CORSIKAgeometry
+    CORSIKAprocesssequence
+    CORSIKAtesting
+    )
diff --git a/Framework/ProcessSequence/ConditionalProcessSequence.h b/Framework/ProcessSequence/ConditionalProcessSequence.h
index 9766ac1c2a60d12b6cfc3057b899aac26890f9bc..1c81b4561bce1e48f486db532a3d82ba7ffe35c5 100644
--- a/Framework/ProcessSequence/ConditionalProcessSequence.h
+++ b/Framework/ProcessSequence/ConditionalProcessSequence.h
@@ -14,16 +14,26 @@
 #include <corsika/process/ProcessReturn.h>
 #include <corsika/process/ProcessSequence.h>
 #include <corsika/units/PhysicalUnits.h>
+#include <boost/mp11.hpp>
+#include <type_traits>
 
 namespace corsika::process {
 
-  template <class TPredicate, class... Ts, class... Us>
+  template <class TPredicate, class TSeq, class USeq>
   class ConditionalProcessSequence {
     using predicate_t = TPredicate;
-    using true_seq_t = ProcessSequence<Ts...>;
-    using false_seq_t = ProcessSequence<Us...>;
+    using true_seq_t = TSeq;
+    using false_seq_t = USeq;
 
   public:
+    static constexpr bool is_boundary_crossing =
+        TSeq::is_boundary_crossing || USeq::is_boundary_crossing;
+    static constexpr bool is_continuous = TSeq::is_continuous || USeq::is_continuous;
+    static constexpr bool is_decay = TSeq::is_decay || USeq::is_decay;
+    static constexpr bool is_interaction = TSeq::is_interaction || USeq::is_interaction;
+    static constexpr bool is_secondaries = TSeq::is_secondaries || USeq::is_secondaries;
+    static constexpr bool is_stack = TSeq::is_stack || USeq::is_stack;
+
     template <class TPredicate_, class TTrueSeq, class TFalseSeq>
     ConditionalProcessSequence(TPredicate_&& pred, TTrueSeq&& true_seq,
                                TFalseSeq&& false_seq)
@@ -116,8 +126,8 @@ namespace corsika::process {
     EProcessReturn SelectDecay(TParticle& vP, TSecondaries& vS,
                                corsika::units::si::InverseTimeType decay_select,
                                corsika::units::si::InverseTimeType& decay_inv_count) {
-      return pred_(vP) ? true_seq_.SelectDecay(vP, vS, lambda_select, lambda_inv_count)
-                       : false_seq_.SelectDecay(vP, vS, lambda_select, lambda_inv_count);
+      return pred_(vP) ? true_seq_.SelectDecay(vP, vS, decay_select, decay_inv_count)
+                       : false_seq_.SelectDecay(vP, vS, decay_select, decay_inv_count);
     }
 
     // TODO: this should be removed along with all Init() functions of the processes
@@ -132,6 +142,37 @@ namespace corsika::process {
     false_seq_t false_seq_;
   };
 
+  // deduction guides
+  template <class P, class T, class U>
+  ConditionalProcessSequence(P&&, T&&, U &&)
+      ->ConditionalProcessSequence<
+          P, boost::mp11::mp_rename<std::decay_t<T>, ProcessSequence>,
+          boost::mp11::mp_rename<std::decay_t<U>, ProcessSequence>>;
+
+  // template <class T, class U>
+  // ConditionalProcessSequence(corsika::units::si::HEPEnergyType, T&&, U &&)
+  //     ->ConditionalProcessSequence<
+  //         ByThreshold, boost::mp11::mp_rename<std::decay_t<T>, ProcessSequence>,
+  //         boost::mp11::mp_rename<std::decay_t<U>, ProcessSequence>>;
+
+  struct EnergyThreshold {
+    EnergyThreshold(corsika::units::si::HEPEnergyType x)
+        : value{x} {}
+
+    template <class T>
+    bool operator()(const T& t) const {
+      return t.GetEnergy() > value;
+    }
+
+    corsika::units::si::HEPEnergyType value;
+  };
+
+  template <class... Ts, class... Us>
+  ConditionalProcessSequence(corsika::units::si::HEPEnergyType,
+                             const ProcessSequence<Ts...>&, const ProcessSequence<Us...>&)
+      ->ConditionalProcessSequence<EnergyThreshold, ProcessSequence<Ts...>,
+                                   ProcessSequence<Us...>>;
+
 } // namespace corsika::process
 
 #endif
\ No newline at end of file
diff --git a/Framework/ProcessSequence/ContinuousProcess.h b/Framework/ProcessSequence/ContinuousProcess.h
index d1f9a8b542e4079f06d7896c76ce5a18f3af43e7..c81c510ee6719607c5485c69efe4acf364d490dd 100644
--- a/Framework/ProcessSequence/ContinuousProcess.h
+++ b/Framework/ProcessSequence/ContinuousProcess.h
@@ -28,6 +28,7 @@ namespace corsika::process {
 
   template <typename TDerived>
   struct ContinuousProcess : BaseProcess {
+    static constexpr bool is_continuous = true;
 
     // enforce TDerived to implement this
     template <typename Particle, typename Track>
diff --git a/Framework/ProcessSequence/DecayProcess.h b/Framework/ProcessSequence/DecayProcess.h
index 0cc3aa754e460d3b4750a3b744599a99fb4bc54c..b98dc8a5d4dc4bef055a8384cf689d6d238d5455 100644
--- a/Framework/ProcessSequence/DecayProcess.h
+++ b/Framework/ProcessSequence/DecayProcess.h
@@ -29,6 +29,7 @@ namespace corsika::process {
 
   template <typename TDerived>
   struct DecayProcess : BaseProcess {
+    static constexpr bool is_decay = true;
 
     // enforce TDerived to implement this
     template <typename TParticle>
diff --git a/Framework/ProcessSequence/InteractionProcess.h b/Framework/ProcessSequence/InteractionProcess.h
index c3398a9a8ce73af30d66a6d382a729fb5313ded1..49907064987bcd8324aa12b87bfaa330a941101a 100644
--- a/Framework/ProcessSequence/InteractionProcess.h
+++ b/Framework/ProcessSequence/InteractionProcess.h
@@ -29,6 +29,7 @@ namespace corsika::process {
 
   template <typename TDerived>
   struct InteractionProcess : BaseProcess {
+    static constexpr bool is_interaction = true;
 
     // enforce TDerived to implement this
     template <typename TParticle>
diff --git a/Framework/ProcessSequence/ProcessSequence.h b/Framework/ProcessSequence/ProcessSequence.h
index 24f44d43a05f39bdc4c9535a5230eefe011c2b01..69a610d25690f0b82d9c1543a2840464b01a0bc4 100644
--- a/Framework/ProcessSequence/ProcessSequence.h
+++ b/Framework/ProcessSequence/ProcessSequence.h
@@ -44,54 +44,72 @@ namespace corsika::process {
 
   // marker to track whether some T is a process
   template <class T>
-  constexpr bool is_process_v = std::is_base_of_v<BaseProcess, T>;
+  constexpr bool is_process_v =
+      T::is_boundary_crossing || T::is_continuous || T::is_decay || T::is_interaction ||
+      T::is_secondaries || T::is_stack;
 
-  // forward declare ProcessSequence for is_process_sequence
-  template <class... Ts>
-  class ProcessSequence;
+  template <class T>
+  struct has_boundary_crossing_trait {
+    static constexpr bool value = T::is_boundary_crossing;
+  };
 
-  // forward declare ConditionalProcessSequence for is_process_sequence
-  template <class... Ts>
-  class ConditionalProcessSequence;
+  template <class T>
+  struct has_continuous_trait {
+    static constexpr bool value = T::is_continuous;
+  };
 
   template <class T>
-  struct is_process_sequence : std::false_type {};
+  struct has_decay_trait {
+    static constexpr bool value = T::is_decay;
+  };
 
-  template <class... Ts>
-  struct is_process_sequence<ProcessSequence<Ts...>> : std::true_type {};
+  template <class T>
+  struct has_interaction_trait {
+    static constexpr bool value = T::is_interaction;
+  };
 
-  template <class... Ts>
-  struct is_process_sequence<ConditionalProcessSequence<Ts...>> : std::true_type {};
+  template <class T>
+  struct has_secondaries_trait {
+    static constexpr bool value = T::is_secondaries;
+  };
 
   template <class T>
-  constexpr bool is_process_sequence_v = is_process_sequence<T>::value;
+  struct has_stack_trait {
+    static constexpr bool value = T::is_stack;
+  };
 
   template <class... Ts>
   class ProcessSequence : public std::tuple<Ts...> {
     using storage_t = std::tuple<Ts...>;
 
   public:
+    static constexpr bool is_boundary_crossing =
+        (... || has_boundary_crossing_trait<std::decay_t<Ts>>::value);
+    static constexpr bool is_continuous =
+        (... || has_continuous_trait<std::decay_t<Ts>>::value);
+    static constexpr bool is_decay = (... || has_decay_trait<std::decay_t<Ts>>::value);
+    static constexpr bool is_interaction =
+        (... || has_interaction_trait<std::decay_t<Ts>>::value);
+    static constexpr bool is_secondaries =
+        (... || has_secondaries_trait<std::decay_t<Ts>>::value);
+    static constexpr bool is_stack = (... || has_stack_trait<std::decay_t<Ts>>::value);
+
     template <class... Us>
     ProcessSequence(Us&&... us)
         : storage_t(std::forward<Us>(us)...) {
-      static_assert((... && (is_process_v<std::decay_t<Us>> ||
-                             is_process_sequence_v<std::decay_t<Us>>)),
-                    "all arguments must be processes or other process sequences");
+      static_assert((... && is_process_v<std::decay_t<Us>>),
+                    "all arguments must be processes");
     }
 
     // example for a trait-based call:
     // void Hello() const  { detail::CallHello<T1,T2>::Call(A, B); }
 
-    template <template <class> class Base, class Functor>
+    template <template <class> class Trait, class Functor>
     void for_each(Functor&& functor) {
       boost::mp11::tuple_for_each(static_cast<storage_t&>(*this), [&](auto&& x) {
-        using T = std::decay_t<decltype(x)>;
         // if x is the right kind of Process, run the functor on the Process
-        if constexpr (std::is_base_of_v<Base<T>, T>)
+        if constexpr (Trait<std::decay_t<decltype(x)>>::value)
           std::forward<Functor>(functor)(std::forward<decltype(x)>(x));
-        // if x is a nested process sequence, run the nested for_each loop
-        if constexpr (is_process_sequence_v<T>)
-          x.template for_each<Base>(std::forward<Functor>(functor));
       });
     }
 
@@ -99,7 +117,7 @@ namespace corsika::process {
     EProcessReturn DoBoundaryCrossing(Particle& p, VTNType const& from,
                                       VTNType const& to) {
       EProcessReturn ret = EProcessReturn::eOk;
-      for_each<BoundaryCrossingProcess>(
+      for_each<has_boundary_crossing_trait>(
           [&](auto&& proc) { ret |= proc.DoBoundaryCrossing(p, from, to); });
       return ret;
     }
@@ -107,14 +125,16 @@ namespace corsika::process {
     template <typename TParticle, typename TTrack>
     EProcessReturn DoContinuous(TParticle& vP, TTrack& vT) {
       EProcessReturn ret = EProcessReturn::eOk;
-      for_each<ContinuousProcess>([&](auto&& proc) { ret |= proc.DoContinuous(vP, vT); });
+      for_each<has_continuous_trait>(
+          [&](auto&& proc) { ret |= proc.DoContinuous(vP, vT); });
       return ret;
     }
 
     template <typename TSecondaries>
     EProcessReturn DoSecondaries(TSecondaries& vS) {
       EProcessReturn ret = EProcessReturn::eOk;
-      for_each<SecondariesProcess>([&](auto&& proc) { ret |= proc.DoSecondaries(vS); });
+      for_each<has_secondaries_trait>(
+          [&](auto&& proc) { ret |= proc.DoSecondaries(vS); });
       return ret;
     }
 
@@ -128,7 +148,7 @@ namespace corsika::process {
      */
     bool CheckStep() {
       bool ret = false;
-      for_each<StackProcess>([&](auto&& proc) { ret |= proc.CheckStep(); });
+      for_each<has_stack_trait>([&](auto&& proc) { ret |= proc.CheckStep(); });
       return ret;
     }
 
@@ -138,7 +158,7 @@ namespace corsika::process {
     template <typename TStack>
     EProcessReturn DoStack(TStack& vS) {
       EProcessReturn ret = EProcessReturn::eOk;
-      for_each<StackProcess>([&](auto&& proc) {
+      for_each<has_stack_trait>([&](auto&& proc) {
         if (proc.CheckStep()) ret |= proc.DoStack(vS);
       });
       return ret;
@@ -150,7 +170,7 @@ namespace corsika::process {
 
       // infinite if no other process in the sequence implements it
       LengthType max_length = std::numeric_limits<double>::infinity() * meter;
-      for_each<ContinuousProcess>([&](auto&& proc) {
+      for_each<has_continuous_trait>([&](auto&& proc) {
         const auto len = proc.MaxStepLength(vP, vTrack);
         if (len < max_length) max_length = len;
       });
@@ -173,7 +193,7 @@ namespace corsika::process {
       using namespace corsika::units::si;
 
       InverseGrammageType tot = 0 * meter * meter / gram;
-      for_each<InteractionProcess>(
+      for_each<has_interaction_trait>(
           [&](auto&& proc) { tot += proc.GetInverseInteractionLength(vP); });
       return tot;
     }
@@ -192,7 +212,7 @@ namespace corsika::process {
     corsika::units::si::InverseTimeType GetInverseLifetime(TParticle& p) {
       using namespace corsika::units::si;
       InverseTimeType tot = 0 / second;
-      for_each<DecayProcess>([&](auto&& proc) { tot += proc.GetInverseLifetime(p); });
+      for_each<has_decay_trait>([&](auto&& proc) { tot += proc.GetInverseLifetime(p); });
       return tot;
     }
 
@@ -203,7 +223,7 @@ namespace corsika::process {
         corsika::units::si::InverseGrammageType lambda_select,
         corsika::units::si::InverseGrammageType& lambda_inv_count) {
       EProcessReturn ret = EProcessReturn::eOk;
-      for_each<InteractionProcess>([&](auto&& proc) {
+      for_each<has_interaction_trait>([&](auto&& proc) {
         // check if we should execute THIS process and then EXIT
         if (ret == EProcessReturn::eOk) {
           // if this is not a ContinuousProcess --> evaluate probability
@@ -223,7 +243,7 @@ namespace corsika::process {
                                corsika::units::si::InverseTimeType decay_select,
                                corsika::units::si::InverseTimeType& decay_inv_count) {
       EProcessReturn ret = EProcessReturn::eOk;
-      for_each<DecayProcess>([&](auto&& proc) {
+      for_each<has_decay_trait>([&](auto&& proc) {
         // check if we should execute THIS process and then skip all others
         if (ret == EProcessReturn::eOk) {
           // if this is not a ContinuousProcess --> evaluate probability
@@ -244,13 +264,11 @@ namespace corsika::process {
     }
   };
 
-  // deduction guide: lvalue references are stored as references
-  template <class... Ts>
-  ProcessSequence(Ts&... ts)->ProcessSequence<Ts&...>;
-
-  // deduction guide: rvalue references are stored as values
+  // deduction guide: store lvalue references as references, rvalue references as values
   template <class... Ts>
-  ProcessSequence(Ts&&... ts)->ProcessSequence<Ts...>;
+  ProcessSequence(Ts&&... ts)
+      ->ProcessSequence<
+          boost::mp11::mp_if<std::is_rvalue_reference<Ts>, std::decay_t<Ts>, Ts>...>;
 
 } // namespace corsika::process
 
diff --git a/Framework/ProcessSequence/SecondariesProcess.h b/Framework/ProcessSequence/SecondariesProcess.h
index 5b90e2917d5d2364b3df15d758bebb981fb6af1b..df2a11cf5e27e654ee834ed963377beec60ad640 100644
--- a/Framework/ProcessSequence/SecondariesProcess.h
+++ b/Framework/ProcessSequence/SecondariesProcess.h
@@ -29,6 +29,7 @@ namespace corsika::process {
 
   template <typename TDerived>
   struct SecondariesProcess : BaseProcess {
+    static constexpr bool is_secondaries = true;
 
     // enforce TDerived to implement this
     template <typename TSecondaries>
diff --git a/Framework/ProcessSequence/StackProcess.h b/Framework/ProcessSequence/StackProcess.h
index 5a4e1943c200b4a5744fa43c5dd2475392dbf842..a3f3558dfaa8c462edd3293df86b33f312a6ede8 100644
--- a/Framework/ProcessSequence/StackProcess.h
+++ b/Framework/ProcessSequence/StackProcess.h
@@ -29,6 +29,7 @@ namespace corsika::process {
 
   template <typename TDerived>
   struct StackProcess : BaseProcess {
+    static constexpr bool is_stack = true;
 
     StackProcess() = delete;
     StackProcess(const unsigned int nStep)
diff --git a/Framework/ProcessSequence/testConditionalProcessSequence.cc b/Framework/ProcessSequence/testConditionalProcessSequence.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8961360f1841d962d54ce13dd2d2094939576fbd
--- /dev/null
+++ b/Framework/ProcessSequence/testConditionalProcessSequence.cc
@@ -0,0 +1,129 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <catch2/catch.hpp>
+
+#include <corsika/process/ConditionalProcessSequence.h>
+#include <corsika/process/ProcessSequence.h>
+#include <corsika/units/PhysicalUnits.h>
+#include <tuple>
+#include <vector>
+
+using namespace corsika;
+using namespace corsika::units::si;
+using namespace corsika::process;
+using namespace std;
+
+auto constexpr kgMSq = 1_kg / (1_m * 1_m);
+
+template <int N>
+struct DummyProcess : InteractionProcess<DummyProcess<N>> {
+  void Init() {}
+
+  template <typename TParticle>
+  corsika::units::si::GrammageType GetInteractionLength(TParticle const&) const {
+    return N * kgMSq;
+  }
+
+  template <typename TSecondaries>
+  corsika::process::EProcessReturn DoInteraction(TSecondaries& vSec) {
+    // to figure out which process was selected in the end, we produce N
+    // secondaries for DummyProcess<N>
+
+    for (int i = 0; i < N; ++i) {
+      vSec.AddSecondary(std::tuple<HEPEnergyType>{vSec.GetEnergy() / N});
+    }
+
+    return EProcessReturn::eOk;
+  }
+};
+
+template <class T>
+struct DummySecondaries : std::vector<T> {
+  void AddSecondary(T&& t) { std::vector<T>::push_back(t); }
+};
+
+struct DummyParticle {
+  DummyParticle(corsika::units::si::HEPEnergyType e)
+      : energy(e) {}
+
+  corsika::units::si::HEPEnergyType GetEnergy() const { return energy; }
+
+  corsika::units::si::HEPEnergyType energy;
+};
+
+TEST_CASE("ConditionalProcessSequence") {
+  DummyProcess<1> true_A;
+  DummyProcess<2> true_B;
+  DummyProcess<3> false_P;
+  DummyProcess<4> additional;
+
+  ConditionalProcessSequence<EnergyThreshold,
+                             ProcessSequence<DummyProcess<1>&, DummyProcess<2>&>,
+                             ProcessSequence<DummyProcess<3>&>>
+      cseq(1_TeV, ProcessSequence(true_A, true_B), false_P);
+  ProcessSequence seq(cseq, additional);
+
+  SECTION("low energy") {
+    auto p = DummyParticle{0.5_TeV};
+
+    SECTION("interaction length") {
+      REQUIRE(cseq.GetTotalInteractionLength(p) / kgMSq == Approx(2. / 3));
+      REQUIRE(seq.GetTotalInteractionLength(p) / kgMSq == Approx(4. / 7));
+    }
+
+    // SECTION("SelectInteraction") {
+    //   DummySecondaries<DummyParticle> secondaries;
+    //
+    //   InverseGrammageType invLambda = r * 7. / 4 / kgMSq;
+    //   InverseGrammageType accumulator = 0 / kgMSq;
+    //   seq.SelectInteraction(p, secondaries, invLambda, accumulator);
+    //
+    //   REQUIRE(secondaries.size(), 7);
+    //
+    //   const auto mean = std::accumulate(secondaries.begin(), secondaries.end(), 0.) /
+    //                     secondaries.size();
+    //   REQUIRE(mean == Approx(12. / 7.).margin(0.01));
+    // }
+  }
+
+  SECTION("high energy") {
+    auto p = DummyParticle{3_TeV};
+
+    SECTION("interaction length") {
+      REQUIRE(cseq.GetTotalInteractionLength(p) / kgMSq == Approx(3));
+      REQUIRE(seq.GetTotalInteractionLength(p) / kgMSq == Approx(12. / 7.));
+    }
+
+    // SECTION("SelectInteraction") {
+    //   std::vector<int> numberOfSecondaries;
+    //
+    //   for (int i = 0; i < 1000; ++i) {
+    //     typename SimpleStack::DummyParticle theParticle =
+    //         stack.GetNextParticle(); // as in corsika::Cascade
+    //     StackTestView view(theParticle);
+    //     auto projectile = view.GetProjectile();
+    //
+    //     double r = i / 1000.;
+    //     InverseGrammageType invLambda = r * 7. / 12. / kgMSq;
+    //
+    //     InverseGrammageType accumulator = 0 / kgMSq;
+    //     completeSeq.SelectInteraction(p, projectile, invLambda, accumulator);
+    //
+    //     numberOfSecondaries.push_back(view.GetSize());
+    //   }
+    //
+    //   auto const mean =
+    //       std::accumulate(numberOfSecondaries.cbegin(), numberOfSecondaries.cend(), 0.)
+    //       / numberOfSecondaries.size();
+    //   REQUIRE(mean == Approx(24. / 7.).margin(0.01));
+    // }
+  }
+}
diff --git a/Framework/ProcessSequence/testProcessSequence.cc b/Framework/ProcessSequence/testProcessSequence.cc
index 0b8c95e4a6ce6ba1cbb7411ca8350c28d01ff0f5..ec0baa2dccb7fe467488e645fc676ed2e60bd81e 100644
--- a/Framework/ProcessSequence/testProcessSequence.cc
+++ b/Framework/ProcessSequence/testProcessSequence.cc
@@ -15,7 +15,6 @@
 #include <iostream>
 
 #include <corsika/process/ProcessSequence.h>
-#include <corsika/process/switch_process/SwitchProcess.h>
 
 using namespace corsika;
 using namespace corsika::units::si;
@@ -132,6 +131,9 @@ class Process4 : public BaseProcess {
   int fV = 0;
 
 public:
+  static constexpr bool is_continuous = true;
+  static constexpr bool is_interaction = true;
+
   Process4(const int v)
       : fV(v) {}
   void Init() {
diff --git a/Processes/NullModel/NullModel.cc b/Processes/NullModel/NullModel.cc
index 2e2861dc9375d3340dd4da1c56459b654fc463dd..10c678cb620c1981c1f57fcb7dcbf55d282de6dc 100644
--- a/Processes/NullModel/NullModel.cc
+++ b/Processes/NullModel/NullModel.cc
@@ -20,16 +20,4 @@ namespace corsika::process::null_model {
   NullModel::NullModel(units::si::LengthType maxStepLength)
       : fMaxStepLength(maxStepLength) {}
 
-  template <>
-  process::EProcessReturn NullModel::DoContinuous(setup::Stack::ParticleType&,
-                                                  setup::Trajectory&) const {
-    return process::EProcessReturn::eOk;
-  }
-
-  template <>
-  units::si::LengthType NullModel::MaxStepLength(setup::Stack::ParticleType&,
-                                                 setup::Trajectory&) const {
-    return fMaxStepLength;
-  }
-
 } // namespace corsika::process::null_model
diff --git a/Processes/NullModel/NullModel.h b/Processes/NullModel/NullModel.h
index a46e47ecd8121602cf31dd7137ccc991d5b43594..55cbba7f887d56934e6289cb691317af962ecf39 100644
--- a/Processes/NullModel/NullModel.h
+++ b/Processes/NullModel/NullModel.h
@@ -20,16 +20,22 @@ namespace corsika::process::null_model {
     corsika::units::si::LengthType const fMaxStepLength;
 
   public:
+    static constexpr bool is_continuous = true;
+
     NullModel(corsika::units::si::LengthType maxStepLength =
                   corsika::units::si::meter * std::numeric_limits<double>::infinity());
 
     void Init();
 
     template <typename Particle, typename Track>
-    process::EProcessReturn DoContinuous(Particle&, Track&) const;
+    process::EProcessReturn DoContinuous(Particle&, Track&) const {
+      return process::EProcessReturn::eOk;
+    }
 
     template <typename Particle, typename Track>
-    corsika::units::si::LengthType MaxStepLength(Particle&, Track&) const;
+    corsika::units::si::LengthType MaxStepLength(Particle&, Track&) const {
+      return fMaxStepLength;
+    }
   };
 
 } // namespace corsika::process::null_model