diff --git a/corsika/detail/framework/process/ProcessSequence.inl b/corsika/detail/framework/process/ProcessSequence.inl
index 8492f3d0d924f01e580084a52b234934d7a3f270..d6ad50a44a14372a105d8738cb5f603e785f8b82 100644
--- a/corsika/detail/framework/process/ProcessSequence.inl
+++ b/corsika/detail/framework/process/ProcessSequence.inl
@@ -26,233 +26,239 @@
 
 namespace corsika {
 
-  template <typename T1, typename T2>
+  template <typename TProcess1, typename TProcess2>
   template <typename Particle, typename VTNType>
-  EProcessReturn ProcessSequence<T1, T2>::DoBoundaryCrossing(Particle& p,
+  EProcessReturn ProcessSequence<TProcess1, TProcess2>::doBoundaryCrossing(Particle& particle,
                                                              VTNType const& from,
                                                              VTNType const& to) {
     EProcessReturn ret = EProcessReturn::eOk;
 
-    if constexpr (std::is_base_of<BoundaryCrossingProcess<T1type>, T1type>::value ||
+    if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process1_type>,
+                                    process1_type> ||
                   t1ProcSeq) {
-      ret |= A.DoBoundaryCrossing(p, from, to);
+      ret |= A_.doBoundaryCrossing(particle, from, to);
     }
 
-    if constexpr (std::is_base_of<BoundaryCrossingProcess<T2type>, T2type>::value ||
+    if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process2_type>,
+                                    process2_type> ||
                   t2ProcSeq) {
-      ret |= B.DoBoundaryCrossing(p, from, to);
+      ret |= B_.doBoundaryCrossing(particle, from, to);
     }
 
     return ret;
   }
 
-  template <typename T1, typename T2>
+  template <typename TProcess1, typename TProcess2>
   template <typename TParticle, typename TTrack>
-  EProcessReturn ProcessSequence<T1, T2>::DoContinuous(TParticle& vP, TTrack& vT) {
+  EProcessReturn ProcessSequence<TProcess1, TProcess2>::doContinuous(TParticle& particle, TTrack& vT) {
     EProcessReturn ret = EProcessReturn::eOk;
-    if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value ||
+    if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>, process1_type> ||
                   t1ProcSeq) {
-
-      ret |= A.DoContinuous(vP, vT);
+      ret |= A_.doContinuous(particle, vT);
     }
-    if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value ||
+    if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>, process2_type> ||
                   t2ProcSeq) {
-      ret |= B.DoContinuous(vP, vT);
+      if (!isAbsorbed(ret)) { ret |= B_.doContinuous(particle, vT); }
     }
     return ret;
   }
 
-  template <typename T1, typename T2>
+  template <typename TProcess1, typename TProcess2>
   template <typename TSecondaries>
-  EProcessReturn ProcessSequence<T1, T2>::DoSecondaries(TSecondaries& vS) {
-    EProcessReturn ret = EProcessReturn::eOk;
-    if constexpr (std::is_base_of<SecondariesProcess<T1type>, T1type>::value ||
+  void ProcessSequence<TProcess1, TProcess2>::doSecondaries(TSecondaries& vS) {
+    if constexpr (std::is_base_of_v<SecondariesProcess<process1_type>, process1_type> ||
                   t1ProcSeq) {
-      ret |= A.DoSecondaries(vS);
+      A_.doSecondaries(vS);
     }
-    if constexpr (std::is_base_of<SecondariesProcess<T2type>, T2type>::value ||
+    if constexpr (std::is_base_of_v<SecondariesProcess<process2_type>, process2_type> ||
                   t2ProcSeq) {
-      ret |= B.DoSecondaries(vS);
+      B_.doSecondaries(vS);
     }
-    return ret;
   }
 
-  template <typename T1, typename T2>
-  bool ProcessSequence<T1, T2>::CheckStep() {
+  template <typename TProcess1, typename TProcess2>
+  bool ProcessSequence<TProcess1, TProcess2>::checkStep() {
     bool ret = false;
-    if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) {
-      ret |= A.CheckStep();
+    if constexpr (std::is_base_of_v<StackProcess<process1_type>, process1_type> ||
+                  (t1ProcSeq && !t1SwitchProcSeq)) {
+      ret |= A_.checkStep();
     }
-    if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) {
-      ret |= B.CheckStep();
+    if constexpr (std::is_base_of_v<StackProcess<process2_type>, process2_type> ||
+                  (t2ProcSeq && !t2SwitchProcSeq)) {
+      ret |= B_.checkStep();
     }
     return ret;
   }
 
-  template <typename T1, typename T2>
+  template <typename TProcess1, typename TProcess2>
   template <typename TStack>
-  EProcessReturn ProcessSequence<T1, T2>::DoStack(TStack& vS) {
-    EProcessReturn ret = EProcessReturn::eOk;
-    if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) {
-      if (A.CheckStep()) { ret |= A.DoStack(vS); }
+  void ProcessSequence<TProcess1, TProcess2>::doStack(TStack& stack) {
+    if constexpr (std::is_base_of_v<StackProcess<process1_type>, process1_type> ||
+                  (t1ProcSeq && !t1SwitchProcSeq)) {
+      if (A_.checkStep()) { A_.doStack(stack); }
     }
-    if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) {
-      if (B.CheckStep()) { ret |= B.DoStack(vS); }
+    if constexpr (std::is_base_of_v<StackProcess<process2_type>, process2_type> ||
+                  (t2ProcSeq && !t2SwitchProcSeq)) {
+      if (B_.checkStep()) { B_.doStack(stack); }
     }
-    return ret;
   }
 
-  template <typename T1, typename T2>
+  template <typename TProcess1, typename TProcess2>
   template <typename TParticle, typename TTrack>
-  LengthType ProcessSequence<T1, T2>::MaxStepLength(TParticle& vP, TTrack& vTrack) {
+  LengthType ProcessSequence<TProcess1, TProcess2>::maxStepLength(TParticle& particle, TTrack& vTrack) {
     LengthType max_length = // if no other process in the sequence implements it
         std::numeric_limits<double>::infinity() * meter;
 
-    if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value ||
+    if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>, process1_type> ||
                   t1ProcSeq) {
-      LengthType const len = A.MaxStepLength(vP, vTrack);
+      LengthType const len = A_.maxStepLength(particle, vTrack);
       max_length = std::min(max_length, len);
     }
-    if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value ||
+    if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>, process2_type> ||
                   t2ProcSeq) {
-      LengthType const len = B.MaxStepLength(vP, vTrack);
+      LengthType const len = B_.maxStepLength(particle, vTrack);
       max_length = std::min(max_length, len);
     }
     return max_length;
   }
 
-  template <typename T1, typename T2>
-  template <typename TParticle>
-  GrammageType ProcessSequence<T1, T2>::GetTotalInteractionLength(TParticle& vP) {
-    return 1. / GetInverseInteractionLength(vP);
-  }
-
-  template <typename T1, typename T2>
+  template <typename TProcess1, typename TProcess2>
   template <typename TParticle>
-  InverseGrammageType ProcessSequence<T1, T2>::GetTotalInverseInteractionLength(
-      TParticle& vP) {
-    return GetInverseInteractionLength(vP);
-  }
+  InverseGrammageType ProcessSequence<TProcess1, TProcess2>::getInverseInteractionLength(
+      TParticle&& particle) {
 
-  template <typename T1, typename T2>
-  template <typename TParticle>
-  InverseGrammageType ProcessSequence<T1, T2>::GetInverseInteractionLength(
-      TParticle& vP) {
-    InverseGrammageType tot = 0 * meter * meter / gram;
+    InverseGrammageType tot = 0 * meter * meter / gram; // default value
 
-    if constexpr (std::is_base_of<InteractionProcess<T1type>, T1type>::value ||
-                  t1ProcSeq || t1SwitchProc) {
-      tot += A.GetInverseInteractionLength(vP);
+    if constexpr (std::is_base_of_v<InteractionProcess<process1_type>, process1_type> ||
+                  t1ProcSeq) {
+      tot += A_.getInverseInteractionLength(particle);
     }
-    if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value ||
-                  t2ProcSeq || t2SwitchProc) {
-      tot += B.GetInverseInteractionLength(vP);
+    if constexpr (std::is_base_of_v<InteractionProcess<process2_type>, process2_type> ||
+                  t2ProcSeq) {
+      tot += B_.getInverseInteractionLength(particle);
     }
     return tot;
   }
 
-  template <typename T1, typename T2>
-  template <typename TParticle, typename TSecondaries>
-  EProcessReturn ProcessSequence<T1, T2>::SelectInteraction(
-      TParticle& vP, TSecondaries& vS, [[maybe_unused]] InverseGrammageType lambda_select,
-      InverseGrammageType& lambda_inv_count) {
+  template <typename TProcess1, typename TProcess2>
+  template <typename TSecondaryView>
+  inline EProcessReturn ProcessSequence<TProcess1, TProcess2>::selectInteraction(
+      TSecondaryView& view, [[maybe_unused]] InverseGrammageType lambda_inv_select,
+      [[maybe_unused]] InverseGrammageType lambda_inv_sum) {
 
-    if constexpr (t1ProcSeq || t1SwitchProc) {
+    // TODO: add check for lambda_inv_select>lambda_inv_tot
+
+    if constexpr (t1ProcSeq) {
       // if A is a process sequence --> check inside
-      const EProcessReturn ret =
-          A.SelectInteraction(vP, vS, lambda_select, lambda_inv_count);
-      // if A did succeed, stop routine
+      EProcessReturn const ret =
+          A_.selectInteraction(view, lambda_inv_select, lambda_inv_sum);
+      // if A_ did succeed, stop routine. Not checking other static branch B_.
       if (ret != EProcessReturn::eOk) { return ret; }
-    } else if constexpr (std::is_base_of<InteractionProcess<T1type>, T1type>::value) {
+    } else if constexpr (std::is_base_of_v<InteractionProcess<process1_type>,
+                                           process1_type>) {
       // if this is not a ContinuousProcess --> evaluate probability
-      lambda_inv_count += A.GetInverseInteractionLength(vP);
+      auto const particle = view.parent();
+      lambda_inv_sum += A_.getInverseInteractionLength(particle);
       // check if we should execute THIS process and then EXIT
-      if (lambda_select < lambda_inv_count) {
-        A.DoInteraction(vS);
+      if (lambda_inv_select < lambda_inv_sum) {
+        A_.doInteraction(view);
         return EProcessReturn::eInteracted;
       }
-    } // end branch A
+    } // end branch A_
 
-    if constexpr (t2ProcSeq || t2SwitchProc) {
-      // if A is a process sequence --> check inside
-      const EProcessReturn ret =
-          B.SelectInteraction(vP, vS, lambda_select, lambda_inv_count);
-      // if A did succeed, stop routine
-      if (ret != EProcessReturn::eOk) { return ret; }
-    } else if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value) {
+    if constexpr (t2ProcSeq) {
+      // if B_ is a process sequence --> check inside
+      return B_.selectInteraction(view, lambda_inv_select, lambda_inv_sum);
+    } else if constexpr (std::is_base_of_v<InteractionProcess<process2_type>,
+                                           process2_type>) {
       // if this is not a ContinuousProcess --> evaluate probability
-      lambda_inv_count += B.GetInverseInteractionLength(vP);
+      lambda_inv_sum += B_.getInverseInteractionLength(view.parent());
       // check if we should execute THIS process and then EXIT
-      if (lambda_select < lambda_inv_count) {
-        B.DoInteraction(vS);
+      if (lambda_inv_select < lambda_inv_sum) {
+        B_.doInteraction(view);
         return EProcessReturn::eInteracted;
       }
-    } // end branch A
+    } // end branch B_
     return EProcessReturn::eOk;
   }
 
-  template <typename T1, typename T2>
-  template <typename TParticle>
-  TimeType ProcessSequence<T1, T2>::GetTotalLifetime(TParticle& p) {
-    return 1. / GetInverseLifetime(p);
-  }
-
-  template <typename T1, typename T2>
+  template <typename TProcess1, typename TProcess2>
   template <typename TParticle>
-  InverseTimeType ProcessSequence<T1, T2>::GetTotalInverseLifetime(TParticle& p) {
-    return GetInverseLifetime(p);
-  }
+  inline InverseTimeType ProcessSequence<TProcess1, TProcess2>::getInverseLifetime(
+      TParticle&& particle) {
 
-  template <typename T1, typename T2>
-  template <typename TParticle>
-  InverseTimeType ProcessSequence<T1, T2>::GetInverseLifetime(TParticle& p) {
-    InverseTimeType tot = 0 / second;
+    InverseTimeType tot = 0 / second; // default value
 
-    if constexpr (std::is_base_of<DecayProcess<T1type>, T1type>::value || t1ProcSeq) {
-      tot += A.GetInverseLifetime(p);
+    if constexpr (std::is_base_of_v<DecayProcess<process1_type>, process1_type> ||
+                  t1ProcSeq) {
+      tot += A_.getInverseLifetime(particle);
     }
-    if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value || t2ProcSeq) {
-      tot += B.GetInverseLifetime(p);
+    if constexpr (std::is_base_of_v<DecayProcess<process2_type>, process2_type> ||
+                  t2ProcSeq) {
+      tot += B_.getInverseLifetime(particle);
     }
     return tot;
   }
 
-  template <typename T1, typename T2>
-  template <typename TParticle, typename TSecondaries>
-  EProcessReturn ProcessSequence<T1, T2>::SelectDecay(
-      TParticle& vP, TSecondaries& vS, [[maybe_unused]] InverseTimeType decay_select,
-      InverseTimeType& decay_inv_count) {
+  template <typename TProcess1, typename TProcess2>
+  // select decay process
+  template <typename TSecondaryView>
+  inline EProcessReturn ProcessSequence<TProcess1, TProcess2>::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
+
     if constexpr (t1ProcSeq) {
-      // if A is a process sequence --> check inside
-      const EProcessReturn ret = A.SelectDecay(vP, vS, decay_select, decay_inv_count);
-      // if A did succeed, stop routine
+      // if A_ is a process sequence --> check inside
+      EProcessReturn const ret = A_.selectDecay(view, decay_inv_select, decay_inv_sum);
+      // if A_ did succeed, stop routine here (not checking other static branch B_)
       if (ret != EProcessReturn::eOk) { return ret; }
-    } else if constexpr (std::is_base_of<DecayProcess<T1type>, T1type>::value) {
+    } else if constexpr (std::is_base_of_v<DecayProcess<process1_type>, process1_type>) {
       // if this is not a ContinuousProcess --> evaluate probability
-      decay_inv_count += A.GetInverseLifetime(vP);
+      decay_inv_sum += A_.getInverseLifetime(view.parent());
       // check if we should execute THIS process and then EXIT
-      if (decay_select < decay_inv_count) { // more pedagogical: rndm_select <
-        // decay_inv_count / decay_inv_tot
-        A.DoDecay(vS);
+      if (decay_inv_select < decay_inv_sum) { // more pedagogical: rndm_select <
+                                              // decay_inv_sum / decay_inv_tot
+        A_.doDecay(view);
         return EProcessReturn::eDecayed;
       }
-    } // end branch A
+    } // end branch A_
 
     if constexpr (t2ProcSeq) {
-      // if A is a process sequence --> check inside
-      const EProcessReturn ret = B.SelectDecay(vP, vS, decay_select, decay_inv_count);
-      // if A did succeed, stop routine
-      if (ret != EProcessReturn::eOk) { return ret; }
-    } else if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value) {
+      // if B_ is a process sequence --> check inside
+      return B_.selectDecay(view, decay_inv_select, decay_inv_sum);
+    } else if constexpr (std::is_base_of_v<DecayProcess<process2_type>, process2_type>) {
       // if this is not a ContinuousProcess --> evaluate probability
-      decay_inv_count += B.GetInverseLifetime(vP);
+      decay_inv_sum += B_.getInverseLifetime(view.parent());
       // check if we should execute THIS process and then EXIT
-      if (decay_select < decay_inv_count) {
-        B.DoDecay(vS);
+      if (decay_inv_select < decay_inv_sum) {
+        B_.doDecay(view);
         return EProcessReturn::eDecayed;
       }
-    } // end branch B
+    } // end branch B_
     return EProcessReturn::eOk;
   }
 
+  /**
+   * traits marker to identify objects containing any StackProcesses
+   **/
+  namespace detail {
+    // need helper alias to achieve this:
+    template <typename TProcess1, typename TProcess2,
+              typename = typename std::enable_if_t<
+                  contains_stack_process_v<TProcess1> ||
+                      std::is_base_of_v<StackProcess<typename std::decay_t<TProcess1>>,
+                                        typename std::decay_t<TProcess1>> ||
+                      contains_stack_process_v<TProcess2> ||
+                      std::is_base_of_v<StackProcess<typename std::decay_t<TProcess2>>,
+                                        typename std::decay_t<TProcess2>>,
+                  int>>
+    using enable_if_stack = ProcessSequence<TProcess1, TProcess2>;
+  } // namespace detail
+
+  template <typename TProcess1, typename TProcess2>
+  struct contains_stack_process<detail::enable_if_stack<TProcess1, TProcess2>>
+      : std::true_type {};
+
 } // namespace corsika
diff --git a/corsika/framework/process/BaseProcess.hpp b/corsika/framework/process/BaseProcess.hpp
index a8a353c581067467318c97a9747c3ab0e052d3ca..d5d939201812222528bbececf3cfecd6a0d7dc3e 100644
--- a/corsika/framework/process/BaseProcess.hpp
+++ b/corsika/framework/process/BaseProcess.hpp
@@ -8,9 +8,6 @@ n/*
 
 #pragma once
 
-#include <corsika/framework/process/ProcessReturn.hpp> // for convenience
-#include <type_traits>
-
 namespace corsika {
 
   class TDerived; // fwd decl
@@ -23,11 +20,14 @@ namespace corsika {
      are of type BaseProcess<T>
 
      \todo rename BaseProcess into just Process
+     \todo rename _BaseProcess, or find better alternative in
+     ./Processes/AnalyticProcessors/ExecTime.h, see e.g. how this is done in
+     ProcessSequence.hpp/make_sequence
    */
   class _BaseProcess {};
 
   template <typename TDerived>
-  class BaseProcess : _BaseProcess {
+  struct BaseProcess : _BaseProcess {
   protected:
     friend TDerived;
 
@@ -35,16 +35,12 @@ namespace corsika {
                              // derived classes to be created, not
                              // BaseProcess itself
 
-    TDerived& GetRef() { return static_cast<TDerived&>(*this); }
-    const TDerived& GetRef() const { return static_cast<const TDerived&>(*this); }
+    TDerived& ref() { return static_cast<TDerived&>(*this); }
+    const TDerived& ref() const { return static_cast<const TDerived&>(*this); }
 
   public:
     // Base processor type for use in other template classes
     using TProcessType = TDerived;
   };
 
-  // overwrite the default trait class, to mark BaseProcess<T> as useful process
-  template <class T>
-  std::true_type is_process_impl(const BaseProcess<T>* impl);
-
 } // namespace corsika
diff --git a/corsika/framework/process/BoundaryCrossingProcess.hpp b/corsika/framework/process/BoundaryCrossingProcess.hpp
index 59d2fa043123b652ffba03f8237e0c1f966fde37..80d0246f17ce36f8e316dd9be56e48d4c97e27ca 100644
--- a/corsika/framework/process/BoundaryCrossingProcess.hpp
+++ b/corsika/framework/process/BoundaryCrossingProcess.hpp
@@ -13,15 +13,8 @@ n/*
 
 namespace corsika {
 
-  template <typename TDerived>
-  struct BoundaryCrossingProcess {
-    auto& GetRef() { return static_cast<TDerived&>(*this); }
-    auto const& GetRef() const { return static_cast<const TDerived&>(*this); }
-
   template <typename TDerived>
   class BoundaryCrossingProcess : public BaseProcess<TDerived> {
-  private:
-  protected:
   public:
     /**
      * This method is called when a particle crosses the boundary between the nodes
@@ -32,7 +25,4 @@ namespace corsika {
                                       TVolumeNode const& to);
   };
 
-  template <class T>
-  std::true_type is_process_impl(BoundaryCrossingProcess<T> const* impl);
-
 } // namespace corsika
diff --git a/corsika/framework/process/ContinuousProcess.hpp b/corsika/framework/process/ContinuousProcess.hpp
index b24bed9b1017adbbc0748d2688a91eb6fcb270ca..a397ef79e40db01b5717d4992525f83ef2fabda1 100644
--- a/corsika/framework/process/ContinuousProcess.hpp
+++ b/corsika/framework/process/ContinuousProcess.hpp
@@ -8,8 +8,8 @@ n/*
 
 #pragma once
 
-#include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/process/ProcessReturn.hpp> // for convenience
+#include <corsika/framework/process/BaseProcess.hpp>
+#include <corsika/framework/process/ProcessReturn.hpp>
 
 namespace corsika {
 
@@ -30,15 +30,11 @@ namespace corsika {
     // here starts the interface part
     // -> enforce TDerived to implement DoContinuous...
     template <typename TParticle, typename TTrack>
-    EProcessReturn DoContinuous(TParticle&, TTrack const&) const;
+    EProcessReturn doContinuous(TParticle&, TTrack const&) const;
 
-    // -> enforce derived to implement MaxStepLength...
-    template <typename Particle, typename Track>
-    LengthType MaxStepLength(Particle const& p, Track const& track) const;
+    // -> enforce TDerived to implement MaxStepLength...
+    template <typename TParticle, typename TTrack>
+    units::si::LengthType maxStepLength(TParticle const& p, TTrack const& track) const;
   };
 
-  // overwrite the default trait class, to mark BaseProcess<T> as useful process
-  template <class T>
-  std::true_type is_process_impl(const ContinuousProcess<T>* impl);
-
 } // namespace corsika
diff --git a/corsika/framework/process/DecayProcess.hpp b/corsika/framework/process/DecayProcess.hpp
index 84acb4d8c5abcb70287737abc0db1c2f4810a721..6794e8be372b48833553ea599f27bf5f1a897a29 100644
--- a/corsika/framework/process/DecayProcess.hpp
+++ b/corsika/framework/process/DecayProcess.hpp
@@ -8,10 +8,8 @@ n/*
 
 #pragma once
 
-#include <type_traits>
-
+#include <corsika/framework/process/BaseProcess.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/process/ProcessReturn.hpp>
 
 namespace corsika {
 
@@ -27,25 +25,19 @@ namespace corsika {
   template <typename TDerived>
   struct DecayProcess : BaseProcess<TDerived> {
   public:
-    using BaseProcess<TDerived>::GetRef;
+    using BaseProcess<TDerived>::ref;
 
     /// here starts the interface-definition part
     // -> enforce TDerived to implement DoDecay...
     template <typename TParticle>
-    EProcessReturn DoDecay(TParticle&);
+    EProcessReturn doDecay(TParticle&);
 
-    template <typename Particle>
-    TimeType GetLifetime(Particle& p);
+    template <typename TParticle>
+    TimeType getLifetime(TParticle const&);
 
-    template <typename Particle>
-    InverseTimeType GetInverseLifetime(Particle& vP) {
-      return 1. / GetRef().GetLifetime(vP);
+    template <typename TParticle>
+    InverseTimeType getInverseLifetime(TParticle const& particle) {
+      return 1. / ref().getLifetime(particle);
     }
 
-    /*    template <typename TParticle>
-    corsika::units::si::InverseTimeType GetInverseInteractionLength(TParticle&& particle)
-    { auto p = std::move(particle); return 1. / GetRef().GetLifetime(p);
-      }*/
-  };
-
 } // namespace corsika
diff --git a/corsika/framework/process/InteractionProcess.hpp b/corsika/framework/process/InteractionProcess.hpp
index 13a0dce1eb560ff0fc82e5fa1666e73abe6e5938..1b1c632edbeba9cbd3568cecc3b1833d905004a1 100644
--- a/corsika/framework/process/InteractionProcess.hpp
+++ b/corsika/framework/process/InteractionProcess.hpp
@@ -8,10 +8,8 @@ n/*
 
 #pragma once
 
-#include <type_traits>
-
+#include <corsika/framework/process/BaseProcess.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/process/ProcessReturn.hpp>
 
 namespace corsika {
 
@@ -27,24 +25,21 @@ namespace corsika {
   template <typename TDerived>
   class InteractionProcess : public BaseProcess<TDerived> {
   public:
-    using BaseProcess<TDerived>::GetRef;
+    using BaseProcess<TDerived>::ref;
 
     /// here starts the interface-definition part
     // -> enforce TDerived to implement DoInteraction...
     template <typename TParticle>
-    EProcessReturn DoInteraction(TParticle&);
+    EProcessReturn doInteraction(TParticle&);
 
     template <typename TParticle>
-    GrammageType GetInteractionLength(TParticle& p);
+    corsika::units::si::GrammageType getInteractionLength(TParticle const&);
 
     template <typename TParticle>
-    InverseGrammageType GetInverseInteractionLength(TParticle& p) {
-      return 1. / GetRef().GetInteractionLength(p);
+    corsika::units::si::InverseGrammageType getInverseInteractionLength(
+        TParticle const& particle) {
+      return 1. / ref().getInteractionLength(particle);
     }
   };
 
-  // overwrite the default trait class, to mark BaseProcess<T> as useful process
-  template <class T>
-  std::true_type is_process_impl(const InteractionProcess<T>* impl);
-
 } // namespace corsika
diff --git a/corsika/framework/process/ProcessReturn.hpp b/corsika/framework/process/ProcessReturn.hpp
index 72949ea01358bdc791e605cd8bb7c2f55d526932..c03721cd5ec453c15a772cab77c99ca86b91a5f4 100644
--- a/corsika/framework/process/ProcessReturn.hpp
+++ b/corsika/framework/process/ProcessReturn.hpp
@@ -39,4 +39,20 @@ namespace corsika {
     return (static_cast<int>(a) & static_cast<int>(b)) != 0;
   }
 
+  inline bool isOk(const EProcessReturn a) {
+    return static_cast<int>(a & EProcessReturn::eOk);
+  }
+
+  inline bool isAbsorbed(const EProcessReturn a) {
+    return static_cast<int>(a & EProcessReturn::eParticleAbsorbed);
+  }
+
+  inline bool isDecayed(const EProcessReturn a) {
+    return static_cast<int>(a & EProcessReturn::eDecayed);
+  }
+
+  inline bool isInteracted(const EProcessReturn a) {
+    return static_cast<int>(a & EProcessReturn::eInteracted);
+  }
+
 } // namespace corsika
diff --git a/corsika/framework/process/ProcessSequence.hpp b/corsika/framework/process/ProcessSequence.hpp
index fdc8565e9a646c64aa6d2d7d8ad23d22bb01258f..be7a93f085534374a3cf791227dd8c7710fd23e0 100644
--- a/corsika/framework/process/ProcessSequence.hpp
+++ b/corsika/framework/process/ProcessSequence.hpp
@@ -8,9 +8,8 @@ n/*
 
 #pragma once
 
-#include <corsika/framework/core/PhysicalUnits.hpp>
-
 #include <corsika/framework/process/BaseProcess.hpp>
+#include <corsika/framework/process/ProcessTraits.hpp>
 #include <corsika/framework/process/BoundaryCrossingProcess.hpp>
 #include <corsika/framework/process/ContinuousProcess.hpp>
 #include <corsika/framework/process/DecayProcess.hpp>
@@ -18,15 +17,13 @@ n/*
 #include <corsika/framework/process/ProcessReturn.hpp>
 #include <corsika/framework/process/SecondariesProcess.hpp>
 #include <corsika/framework/process/StackProcess.hpp>
-
-#include <cmath>
-#include <limits>
-#include <type_traits>
+#include <corsika/framework/process/NullModel.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
 
 namespace corsika {
 
   /**
-   * FIXME
+   *
      \class ProcessSequence
 
      A compile time static list of processes. The compiler will
@@ -38,26 +35,26 @@ namespace corsika {
      they are just classes. This allows us to handle both, rvalue as
      well as lvalue Processes in the ProcessSequence.
 
-     \comment Using CRTP pattern,
-     https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
+     The sequence, and the processes use CRTP.
    */
+
   template <typename TProcess1, typename TProcess2 = NullModel>
   class ProcessSequence : public BaseProcess<ProcessSequence<TProcess1, TProcess2>> {
 
-    using TProcess1type = typename std::decay_t<TProcess1>;
-    using TProcess2type = typename std::decay_t<TProcess2>;
+    using process1_type = typename std::decay_t<TProcess1>;
+    using process2_type = typename std::decay_t<TProcess2>;
 
-    static bool constexpr t1ProcSeq = is_process_sequence_v<TProcess1type>;
-    static bool constexpr t2ProcSeq = is_process_sequence_v<TProcess2type>;
+    static bool constexpr t1ProcSeq = is_process_sequence_v<process1_type>;
+    static bool constexpr t2ProcSeq = is_process_sequence_v<process2_type>;
 
-    static bool constexpr t1SwitchProcSeq = is_switch_process_sequence_v<TProcess1type>;
-    static bool constexpr t2SwitchProcSeq = is_switch_process_sequence_v<TProcess2type>;
+    static bool constexpr t1SwitchProcSeq = is_switch_process_sequence_v<process1_type>;
+    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<TProcess1type>, TProcess1type>,
+    static_assert(std::is_base_of_v<BaseProcess<process1_type>, process1_type>,
                   "can only use process derived from BaseProcess in "
                   "ProcessSequence, for Process 1");
-    static_assert(std::is_base_of_v<BaseProcess<TProcess2type>, TProcess2type>,
+    static_assert(std::is_base_of_v<BaseProcess<process2_type>, process2_type>,
                   "can only use process derived from BaseProcess in "
                   "ProcessSequence, for Process 2");
 
@@ -69,18 +66,15 @@ namespace corsika {
         : A_(in_A)
         , B_(in_B) {}
 
-    // example for a trait-based call:
-    // void Hello() const  { detail::CallHello<T1,T2>::Call(A, B); }
-
-    template <typename Particle, typename VTNType>
-    EProcessReturn DoBoundaryCrossing(Particle& p, VTNType const& from,
-                                      VTNType const& to);
+    template <typename TParticle, typename TVTNType>
+    EProcessReturn doBoundaryCrossing(TParticle& particle, TVTNType const& from,
+                                      TVTNType const& to);
 
     template <typename TParticle, typename TTrack>
-    EProcessReturn DoContinuous(TParticle& vP, TTrack& vT);
+    inline EProcessReturn doContinuous(TParticle& particle, TTrack& vT);
 
     template <typename TSecondaries>
-    EProcessReturn DoSecondaries(TSecondaries& vS);
+    inline void doSecondaries(TSecondaries& vS);
 
     /**
        The processes of type StackProcess do have an internal counter,
@@ -90,53 +84,48 @@ namespace corsika {
        tested if either A_ or B_ are StackProcess and if they are due
        for execution.
      */
-    bool CheckStep();
+    inline bool checkStep();
 
     /**
        Execute the StackProcess-es in the ProcessSequence
      */
     template <typename TStack>
-    EProcessReturn DoStack(TStack& vS);
+    inline void doStack(TStack& stack);
 
     template <typename TParticle, typename TTrack>
-    LengthType MaxStepLength(TParticle& vP, TTrack& vTrack);
-    template <typename TParticle>
-    GrammageType GetTotalInteractionLength(TParticle& vP);
+    inline LengthType maxStepLength(TParticle& particle, TTrack& vTrack);
 
     template <typename TParticle>
-    inline InverseGrammageType GetTotalInverseInteractionLength(TParticle& vP);
+    inline GrammageType getInteractionLength(TParticle&& particle) {
+      return 1. / getInverseInteractionLength(particle);
+    }
 
     template <typename TParticle>
-    inline InverseGrammageType GetInverseInteractionLength(TParticle& vP);
+    inline InverseGrammageType getInverseInteractionLength(TParticle&& particle);
 
-    template <typename TParticle, typename TSecondaries>
-    EProcessReturn SelectInteraction(TParticle& vP, TSecondaries& vS,
-                                     [[maybe_unused]] InverseGrammageType lambda_select,
-                                     InverseGrammageType& lambda_inv_count);
-
-    template <typename TParticle>
-    TimeType GetTotalLifetime(TParticle& p);
+    template <typename TSecondaryView>
+    inline EProcessReturn selectInteraction(
+        TSecondaryView& view, [[maybe_unused]] InverseGrammageType lambda_inv_select,
+        [[maybe_unused]] InverseGrammageType lambda_inv_sum =
+            InverseGrammageType::zero());
 
     template <typename TParticle>
-    InverseTimeType GetTotalInverseLifetime(TParticle& p);
+    inline TimeType getLifetime(TParticle& particle) {
+      return 1. / getInverseLifetime(particle);
+    }
 
     template <typename TParticle>
-    InverseTimeType GetInverseLifetime(TParticle& p);
+    inline InverseTimeType getInverseLifetime(TParticle&& particle);
 
     // select decay process
-    template <typename TParticle, typename TSecondaries>
-    EProcessReturn SelectDecay(TParticle& vP, TSecondaries& vS,
-                               [[maybe_unused]] InverseTimeType decay_select,
-                               InverseTimeType& decay_inv_count);
-
-    void Init() {
-      A.Init();
-      B.Init();
-    }
+    template <typename TSecondaryView>
+    inline EProcessReturn selectDecay(
+        TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select,
+        [[maybe_unused]] InverseTimeType decay_inv_sum = InverseTimeType::zero());
   };
 
   /**
-   * \function sequence
+   * \function make_sequence
    *
    * to construct ProcessSequences in a flexible and dynamic way the
    * `sequence` factory functions are provided
@@ -159,15 +148,55 @@ namespace corsika {
   inline typename std::enable_if_t<
       std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>,
                         typename std::decay_t<TProcess1>>,
-      ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>>
-  sequence(TProcess1&& vA, TProcesses&&... vBs) {
-    return ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>(
-        vA, sequence(std::forward<TProcesses>(vBs)...));
+      ProcessSequence<TProcess1, decltype(make_sequence(std::declval<TProcesses>()...))>>
+  make_sequence(TProcess1&& vA, TProcesses&&... vBs) {
+    return ProcessSequence<TProcess1,
+                           decltype(make_sequence(std::declval<TProcesses>()...))>(
+        vA, make_sequence(std::forward<TProcesses>(vBs)...));
   }
 
-  /// marker to identify objectas ProcessSequence
-  template <typename A, typename B>
-  struct is_process_sequence<corsika::ProcessSequence<A, B>> : std::true_type {};
+  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>>
+  make_sequence(TProcess1&& vA, TProcess2&& vB) {
+    return ProcessSequence<TProcess1, TProcess2>(vA, vB);
+  }
+
+  /**
+   * \ function make_sequence
+   *
+   * also allow a single Process in ProcessSequence, accompany by
+   * `NullModel`
+   **/
+  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>>
+  make_sequence(TProcess&& vA) {
+    return ProcessSequence<TProcess, NullModel>(vA, NullModel());
+  }
+
+  /**
+   * \class is_process_sequence
+   *
+   * traits marker to identify objectas ProcessSequence
+   **/
+  template <typename TProcess1, typename TProcess2>
+  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_sequence() {}
+  };
 
 } // namespace corsika
 
diff --git a/corsika/framework/process/ProcessSignature.hpp b/corsika/framework/process/ProcessSignature.hpp
deleted file mode 100644
index a7cca793ea6171f9215a64516628ad40b8e0cc64..0000000000000000000000000000000000000000
--- a/corsika/framework/process/ProcessSignature.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-n/*
- * (c) Copyright 2020 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
-
-#define FORCE_SIGNATURE(nameTrait, nameMethod, signatureMethod)                \
-  template <typename U>                                                        \
-  class nameTrait {                                                            \
-  private:                                                                     \
-    template <typename T, T>                                                   \
-    struct helper;                                                             \
-    template <typename T>                                                      \
-    static std::uint8_t check(helper<signatureMethod, &nameMethod>*);          \
-    template <typename T>                                                      \
-    static std::uint16_t check(...);                                           \
-                                                                               \
-  public:                                                                      \
-    static constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
-  }
-
-// FORCE_SIGNATURE(thisMustBeDefined, T::thisMustBeDefined, int(*)(void));
diff --git a/corsika/framework/process/SecondariesProcess.hpp b/corsika/framework/process/SecondariesProcess.hpp
index 273d1a730fe2686ff8086f4ae2a0cdcddcd58c18..e7e80a8673a85a23c5bf1186b1f532f5e25ead3e 100644
--- a/corsika/framework/process/SecondariesProcess.hpp
+++ b/corsika/framework/process/SecondariesProcess.hpp
@@ -8,8 +8,8 @@
 
 #pragma once
 
+#include <corsika/framework/process/BaseProcess.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/process/ProcessReturn.hpp>
 
 namespace corsika {
 
@@ -28,11 +28,7 @@ namespace corsika {
     /// here starts the interface-definition part
     // -> enforce TDerived to implement DoSecondaries...
     template <typename TSecondaries>
-    inline void DoSecondaries(TSecondaries&);
+    inline void doSecondaries(TSecondaries&);
   };
 
-  // overwrite the default trait class, to mark BaseProcess<T> as useful process
-  template <class T>
-  std::true_type is_process_impl(const SecondariesProcess<T>* impl);
-
 } // namespace corsika
diff --git a/corsika/framework/process/StackProcess.hpp b/corsika/framework/process/StackProcess.hpp
index 162bb789b0d4e8fbcee34f71cba6cc43b7438650..5eeb2bb4884cda3ab2602c419de0a3eae9d2e6b6 100644
--- a/corsika/framework/process/StackProcess.hpp
+++ b/corsika/framework/process/StackProcess.hpp
@@ -8,8 +8,8 @@
 
 #pragma once
 
+#include <corsika/framework/process/BaseProcess.hpp>
 #include <corsika/framework/core/PhysicalUnits.hpp>
-#include <corsika/framework/process/ProcessReturn.hpp> // for convenience
 
 namespace corsika {
 
@@ -29,15 +29,15 @@ namespace corsika {
   public:
     StackProcess() = delete;
     StackProcess(const unsigned int nStep)
-        : fNStep(nStep) {}
+        : nStep_(nStep) {}
 
     /// here starts the interface-definition part
     // -> enforce TDerived to implement DoStack...
     template <typename TStack>
-    inline void DoStack(TStack&);
+    inline void doStack(TStack&);
 
-    int GetStep() const { return fIStep; }
-    bool CheckStep() { return !((++fIStep) % fNStep); }
+    int getStep() const { return iStep_; }
+    bool checkStep() { return !((++iStep_) % nStep_); }
 
   private:
     /**
@@ -46,13 +46,9 @@ namespace corsika {
        "fIStep modulo fNStep"
        @{
      */
-    unsigned int fNStep = 0;
-    unsigned long int fIStep = 0;
+    unsigned int nStep_ = 0;
+    unsigned long int iStep_ = 0;
     //! @}
   };
 
-  // overwrite the default trait class, to mark BaseProcess<T> as useful process
-  template <class T>
-  std::true_type is_process_impl(const StackProcess<T>* impl);
-
 } // namespace corsika
diff --git a/tests/framework/CMakeLists.txt b/tests/framework/CMakeLists.txt
index 3def966d1729e33ba9461ead21bb477f459be6d6..194438a92c399273dbe31bacbacdf0cede74f2d8 100644
--- a/tests/framework/CMakeLists.txt
+++ b/tests/framework/CMakeLists.txt
@@ -12,7 +12,8 @@ set (test_framework_sources
   testLogging.cpp
   TestMain.cpp
   testParticles.cpp
-  #testProcessSequence.cpp #FIXME: reenable this
+  testNullModel.cpp
+  testProcessSequence.cpp
   testRandom.cpp
   testSecondaryView.cpp
   testStackInterface.cpp
diff --git a/tests/framework/testCascade.cpp b/tests/framework/testCascade.cpp
index f8b0d8734bd377b6c72067d8e6672e2394332950..6fdbb86abacb8d35f6167970997727e73f5e5b9b 100644
--- a/tests/framework/testCascade.cpp
+++ b/tests/framework/testCascade.cpp
@@ -11,9 +11,9 @@
 #include <corsika/framework/core/Cascade.hpp>
 
 #include <corsika/framework/sequence/ProcessSequence.hpp>
-#include <corsika/process/NullModel.hpp>
-#include <corsika/process/StackInspector.hpp>
-#include <corsika/process/TrackingLine.hpp>
+#include <corsika/framework/sequence/NullModel.hpp>
+#include <corsika/modules/StackInspector.hpp>
+#include <corsika/modules/TrackingLine.hpp>
 
 #include <corsika/framework/core/ParticleProperties.hpp>
 
diff --git a/tests/framework/testProcessSequence.cpp b/tests/framework/testProcessSequence.cpp
index 53ae9e26fb0a6f2e289652abf1a7f36e8641fc4f..c5f2668a86d3a24cbbe2a87d848b3b9c537e7caa 100644
--- a/tests/framework/testProcessSequence.cpp
+++ b/tests/framework/testProcessSequence.cpp
@@ -7,6 +7,8 @@
  */
 
 #include <corsika/framework/process/ProcessSequence.hpp>
+#include <corsika/framework/process/SwitchProcessSequence.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
 
 #include <catch2/catch.hpp>
 
@@ -15,8 +17,6 @@
 #include <iostream>
 #include <typeinfo>
 
-using namespace corsika;
-using namespace corsika::units::si;
 using namespace corsika;
 using namespace std;
 
@@ -41,7 +41,7 @@ public:
   }
 
   template <typename D, typename T>
-  inline EProcessReturn DoContinuous(D& d, T&) const {
+  inline EProcessReturn doContinuous(D& d, T&) const {
     cout << "ContinuousProcess1::DoContinuous" << endl;
     checkCont |= 1;
     for (int i = 0; i < nData; ++i) d.data_[i] += 0.933;
@@ -60,7 +60,7 @@ public:
   }
 
   template <typename D, typename T>
-  inline EProcessReturn DoContinuous(D& d, T&) const {
+  inline EProcessReturn doContinuous(D& d, T&) const {
     cout << "ContinuousProcess2::DoContinuous" << endl;
     checkCont |= 2;
     for (int i = 0; i < nData; ++i) d.data_[i] += 0.111;
@@ -79,7 +79,7 @@ public:
   }
 
   template <typename D, typename T>
-  inline EProcessReturn DoContinuous(D& d, T&) const {
+  inline EProcessReturn doContinuous(D& d, T&) const {
     cout << "ContinuousProcess3::DoContinuous" << endl;
     checkCont |= 4;
     for (int i = 0; i < nData; ++i) d.data_[i] += 0.333;
@@ -96,11 +96,17 @@ public:
   }
 
   template <typename TView>
-  inline EProcessReturn DoInteraction(TView& v) const {
+  inline EProcessReturn doInteraction(TView& v) const {
     checkInteract |= 1;
     for (int i = 0; i < nData; ++i) v.parent().data_[i] += 1 + i;
     return EProcessReturn::eOk;
   }
+
+  template <typename TParticle>
+  GrammageType getInteractionLength(TParticle&) const {
+    return 10_g / square(1_cm);
+  }
+
 private:
   [[maybe_unused]] int fV;
 };
@@ -116,14 +122,14 @@ public:
   }
 
   template <typename TView>
-  inline EProcessReturn DoInteraction(TView& v) const {
+  inline EProcessReturn doInteraction(TView& v) const {
     checkInteract |= 2;
     for (int i = 0; i < nData; ++i) v.parent().data_[i] /= 1.1;
     cout << "Process2::DoInteraction" << endl;
     return EProcessReturn::eOk;
   }
   template <typename Particle>
-  GrammageType GetInteractionLength(Particle&) const {
+  GrammageType getInteractionLength(Particle&) const {
     cout << "Process2::GetInteractionLength" << endl;
     return 20_g / (1_cm * 1_cm);
   }
@@ -140,14 +146,14 @@ public:
   }
 
   template <typename TView>
-  inline EProcessReturn DoInteraction(TView& v) const {
+  inline EProcessReturn doInteraction(TView& v) const {
     checkInteract |= 4;
     for (int i = 0; i < nData; ++i) v.parent().data_[i] *= 1.01;
     cout << "Process3::DoInteraction" << endl;
     return EProcessReturn::eOk;
   }
   template <typename Particle>
-  GrammageType GetInteractionLength(Particle&) const {
+  GrammageType getInteractionLength(Particle&) const {
     cout << "Process3::GetInteractionLength" << endl;
     return 30_g / (1_cm * 1_cm);
   }
@@ -164,34 +170,31 @@ public:
   }
 
   template <typename D, typename T>
-  inline EProcessReturn DoContinuous(D& d, T&) const {
+  inline EProcessReturn doContinuous(D& d, T&) const {
     std::cout << "Base::DoContinuous" << std::endl;
     checkCont |= 8;
     for (int i = 0; i < nData; ++i) { d.data_[i] /= 1.2; }
     return EProcessReturn::eOk;
   }
   template <typename TView>
-  EProcessReturn DoInteraction(TView&) const {
+  EProcessReturn doInteraction(TView&) const {
     checkInteract |= 8;
     return EProcessReturn::eOk;
   }
 };
 
 class Decay1 : public DecayProcess<Decay1> {
-  [[maybe_unused]] int fV = 0;
-
-public:
   Decay1(const int) {
     cout << "Decay1()" << endl;
     globalCount++;
   }
 
   template <typename Particle>
-  TimeType GetLifetime(Particle&) const {
+  TimeType getLifetime(Particle&) const {
     return 1_s;
   }
   template <typename TView>
-  EProcessReturn DoDecay(TView&) const {
+  EProcessReturn doDecay(TView&) const {
     checkDecay |= 1;
     return EProcessReturn::eOk;
   }
@@ -206,11 +209,11 @@ public:
   }
 
   template <typename Particle>
-  TimeType GetLifetime(Particle&) const {
+  TimeType getLifetime(Particle&) const {
     return 2_s;
   }
   template <typename TView>
-  EProcessReturn DoDecay(TView&) const {
+  EProcessReturn doDecay(TView&) const {
     checkDecay |= 2;
     return EProcessReturn::eOk;
   }
@@ -223,11 +226,11 @@ public:
   Stack1(const int n)
       : StackProcess(n) {}
   template <typename TStack>
-  EProcessReturn DoStack(TStack&) {
+  EProcessReturn doStack(TStack&) {
     fCount++;
     return EProcessReturn::eOk;
   }
-  int GetCount() const { return fCount; }
+  int getCount() const { return fCount; }
 };
 
 struct DummyStack {};
@@ -256,16 +259,16 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     Process4 m4(3);
     CHECK(globalCount == 4);
 
-    auto sequence1 = process::sequence(m1, m2, m3, m4);
+    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);
 
-    auto sequence2 = process::sequence(m1, m2, m3);
+    auto sequence2 = make_sequence(m1, m2, m3);
     CHECK(is_process_sequence_v<decltype(sequence2)> == true);
 
-    auto sequence3 = process::sequence(m4);
+    auto sequence3 = make_sequence(m4);
     CHECK(is_process_sequence_v<decltype(sequence3)> == true);
   }
 
@@ -277,9 +280,9 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
 
     DummyData particle;
 
-    auto sequence2 = sequence(cp1, m2, m3);
-    GrammageType const tot = sequence2.GetInteractionLength(particle);
-    InverseGrammageType const tot_inv = sequence2.GetInverseInteractionLength(particle);
+    auto sequence2 = make_sequence(cp1, m2, m3);
+    GrammageType const tot = sequence2.getInteractionLength(particle);
+    InverseGrammageType const tot_inv = sequence2.getInverseInteractionLength(particle);
     cout << "lambda_tot=" << tot << "; lambda_tot_inv=" << tot_inv << endl;
 
     CHECK(tot / 1_g * square(1_cm) == 12);
@@ -296,9 +299,9 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
 
     DummyData particle;
 
-    auto sequence2 = sequence(cp1, m2, m3, d3);
-    TimeType const tot = sequence2.GetLifetime(particle);
-    InverseTimeType const tot_inv = sequence2.GetInverseLifetime(particle);
+    auto sequence2 = make_sequence(cp1, m2, m3, d3);
+    TimeType const tot = sequence2.getLifetime(particle);
+    InverseTimeType const tot_inv = sequence2.getInverseLifetime(particle);
     cout << "lambda_tot=" << tot << "; lambda_tot_inv=" << tot_inv << endl;
 
     CHECK(tot / 1_s == 1);
@@ -313,7 +316,7 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     Process2 m2(2);            //  /= 1.1
     Process3 m3(3);            //  *= 1.01
 
-    auto sequence2 = sequence(cp1, m2, m3, cp2);
+    auto sequence2 = make_sequence(cp1, m2, m3, cp2);
 
     DummyData particle;
     DummyTrajectory track;
@@ -329,7 +332,7 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     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);
     }
     for (int i = 0; i < nData; i++) {
       cout << "data_[" << i << "]=" << particle.data_[i] << endl;
@@ -344,20 +347,20 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
     Stack1 s1(1);
     Stack1 s2(2);
 
-    auto sequence = process::sequence(s1, s2);
+    auto sequence1 = make_sequence(s1, s2);
 
     DummyStack stack;
 
     const int nLoop = 20;
-    for (int i = 0; i < nLoop; ++i) { sequence.DoStack(stack); }
+    for (int i = 0; i < nLoop; ++i) { sequence1.doStack(stack); }
 
-    CHECK(s1.GetCount() == 20);
-    CHECK(s2.GetCount() == 10);
+    CHECK(s1.getCount() == 20);
+    CHECK(s2.getCount() == 10);
 
     ContinuousProcess2 cp2(1); // += 0.111
     Process2 m2(2);            //  /= 1.1
-    auto sequence2 = process::sequence(cp2, m2);
-    auto sequence3 = process::sequence(cp2, m2, s1);
+    auto sequence2 = make_sequence(cp2, m2);
+    auto sequence3 = make_sequence(cp2, m2, s1);
 
     CHECK(is_process_sequence_v<decltype(sequence2)> == true);
     CHECK(is_process_sequence_v<decltype(sequence3)> == true);
@@ -366,14 +369,106 @@ TEST_CASE("Process Sequence", "[Process Sequence]") {
   }
 }
 
-/*
-  Note: there is a fine-grained dedicated test-suite for SwitchProcess
-  in Processes/SwitchProcess/testSwtichProcess
- */
-/*
-TEST_CASE("SwitchProcess") {
-  Process1 p1(0);
-  Process2 p2(0);
-  switch_process::SwitchProcess s(p1, p2, 10_GeV);
-  REQUIRE(is_switch_process_v<decltype(s)>);
-  }*/
+TEST_CASE("Switch Process Sequence", "[Process Sequence]") {
+
+  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 sequence1 = make_sequence(Process1(0), ContinuousProcess2(0), Decay1(0));
+    auto sequence2 = make_sequence(ContinuousProcess3(0), Process2(0), Decay2(0));
+
+    auto sequence3 = make_sequence(ContinuousProcess1(0), Process3(0),
+                                   SwitchProcessSequence(sequence1, sequence2, select1));
+
+    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 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(
+              SwitchProcessSequence(sequence1, sequence2, select1))> == true);
+
+    DummyData particle;
+    DummyTrajectory track;
+    DummyView view(particle);
+
+    checkDecay = 0;
+    checkInteract = 0;
+    checkSec = 0;
+    checkCont = 0;
+    particle.data_[0] = 100; // data positive
+    sequence3.doContinuous(particle, track);
+    CHECK(checkInteract == 0);
+    CHECK(checkDecay == 0);
+    CHECK(checkCont == 0b011);
+    CHECK(checkSec == 0);
+
+    checkDecay = 0;
+    checkInteract = 0;
+    checkSec = 0;
+    checkCont = 0;
+    particle.data_[0] = -100; // data negative
+    sequence_alt.doContinuous(particle, track);
+    CHECK(checkInteract == 0);
+    CHECK(checkDecay == 0);
+    CHECK(checkCont == 0b101);
+    CHECK(checkSec == 0);
+
+    // 1/(30g/cm2) is Process3
+    InverseGrammageType lambda_select = .9 / 30. * square(1_cm) / 1_g;
+    InverseTimeType time_select = 0.1 / second;
+
+    checkDecay = 0;
+    checkInteract = 0;
+    checkSec = 0;
+    checkCont = 0;
+    particle.data_[0] = 100; // data positive
+    sequence3.selectInteraction(view, lambda_select);
+    sequence3.selectDecay(view, time_select);
+    CHECK(checkInteract == 0b100); // this is Process3
+    CHECK(checkDecay == 0b001);    // this is Decay1
+    CHECK(checkCont == 0);
+    CHECK(checkSec == 0);
+    lambda_select = 1.01 / 30. * square(1_cm) / 1_g;
+    checkInteract = 0;
+    sequence3.selectInteraction(view, lambda_select);
+    CHECK(checkInteract == 0b001); // this is Process1
+
+    checkDecay = 0;
+    checkInteract = 0;
+    checkSec = 0;
+    checkCont = 0;
+    particle.data_[0] = -100; // data negative
+    sequence3.selectInteraction(view, lambda_select);
+    sequence3.selectDecay(view, time_select);
+    CHECK(checkInteract == 0b010); // this is Process2
+    CHECK(checkDecay == 0b010);    // this is Decay2
+    CHECK(checkCont == 0);
+    CHECK(checkSec == 0);
+
+    checkDecay = 0;
+    checkInteract = 0;
+    checkSec = 0;
+    checkCont = 0;
+    particle.data_[0] = -100; // data negative
+    sequence3.doSecondaries(view);
+    Stack1 stack(0);
+    sequence3.doStack(stack);
+    CHECK(checkInteract == 0);
+    CHECK(checkDecay == 0);
+    CHECK(checkCont == 0);
+    CHECK(checkSec == 0);
+  }
+}