diff --git a/corsika/detail/framework/process/InteractionProcess.hpp b/corsika/detail/framework/process/InteractionProcess.hpp
index 462556675b8526acafd06dfed68861afbaf045af..7319027194015b5caaf23946a1c12d2b4fd79c84 100644
--- a/corsika/detail/framework/process/InteractionProcess.hpp
+++ b/corsika/detail/framework/process/InteractionProcess.hpp
@@ -40,9 +40,9 @@ namespace corsika {
 
   public:
     /**
-        @name traits results
-        @{
-    */
+     *  @name traits results
+     * @{
+     */
     using type = decltype(test<std::decay_t<TProcess>>(nullptr));
     static const bool value = type::value;
     //! @}
@@ -54,11 +54,11 @@ namespace corsika {
       has_method_doInteract<TProcess, TReturn, TTemplate, TArgs...>::value;
 
   /**
-   * traits test for InteractionProcess::getInteractionLength method.
+   *  traits test for TEMPLATED InteractionProcess::getCrossSection method (PROPOSAL).
    */
 
-  template <class TProcess, typename TReturn, typename... TArgs>
-  struct has_method_getInteractionLength
+  template <class TProcess, typename TReturn, typename TTemplate, typename... TArgs>
+  struct has_method_getCrossSectionTemplate
       : public detail::has_method_signature<TReturn, TArgs...> {
 
     ///! method signature
@@ -70,12 +70,12 @@ namespace corsika {
 
     //! templated parameter option
     template <class T>
-    static decltype(testSignature(&T::template getInteractionLength<TArgs...>)) test(
+    static decltype(testSignature(&T::template getCrossSection<TTemplate>)) test(
         std::nullptr_t);
 
     //! non templated parameter option
     template <class T>
-    static decltype(testSignature(&T::getInteractionLength)) test(std::nullptr_t);
+    static decltype(testSignature(&T::getCrossSection)) test(std::nullptr_t);
 
   public:
     /**
@@ -88,9 +88,9 @@ namespace corsika {
   };
 
   //! value traits type shortcut
-  template <class TProcess, typename TReturn, typename... TArgs>
-  bool constexpr has_method_getInteractionLength_v =
-      has_method_getInteractionLength<TProcess, TReturn, TArgs...>::value;
+  template <class TProcess, typename TReturn, typename TTemplate, typename... TArgs>
+  bool constexpr has_method_getCrossSectionTemplate_v =
+      has_method_getCrossSectionTemplate<TProcess, TReturn, TTemplate, TArgs...>::value;
 
   /**
    *  traits test for InteractionProcess::getCrossSection method.
diff --git a/corsika/detail/framework/process/ProcessSequence.inl b/corsika/detail/framework/process/ProcessSequence.inl
index 5711ff24991ce6113d16b74cf487c354f3a205d6..c8bd3d0a4b9b9a2cb065a21cf45c732775a9d2a1 100644
--- a/corsika/detail/framework/process/ProcessSequence.inl
+++ b/corsika/detail/framework/process/ProcessSequence.inl
@@ -322,9 +322,22 @@ namespace corsika {
     if constexpr (is_process_v<process1_type>) { // to protect from further compiler
                                                  // errors if process1_type is invalid
       if constexpr (is_interaction_process_v<process1_type>) {
-        tot += A_.getCrossSection(projectile.getPID(), targetId,
-                                  {projectile.getEnergy(), projectile.getMomentum()},
-                                  targetP4);
+
+        bool constexpr has_signature_cx1 =
+            has_method_getCrossSection_v<TProcess1,        // process object
+                                         CrossSectionType, // return type
+                                         Code, Code,       // parameters
+                                         FourMomentum const&, FourMomentum const&>;
+
+        if constexpr (has_signature_cx1) {
+          tot += A_.getCrossSection(projectile.getPID(), targetId,
+                                    {projectile.getEnergy(), projectile.getMomentum()},
+                                    targetP4);
+        } else { // for PROPOSAL
+          tot += A_.getCrossSection(projectile, projectile.getPID(),
+                                    {projectile.getEnergy(), projectile.getMomentum()});
+        }
+
       } else if constexpr (process1_type::is_process_sequence) {
         tot += A_.getCrossSection(projectile, targetId, targetP4);
       }
@@ -332,9 +345,22 @@ namespace corsika {
     if constexpr (is_process_v<process2_type>) { // to protect from further compiler
                                                  // errors if process2_type is invalid
       if constexpr (is_interaction_process_v<process2_type>) {
-        tot += B_.getCrossSection(projectile.getPID(), targetId,
-                                  {projectile.getEnergy(), projectile.getMomentum()},
-                                  targetP4);
+
+        bool constexpr has_signature_cx1 =
+            has_method_getCrossSection_v<TProcess2,        // process object
+                                         CrossSectionType, // return type
+                                         Code, Code,       // parameters
+                                         FourMomentum const&, FourMomentum const&>;
+
+        if constexpr (has_signature_cx1) {
+          tot += B_.getCrossSection(projectile.getPID(), targetId,
+                                    {projectile.getEnergy(), projectile.getMomentum()},
+                                    targetP4);
+        } else { // for PROPOSAL
+          tot += B_.getCrossSection(projectile, projectile.getPID(),
+                                    {projectile.getEnergy(), projectile.getMomentum()});
+        }
+
       } else if constexpr (process2_type::is_process_sequence) {
         tot += B_.getCrossSection(projectile, targetId, targetP4);
       }
@@ -443,52 +469,74 @@ namespace corsika {
 
         // get cross section vector for all material components
         // for selected process A
-        static_assert(
+
+        bool constexpr has_signature_cx1 =
             has_method_getCrossSection_v<TProcess1,        // process object
                                          CrossSectionType, // return type
                                          Code, Code,       // parameters
-                                         FourMomentum const&, FourMomentum const&>,
-            "TProcess1 has no method with correct signature \"CrossSectionType "
-            "getCrossSection(Code, Code, FourMomentum const&, FourMomentum "
-            "const&)\" required by "
-            "InteractionProcess<TProcess1>. ");
-
-        std::vector<CrossSectionType> const weightedCrossSections =
-            composition.getWeighted([=](Code const targetId) -> CrossSectionType {
-              FourMomentum const targetP4(
-                  get_mass(targetId),
-                  MomentumVector(projectile.getMomentum().getCoordinateSystem(),
-                                 {0_GeV, 0_GeV, 0_GeV}));
-              return A_.getCrossSection(projectileId, targetId, projectileP4, targetP4);
-            });
-
-        cx_sum += std::accumulate(weightedCrossSections.cbegin(),
-                                  weightedCrossSections.cend(), CrossSectionType::zero());
+                                         FourMomentum const&, FourMomentum const&>;
+        bool constexpr has_signature_cx2 = // needed for PROPOSAL interface
+            has_method_getCrossSectionTemplate_v<
+                TProcess1,                   // process object
+                CrossSectionType,            // return type
+                decltype(projectile) const&, // template argument
+                decltype(projectile) const&, // parameters
+                Code, FourMomentum const&>;
+        static_assert((has_signature_cx1 || has_signature_cx2),
+                      "TProcess1 has no method with correct signature \"CrossSectionType "
+                      "getCrossSection(Code, Code, FourMomentum const&, FourMomentum "
+                      "const&)\" required by "
+                      "InteractionProcess<TProcess1>. ");
+
+        std::vector<CrossSectionType> weightedCrossSections;
+        if constexpr (has_signature_cx1) {
+          /*std::vector<CrossSectionType> const*/ weightedCrossSections =
+              composition.getWeighted([=](Code const targetId) -> CrossSectionType {
+                FourMomentum const targetP4(
+                    get_mass(targetId),
+                    MomentumVector(projectile.getMomentum().getCoordinateSystem(),
+                                   {0_GeV, 0_GeV, 0_GeV}));
+                return A_.getCrossSection(projectileId, targetId, projectileP4, targetP4);
+              });
+
+          cx_sum +=
+              std::accumulate(weightedCrossSections.cbegin(),
+                              weightedCrossSections.cend(), CrossSectionType::zero());
+
+        } else { // this is for PROPOSAL
+          cx_sum += A_.template getCrossSection(projectile, projectileId, projectileP4);
+        }
 
         // check if we should execute THIS process and then EXIT
         if (cx_select <= cx_sum) {
 
-          // now also sample targetId from weighted cross sections
-          Code const targetId = composition.sampleTarget(weightedCrossSections, rng);
-          FourMomentum const targetP4(
-              get_mass(targetId),
-              MomentumVector(projectile.getMomentum().getCoordinateSystem(),
-                             {0_GeV, 0_GeV, 0_GeV}));
-
-          // interface checking on TProcess1
-          static_assert(
-              has_method_doInteract_v<TProcess1,       // process object
-                                      void,            // return type
-                                      TSecondaryView,  // template argument
-                                      TSecondaryView&, // method parameters
-                                      Code, Code, FourMomentum const&,
-                                      FourMomentum const&>,
-              "TProcess1 has no method with correct signature \"void "
-              "doInteraction<TSecondaryView>(TSecondaryView&, "
-              "Code, Code, FourMomentum const&, FourMomentum const&)\" required for "
-              "InteractionProcess<TProcess1>. ");
-
-          A_.template doInteraction(view, projectileId, targetId, projectileP4, targetP4);
+          if constexpr (has_signature_cx1) {
+            // now also sample targetId from weighted cross sections
+            Code const targetId = composition.sampleTarget(weightedCrossSections, rng);
+            FourMomentum const targetP4(
+                get_mass(targetId),
+                MomentumVector(projectile.getMomentum().getCoordinateSystem(),
+                               {0_GeV, 0_GeV, 0_GeV}));
+
+            // interface checking on TProcess1
+            static_assert(
+                has_method_doInteract_v<TProcess1,       // process object
+                                        void,            // return type
+                                        TSecondaryView,  // template argument
+                                        TSecondaryView&, // method parameters
+                                        Code, Code, FourMomentum const&,
+                                        FourMomentum const&>,
+                "TProcess1 has no method with correct signature \"void "
+                "doInteraction<TSecondaryView>(TSecondaryView&, "
+                "Code, Code, FourMomentum const&, FourMomentum const&)\" required for "
+                "InteractionProcess<TProcess1>. ");
+
+            A_.template doInteraction(view, projectileId, targetId, projectileP4,
+                                      targetP4);
+
+          } else { // this is for PROPOSAL
+            A_.template doInteraction(view, projectileId, projectileP4);
+          }
 
           return ProcessReturn::Interacted;
         }
@@ -508,52 +556,72 @@ namespace corsika {
         Code const projectileId = projectile.getPID();
 
         // get cross section vector for all material components, for selected process B
-        static_assert(has_method_getCrossSection_v<TProcess2,        // process object
-                                                   CrossSectionType, // return type
-                                                   Code, Code, FourMomentum const&,
-                                                   FourMomentum const&>, // parameters
+        bool constexpr has_signature_cx1 =
+            has_method_getCrossSection_v<TProcess2,        // process object
+                                         CrossSectionType, // return type
+                                         Code, Code,       // parameters
+                                         FourMomentum const&, FourMomentum const&>;
+        bool constexpr has_signature_cx2 = // needed for PROPOSAL interface
+            has_method_getCrossSectionTemplate_v<
+                TProcess2,                    // process object
+                CrossSectionType,             // return type
+                decltype(*projectile) const&, // template argument
+                decltype(*projectile) const&, // parameters
+                Code,                         // parameters
+                FourMomentum const&>;
+        static_assert((has_signature_cx1 || has_signature_cx2),
                       "TProcess2 has no method with correct signature \"CrossSectionType "
                       "getCrossSection(Code, Code, FourMomentum const&, FourMomentum "
                       "const&)\" required by "
                       "InteractionProcess<TProcess1>. ");
 
-        std::vector<CrossSectionType> const weightedCrossSections =
-            composition.getWeighted([=](Code const targetId) -> CrossSectionType {
-              FourMomentum const targetP4(
-                  get_mass(targetId),
-                  MomentumVector(projectile.getMomentum().getCoordinateSystem(),
-                                 {0_GeV, 0_GeV, 0_GeV}));
-              return B_.getCrossSection(projectileId, targetId, projectileP4, targetP4);
-            });
-
-        cx_sum += std::accumulate(weightedCrossSections.begin(),
-                                  weightedCrossSections.end(), CrossSectionType::zero());
+        std::vector<CrossSectionType> weightedCrossSections;
+        if constexpr (has_signature_cx1) {
+          /* std::vector<CrossSectionType> const*/ weightedCrossSections =
+              composition.getWeighted([=](Code const targetId) -> CrossSectionType {
+                FourMomentum const targetP4(
+                    get_mass(targetId),
+                    MomentumVector(projectile.getMomentum().getCoordinateSystem(),
+                                   {0_GeV, 0_GeV, 0_GeV}));
+                return B_.getCrossSection(projectileId, targetId, projectileP4, targetP4);
+              });
+
+          cx_sum +=
+              std::accumulate(weightedCrossSections.begin(), weightedCrossSections.end(),
+                              CrossSectionType::zero());
+        } else { // this is for PROPOSAL
+          cx_sum += B_.template getCrossSection(projectile, projectileId, projectileP4);
+        }
 
         // check if we should execute THIS process and then EXIT
         if (cx_select <= cx_sum) {
 
-          // now also sample targetId from weighted cross sections
-          Code const targetId = composition.sampleTarget(weightedCrossSections, rng);
-          FourMomentum const targetP4(
-              get_mass(targetId),
-              MomentumVector(projectile.getMomentum().getCoordinateSystem(),
-                             {0_GeV, 0_GeV, 0_GeV}));
-
-          // interface checking on TProcess2
-          static_assert(
-              has_method_doInteract_v<TProcess2,       // process object
-                                      void,            // return type
-                                      TSecondaryView,  // template argument
-                                      TSecondaryView&, // method parameters
-                                      Code, Code, FourMomentum const&,
-                                      FourMomentum const&>,
-              "TProcess1 has no method with correct signature \"void "
-              "doInteraction<TSecondaryView>(TSecondaryView&, "
-              "Code, Code, FourMomentum const&, FourMomentum const&)\" required for "
-              "InteractionProcess<TProcess2>. ");
-
-          B_.doInteraction(view, projectileId, targetId, projectileP4, targetP4);
-
+          if constexpr (has_signature_cx1) {
+
+            // now also sample targetId from weighted cross sections
+            Code const targetId = composition.sampleTarget(weightedCrossSections, rng);
+            FourMomentum const targetP4(
+                get_mass(targetId),
+                MomentumVector(projectile.getMomentum().getCoordinateSystem(),
+                               {0_GeV, 0_GeV, 0_GeV}));
+
+            // interface checking on TProcess2
+            static_assert(
+                has_method_doInteract_v<TProcess2,       // process object
+                                        void,            // return type
+                                        TSecondaryView,  // template argument
+                                        TSecondaryView&, // method parameters
+                                        Code, Code, FourMomentum const&,
+                                        FourMomentum const&>,
+                "TProcess1 has no method with correct signature \"void "
+                "doInteraction<TSecondaryView>(TSecondaryView&, "
+                "Code, Code, FourMomentum const&, FourMomentum const&)\" required for "
+                "InteractionProcess<TProcess2>. ");
+
+            B_.doInteraction(view, projectileId, targetId, projectileP4, targetP4);
+          } else { // this is for PROPOSAL
+            B_.doInteraction(view, projectileId, projectileP4);
+          }
           return ProcessReturn::Interacted;
         }
       }
diff --git a/corsika/detail/modules/proposal/Interaction.inl b/corsika/detail/modules/proposal/Interaction.inl
index c450594146f13a7afaa809c99d0f3354d9427b02..e81f9984b7b880ddd208556b087df0d0302b3d59 100644
--- a/corsika/detail/modules/proposal/Interaction.inl
+++ b/corsika/detail/modules/proposal/Interaction.inl
@@ -39,24 +39,26 @@ namespace corsika::proposal {
     auto c = p_cross->second(media.at(comp.getHash()), emCut);
 
     // Look which interactions take place and build the corresponding
-    // interaction and secondarie builder. The interaction integral will
+    // interaction and secondary builder. The interaction integral will
     // interpolated too and saved in the calc map by a key build out of a hash
     // of composed of the component and particle code.
     auto inter_types = PROPOSAL::CrossSectionVector::GetInteractionTypes(c);
-    calc[std::make_pair(comp.getHash(), code)] = std::make_tuple(
+    calc_[std::make_pair(comp.getHash(), code)] = std::make_tuple(
         PROPOSAL::make_secondaries(inter_types, particle[code], media.at(comp.getHash())),
         PROPOSAL::make_interaction(c, true));
   }
 
   template <typename TStackView>
-  inline ProcessReturn Interaction::doInteraction(TStackView& view) {
+  inline ProcessReturn Interaction::doInteraction(TStackView& view,
+                                                  Code const projectileId,
+                                                  FourMomentum const& projectileP4) {
 
     auto const projectile = view.getProjectile();
 
-    if (canInteract(projectile.getPID())) {
+    if (canInteract(projectileId)) {
 
       // get or build corresponding calculators
-      auto c = getCalculator(projectile, calc);
+      auto c = getCalculator(projectile, calc_);
 
       // get the rates of the interaction types for every component.
       std::uniform_real_distribution<double> distr(0., 1.);
@@ -103,14 +105,27 @@ namespace corsika::proposal {
   }
 
   template <typename TParticle>
-  inline GrammageType Interaction::getInteractionLength(TParticle const& projectile) {
-
-    if (canInteract(projectile.getPID())) {
-      auto c = getCalculator(projectile, calc);
-      return std::get<eINTERACTION>(c->second)->MeanFreePath(projectile.getEnergy() /
-                                                             1_MeV) *
-             1_g / (1_cm * 1_cm);
+  inline CrossSectionType Interaction::getCrossSection(TParticle const& projectile,
+                                                       Code const projectileId,
+                                                       FourMomentum const& projectileP4) {
+
+    // ==============================================
+    // this block better diappears. RU 26.10.2021
+    //
+    // determine the volume where the particle is (last) known to be
+    auto const* currentLogicalNode = projectile.getNode();
+    NuclearComposition const& composition =
+        currentLogicalNode->getModelProperties().getNuclearComposition();
+    auto const meanMass = composition.getAverageMassNumber() * constants::u;
+    // ==============================================
+
+    if (canInteract(projectileId)) {
+      auto c = getCalculator(projectile, calc_);
+      return meanMass / (std::get<eINTERACTION>(c->second)->MeanFreePath(
+                             projectileP4.getTimeLikeComponent() / 1_MeV) *
+                         1_g / (1_cm * 1_cm));
     }
-    return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm);
+
+    return CrossSectionType::zero();
   }
 } // namespace corsika::proposal
diff --git a/corsika/detail/modules/proposal/ProposalProcessBase.inl b/corsika/detail/modules/proposal/ProposalProcessBase.inl
index c7c38c10423ab6fe270c0851f7b77ca21d8ab73c..936798ea1cd05340ba2f0c4b397d5af9c47a068e 100644
--- a/corsika/detail/modules/proposal/ProposalProcessBase.inl
+++ b/corsika/detail/modules/proposal/ProposalProcessBase.inl
@@ -56,8 +56,8 @@ namespace corsika::proposal {
     PROPOSAL::InterpolationSettings::TABLES_PATH = corsika_data("PROPOSAL").c_str();
   }
 
-  inline size_t ProposalProcessBase::hash::operator()(const calc_key_t& p) const
-      noexcept {
+  inline size_t ProposalProcessBase::hash::operator()(
+      const calc_key_t& p) const noexcept {
     return p.first ^ std::hash<Code>{}(p.second);
   }
 
diff --git a/corsika/detail/modules/pythia8/Interaction.inl b/corsika/detail/modules/pythia8/Interaction.inl
index 9e13f4de82834de41ad14f411583169ec811a79f..5c495e69375dd6b7b767a8501c07611ee5e649f1 100644
--- a/corsika/detail/modules/pythia8/Interaction.inl
+++ b/corsika/detail/modules/pythia8/Interaction.inl
@@ -80,22 +80,22 @@ namespace corsika::pythia8 {
     Pythia8::Pythia::particleData.mayDecay(static_cast<int>(get_PDG(pCode)), false);
   }
 
-  inline void Interaction::configureLabFrameCollision(Code const BeamId,
-                                                      Code const TargetId,
+  inline void Interaction::configureLabFrameCollision(Code const projectileId,
+                                                      Code const targetId,
                                                       HEPEnergyType const BeamEnergy) {
     // Pythia configuration of the current event
     // very clumsy. I am sure this can be done better..
 
     // set beam
     // beam id for pythia
-    auto const pdgBeam = static_cast<int>(get_PDG(BeamId));
+    auto const pdgBeam = static_cast<int>(get_PDG(projectileId));
     std::stringstream stBeam;
     stBeam << "Beams:idA = " << pdgBeam;
     Pythia8::Pythia::readString(stBeam.str());
     // set target
-    auto pdgTarget = static_cast<int>(get_PDG(TargetId));
+    auto pdgTarget = static_cast<int>(get_PDG(targetId));
     // replace hydrogen with proton, otherwise pythia goes into heavy ion mode!
-    if (TargetId == Code::Hydrogen) pdgTarget = static_cast<int>(get_PDG(Code::Proton));
+    if (targetId == Code::Hydrogen) pdgTarget = static_cast<int>(get_PDG(Code::Proton));
     std::stringstream stTarget;
     stTarget << "Beams:idB = " << pdgTarget;
     Pythia8::Pythia::readString(stTarget.str());
@@ -116,26 +116,34 @@ namespace corsika::pythia8 {
     // LCOV_EXCL_STOP
   }
 
-  inline bool Interaction::canInteract(Code const pCode) {
+  inline bool Interaction::canInteract(Code const pCode) const {
     return pCode == Code::Proton || pCode == Code::Neutron || pCode == Code::AntiProton ||
            pCode == Code::AntiNeutron || pCode == Code::PiMinus || pCode == Code::PiPlus;
   }
 
-  inline std::tuple<CrossSectionType, CrossSectionType> Interaction::getCrossSection(
-      Code const BeamId, Code const TargetId, HEPEnergyType const CoMenergy) {
+  inline std::tuple<CrossSectionType, CrossSectionType>
+  Interaction::getCrossSectionInelEla(Code const projectileId, Code const targetId,
+                                      FourMomentum const& projectileP4,
+                                      FourMomentum const& targetP4) const {
+
+    HEPEnergyType const CoMenergy = (projectileP4 + targetP4).getNorm();
+
     // interaction possible in pythia?
-    if (TargetId == Code::Proton || TargetId == Code::Hydrogen) {
-      if (canInteract(BeamId) && isValidCoMEnergy(CoMenergy)) {
+    if (targetId == Code::Proton || targetId == Code::Hydrogen) {
+      if (canInteract(projectileId) && isValidCoMEnergy(CoMenergy)) {
         // input particle PDG
-        auto const pdgCodeBeam = static_cast<int>(get_PDG(BeamId));
-        auto const pdgCodeTarget = static_cast<int>(get_PDG(TargetId));
+        auto const pdgCodeBeam = static_cast<int>(get_PDG(projectileId));
+        auto const pdgCodeTarget = static_cast<int>(get_PDG(targetId));
         double const ecm = CoMenergy / 1_GeV;
 
+        //! @todo: remove this const_cast, when Pythia8 becomes const-correct! CHECK!
+        Pythia8::SigmaTotal& sigma = *const_cast<Pythia8::SigmaTotal*>(&sigma_);
+
         // calculate cross section
-        sigma_.calc(pdgCodeBeam, pdgCodeTarget, ecm);
-        if (sigma_.hasSigmaTot()) {
-          double const sigEla = sigma_.sigmaEl();
-          double const sigProd = sigma_.sigmaTot() - sigEla;
+        sigma.calc(pdgCodeBeam, pdgCodeTarget, ecm);
+        if (sigma.hasSigmaTot()) {
+          double const sigEla = sigma.sigmaEl();
+          double const sigProd = sigma.sigmaTot() - sigEla;
 
           return std::make_tuple(sigProd * (1_fm * 1_fm), sigEla * (1_fm * 1_fm));
 
@@ -153,92 +161,24 @@ namespace corsika::pythia8 {
     }
   }
 
-  template <typename TParticle>
-  inline GrammageType Interaction::getInteractionLength(TParticle const& particle) {
-
-    // coordinate system, get global frame of reference
-    MomentumVector const& pMomentum = particle.getMomentum();
-    CoordinateSystemPtr const& labCS = pMomentum.getCoordinateSystem();
-
-    Code corsikaBeamId = particle.getPID();
-
-    // beam particles for pythia : 1, 2, 3 for p, pi, k
-    // read from cross section code table
-    bool const kInteraction = canInteract(corsikaBeamId);
-
-    // FOR NOW: assume target is at rest
-    MomentumVector pTarget(labCS, {0_GeV, 0_GeV, 0_GeV});
-
-    // total momentum and energy
-    HEPEnergyType Elab = particle.getEnergy() + constants::nucleonMass;
-    MomentumVector pTotLab(labCS, {0_GeV, 0_GeV, 0_GeV});
-    pTotLab += pMomentum;
-    pTotLab += pTarget;
-    auto const pTotLabNorm = pTotLab.getNorm();
-    // calculate cm. energy
-    HEPEnergyType const ECoM = sqrt(
-        (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy
-
-    CORSIKA_LOG_DEBUG(
-        "Interaction: LambdaInt: \n"
-        " input energy: {} GeV"
-        " beam can interact: {}"
-        " beam pid: {}",
-        particle.getEnergy() / 1_GeV, kInteraction, particle.getPID());
-
-    // TODO: move limits into variables
-    if (kInteraction && Elab >= 8.5_GeV && isValidCoMEnergy(ECoM)) {
-
-      // get target from environment
-      /*
-        the target should be defined by the Environment,
-        ideally as full particle object so that the four momenta
-        and the boosts can be defined..
-      */
-      auto const* currentNode = particle.getNode();
-      auto const mediumComposition =
-          currentNode->getModelProperties().getNuclearComposition();
-      // determine average interaction length
-
-      auto const weightedProdCrossSection =
-          mediumComposition.getWeightedSum([=](auto vTargetID) {
-            return std::get<0>(this->getCrossSection(corsikaBeamId, vTargetID, ECoM));
-          });
-
-      CORSIKA_LOG_DEBUG(
-          "Interaction: IntLength: weighted CrossSection (mb): {} "
-          "Interaction: IntLength: average mass number: {} ",
-          weightedProdCrossSection / 1_mb, mediumComposition.getAverageMassNumber());
-
-      // calculate interaction length in medium
-      GrammageType const int_length = mediumComposition.getAverageMassNumber() *
-                                      constants::u / weightedProdCrossSection;
-      CORSIKA_LOG_DEBUG("Interaction: interaction length (g/cm2): {} ",
-                        int_length / (0.001_kg) * 1_cm * 1_cm);
-
-      return int_length;
-    }
-
-    return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm);
-  }
-
   template <class TView>
-  inline void Interaction::doInteraction(TView& view) {
+  inline void Interaction::doInteraction(TView& view, Code const projectileId,
+                                         Code const targetId, FourMomentum const&,
+                                         FourMomentum const&) {
 
     auto projectile = view.getProjectile();
 
-    const auto corsikaBeamId = projectile.getPID();
     CORSIKA_LOG_DEBUG(
         "Pythia::Interaction: "
         "DoInteraction: {} interaction? ",
-        corsikaBeamId, corsika::pythia8::Interaction::canInteract(corsikaBeamId));
+        projectileId, corsika::pythia8::Interaction::canInteract(projectileId));
 
-    if (is_nucleus(corsikaBeamId)) {
+    if (is_nucleus(projectileId)) {
       // nuclei handled by different process, this should not happen
       throw std::runtime_error("Nuclear projectile are not handled by PYTHIA!");
     }
 
-    if (corsika::pythia8::Interaction::canInteract(corsikaBeamId)) {
+    if (corsika::pythia8::Interaction::canInteract(projectileId)) {
 
       // define projectile
       HEPEnergyType const eProjectileLab = projectile.getEnergy();
@@ -299,32 +239,8 @@ namespace corsika::pythia8 {
       // invariant mass, i.e. cm. energy
       HEPEnergyType Ecm = sqrt(Etot * Etot - Ptot.getSquaredNorm());
 
-      // sample target mass number
-      auto const* currentNode = projectile.getNode();
-      auto const& mediumComposition =
-          currentNode->getModelProperties().getNuclearComposition();
-      // get cross sections for target materials
-      /*
-        Here we read the cross section from the interaction model again,
-        should be passed from getInteractionLength if possible
-       */
-      //#warning reading interaction cross section again, should not be necessary
-      auto const& compVec = mediumComposition.getComponents();
-      std::vector<si::CrossSectionType> cross_section_of_components(compVec.size());
-
-      for (size_t i = 0; i < compVec.size(); ++i) {
-        auto const targetId = compVec[i];
-        auto const [sigProd, sigEla] = getCrossSection(corsikaBeamId, targetId, Ecm);
-        [[maybe_unused]] auto const& dummy_sigEla = sigEla;
-        cross_section_of_components[i] = sigProd;
-      }
-
-      auto const corsikaTargetId =
-          mediumComposition.sampleTarget(cross_section_of_components, RNG_);
-      CORSIKA_LOG_DEBUG("Interaction: target selected: {}", corsikaTargetId);
-
-      if (corsikaTargetId != Code::Hydrogen && corsikaTargetId != Code::Neutron &&
-          corsikaTargetId != Code::Proton)
+      if (targetId != Code::Hydrogen && targetId != Code::Neutron &&
+          targetId != Code::Proton)
         throw std::runtime_error("DoInteraction: wrong target for PYTHIA");
 
       CORSIKA_LOG_DEBUG(
@@ -343,7 +259,7 @@ namespace corsika::pythia8 {
       } else {
         count_++;
 
-        configureLabFrameCollision(corsikaBeamId, corsikaTargetId, eProjectileLab);
+        configureLabFrameCollision(projectileId, targetId, eProjectileLab);
 
         // create event in pytia. LCOV_EXCL_START: we don't validate pythia8 internals
         if (!Pythia8::Pythia::next())
diff --git a/corsika/framework/process/ProcessSequence.hpp b/corsika/framework/process/ProcessSequence.hpp
index 06111acf8c0f534adbddf1aabfa91f1a0aac8338..3b647ec8238585a4633d1135277981d197a6d8d7 100644
--- a/corsika/framework/process/ProcessSequence.hpp
+++ b/corsika/framework/process/ProcessSequence.hpp
@@ -50,111 +50,109 @@ namespace corsika {
   };
 
   /**
-    * @defgroup Processes Physics Processes and Modules
-    *
-    * Physics processes in CORSIKA 8 are clustered in ProcessSequence and
-    * SwitchProcessSequence containers. The former is a mere (ordered) collection, while
-    * the latter has the option to switch between two alternative ProcessSequences.
-    *
-    * Depending on the type of data to act on and on the allowed actions of processes
-  there
-    * are several interface options:
-    * - InteractionProcess
-    * - DecayProcess
-    * - ContinuousProcess
-    * - StackProcess
-    * - SecondariesProcess
-    * - BoundaryCrossingProcess
-    *
-    * And all processes (including ProcessSequence and SwitchProcessSequence) are derived
-    * from BaseProcess.
-    *
-    * Processes of any type (e.g. p1, p2, p3,...) can be assembled into a ProcessSequence
-    * using the `make_sequence` factory function.
-    *
-    * @code{.cpp}
-    *   auto sequence1 = make_sequence(p1, p2, p3);
-    *   auto sequence2 = make_sequence(p4, p5, p6, p7);
-    *   auto sequence3 = make_sequence(sequence1, sequemce2, p8, p9);
-    * @endcode
-    *
-    * Note, if the order of processes
-    * matters, the order of occurence
-    * in the ProcessSequence determines
-    * the executiion order.
-    *
-    * SecondariesProcess alyways act on
-    * new secondaries produced (i.e. in
-    * InteractionProcess and
-    * DecayProcess) in the scope of
-    * their ProcessSequence. For
-    * example if i1 and i2 are
-    * InteractionProcesses and s1 is a
-    * SecondariesProcess, then
-    *
-    * @code{.cpp}
-    *   auto sequence = make_sequence(i1, make_sequence(i2, s1))
-    * @endcode
-    *
-    * will result in s1 acting only on
-    * the particles produced by i2 and
-    * not by i1. This can be very
-    * useful, e.g. to fine tune thinning.
-    *
-    * A special type of ProcessSequence
-    * is SwitchProcessSequence, which
-    * has two branches and a functor
-    * that can select between these two
-    * branches.
-    *
-    * @code{.cpp}
-    *   auto sequence = make_switch(sequence1, sequence2, selector);
-    * @endcode
-    *
-    * where the only requirement to
-    * `selector` is that it
-    * provides a `SwitchResult operator()(Particle const& particle) const` method. Thus,
-    * based on the dynamic properties
-    * of `particle` the functor
-    * can make its decision. This is
-    * clearly important for switching
-    * between low-energy and
-    * high-energy models, but not
-    * limited to this. The selection
-    * can even be done with a lambda
-    * function.
-    *
-    *
-    * @class ProcessSequence
-    * @ingroup Processes
-    *
-    *   Definition of a static process list/sequence
-    *
-    *  A compile time static list of processes. The compiler will
-    *  generate a new type based on template logic containing all the
-    *  elements provided by the user.
-    *
-    *  TProcess1 and TProcess2 must both be derived from BaseProcess,
-    *  and are both references if possible (lvalue), otherwise (rvalue)
-    *  they are just classes. This allows us to handle both, rvalue as
-    *  well as lvalue Processes in the ProcessSequence.
-    *
-    *  (For your potential interest,
-    *  the static version of the
-    *  ProcessSequence and all Process
-    *  types are based on the CRTP C++
-    *  design pattern)
-    *
-    * Template parameters:
-    *   @tparam TProcess1 is of type BaseProcess, either a dedicatd process, or a
-    *           ProcessSequence.
-    *   @tparam TProcess2 is of type BaseProcess, either a dedicatd process, or a
-    *           ProcessSequence.
-    * @tparam IndexFirstProcess to count and index each Process in the entire
-    *         process-chain. The offset is the starting value for this ProcessSequence.
-    *  @tparam IndexOfProcess1 index of TProcess1 (counting of Process).
-    *  @tparam IndexOfProcess2 index of TProcess2 (counting of Process).
-  */
+   * @defgroup Processes Physics Processes and Modules
+   *
+   * Physics processes in CORSIKA 8 are clustered in ProcessSequence and
+   * SwitchProcessSequence containers. The former is a mere (ordered) collection, while
+   * the latter has the option to switch between two alternative ProcessSequences.
+   *
+   * Depending on the type of data to act on and on the allowed actions of
+   * processes there are several interface options:
+   * - InteractionProcess
+   * - DecayProcess
+   * - ContinuousProcess
+   * - StackProcess
+   * - SecondariesProcess
+   * - BoundaryCrossingProcess
+   *
+   * And all processes (including ProcessSequence and SwitchProcessSequence) are derived
+   * from BaseProcess.
+   *
+   * Processes of any type (e.g. p1, p2, p3,...) can be assembled into a ProcessSequence
+   * using the `make_sequence` factory function.
+   *
+   * @code{.cpp}
+   *   auto sequence1 = make_sequence(p1, p2, p3);
+   *   auto sequence2 = make_sequence(p4, p5, p6, p7);
+   *   auto sequence3 = make_sequence(sequence1, sequemce2, p8, p9);
+   * @endcode
+   *
+   * Note, if the order of processes
+   * matters, the order of occurence
+   * in the ProcessSequence determines
+   * the executiion order.
+   *
+   * SecondariesProcess alyways act on
+   * new secondaries produced (i.e. in
+   * InteractionProcess and
+   * DecayProcess) in the scope of
+   * their ProcessSequence. For
+   * example if i1 and i2 are
+   * InteractionProcesses and s1 is a
+   * SecondariesProcess, then:
+   *
+   * @code{.cpp}
+   *   auto sequence = make_sequence(i1, make_sequence(i2, s1))
+   * @endcode
+   *
+   * will result in s1 acting only on
+   * the particles produced by i2 and
+   * not by i1. This can be very
+   * useful, e.g. to fine tune thinning.
+   *
+   * A special type of ProcessSequence
+   * is SwitchProcessSequence, which
+   * has two branches and a functor
+   * that can select between these two
+   * branches.
+   *
+   * @code{.cpp}
+   *   auto sequence = make_switch(sequence1, sequence2, selector);
+   * @endcode
+   *
+   * where the only requirement to
+   * `selector` is that it
+   * provides a `SwitchResult operator()(Particle const& particle) const` method. Thus,
+   * based on the dynamic properties
+   * of `particle` the functor
+   * can make its decision. This is
+   * clearly important for switching
+   * between low-energy and
+   * high-energy models, but not
+   * limited to this. The selection
+   * can even be done with a lambda
+   * function.
+   *
+   * @class ProcessSequence
+   * @ingroup Processes
+   *
+   *   Definition of a static process list/sequence.
+   *
+   *  A compile time static list of processes. The compiler will
+   *  generate a new type based on template logic containing all the
+   *  elements provided by the user.
+   *
+   *  TProcess1 and TProcess2 must both be derived from BaseProcess,
+   *  and are both references if possible (lvalue), otherwise (rvalue)
+   *  they are just classes. This allows us to handle both, rvalue as
+   *  well as lvalue Processes in the ProcessSequence.
+   *
+   *  (For your potential interest,
+   *  the static version of the
+   *  ProcessSequence and all Process
+   *  types are based on the CRTP C++
+   *  design pattern)
+   *
+   * Template parameters:
+   *   @tparam TProcess1 is of type BaseProcess, either a dedicatd process, or a
+   *           ProcessSequence.
+   *   @tparam TProcess2 is of type BaseProcess, either a dedicatd process, or a
+   *           ProcessSequence.
+   * @tparam IndexFirstProcess to count and index each Process in the entire
+   *         process-chain. The offset is the starting value for this ProcessSequence.
+   *  @tparam IndexOfProcess1 index of TProcess1 (counting of Process).
+   *  @tparam IndexOfProcess2 index of TProcess2 (counting of Process).
+   */
 
   template <typename TProcess1, typename TProcess2 = NullModel,
             int ProcessIndexOffset = 0,
@@ -190,6 +188,15 @@ namespace corsika {
      */
     ProcessSequence(TProcess1 in_A, TProcess2 in_B);
 
+    /**
+     * List of all BoundaryProcess.
+     *
+     * @tparam TParticle
+     * @param particle The particle.
+     * @param from Volume the particle is exiting.
+     * @param to Volume the particle is entering.
+     * @return ProcessReturn
+     */
     template <typename TParticle>
     ProcessReturn doBoundaryCrossing(TParticle& particle,
                                      typename TParticle::node_type const& from,
@@ -199,6 +206,15 @@ namespace corsika {
     ProcessReturn doContinuous(TParticle& particle, TTrack& vT,
                                ContinuousProcessIndex const limitID);
 
+    /**
+     * Process all secondaries in TSecondaries.
+     *
+     * The seondaries produced by other processes and accessible via TSecondaries
+     * are processed by all SecondariesProcesse via a call here.
+     *
+     * @tparam TSecondaries
+     * @param vS
+     */
     template <typename TSecondaries>
     void doSecondaries(TSecondaries& vS);
 
@@ -243,6 +259,15 @@ namespace corsika {
     template <typename TParticle, typename TTrack>
     ContinuousProcessStepLength getMaxStepLength(TParticle&& particle, TTrack&& vTrack);
 
+    /**
+     * @brief Calculates the cross section of a projectile with a target.
+     *
+     * @tparam TParticle
+     * @param projectile
+     * @param targetId
+     * @param targetP4
+     * @return CrossSectionType
+     */
     template <typename TParticle>
     CrossSectionType getCrossSection(TParticle const& projectile, Code const targetId,
                                      FourMomentum const& targetP4) const;
@@ -253,7 +278,7 @@ namespace corsika {
     }
 
     /**
-     * @brief Selects one concrete InteractionProcess and samples a target nucleus from
+     * Selects one concrete InteractionProcess and samples a target nucleus from
      * the material.
      *
      * The selectInteraction method statically loops over all active InteractionProcess
diff --git a/corsika/modules/proposal/Interaction.hpp b/corsika/modules/proposal/Interaction.hpp
index b6f2fabbab60f772f69eb83bd9f78697a08fb8f8..3b769bc34281487885aab4f3e022e21a54fe564b 100644
--- a/corsika/modules/proposal/Interaction.hpp
+++ b/corsika/modules/proposal/Interaction.hpp
@@ -13,6 +13,7 @@
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/process/InteractionProcess.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
+#include <corsika/framework/geometry/FourVector.hpp>
 #include <corsika/framework/random/RNGManager.hpp>
 #include <corsika/framework/random/UniformRealDistribution.hpp>
 
@@ -32,7 +33,7 @@ namespace corsika::proposal {
                                     std::unique_ptr<PROPOSAL::Interaction>>;
 
     std::unordered_map<calc_key_t, calculator_t, hash>
-        calc; //!< Stores the secondaries and interaction calculators.
+        calc_; //!< Stores the secondaries and interaction calculators.
 
     //!
     //! Build the secondaries and interaction calculators and add it to calc.
@@ -53,13 +54,15 @@ namespace corsika::proposal {
     //! produce the corresponding secondaries and store them on the particle stack.
     //!
     template <typename TSecondaryView>
-    ProcessReturn doInteraction(TSecondaryView&);
+    ProcessReturn doInteraction(TSecondaryView&, Code const projectileId,
+                                FourMomentum const& projectileP4);
 
     //!
-    //! Calculates the  mean free path length
+    //! Calculates and returns the cross section.
     //!
     template <typename TParticle>
-    GrammageType getInteractionLength(TParticle const& p);
+    CrossSectionType getCrossSection(TParticle const& p, Code const projectileId,
+                                     FourMomentum const& projectileP4);
   };
 } // namespace corsika::proposal
 
diff --git a/corsika/modules/pythia8/Interaction.hpp b/corsika/modules/pythia8/Interaction.hpp
index c099997a4019de54deb00980ef7349669b744e08..63376ab17e69943c9287cce169a33603fd152c39 100644
--- a/corsika/modules/pythia8/Interaction.hpp
+++ b/corsika/modules/pythia8/Interaction.hpp
@@ -28,23 +28,62 @@ namespace corsika::pythia8 {
     void setUnstable(const Code);
     void setStable(const Code);
 
-    bool isValidCoMEnergy(HEPEnergyType ecm) { return (10_GeV < ecm) && (ecm < 1_PeV); }
+    bool isValidCoMEnergy(HEPEnergyType const ecm) const {
+      return (10_GeV < ecm) && (ecm < 1_PeV);
+    }
 
-    bool canInteract(const Code);
+    bool canInteract(const Code) const;
     void configureLabFrameCollision(const Code, const Code, const HEPEnergyType);
 
-    std::tuple<CrossSectionType, CrossSectionType> getCrossSection(
-        const Code BeamId, const Code TargetId, const HEPEnergyType CoMenergy);
+    /**
+     * Returns inelastic AND elastic cross sections.
+     *
+     * These cross sections must correspond to the process described in doInteraction
+     * AND elastic scattering (sigma_tot = sigma_inel + sigma_el). Allowed targets are:
+     * nuclei or single nucleons (p,n,hydrogen). This "InelEla" method is used since
+     * Sibyll must be useful inside the NuclearInteraction model, which requires that.
+     *
+     * @param projectile is the Code of the projectile
+     * @param target is the Code of the target
+     * @param sqrtSnn is the center-of-mass energy (per nucleon pair)
+     * @param Aprojectil is the mass number of the projectils, if it is a nucleus
+     * @param Atarget is the mass number of the target, if it is a nucleus
+     *
+     * @return a tuple of: inelastic cross section, elastic cross section
+     */
+    std::tuple<CrossSectionType, CrossSectionType> getCrossSectionInelEla(
+        Code const projectile, Code const target, FourMomentum const& projectileP4,
+        FourMomentum const& targetP4) const;
 
-    template <typename TParticle>
-    GrammageType getInteractionLength(TParticle const&);
+    /**
+     * Returns inelastic (production) cross section.
+     *
+     * This cross section must correspond to the process described in doInteraction.
+     * Allowed targets are: nuclei or single nucleons (p,n,hydrogen).
+     *
+     * @param projectile is the Code of the projectile
+     * @param target is the Code of the target
+     * @param sqrtSnn is the center-of-mass energy (per nucleon pair)
+     * @param Aprojectil is the mass number of the projectils, if it is a nucleus
+     * @param Atarget is the mass number of the target, if it is a nucleus
+     *
+     * @return inelastic cross section
+     * elastic cross section
+     */
+    CrossSectionType getCrossSection(Code const projectile, Code const target,
+                                     FourMomentum const& projectileP4,
+                                     FourMomentum const& targetP4) const {
+      return std::get<0>(
+          getCrossSectionInelEla(projectile, target, projectileP4, targetP4));
+    }
 
     /**
-       In this function PYTHIA is called to produce one event. The
-       event is copied (and boosted) into the shower lab frame.
+     * In this function PYTHIA is called to produce one event. The
+     * event is copied (and boosted) into the shower lab frame.
      */
     template <typename TView>
-    void doInteraction(TView&);
+    void doInteraction(TView& output, Code const projectileId, Code const targetId,
+                       FourMomentum const& projectileP4, FourMomentum const& targetP4);
 
   private:
     default_prng_type& RNG_ = RNGManager<>::getInstance().getRandomStream("pythia");
diff --git a/examples/corsika.cpp b/examples/corsika.cpp
index 86734017907bd60e4b1c8013bb3185781aa5b19d..dbf99a5cba85272435cfd0827862981698a23e39 100644
--- a/examples/corsika.cpp
+++ b/examples/corsika.cpp
@@ -317,8 +317,10 @@ int main(int argc, char** argv) {
   HEPEnergyType const emcut = 1_GeV;
   HEPEnergyType const hadcut = 1_GeV;
   ParticleCut cut(emcut, emcut, hadcut, hadcut, true);
+
   corsika::proposal::Interaction emCascade(env);
-  InteractionCounter emCascadeCounted(emCascade);
+  // NOT available for PROPOSAL due to interface trouble:
+  //  InteractionCounter emCascadeCounted(emCascade);
   // corsika::proposal::ContinuousProcess emContinuous(env);
   BetheBlochPDG emContinuous(showerAxis);
 
@@ -335,7 +337,7 @@ int main(int argc, char** argv) {
     HEPEnergyType cutE_;
     EnergySwitch(HEPEnergyType cutE)
         : cutE_(cutE) {}
-    bool operator()(const Particle& p) { return (p.getKineticEnergy() < cutE_); }
+    bool operator()(const Particle& p) const { return (p.getKineticEnergy() < cutE_); }
   };
   auto hadronSequence = make_select(EnergySwitch(63.1_GeV), urqmdCounted, heModelCounted);
   auto decaySequence = make_sequence(decayPythia, decaySibyll);
@@ -352,8 +354,8 @@ int main(int argc, char** argv) {
   output.add("particles", observationLevel);
 
   // assemble the final process sequence
-  auto sequence = make_sequence(stackInspect, hadronSequence, decaySequence,
-                                emCascadeCounted, cut, emContinuous, // trackWriter,
+  auto sequence = make_sequence(stackInspect, hadronSequence, decaySequence, cut,
+                                emCascade, emContinuous, // trackWriter,
                                 observationLevel, longprof);
   /* === END: SETUP PROCESS LIST === */
 
diff --git a/examples/em_shower.cpp b/examples/em_shower.cpp
index 62aa91e564010d12a0fbcb3ab48062917ca42da4..b01d7b608b85d661d7fdce6004a1ef9efcd3cd4b 100644
--- a/examples/em_shower.cpp
+++ b/examples/em_shower.cpp
@@ -144,7 +144,9 @@ int main(int argc, char** argv) {
   ParticleCut cut(60_GeV, 60_GeV, 100_PeV, 100_PeV, true);
   corsika::proposal::Interaction emCascade(env);
   corsika::proposal::ContinuousProcess emContinuous(env);
-  InteractionCounter emCascadeCounted(emCascade);
+
+  //  NOT possible right now, due to interface differenc in PROPOSAL
+  //  InteractionCounter emCascadeCounted(emCascade);
 
   TrackWriter trackWriter;
   output.add("tracks", trackWriter); // register TrackWriter
@@ -157,8 +159,8 @@ int main(int argc, char** argv) {
       obsPlane, DirectionVector(rootCS, {1., 0., 0.}), "particles.dat");
   output.add("obsplane", observationLevel);
 
-  auto sequence = make_sequence(emCascadeCounted, emContinuous, longprof, cut,
-                                observationLevel, trackWriter);
+  auto sequence = make_sequence(emCascade, emContinuous, longprof, cut, observationLevel,
+                                trackWriter);
   // define air shower object, run simulation
   setup::Tracking tracking;
   Cascade EAS(env, tracking, sequence, output, stack);
@@ -183,9 +185,6 @@ int main(int argc, char** argv) {
   cut.reset();
   emContinuous.reset();
 
-  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");
 
   output.endOfLibrary();
diff --git a/examples/hybrid_MC.cpp b/examples/hybrid_MC.cpp
index 4a85351b0e9e5ebdb4c24910a9fa77655c14215a..0ff10af164ff51fc3db6cde5bbb7324dea410d24 100644
--- a/examples/hybrid_MC.cpp
+++ b/examples/hybrid_MC.cpp
@@ -248,7 +248,7 @@ int main(int argc, char** argv) {
     HEPEnergyType cutE_;
     EnergySwitch(HEPEnergyType cutE)
         : cutE_(cutE) {}
-    bool operator()(const setup::Stack::particle_type& p) {
+    bool operator()(const setup::Stack::particle_type& p) const {
       return (p.getEnergy() < cutE_);
     }
   };
diff --git a/examples/mars.cpp b/examples/mars.cpp
index 60b4f87d43d29004285c6fafd59168f693d5ca43..a284f1ecd85580ace4ec82867bf5ad8573ea5b05 100644
--- a/examples/mars.cpp
+++ b/examples/mars.cpp
@@ -345,7 +345,8 @@ int main(int argc, char** argv) {
   HEPEnergyType const hadcut = 1_GeV;
   ParticleCut cut(emcut, emcut, hadcut, hadcut, true);
   corsika::proposal::Interaction emCascade(env);
-  InteractionCounter emCascadeCounted(emCascade);
+  // NOT possible right now, due to interface difference for PROPOSAL:
+  //  InteractionCounter emCascadeCounted(emCascade);
   // corsika::proposal::ContinuousProcess emContinuous(env);
   BetheBlochPDG emContinuous(showerAxis);
 
@@ -378,8 +379,8 @@ int main(int argc, char** argv) {
 
   // assemble the final process sequence
   auto sequence =
-      make_sequence(stackInspect, hadronSequence, decaySequence, emCascadeCounted,
-                    emContinuous, cut, trackWriter, observationLevel, longprof);
+      make_sequence(stackInspect, hadronSequence, decaySequence, emCascade, emContinuous,
+                    cut, trackWriter, observationLevel, longprof);
   /* === END: SETUP PROCESS LIST === */
 
   // create the cascade object using the default stack and tracking implementation
diff --git a/examples/vertical_EAS.cpp b/examples/vertical_EAS.cpp
index 911f45c528f6f440c45b7a94048c2e3478b5a8a3..d6c1af1dd4dada9e68f4adb4d2cec4f92facb42b 100644
--- a/examples/vertical_EAS.cpp
+++ b/examples/vertical_EAS.cpp
@@ -236,7 +236,7 @@ int main(int argc, char** argv) {
     HEPEnergyType cutE_;
     EnergySwitch(HEPEnergyType cutE)
         : cutE_(cutE) {}
-    bool operator()(const Particle& p) { return (p.getEnergy() < cutE_); }
+    bool operator()(const Particle& p) const { return (p.getEnergy() < cutE_); }
   };
   auto hadronSequence =
       make_select(EnergySwitch(55_GeV), urqmdCounted,
diff --git a/tests/framework/testProcessSequence.cpp b/tests/framework/testProcessSequence.cpp
index 7cf2c55c48fdcc32cb81daa0b65a59e4a4600bc3..9b6dce5056a78abe10529b96f75a32e521b31055 100644
--- a/tests/framework/testProcessSequence.cpp
+++ b/tests/framework/testProcessSequence.cpp
@@ -50,9 +50,6 @@ struct DummyNode {
   int data_ = 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};
@@ -65,6 +62,9 @@ struct DummyData {
   HEPEnergyType getEnergy() const { return 10_GeV; }
 };
 
+// The stack is non-existent for this example
+struct DummyStack {};
+
 // there is no real trajectory/track
 struct DummyTrajectory {};
 
@@ -75,6 +75,7 @@ struct DummyView {
       : p_(p) {}
   DummyData& p_;
   DummyData& parent() { return p_; }
+  // this is only needed because of PROPOSAL interface right now:
 };
 
 int globalCount = 0; // simple counter
diff --git a/tests/modules/CMakeLists.txt b/tests/modules/CMakeLists.txt
index 1f36ee5f4a6d29d3640039cae80206d35979220d..a4e1c1b63c1b86df66e347d3ab28ca294985e97e 100644
--- a/tests/modules/CMakeLists.txt
+++ b/tests/modules/CMakeLists.txt
@@ -5,13 +5,13 @@ set (test_modules_sources
   ## testExecTime.cpp --> needs to be fixed, see #326
   testObservationPlane.cpp
   testQGSJetII.cpp
-  #testPythia8.cpp
+  testPythia8.cpp
   testUrQMD.cpp
-  #testCONEX.cpp
+  testCONEX.cpp
   ## testOnShellCheck.cpp
   testParticleCut.cpp
   testSibyll.cpp
-  #testEpos.cpp
+  testEpos.cpp
   )
 
 CORSIKA_ADD_TEST (testModules SOURCES ${test_modules_sources})
diff --git a/tests/modules/testPythia8.cpp b/tests/modules/testPythia8.cpp
index 0e449f16b6a38eaeac30b95a3475c7b302532f76..2ccc5407d7c26e42df552c942b62a8c0f6affd7f 100644
--- a/tests/modules/testPythia8.cpp
+++ b/tests/modules/testPythia8.cpp
@@ -94,6 +94,8 @@ auto sumMomentum(TStackView const& view, CoordinateSystemPtr const& vCS) {
 TEST_CASE("Pythia8Interface", "modules") {
 
   logging::set_level(logging::level::info);
+
+  auto const rootCS = get_root_CoordinateSystem();
   auto [env, csPtr, nodePtr] = setup::testing::setup_environment(Code::Proton);
   auto const& cs = *csPtr;
   {
@@ -166,7 +168,6 @@ TEST_CASE("Pythia8Interface", "modules") {
     auto [stackPtr, secViewPtr] = setup::testing::setup_stack(
         Code::Proton, 7_TeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr);
     auto& view = *secViewPtr;
-    auto const particle = stackPtr->getNextParticle();
 
     corsika::pythia8::Interaction collision;
 
@@ -179,50 +180,36 @@ TEST_CASE("Pythia8Interface", "modules") {
     CHECK_FALSE(collision.canInteract(Code::Electron));
 
     // nuclei not supported
-    CHECK_THROWS(collision.getCrossSection(Code::Proton, Code::Helium, 1_TeV));
     std::tuple<CrossSectionType, CrossSectionType> xs_test =
-        collision.getCrossSection(Code::Iron, Code::Hydrogen, 1_GeV);
-    CHECK(std::get<0>(xs_test) == std::numeric_limits<double>::infinity() * 1_mb);
-    CHECK(std::get<1>(xs_test) == std::numeric_limits<double>::infinity() * 1_mb);
-
-    collision.getInteractionLength(particle);
-
-    collision.doInteraction(view);
-    [[maybe_unused]] const GrammageType length = collision.getInteractionLength(particle);
-    CHECK(length / 1_kg * square(1_m) == Approx(43.04).margin(5e-1));
+        collision.getCrossSectionInelEla(
+            Code::Proton, Code::Hydrogen,
+            {sqrt(static_pow<2>(Iron::mass) + static_pow<2>(100_GeV)),
+             {rootCS, {0_eV, 0_eV, 100_GeV}}},
+            {Hydrogen::mass, {rootCS, {0_eV, 0_eV, 0_eV}}});
+    CHECK(std::get<0>(xs_test) / 1_mb == Approx(353).margin(2));
+    CHECK(std::get<1>(xs_test) / 1_mb == Approx(75).margin(2));
+
+    collision.doInteraction(view, Code::Proton, Code::Hydrogen,
+                            {sqrt(static_pow<2>(Iron::mass) + static_pow<2>(100_GeV)),
+                             {rootCS, {0_eV, 0_eV, 100_GeV}}},
+                            {Hydrogen::mass, {rootCS, {0_eV, 0_eV, 0_eV}}});
     CHECK(view.getSize() == 38);
   }
 
-  SECTION("pythia nucleus projectile") {
-
-    // this is a projectile nucleus with very little energy
-    auto [stackPtr, secViewPtr] = setup::testing::setup_stack(
-        Code::Oxygen, 17_GeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr);
-    auto& view = *secViewPtr;
-    auto particle = stackPtr->first();
-
-    corsika::pythia8::Interaction collision;
-
-    GrammageType lambda_test = collision.getInteractionLength(particle);
-    CHECK(lambda_test == std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm));
-
-    CHECK_THROWS(collision.doInteraction(view));
-  }
-
   SECTION("pythia too low energy") {
 
     // this is a projectile neutron with very little energy
     auto [stackPtr, secViewPtr] = setup::testing::setup_stack(
         Code::Neutron, 1_GeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr);
     auto& view = *secViewPtr;
-    auto particle = stackPtr->first();
 
     corsika::pythia8::Interaction collision;
 
-    GrammageType lambda_test = collision.getInteractionLength(particle);
-    CHECK(lambda_test == std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm));
-
-    CHECK_THROWS(collision.doInteraction(view));
+    CHECK_THROWS(collision.doInteraction(
+        view, Code::Neutron, Code::Hydrogen,
+        {sqrt(static_pow<2>(Neutron::mass) + static_pow<2>(100_GeV)),
+         {rootCS, {0_eV, 0_eV, 100_GeV}}},
+        {Hydrogen::mass, {rootCS, {0_eV, 0_eV, 0_eV}}}));
   }
 
   SECTION("pythia wrong target") {
@@ -244,6 +231,32 @@ TEST_CASE("Pythia8Interface", "modules") {
 
     corsika::pythia8::Interaction collision;
 
-    CHECK_THROWS(collision.doInteraction(view));
+    CHECK_THROWS(collision.getCrossSection(
+        Code::Proton, Code::Iron,
+        {sqrt(static_pow<2>(Proton::mass) + static_pow<2>(100_GeV)),
+         {rootCS, {0_eV, 0_eV, 100_GeV}}},
+        {Iron::mass, {rootCS, {0_eV, 0_eV, 0_eV}}}));
+
+    CHECK_THROWS(collision.doInteraction(
+        view, Code::Proton, Code::Iron,
+        {sqrt(static_pow<2>(Proton::mass) + static_pow<2>(100_GeV)),
+         {rootCS, {0_eV, 0_eV, 100_GeV}}},
+        {Iron::mass, {rootCS, {0_eV, 0_eV, 0_eV}}}));
+  }
+
+  SECTION("pythia wrong projectile") {
+
+    // resonable projectile, but tool low energy
+    auto [stackPtr, secViewPtr] = setup::testing::setup_stack(
+        Code::Iron, 1_GeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr);
+    { [[maybe_unused]] auto const& dummy_StackPtr = stackPtr; }
+
+    corsika::pythia8::Interaction collision;
+
+    CHECK_THROWS(
+        collision.doInteraction(*secViewPtr, Code::Iron, Code::Hydrogen,
+                                {sqrt(static_pow<2>(Iron::mass) + static_pow<2>(100_GeV)),
+                                 {rootCS, {0_eV, 0_eV, 100_GeV}}},
+                                {Hydrogen::mass, {rootCS, {0_eV, 0_eV, 0_eV}}}));
   }
 }
diff --git a/tests/modules/testSibyll.cpp b/tests/modules/testSibyll.cpp
index 94fb90792bfb3c7184f0db69051b7ad3f7d411bb..105f5b983905137804bc1ec5eabcfc157702406d 100644
--- a/tests/modules/testSibyll.cpp
+++ b/tests/modules/testSibyll.cpp
@@ -28,10 +28,6 @@
  */
 #include <corsika/modules/sibyll/Random.hpp>
 
-// TODODODODODODODODOODOD THIS MUST BE REMOVED
-#include <corsika/modules/epos/Random.hpp>
-// TODODODODODODODODOODOD THIS MUST BE REMOVED
-
 using namespace corsika;
 using namespace corsika::sibyll;
 
@@ -278,7 +274,7 @@ TEST_CASE("SibyllInterface", "modules") {
     // CHECK(view.getSize() == 11);
     CHECK(cx / 1_mb == Approx(1100).margin(100)); // this is not physics validation
     // CHECK(view.getSize() == 20); // also sibyll not stable wrt. to compiler changes
-    CHECK(view.getSize() == Approx(90).margin(10)); // this is not physics validation
+    CHECK(view.getSize() == Approx(25).margin(10)); // this is not physics validation
   }
 }