diff --git a/corsika/detail/modules/epos/Interaction.inl b/corsika/detail/modules/epos/Interaction.inl
index c3053ba3c52083a8e1e3e005f3564c7836ae271a..dc4b0df99ab194587631f6f0d24dc58181523927 100644
--- a/corsika/detail/modules/epos/Interaction.inl
+++ b/corsika/detail/modules/epos/Interaction.inl
@@ -13,8 +13,7 @@
 #include <corsika/media/Environment.hpp>
 #include <corsika/media/NuclearComposition.hpp>
 #include <corsika/framework/geometry/FourVector.hpp>
-//#include <corsika/modules/sibyll/ParticleConversion.hpp>
-//#include <corsika/modules/sibyll/SibStack.hpp>
+#include <corsika/modules/epos/EposStack.hpp>
 #include <corsika/setup/SetupStack.hpp>
 #include <corsika/setup/SetupTrajectory.hpp>
 #include <corsika/framework/utility/COMBoost.hpp>
@@ -46,7 +45,6 @@ namespace corsika::epos {
     }
   }
 
-  
   inline void Interaction::initialize_eposlhc_c7() {
 
     // corsika7 ini
@@ -57,19 +55,19 @@ namespace corsika::epos {
     //::epos::prnt1_.ish = 3; // debug level in epos
     //::epos::prnt1_.ifch = 6; // output unit
     //::epos::prnt1_.iecho = 1;
-	
+
     // dummy set seeds for random number generator in epos. need to fool epos checks...
     // we will use external generator
-    ::epos::cseed_.seedi = 1; 
+    ::epos::cseed_.seedi = 1;
     ::epos::cseed_.seedj = 1;
-    ::epos::cseed_.seedc = 1;  
+    ::epos::cseed_.seedc = 1;
 
     ::epos::enrgy_.egymin = 6.;
     ::epos::enrgy_.egymax = 2.e6;
-    
+
     ::epos::lhcparameters_();
-    
-    ::epos::hadr6_.isigma = 0;// do not show cross section
+
+    ::epos::hadr6_.isigma = 0; // do not show cross section
     ::epos::hadr6_.isetcs = 3; /*  !option to obtain pomeron parameters
       ! 0.....determine parameters but do not use Kfit
       ! 1.....determine parameters and use Kfit
@@ -83,11 +81,11 @@ namespace corsika::epos {
                                */
     ::epos::cjinti_.ionudi =
         1; // !include quasi elastic events but strict calculation of xs
-    ::epos::cjinti_.iorsce = 0;  // !color exchange turned on(1) or off(0)
-    ::epos::cjinti_.iorsdf = 3;  //  !droplet formation turned on(>0) or off(0)
-    ::epos::cjinti_.iorshh = 0;  //    !other hadron-hadron int. turned on(1) or off(0)
+    ::epos::cjinti_.iorsce = 0; // !color exchange turned on(1) or off(0)
+    ::epos::cjinti_.iorsdf = 3; //  !droplet formation turned on(>0) or off(0)
+    ::epos::cjinti_.iorshh = 0; //    !other hadron-hadron int. turned on(1) or off(0)
 
-    ::epos::othe1_.istore = 0; // do not produce epos output file
+    ::epos::othe1_.istore = 0;  // do not produce epos output file
     ::epos::nucl6_.infragm = 0; // keep free nucleons in fragmentation
 
     ::epos::othe2_.iframe = 12; // lab frame, target at rest
@@ -96,7 +94,7 @@ namespace corsika::epos {
     ::epos::datadir BASE(data_path_);
     strcpy(::epos::fname_.fnnx, BASE.data);
     ::epos::nfname_.nfnnx = BASE.length;
-    
+
     ::epos::datadir TL(data_path_ + "epos.initl");
     strcpy(::epos::fname_.fnii, TL.data);
     ::epos::nfname_.nfnii = TL.length;
@@ -104,15 +102,15 @@ namespace corsika::epos {
     ::epos::datadir EV(data_path_ + "epos.iniev");
     strcpy(::epos::fname_.fnie, EV.data);
     ::epos::nfname_.nfnie = EV.length;
-    
+
     ::epos::datadir RJ(data_path_ + "epos.inirj"); // lhcparameters adds ".lhc"
     strcpy(::epos::fname_.fnrj, RJ.data);
     ::epos::nfname_.nfnrj = RJ.length;
-    
+
     ::epos::datadir CS(data_path_ + "epos.inics"); // lhcparameters adds ".lhc"
     strcpy(::epos::fname_.fncs, CS.data);
     ::epos::nfname_.nfncs = CS.length;
-    
+
     //::epos::fname_.fnid="/home/felix/ngcorsika/corsika/modules/data/EPOS/epos.inidi";
     //     EPOPAR input ../epos/epos.param        !initialization input file for epos
     //       EPOPAR fname inics ../epos/epos.inics  !initialization input file for epos
@@ -134,9 +132,8 @@ namespace corsika::epos {
     ::epos::nucl1_.latarg = 1;
     ::epos::hadr1_.pnll = 200.;
     ::epos::lept1_.engy = -1.;
-    
-    ::epos::ainit_();
 
+    ::epos::ainit_();
   }
 
   inline Interaction::~Interaction() {
@@ -160,154 +157,195 @@ namespace corsika::epos {
     auto const projectile = view.getProjectile();
     auto const corsikaBeamId = projectile.getPID();
 
-    if (corsika::is_nucleus(corsikaBeamId)) {
-      // nuclei handled by different process, this should not happen
-      throw std::runtime_error("Nuclear projectile are not handled by EPOSLHC!");
-    }
-
-    // position and time of interaction, not used in Epos
-    Point const pOrig = projectile.getPosition();
-    TimeType const tOrig = projectile.getTime();
-
-    // define projectile
-    HEPEnergyType const eProjectileLab = projectile.getEnergy();
-    auto const pProjectileLab = projectile.getMomentum();
-    CoordinateSystemPtr const& originalCS = pProjectileLab.getCoordinateSystem();
-
-    CORSIKA_LOG_DEBUG(
-        "ProcessEPOS: "
-        "DoInteraction: {} interaction ",
-        corsikaBeamId);
-
-    // define target
-    // for Sibyll is always a single nucleon
-    // FOR NOW: target is always at rest
-    const auto eTargetLab = 0_GeV + constants::nucleonMass;
-    const auto pTargetLab = MomentumVector(originalCS, 0_GeV, 0_GeV, 0_GeV);
-    const FourVector PtargLab(eTargetLab, pTargetLab);
-
-    CORSIKA_LOG_DEBUG(
-        "Interaction: ebeam lab: {} GeV"
-        "Interaction: pbeam lab: {} GeV",
-        eProjectileLab / 1_GeV, pProjectileLab.getComponents());
-    CORSIKA_LOG_DEBUG(
-        "Interaction: etarget lab: {} GeV "
-        "Interaction: ptarget lab: {} GeV",
-        eTargetLab / 1_GeV, pTargetLab.getComponents() / 1_GeV);
-
-    const FourVector PprojLab(eProjectileLab, pProjectileLab);
-
-    // define target kinematics in lab frame
-    // define boost to and from CoM frame
-    // CoM frame definition in Sibyll projectile: +z
-    COMBoost const boost(PprojLab, constants::nucleonMass);
-    auto const& csPrime = boost.getRotatedCS();
-
-    // just for show:
-    // boost projecticle
-    [[maybe_unused]] auto const PprojCoM = boost.toCoM(PprojLab);
-
-    // boost target
-    [[maybe_unused]] auto const PtargCoM = boost.toCoM(PtargLab);
-
-    CORSIKA_LOG_DEBUG(
-        "Interaction: ebeam CoM: {} GeV "
-        "Interaction: pbeam CoM: {} GeV ",
-        PprojCoM.getTimeLikeComponent() / 1_GeV,
-        PprojCoM.getSpaceLikeComponents().getComponents(csPrime) / 1_GeV);
-    CORSIKA_LOG_DEBUG(
-        "Interaction: etarget CoM: {} GeV "
-        "Interaction: ptarget CoM: {} GeV ",
-        PtargCoM.getTimeLikeComponent() / 1_GeV,
-        PtargCoM.getSpaceLikeComponents().getComponents(csPrime) / 1_GeV);
-
-    CORSIKA_LOG_DEBUG("Interaction: position of interaction: {} ",
-                      pOrig.getCoordinates());
-    CORSIKA_LOG_DEBUG("Interaction: time: {} ", tOrig);
-
-    HEPEnergyType Etot = eProjectileLab + eTargetLab;
-    MomentumVector Ptot = projectile.getMomentum();
-    // 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<CrossSectionType> cross_section_of_components(compVec.size());
-
-    for (size_t i = 0; i < compVec.size(); ++i) {
-      auto const targetId = compVec[i];
-      [[maybe_unused]] auto const [sigProd, sigEla] =
-          getCrossSection(corsikaBeamId, targetId, Ecm);
-      cross_section_of_components[i] = sigProd;
-    }
+    if (corsika::epos::canInteract(corsikaBeamId)) {
+
+      // position and time of interaction, not used in Epos
+      Point const pOrig = projectile.getPosition();
+      TimeType const tOrig = projectile.getTime();
+
+      // define projectile
+      HEPEnergyType const eProjectileLab = projectile.getEnergy();
+      auto const pProjectileLab = projectile.getMomentum();
+      auto const projectileMomentum = pProjectileLab.getNorm();
+      CoordinateSystemPtr const& originalCS = pProjectileLab.getCoordinateSystem();
+
+      // epos frame with z along the projectile direction
+      CoordinateSystemPtr const zAxisFrame = make_rotationToZ(originalCS, pProjectileLab);
+
+      int beamA = 1;
+      if (is_nucleus(corsikaBeamId)) beamA = projectile.getNuclearA();
+
+      HEPEnergyType const projectileMomentumLabPerNucleon = projectileMomentum / beamA;
+
+      CORSIKA_LOG_DEBUG(
+          "ProcessEPOS: "
+          "DoInteraction: {} interaction ",
+          corsikaBeamId);
+
+      // define target
+      // for Sibyll is always a single nucleon
+      // FOR NOW: target is always at rest
+      const auto eTargetLab = 0_GeV + constants::nucleonMass;
+      const auto pTargetLab = MomentumVector(originalCS, 0_GeV, 0_GeV, 0_GeV);
+      const FourVector PtargLab(eTargetLab, pTargetLab);
+
+      CORSIKA_LOG_DEBUG(
+          "Interaction: ebeam lab: {} GeV"
+          "Interaction: pbeam lab: {} GeV",
+          eProjectileLab / 1_GeV, pProjectileLab.getComponents());
+      CORSIKA_LOG_DEBUG(
+          "Interaction: etarget lab: {} GeV "
+          "Interaction: ptarget lab: {} GeV",
+          eTargetLab / 1_GeV, pTargetLab.getComponents() / 1_GeV);
+
+      const FourVector PprojLab(eProjectileLab, pProjectileLab);
+
+      // define target kinematics in lab frame
+      // define boost to and from CoM frame
+      // CoM frame definition in Sibyll projectile: +z
+      COMBoost const boost(PprojLab, constants::nucleonMass);
+      auto const& csPrime = boost.getRotatedCS();
+
+      // just for show:
+      // boost projecticle
+      [[maybe_unused]] auto const PprojCoM = boost.toCoM(PprojLab);
+
+      // boost target
+      [[maybe_unused]] auto const PtargCoM = boost.toCoM(PtargLab);
+
+      CORSIKA_LOG_DEBUG(
+          "Interaction: ebeam CoM: {} GeV "
+          "Interaction: pbeam CoM: {} GeV ",
+          PprojCoM.getTimeLikeComponent() / 1_GeV,
+          PprojCoM.getSpaceLikeComponents().getComponents(csPrime) / 1_GeV);
+      CORSIKA_LOG_DEBUG(
+          "Interaction: etarget CoM: {} GeV "
+          "Interaction: ptarget CoM: {} GeV ",
+          PtargCoM.getTimeLikeComponent() / 1_GeV,
+          PtargCoM.getSpaceLikeComponents().getComponents(csPrime) / 1_GeV);
+
+      CORSIKA_LOG_DEBUG("Interaction: position of interaction: {} ",
+                        pOrig.getCoordinates());
+      CORSIKA_LOG_DEBUG("Interaction: time: {} ", tOrig);
+
+      HEPEnergyType Etot = eProjectileLab + eTargetLab;
+      MomentumVector Ptot = projectile.getMomentum();
+      // 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<CrossSectionType> cross_section_of_components(compVec.size());
+
+      for (size_t i = 0; i < compVec.size(); ++i) {
+        auto const targetId = compVec[i];
+        [[maybe_unused]] auto const [sigProd, sigEla] =
+            getCrossSection(corsikaBeamId, targetId, Ecm);
+        cross_section_of_components[i] = sigProd;
+      }
 
-    const auto targetCode =
-        mediumComposition.sampleTarget(cross_section_of_components, RNG_);
-    CORSIKA_LOG_DEBUG("Interaction: target selected: {} ", targetCode);
-
-    // from corsika7 interface
-    // NEXLNK-part
-    
-    //projectile
-    // if(is_nucleus(corsikaBeamId)){
-    //   ::epos::hadr25_.idprojin =1120;
-    //   ::epos::nucl1_.laproj = projectile.get_nucleus_Z();   // Z
-    //   ::epos::nucl1_.maproj = projectile.get_nucleus_A();; // A
-    // } else {
-    ::epos::hadr25_.idprojin = convertToEposRaw(corsikaBeamId); //1120 ; // id "NEXUS code" 
-    ::epos::nucl1_.laproj = -1;   // Z (-1 for hadron)
-    ::epos::nucl1_.maproj = 1; // A
-    //}
-
-    // target
-    int targetMassNumber = 1;     // proton
-    if (is_nucleus(targetCode)) { // nucleus
-      targetMassNumber = get_nucleus_A(targetCode);
-      if (targetMassNumber > maxTargetMassNumber_)
-        throw std::runtime_error("Epos target mass outside range.");
-    } else {
-      if (targetCode != Proton::code || targetCode != Neutron::code)
-        throw std::runtime_error("Epos target not possible.");
-      // proton or neutron target
-      ::epos::hadr25_.idtargin = convertToEposRaw(targetCode);
-      if (targetCode == Proton::code)
-        ::epos::nucl1_.latarg = 1; // Z
-      else
-        ::epos::nucl1_.latarg = -1; // Z (-1 with id 1220 for neutron)
-      ::epos::nucl1_.matarg = 1;    // A
+      const auto targetCode =
+          mediumComposition.sampleTarget(cross_section_of_components, RNG_);
+      CORSIKA_LOG_DEBUG("Interaction: target selected: {} ", targetCode);
+
+      // from corsika7 interface
+      // NEXLNK-part
+
+      // projectile
+      // if(is_nucleus(corsikaBeamId)){
+      //   ::epos::hadr25_.idprojin =1120;
+      //   ::epos::nucl1_.laproj = projectile.get_nucleus_Z();   // Z
+      //   ::epos::nucl1_.maproj = projectile.get_nucleus_A();; // A
+      // } else {
+      ::epos::hadr25_.idprojin =
+          convertToEposRaw(corsikaBeamId); // 1120 ; // id "NEXUS code"
+      ::epos::nucl1_.laproj = -1;          // Z (-1 for hadron)
+      ::epos::nucl1_.maproj = 1;           // A
+      //}
+
+      // target
+      int targetMassNumber = 1;     // proton
+      if (is_nucleus(targetCode)) { // nucleus
+        targetMassNumber = get_nucleus_A(targetCode);
+        if (targetMassNumber > maxTargetMassNumber_)
+          throw std::runtime_error("Epos target mass outside range.");
+      } else {
+        if (targetCode != Proton::code || targetCode != Neutron::code)
+          throw std::runtime_error("Epos target not possible.");
+        // proton or neutron target
+        ::epos::hadr25_.idtargin = convertToEposRaw(targetCode);
+        if (targetCode == Proton::code)
+          ::epos::nucl1_.latarg = 1; // Z
+        else
+          ::epos::nucl1_.latarg = -1; // Z (-1 with id 1220 for neutron)
+        ::epos::nucl1_.matarg = 1;    // A
+      }
+      CORSIKA_LOG_DEBUG("Interaction: target epos code/A: {}", targetMassNumber);
+
+      // hadron-nucleon momentum
+      ::epos::hadr1_.pnll = float(projectileMomentumLabPerNucleon / 1_GeV); // float(200);
+
+      // C  SET ENGY NEGATIVE TO FORCE CALCULATION IN LAB FRAME
+      ::epos::lept1_.engy = -1.;
+      ::epos::enrgy_.ecms = -1.;
+      ::epos::enrgy_.elab = -1.;
+      ::epos::enrgy_.ekin = -1.;
+
+      // C  INTIALIZE ENERGY AND PARTICLE DEPENDENT PORTION OF EPOS/NEXUS
+      // C  AT THE FIRST CALL: READ ALSO DATA SETS
+      ::epos::ainit_();
+
+      // create event
+      int iarg = 1;
+      ::epos::aepos_(iarg);
+
+      ::epos::afinal_();
+      
+      // NSTORE-part
+
+      MomentumVector Plab_final(originalCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
+      HEPEnergyType Elab_final = 0_GeV;
+
+      // secondaries
+      EposStack es;
+      CORSIKA_LOG_DEBUG("npart: {}", es.getSize());
+      for (auto& psec : es) {
+        if (psec.hasDecayed()) continue;
+        auto momentum = psec.getMomentum(zAxisFrame);
+        auto const energy = psec.getEnergy();
+
+        momentum.rebase(originalCS); // transform back into standard lab frame
+	CORSIKA_LOG_DEBUG("id, energy: {} {}", psec.getPID(), psec.getEnergy()/1_GeV);
+	int id = abs(static_cast<int>(psec.getPID()));
+        CORSIKA_LOG_DEBUG("epos id to pdg:",
+                          ::epos::idtrafo_("nxs", "pdg", id));
+
+        auto const pid = corsika::epos::convertFromEpos(psec.getPID());
+        CORSIKA_LOG_DEBUG(
+            "secondary fragment> id= {}"
+            " p= {}",
+            pid, momentum.getComponents() / 1_GeV);
+        auto pnew =
+            view.addSecondary(std::make_tuple(pid, energy, momentum, pOrig, tOrig));
+        Plab_final += pnew.getMomentum();
+        Elab_final += pnew.getEnergy();
+      }
+      CORSIKA_LOG_DEBUG(
+          "conservation (all GeV): Ecm_final= n/a" /* << Ecm_final / 1_GeV*/
+          "Elab_final="
+          ", Plab_final={}",
+          Elab_final / 1_GeV, (Plab_final / 1_GeV).getComponents());
     }
-    CORSIKA_LOG_DEBUG("Interaction: target epos code/A: {}", targetMassNumber);
 
-    // hadron-nucleon momentum
-    ::epos::hadr1_.pnll = float(200);
-
-    // C  SET ENGY NEGATIVE TO FORCE CALCULATION IN LAB FRAME
-    ::epos::lept1_.engy = -1.;
-    ::epos::enrgy_.ecms = -1.;
-    ::epos::enrgy_.elab = -1.;
-    ::epos::enrgy_.ekin = -1.;
-    
-    //C  INTIALIZE ENERGY AND PARTICLE DEPENDENT PORTION OF EPOS/NEXUS
-    //C  AT THE FIRST CALL: READ ALSO DATA SETS
-    ::epos::ainit_();
-
-    // create event
-    int iarg = 1;
-    ::epos::aepos_(iarg);
-
-    ::epos::afinal_();
-    // NSTORE-part
-    std::cout << "npart: " << ::epos::cptl_.nptl << std::endl;
-    
     /*
       maproj=maprojxs
       laproj=laprojxs
@@ -365,5 +403,4 @@ c      xsbmaxim=dble(bmaxim)
 
      */
   }
-
 } // namespace corsika::epos
diff --git a/corsika/modules/epos/EposStack.hpp b/corsika/modules/epos/EposStack.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f40f71a616cf5544575f905206ee5a3eed6a7a6a
--- /dev/null
+++ b/corsika/modules/epos/EposStack.hpp
@@ -0,0 +1,174 @@
+/*
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/geometry/RootCoordinateSystem.hpp>
+#include <corsika/framework/geometry/Vector.hpp>
+#include <corsika/framework/stack/Stack.hpp>
+#include <corsika/modules/epos/ParticleConversion.hpp>
+
+#include <epos.hpp>
+
+namespace corsika::epos {
+
+  typedef corsika::Vector<hepmomentum_d> MomentumVector;
+
+  class EposStackData {
+
+  public:
+    void dump() const {}
+
+    void clear() { ::epos::cptl_.nptl = 0; }
+    unsigned int getSize() const { return ::epos::cptl_.nptl; }
+    unsigned int getCapacity() const { return ::epos::mxptl; }
+
+    void setId(const unsigned int i, const int v) { ::epos::cptl_.idptl[i] = v; }
+    void setEnergy(const unsigned int i, const HEPEnergyType v) {
+      ::epos::cptl_.pptl[3][i] = v / 1_GeV;
+    }
+    void setMass(const unsigned int i, const HEPMassType v) {
+      ::epos::cptl_.pptl[4][i] = v / 1_GeV;
+    }
+    void setMomentum(const unsigned int i, const MomentumVector& v) {
+      auto tmp = v.getComponents();
+      for (int idx = 0; idx < 3; ++idx) ::epos::cptl_.pptl[idx][i] = tmp[idx] / 1_GeV;
+    }
+    void setState(const unsigned int i, const int v) { ::epos::cptl_.istptl[i] = v; }
+
+    int getId(const unsigned int i) const { return ::epos::cptl_.idptl[i]; }
+    int getState(const unsigned int i) const { return ::epos::cptl_.istptl[i]; }
+    HEPEnergyType getEnergy(const int i) const {
+      return ::epos::cptl_.pptl[3][i] * 1_GeV;
+    }
+    HEPEnergyType getMass(const unsigned int i) const {
+      return ::epos::cptl_.pptl[4][i] * 1_GeV;
+    }
+    MomentumVector getMomentum(const unsigned int i) const {
+      CoordinateSystemPtr const& rootCS = get_root_CoordinateSystem();
+      QuantityVector<hepmomentum_d> components = {::epos::cptl_.pptl[0][i] * 1_GeV,
+                                                  ::epos::cptl_.pptl[1][i] * 1_GeV,
+                                                  ::epos::cptl_.pptl[2][i] * 1_GeV};
+      return MomentumVector(rootCS, components);
+    }
+
+    MomentumVector getMomentum(const unsigned int i,
+                               const CoordinateSystemPtr& CS) const {
+      QuantityVector<hepmomentum_d> components = {::epos::cptl_.pptl[0][i] * 1_GeV,
+                                                  ::epos::cptl_.pptl[1][i] * 1_GeV,
+                                                  ::epos::cptl_.pptl[2][i] * 1_GeV};
+      return MomentumVector(CS, components);
+    }
+
+    void copy(const unsigned int i1, const unsigned int i2) {
+      ::epos::cptl_.idptl[i2] = ::epos::cptl_.idptl[i1];
+      ::epos::cptl_.iorptl[i2] = ::epos::cptl_.iorptl[i1];
+      ::epos::cptl_.jorptl[i2] = ::epos::cptl_.jorptl[i1];
+      ::epos::cptl_.istptl[i2] = ::epos::cptl_.istptl[i1];
+      ::epos::cptl_.ityptl[i2] = ::epos::cptl_.ityptl[i1];
+      for (unsigned int i = 0; i < 5; ++i)
+        ::epos::cptl_.pptl[i][i2] = ::epos::cptl_.pptl[i][i1];
+      for (unsigned int i = 0; i < 2; ++i) {
+        ::epos::cptl_.tivptl[i][i2] = ::epos::cptl_.tivptl[i][i1];
+        ::epos::cptl_.ifrptl[i][i2] = ::epos::cptl_.ifrptl[i][i1];
+      }
+      for (unsigned int i = 0; i < 4; ++i) {
+        ::epos::cptl_.xorptl[i][i2] = ::epos::cptl_.xorptl[i][i1];
+        ::epos::cptl_.ibptl[i][i2] = ::epos::cptl_.ibptl[i][i1];
+      }
+    }
+
+    void swap(const unsigned int i1, const unsigned int i2) {
+      std::swap(::epos::cptl_.idptl[i2], ::epos::cptl_.idptl[i1]);
+      std::swap(::epos::cptl_.iorptl[i2], ::epos::cptl_.iorptl[i1]);
+      std::swap(::epos::cptl_.jorptl[i2], ::epos::cptl_.jorptl[i1]);
+      std::swap(::epos::cptl_.istptl[i2], ::epos::cptl_.istptl[i1]);
+      std::swap(::epos::cptl_.ityptl[i2], ::epos::cptl_.ityptl[i1]);
+      for (unsigned int i = 0; i < 5; ++i)
+        std::swap(::epos::cptl_.pptl[i][i2], ::epos::cptl_.pptl[i][i1]);
+      for (unsigned int i = 0; i < 2; ++i) {
+        std::swap(::epos::cptl_.tivptl[i][i2], ::epos::cptl_.tivptl[i][i1]);
+        std::swap(::epos::cptl_.ifrptl[i][i2], ::epos::cptl_.ifrptl[i][i1]);
+      }
+      for (unsigned int i = 0; i < 4; ++i) {
+        std::swap(::epos::cptl_.xorptl[i][i2], ::epos::cptl_.xorptl[i][i1]);
+        std::swap(::epos::cptl_.ibptl[i][i2], ::epos::cptl_.ibptl[i][i1]);
+      }
+    }
+
+    void incrementSize() { ::epos::cptl_.nptl++; }
+    void decrementSize() {
+      if (::epos::cptl_.nptl > 0) { ::epos::cptl_.nptl--; }
+    }
+  };
+
+  template <typename StackIteratorInterface>
+  class ParticleInterface : public corsika::ParticleBase<StackIteratorInterface> {
+
+    using corsika::ParticleBase<StackIteratorInterface>::getStackData;
+    using corsika::ParticleBase<StackIteratorInterface>::getIndex;
+
+  public:
+    void setParticleData(const int vID, // corsika::epos::EposCode vID,
+                         const HEPEnergyType vE, const MomentumVector& vP,
+                         const HEPMassType vM) {
+      setPID(vID);
+      setEnergy(vE);
+      setMomentum(vP);
+      setMass(vM);
+      setState(0);
+    }
+
+    void setParticleData(ParticleInterface<StackIteratorInterface>& /*parent*/,
+                         const int vID, //  corsika::epos::EposCode vID,
+                         const HEPEnergyType vE, const MomentumVector& vP,
+                         const HEPMassType vM) {
+      setPID(vID);
+      setEnergy(vE);
+      setMomentum(vP);
+      setMass(vM);
+      setState(0);
+    }
+
+    void setEnergy(const HEPEnergyType v) { getStackData().setEnergy(getIndex(), v); }
+
+    HEPEnergyType getEnergy() const { return getStackData().getEnergy(getIndex()); }
+
+    bool hasDecayed() const { return getStackData().getState(getIndex()) == 0; }
+
+    void setMass(const HEPMassType v) { getStackData().setMass(getIndex(), v); }
+
+    HEPEnergyType getMass() const { return getStackData().getMass(getIndex()); }
+
+    void setPID(const int v) { getStackData().setId(getIndex(), v); }
+
+    corsika::epos::EposCode getPID() const {
+      return static_cast<corsika::epos::EposCode>(getStackData().getId(getIndex()));
+    }
+
+    void setState(const int v) { getStackData().setState(getIndex(), v); }
+
+    corsika::epos::EposCode getState() const {
+      return static_cast<corsika::epos::EposCode>(getStackData().getState(getIndex()));
+    }
+
+    MomentumVector getMomentum() const { return getStackData().getMomentum(getIndex()); }
+
+    MomentumVector getMomentum(const CoordinateSystemPtr& CS) const {
+      return getStackData().getMomentum(getIndex(), CS);
+    }
+
+    void setMomentum(const MomentumVector& v) {
+      getStackData().setMomentum(getIndex(), v);
+    }
+  };
+
+  typedef corsika::Stack<EposStackData, ParticleInterface> EposStack;
+
+} // end namespace corsika::epos
diff --git a/modules/epos/epos.hpp b/modules/epos/epos.hpp
index a454c4a6e954f5f9a2732dd0bd35402c2eba9e41..383fae4317f198e6632dc7bbd7ad7a8bbe1e9f37 100644
--- a/modules/epos/epos.hpp
+++ b/modules/epos/epos.hpp
@@ -76,7 +76,7 @@ namespace epos {
   // get mass for id
   void idmass_(int&, double&);
   // convert id from one format to another
-    //int idtrafo_(char[3], char[3], int&);
+  int idtrafo_(char[3], char[3], int&);
 
   // conex routine
   //  void cxidmass_(int&, int&);
@@ -126,7 +126,6 @@ namespace epos {
     int modelxs;
   } xsappli_;
 
-    
   extern struct {
     int nevent;
     int nfull;
@@ -139,15 +138,15 @@ namespace epos {
     int iframexs;
   } xsevent_;
 
-    //   common/metr1/iospec,iocova,iopair,iozero,ioflac,iomom
-    extern struct {
-      int iospec;
-      int iocova;
-      int iopair;
-      int iozero;
-      int ioflac;
-      int iomom;
-    } metr1_;
+  //   common/metr1/iospec,iocova,iopair,iozero,ioflac,iomom
+  extern struct {
+    int iospec;
+    int iocova;
+    int iopair;
+    int iozero;
+    int ioflac;
+    int iomom;
+  } metr1_;
 
   extern struct {
     int ifrade;
@@ -332,96 +331,105 @@ namespace epos {
 
   //     integer      istore,istmax,irescl,ntrymx,nclean,iopdg,ioidch
   // common/othe1/istore,istmax,gaumx,irescl,ntrymx,nclean,iopdg,ioidch
-    extern struct {
-      int istore;
-      int istmax;
-      int gaumx;
-      int irescl;
-      int ntrymx;
-      int nclean;
-      int iopdg;
-      int ioidch;
-    } othe1_;
-
-    //  character*500  fnch,fnhi,fndt,fnii,fnid,fnie,fnrj,fnmt
-    // * ,fngrv,fncp,fnnx,fncs,fndr,fnhpf
-    //  common/fname/  fnch, fnhi, fndt, fnii, fnid, fnie, fnrj, fnmt
-    //      * ,fngrv,fncp,fnnx,fncs,fndr,fnhpf
-    extern struct {
-      char fnch[500];
-      char fnhi[500];
-      char fndt[500];
-      char fnii[500];
-      char fnid[500];
-      char fnie[500];
-      char fnrj[500];
-      char fnmt[500];
-      char fngrv[500];
-      char fncp[500];
-      char fnnx[500];
-      char fncs[500];
-      char fndr[500];
-      char fnhpf[500];
-
-    } fname_;
-    
-     //      integer       nfnch,nfnhi,nfndt,nfnii,nfnid,nfnie,nfnrj,nfnmt
-     // *,nfngrv,nfncp,nfnnx,nfncs,nfndr,nfnhpf
-     //  common/nfname/nfnch,nfnhi,nfndt,nfnii,nfnid,nfnie,nfnrj,nfnmt
-     // *,nfngrv,nfncp,nfnnx,nfncs,nfndr,nfnhpf
-    extern struct {
-      int nfnch;
-      int nfnhi;
-      int nfndt;
-      int nfnii;
-      int nfnid;
-      int nfnie;
-      int nfnrj;
-      int nfnmt;
-      int nfngrv;
-      int nfncp;
-      int nfnnx;
-      int nfncs;
-      int nfndr;
-      int nfnhpf;
-    } nfname_;
-
-    // integer      iprmpt,ish,ishsub,irandm,irewch,iecho,modsho,idensi
-    //   common/prnt1/iprmpt,ish,ishsub,irandm,irewch,iecho,modsho,idensi
-    extern struct {
-      int iprmpt;
-      int ish;
-      int ishsub;
-      int irandm;
-      int irewch;
-      int iecho;
-      int modsho;
-      int idensi;
-    } prnt1_;
-    unsigned int constexpr mmry = 1;
-    unsigned int constexpr mxptl = 200000 / mmry;
-    //      real        pptl,tivptl,xorptl
-    //   integer     nptl,iorptl,idptl,istptl,ifrptl,jorptl,ibptl,ityptl
-    //  common/cptl/nptl,pptl(5,mxptl),iorptl(mxptl),idptl(mxptl)
-    extern struct {
-      int nptl;
-      float pptl[mxptl][5];
-      int iorptl[mxptl];
-      int idptl[mxptl];
-    } cptl_;
-    
-    /**
-     Small helper class to provide a data-directory name in the format eposlhc expects
-    */
-    class datadir {
-    private:
-      datadir operator=(const std::string& dir);
-      datadir operator=(const datadir&);
-
-    public:
-      datadir(const std::string& dir);
-      char data[500];
-      int length;
+  extern struct {
+    int istore;
+    int istmax;
+    int gaumx;
+    int irescl;
+    int ntrymx;
+    int nclean;
+    int iopdg;
+    int ioidch;
+  } othe1_;
+
+  //  character*500  fnch,fnhi,fndt,fnii,fnid,fnie,fnrj,fnmt
+  // * ,fngrv,fncp,fnnx,fncs,fndr,fnhpf
+  //  common/fname/  fnch, fnhi, fndt, fnii, fnid, fnie, fnrj, fnmt
+  //      * ,fngrv,fncp,fnnx,fncs,fndr,fnhpf
+  extern struct {
+    char fnch[500];
+    char fnhi[500];
+    char fndt[500];
+    char fnii[500];
+    char fnid[500];
+    char fnie[500];
+    char fnrj[500];
+    char fnmt[500];
+    char fngrv[500];
+    char fncp[500];
+    char fnnx[500];
+    char fncs[500];
+    char fndr[500];
+    char fnhpf[500];
+
+  } fname_;
+
+  //      integer       nfnch,nfnhi,nfndt,nfnii,nfnid,nfnie,nfnrj,nfnmt
+  // *,nfngrv,nfncp,nfnnx,nfncs,nfndr,nfnhpf
+  //  common/nfname/nfnch,nfnhi,nfndt,nfnii,nfnid,nfnie,nfnrj,nfnmt
+  // *,nfngrv,nfncp,nfnnx,nfncs,nfndr,nfnhpf
+  extern struct {
+    int nfnch;
+    int nfnhi;
+    int nfndt;
+    int nfnii;
+    int nfnid;
+    int nfnie;
+    int nfnrj;
+    int nfnmt;
+    int nfngrv;
+    int nfncp;
+    int nfnnx;
+    int nfncs;
+    int nfndr;
+    int nfnhpf;
+  } nfname_;
+
+  // integer      iprmpt,ish,ishsub,irandm,irewch,iecho,modsho,idensi
+  //   common/prnt1/iprmpt,ish,ishsub,irandm,irewch,iecho,modsho,idensi
+  extern struct {
+    int iprmpt;
+    int ish;
+    int ishsub;
+    int irandm;
+    int irewch;
+    int iecho;
+    int modsho;
+    int idensi;
+  } prnt1_;
+  unsigned int constexpr mmry = 1;
+  unsigned int constexpr mxptl = 200000 / mmry;
+  //      real        pptl,tivptl,xorptl
+  //   integer     nptl,iorptl,idptl,istptl,ifrptl,jorptl,ibptl,ityptl
+  //  common/cptl/nptl,pptl(5,mxptl),iorptl(mxptl),idptl(mxptl)
+  // *,istptl(mxptl),tivptl(2,mxptl),ifrptl(2,mxptl),jorptl(mxptl)
+  // *,xorptl(4,mxptl),ibptl(4,mxptl),ityptl(mxptl)
+  extern struct {
+    int nptl;
+    float pptl[mxptl][5];
+    int iorptl[mxptl];
+    int idptl[mxptl];
+    int istptl[mxptl];
+    float tivptl[mxptl][2];
+    int ifrptl[mxptl][2];
+    int jorptl[mxptl];
+    float xorptl[mxptl][4];
+    int ibptl[mxptl][4];
+    int ityptl[mxptl];
+  } cptl_;
+
+  /**
+   Small helper class to provide a data-directory name in the format eposlhc expects
+  */
+  class datadir {
+  private:
+    datadir operator=(const std::string& dir);
+    datadir operator=(const datadir&);
+
+  public:
+    datadir(const std::string& dir);
+    char data[500];
+    int length;
   };
   }
 } // namespace epos