diff --git a/Processes/Proposal/Interaction.cc b/Processes/Proposal/Interaction.cc
index a42cf04f1349c948e4902b76fa0b2bb5ed079756..a62e45ca93e4658b4c0750461c1db2a50af8002a 100644
--- a/Processes/Proposal/Interaction.cc
+++ b/Processes/Proposal/Interaction.cc
@@ -1,262 +1,138 @@
 
+#include <corsika/environment/IMediumModel.h>
+#include <corsika/environment/NuclearComposition.h>
 #include <corsika/process/proposal/Interaction.h>
 #include <corsika/setup/SetupStack.h>
 #include <corsika/setup/SetupTrajectory.h>
-#include <corsika/environment/NuclearComposition.h>
-#include <corsika/environment/IMediumModel.h>
 #include <corsika/units/PhysicalUnits.h>
-#include <set>
+#include <corsika/utl/COMBoost.h>
+#include <limits>
 #include <map>
 #include <memory>
-#include <limits>
 #include <random>
+#include <set>
 #include <tuple>
-#include <corsika/utl/COMBoost.h>
 
+using Component_PROPOSAL = PROPOSAL::Components::Component;
 namespace corsika::process::proposal {
 
-using namespace corsika::setup;
-using namespace corsika::environment;
-using namespace corsika::units::si;
-using namespace corsika;
-
-using SetupParticle = setup::Stack::StackIterator;
-
-template <>
-Interaction<SetupEnvironment>::Interaction(SetupEnvironment const& env, ParticleCut const& cut)
-      : fEnvironment(env),
-        pCut(cut)
-{
-    using namespace corsika::particles;
-    using namespace units::si;
-
-    auto& universe = *(fEnvironment.GetUniverse());
-
-    auto const allCompositionsInUniverse = std::invoke([&]() {
-      std::vector<NuclearComposition> allCompositionsInUniverse;
-      auto collectCompositions = [&](auto& vtn) {
-        if (vtn.HasModelProperties()) {
-          auto const& comp =
-              vtn.GetModelProperties().GetNuclearComposition();
-          allCompositionsInUniverse.push_back(comp);
-        }
+  using namespace corsika::setup;
+  using namespace corsika::environment;
+  using namespace corsika::units::si;
+  using namespace corsika;
+
+  using SetupParticle = corsika::setup::Stack::StackIterator;
+
+  template <>
+  std::unordered_map<particles::Code, PROPOSAL::ParticleDef>
+      Interaction<SetupEnvironment>::particle_map{
+          {particles::Code::Gamma, PROPOSAL::GammaDef()},
+          {particles::Code::Electron, PROPOSAL::EMinusDef()},
+          {particles::Code::Positron, PROPOSAL::EPlusDef()},
+          {particles::Code::MuMinus, PROPOSAL::MuMinusDef()},
+          {particles::Code::MuPlus, PROPOSAL::MuPlusDef()},
+          {particles::Code::TauPlus, PROPOSAL::TauPlusDef()},
+          {particles::Code::TauMinus, PROPOSAL::TauMinusDef()},
       };
-      universe.walk(collectCompositions);
-      return allCompositionsInUniverse;
-    });
-
-
-    std::map<const NuclearComposition*, PROPOSAL::Medium> composition_medium_map;
-    for (const NuclearComposition& ncarg : allCompositionsInUniverse) {
-        std::vector<particles::Code> pcode { ncarg.GetComponents() };
-        std::vector<float> fractions { ncarg.GetFractions() };
-        std::vector<std::shared_ptr<PROPOSAL::Components::Component>> comp_vec;
 
-        for(unsigned int i=0; i< pcode.size(); i++ ) {
-            comp_vec.push_back(
-				std::make_shared<PROPOSAL::Components::Component>(
-				  PROPOSAL::Components::Component(
-					GetName(pcode[i]),
-					GetNucleusZ(pcode[i]),
-					GetNucleusA(pcode[i]),
-					fractions[i])
-				)
-			);
-        }
-
-        // use ionization constants from air, until CORSIKA implements them
-		PROPOSAL::Air tmp_air;
-        const PROPOSAL::Medium air(
-            tmp_air.GetName(),
-            1., // density correction set to 1 because it cancels out
-            tmp_air.GetI(),
-            tmp_air.GetC(),
-            tmp_air.GetA(),
-            tmp_air.GetM(),
-            tmp_air.GetX0(),
-            tmp_air.GetX1(),
-            tmp_air.GetD0(),
-            1.0,// massDensity set to 1, because it cancels out
-           comp_vec
-        );
-
-        composition_medium_map[&ncarg] =  air;
+  template <>
+  Interaction<SetupEnvironment>::Interaction(SetupEnvironment const& env,
+                                             CORSIKA_ParticleCut const& e_cut)
+      : fEnvironment(env)
+      , cut(make_shared<const PROPOSAL::EnergyCutSettings>(e_cut.GetCutEnergy() / 1_GeV,
+                                                           0, false)) {
+
+    auto all_compositions = std::vector<NuclearComposition>();
+    fEnvironment.GetUniverse()->walk([&](auto& vtn) {
+      if (vtn.HasModelProperties())
+        all_compositions.push_back(vtn.GetModelProperties().GetNuclearComposition());
+    });
+    for (auto& ncarg : all_compositions) {
+      auto comp_vec = std::vector<Component_PROPOSAL>();
+      auto frac_iter = ncarg.GetFractions().cbegin();
+      for (auto& pcode : ncarg.GetComponents()) {
+        comp_vec.emplace_back(GetName(pcode), GetNucleusZ(pcode), GetNucleusA(pcode),
+                              *frac_iter);
+        ++frac_iter;
+      }
+      medium_map[&ncarg] = PROPOSAL::Medium(
+          "Modified Air", 1., PROPOSAL::Air().GetI(), PROPOSAL::Air().GetC(),
+          PROPOSAL::Air().GetA(), PROPOSAL::Air().GetM(), PROPOSAL::Air().GetX0(),
+          PROPOSAL::Air().GetX1(), PROPOSAL::Air().GetD0(), 1.0, comp_vec);
     }
-
-	const double e_cut = 500.;
-	const double v_cut = -1.;
-    PROPOSAL::EnergyCutSettings loss_cut(e_cut,v_cut); // energy_loss, relatic_energy loss (negativ means unused)
-
-    std::string bremsstrahlung_param_str ="BremsKelnerKokoulinPetrukhin";
-    std::string photonuclear_param_str = "PhotoAbramowiczLevinLevyMaor97";
-    std::string epairproduction_param_str = "EpairKelnerKokoulinPetrukhin";
-    std::string ionization_param_str = "IonizBetheBlochRossi"; // IonizBergerSeltzerBhabha IonizBergerSeltzerMollerg
-	std::string shadowing_str = "ShadowButkevichMikhailov";
-
-    std::string annihilation_param_str = "None"; // Heitler
-    std::string compton_param_str = "None"; // KleinNishina
-    std::string muPair_param_str = "None"; // KelnerKokoulinPetrukhin
-	std::string photoPair_param_str = "None"; // Tsai
-    std::string weak_param_str = "None"; // CooperSarkarMertsch
-
-	PROPOSAL::Utility::Definition utility_def;
-    utility_def.brems_def.lpm_effect = false;
-    utility_def.epair_def.lpm_effect = false;
-	utility_def.photo_def.hard_component = false;
-	utility_def.photo_def.shadow = PROPOSAL::PhotonuclearFactory::Get().GetShadowEnumFromString(shadowing_str);
-    utility_def.brems_def.parametrization = PROPOSAL::BremsstrahlungFactory::Get().GetEnumFromString(bremsstrahlung_param_str);
-    utility_def.epair_def.parametrization = PROPOSAL::EpairProductionFactory::Get().GetEnumFromString(epairproduction_param_str);
-    utility_def.ioniz_def.parametrization = PROPOSAL::IonizationFactory::Get().GetEnumFromString(ionization_param_str);
-    utility_def.photo_def.parametrization = PROPOSAL::PhotonuclearFactory::Get().GetEnumFromString(photonuclear_param_str);
-
-	utility_def.annihilation_def.parametrization = PROPOSAL::AnnihilationFactory::Get().GetEnumFromString(annihilation_param_str);
-	utility_def.compton_def.parametrization = PROPOSAL::ComptonFactory::Get().GetEnumFromString(compton_param_str);
-	utility_def.mupair_def.parametrization = PROPOSAL::MupairProductionFactory::Get().GetEnumFromString(muPair_param_str);
-	utility_def.photopair_def.parametrization = PROPOSAL::PhotoPairFactory::Get().GetEnumFromString(photoPair_param_str);
-	utility_def.weak_def.parametrization = PROPOSAL::WeakInteractionFactory::Get().GetEnumFromString(weak_param_str);
-
-	PROPOSAL::InterpolationDef interpolation_def;
-	interpolation_def.path_to_tables = "~/.local/share/PROPOSAL/tables";
-	interpolation_def.path_to_tables_readonly = "~/.local/share/PROPOSAL/tables";
-	interpolation_def.order_of_interpolation = 5; // order of interpolation
-	interpolation_def.max_node_energy = 1e14; // upper energy bound for Interpolation (MeV)
-	interpolation_def.nodes_cross_section = 100; // number of interpolation in cross section
-	interpolation_def.nodes_propagate = 1000; // number of interpolation in propagate
-	interpolation_def.do_binary_tables = true;
-	interpolation_def.just_use_readonly_path = false;
-
-	// std::map<particles::Code, double> corsika_particle_to_utility_map;
-
-
-    std::cout << "go PROPOSAL !!!" << std::endl;
-	for(auto const& medium:composition_medium_map){
-		corsika_particle_to_utility_map[Code::MuMinus] = std::make_unique<PROPOSAL::UtilityInterpolantInteraction>(
-			PROPOSAL::UtilityInterpolantInteraction(PROPOSAL::Utility(PROPOSAL::MuMinusDef::Get(), medium.second, loss_cut, utility_def, interpolation_def),
-													interpolation_def)
-		);
-		corsika_particle_to_displacement_map[Code::MuMinus] = std::make_unique<PROPOSAL::UtilityInterpolantDisplacement>(
-			PROPOSAL::UtilityInterpolantDisplacement(PROPOSAL::Utility(PROPOSAL::MuMinusDef::Get(), medium.second, loss_cut, utility_def, interpolation_def),
-										interpolation_def)
-		);
-	}
     std::cout << "PROPOSAL done." << std::endl;
-
-}
-
-// Interaction::~Interaction {}
-
-// template <>
-// template <>
-// corsika::process::EProcessReturn Interaction<SetupEnvironment>::DoInteraction(SetupParticle const& vP) {
-
-//     // double rndi = dist(rng);
-//     // double rndiMin = corsika_particle_to_utility_map[pcode]->Calculate(initial_energy, p_low, 0);
-
-//     // if (rndd >= rnddMin || rnddMin <= 0) {
-//     //     // return particle_.GetLow();
-//     //     return process::EProcessReturn::eOk;
-//     // } else {
-//     //     return corsika_particle_to_utility_map[pcode]->GetUpperLimit(initial_energy, rndi) ;
-//     // }
-
-//     return process::EProcessReturn::eOk;
-// }
-
-template <>
-template <>
-corsika::units::si::GrammageType Interaction<SetupEnvironment>::GetInteractionLength(SetupParticle const& vP) {
-        std::uniform_real_distribution<double> distribution(0., 1.);
-        double rndi = distribution(fRNG);
-        double particle_energy = vP.GetEnergy()  / 1_GeV * 1000;
-        double rndiMin = corsika_particle_to_utility_map[vP.GetPID()]->Calculate(particle_energy, 0, 0);
-
-        if (rndi >= rndiMin || rndiMin <= 0) {
-            return  std::numeric_limits<double>::max() * 1_g / 1_cm / 1_cm;
-        }
-        double final_energy = corsika_particle_to_utility_map[vP.GetPID()]->GetUpperLimit(particle_energy, rndi) ;
-        return corsika_particle_to_displacement_map[vP.GetPID()]->Calculate(
-                    particle_energy,
-                    final_energy,
-                    std::numeric_limits<double>::max(),
-                    PROPOSAL::Vector3D(),
-                    PROPOSAL::Vector3D()
-                ) * 1_g / 1_cm / 1_cm;
-}
-
-template <>
-template <>
-process::EProcessReturn Interaction<SetupEnvironment>::DoInteraction(SetupParticle& vP) {
-    std::uniform_real_distribution<double> distribution(0., 1.);
-    double rnd1 = distribution(fRNG);
-    double rnd2 = distribution(fRNG);
-    double rnd3 = distribution(fRNG);
-    double particle_energy = vP.GetEnergy()  / 1_GeV * 1000;
-
-	corsika::geometry::Point pOrig = vP.GetPosition();
-	corsika::units::si::TimeType tOrig = vP.GetTime();
-	corsika::stack::MomentumVector Ptot = vP.GetMomentum();
-    corsika::geometry::QuantityVector q_momentum = Ptot.GetComponents();
-	PROPOSAL::Vector3D initial_direction(q_momentum[0] / 1_GeV, q_momentum[1] / 1_GeV, q_momentum[2] / 1_GeV);
-	initial_direction.normalise();
-	initial_direction.CalculateSphericalCoordinates();
-	std::pair<double, PROPOSAL::DynamicData::Type> energy_loss;
-	energy_loss = corsika_particle_to_utility_map[vP.GetPID()]->GetUtility().StochasticLoss(particle_energy, rnd1, rnd2, rnd3);
-
-	std::vector<PROPOSAL::CrossSection*> cross_sections = corsika_particle_to_utility_map[vP.GetPID()]->GetUtility().GetCrosssections();
-    std::pair<std::vector<PROPOSAL::Particle*>, bool> products;
-	for (unsigned int i = 0; i < cross_sections.size(); i++) {
-		if (cross_sections[i]->GetTypeId() == energy_loss.second)
-		{
-			// calculate produced particles, get an empty list if no particles
-            // are produced in interaction
-			products = cross_sections[i]->CalculateProducedParticles(particle_energy, energy_loss.first, initial_direction);
-            break;
-		}
-	}
-    double particle_energy_after_loss = particle_energy - energy_loss.first;
-    if (particle_energy_after_loss == 0.)
-    {
-        PROPOSAL::Vector3D particle_direction = initial_direction * particle_energy_after_loss;
-
-        corsika::geometry::QuantityVector q_vec(
-            particle_direction.GetX() * 1_MeV,
-            particle_direction.GetY() * 1_MeV,
-            particle_direction.GetZ() * 1_MeV);
-        // vp.GetCoordinateSystem();
-        const corsika::geometry::CoordinateSystem& rootCS = corsika::geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
-        corsika::stack::MomentumVector p_particle(rootCS, q_vec);
-        // std::cout << p_particle.GetTimeLikeComponent() << " and " << particle_energy_after_loss << std::endl;
-        units::si::HEPEnergyType const converted_particle_energy = particle_energy * 1_GeV;
-        HEPEnergyType const eCoM = particle_energy * 1_GeV ;
-        //auto const Plab = boost.fromCoM(FourVector(eCoM, p_particle));
-	auto pnew = vP.AddSecondary(std::tuple<particles::Code, units::si::HEPEnergyType, stack::MomentumVector,
-								geometry::Point, units::si::TimeType>
-                                {
-                                 //convert_proposal_particle_name_to_corsika_code[PROPOSAL::MuMinusDef::Get().name],
-                                 vP.GetPID(),
-                                 eCoM,
-                                 p_particle,
-                                 pOrig,
-                                 tOrig
-                                 }
-				);
+  }
+
+  template <>
+  template <>
+  auto Interaction<SetupEnvironment>::GetCalculator(SetupParticle const& vP) {
+    auto& mediumComposition = vP.GetNode()->GetModelProperties().GetNuclearComposition();
+    auto calc_it = calculators.find(&mediumComposition);
+    if (calc_it != calculators.end()) return calc_it;
+    auto const& p_def = particle_map[vP.GetPID()];
+    auto& medium = medium_map[&mediumComposition];
+    auto cross = PROPOSAL::GetStdCrossSections(p_def, medium, cut, true);
+    auto inter_types = PROPOSAL::CrossSectionVector::GetInteractionTypes(cross);
+    auto [insert_it, success] = calculators.insert(
+        {&mediumComposition,
+         make_tuple(PROPOSAL::SecondariesCalculator(inter_types, p_def, medium),
+                    PROPOSAL::make_interaction(cross, true),
+                    PROPOSAL::make_displacement(cross, true))});
+    if (success) return insert_it;
+    throw std::logic_error("insert failed.");
+  }
+
+  template <>
+  template <>
+  corsika::process::EProcessReturn Interaction<SetupEnvironment>::DoInteraction(
+      SetupParticle const& vP) {
+    auto calc = GetCalculator(vP); // [CrossSections]
+    std::uniform_real_distribution<double> distr(0., 1.);
+    auto [type, comp_ptr, v] = std::get<INTERACTION>(calc->second)
+                                   ->TypeInteraction(vP.GetEnergy() / 1_GeV, distr(fRNG));
+    auto rnd = std::vector<double>();
+    for (auto i = 0; i < std::get<SECONDARIES>(calc->second).RequiredRandomNumbers(type);
+         ++i)
+      rnd.push_back(distr(fRNG));
+    double primary_energy = vP.GetEnergy() / 1_GeV;
+    auto point =
+        PROPOSAL::Vector3D(vP.GetPosition().GetX() / 1_cm, vP.GetPosition().GetY() / 1_cm,
+                           vP.GetPosition().GetZ() / 1_cm);
+    auto p = vP.GetMomentum().GetComponents();
+    auto direction = PROPOSAL::Vector3D(p[0] / 1_GeV, p[1] / 1_GeV, p[2] / 1_GeV);
+    auto loss =
+        make_tuple(static_cast<int>(type), point, direction, v * primary_energy, 0.);
+    auto sec = std::get<SECONDARIES>(calc->second)
+                   .CalculateSecondaries(primary_energy, loss, *comp_ptr, rnd);
+    for (auto& s : sec) {
+      auto energy = get<PROPOSAL::Loss::ENERGY>(s) * 1_MeV;
+      auto vec = corsika::geometry::QuantityVector(
+          std::get<PROPOSAL::Loss::DIRECTION>(s).GetX() * energy,
+          std::get<PROPOSAL::Loss::DIRECTION>(s).GetY() * energy,
+          std::get<PROPOSAL::Loss::DIRECTION>(s).GetZ() * energy);
+      auto momentum = corsika::stack::MomentumVector(
+          corsika::geometry::RootCoordinateSystem::GetInstance()
+              .GetRootCoordinateSystem(),
+          vec);
+      // particles::Code, units::si::HEPEnergyType, stack::MomentumVector,
+      // geometry::Point, units::si::TimeType
+      auto sec = make_tuple(get<PROPOSAL::Loss::TYPE>(s), energy, momentum,
+                            vP.GetPosition(), vP.GetTime());
+      vP.AddSecondary(sec);
     }
-	// // position and time of interaction, not used in PROPOSAL
-
-	// // add to corsika stack
-	// auto pnew = vP.AddSecondary(tuple<particles::Code, units::si::HEPEnergyType, stack::MomentumVector,
-	// 							geometry::Point, units::si::TimeType>
-	// 							{
-	// 							  process::sibyll::ConvertFromSibyll(psib.GetPID()),
-	// 							  energy_lost,
-                  				  // Plab.GetTimeLikeComponent(),
-	// 							  Plab.GetSpaceLikeComponents(),
-	// 							  pOrig,
-	// 							  tOrig
-	// 							}
-	// 			);
-
-	return process::EProcessReturn::eOk;
-}
-
-} // corsika::process::proposal
+    return process::EProcessReturn::eOk;
+  }
+
+  template <>
+  template <>
+  corsika::units::si::GrammageType Interaction<SetupEnvironment>::GetInteractionLength(
+      SetupParticle const& vP) {
+    auto calc = GetCalculator(vP); // [CrossSections]
+    std::uniform_real_distribution<double> distr(0., 1.);
+    auto energy = get<INTERACTION>(calc->second)
+                      ->EnergyInteraction(vP.GetEnergy() / 1_GeV, distr(fRNG));
+    return get<DISPLACEMENT>(calc->second)
+               ->SolveTrackIntegral(vP.GetEnergy() / 1_GeV, energy) *
+           1_g / 1_cm / 1_cm;
+  }
+} // namespace corsika::process::proposal
diff --git a/Processes/Proposal/Interaction.h b/Processes/Proposal/Interaction.h
index 3defff2a05ea53461fd0862fc61725dcf820da1d..6dfe30995343bd40b21e0610d63cb487303ea8c1 100644
--- a/Processes/Proposal/Interaction.h
+++ b/Processes/Proposal/Interaction.h
@@ -11,76 +11,80 @@
 #ifndef _corsika_process_proposal_interaction_h_
 #define _corsika_process_proposalythia_interaction_h_
 
-#include "PROPOSAL/PROPOSAL.h"
+#include <corsika/environment/Environment.h>
 #include <corsika/particles/ParticleProperties.h>
 #include <corsika/process/InteractionProcess.h>
-#include <corsika/environment/Environment.h>
 #include <corsika/process/particle_cut/ParticleCut.h>
-#include <corsika/random/UniformRealDistribution.h>
 #include <corsika/random/RNGManager.h>
+#include <corsika/random/UniformRealDistribution.h>
 #include <random>
+#include <unordered_map>
+#include "PROPOSAL/PROPOSAL.h"
 
 using namespace corsika::environment;
-using namespace corsika::process::particle_cut;
+
+using CORSIKA_ParticleCut = corsika::process::particle_cut::ParticleCut;
 
 namespace corsika::process::proposal {
 
+  /* static std::unordered_map<particles::Code, PROPOSAL::ParticleDef> particle_map{ */
+  /*     {particles::Code::Gamma, PROPOSAL::GammaDef()}, */
+  /*     {particles::Code::Electron, PROPOSAL::EMinusDef()}, */
+  /*     {particles::Code::Positron, PROPOSAL::EPlusDef()}, */
+  /*     {particles::Code::MuMinus, PROPOSAL::MuMinusDef()}, */
+  /*     {particles::Code::MuPlus, PROPOSAL::MuPlusDef()}, */
+  /*     {particles::Code::TauPlus, PROPOSAL::TauPlusDef()}, */
+  /*     {particles::Code::TauMinus, PROPOSAL::TauMinusDef()}, */
+  /* }; */
+
   template <class TEnvironment>
-  class Interaction : public corsika::process::InteractionProcess<Interaction<TEnvironment>> {
+  class Interaction
+      : public corsika::process::InteractionProcess<Interaction<TEnvironment>> {
 
   private:
     TEnvironment const& fEnvironment;
-    ParticleCut const& pCut;
-    // Initializing of uniform_real_distribution class
-    // double min{0.0};
-    // double max{1.0};
-    // std::uniform_real_distribution<double> rnd_uniform(min,max);
-
-    std::map<particles::Code, std::unique_ptr<PROPOSAL::UtilityInterpolantInteraction>> corsika_particle_to_utility_map;
-	std::map<particles::Code, std::unique_ptr<PROPOSAL::UtilityInterpolantDisplacement>> corsika_particle_to_displacement_map;
-
-    corsika::random::RNG& fRNG = corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
-
-    std::map<std::string, particles::Code> const convert_proposal_particle_name_to_corsika_code = {
-        {"Gamma", particles::Code::Gamma},
-        {"EMinus", particles::Code::Electron},
-        {"EPlus", particles::Code::Positron},
-        {"MuMinu", particles::Code::MuMinus},
-        {"MuPlus", particles::Code::MuPlus},
-        {"TauPlus", particles::Code::TauPlus},
-        {"TauMinus",particles::Code::TauMinus},
-    };
+    shared_ptr<const PROPOSAL::EnergyCutSettings> cut;
 
-    std::map<particles::Code, PROPOSAL::ParticleDef> const convert_corsika_code_to_proposal_particle_def = {
-        {particles::Code::Gamma, PROPOSAL::GammaDef::Get()},
-        {particles::Code::Electron, PROPOSAL::EMinusDef::Get()},
-        {particles::Code::Positron, PROPOSAL::EPlusDef::Get()},
-        {particles::Code::MuMinus, PROPOSAL::MuMinusDef::Get()},
-        {particles::Code::MuPlus, PROPOSAL::MuPlusDef::Get()},
-        {particles::Code::TauPlus, PROPOSAL::TauPlusDef::Get()},
-        {particles::Code::TauMinus, PROPOSAL::TauMinusDef::Get()},
-    };
+    static std::unordered_map<particles::Code, PROPOSAL::ParticleDef> particle_map;
+    std::unordered_map<const NuclearComposition*, PROPOSAL::Medium> medium_map;
+
+    enum { SECONDARIES, INTERACTION, DISPLACEMENT };
+    /* std::uniform_real_distribution<> rnd_uniform(0., 1.); */
+
+    /* std::map<particles::Code, std::unique_ptr<PROPOSAL::UtilityInterpolantInteraction>>
+     * corsika_particle_to_utility_map; */
+    /* std::map<particles::Code,
+     * std::unique_ptr<PROPOSAL::UtilityInterpolantDisplacement>>
+     * corsika_particle_to_displacement_map; */
+
+    corsika::random::RNG& fRNG =
+        corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
 
     // fTrackedParticles[proposal_particle.GetName()] return  particle::Code
 
-    bool IsTracked(particles::Code pcode) {
-        for (auto i : convert_corsika_code_to_proposal_particle_def) if (i.first==pcode) return true;
-        return false;
+    auto IsTracked(particles::Code pcode) const noexcept {
+      auto search = particle_map.find(pcode);
+      if (search != particle_map.end()) return true;
+      return false;
     };
 
+    using calculator_t =
+        tuple<PROPOSAL::SecondariesCalculator, unique_ptr<PROPOSAL::Interaction>,
+              unique_ptr<PROPOSAL::Displacement>>;
+    std::unordered_map<const NuclearComposition*, calculator_t> calculators;
 
-  public:
-    Interaction(TEnvironment const& env, ParticleCut const& cut);
+    template <typename Particle>
+    auto GetCalculator(Particle&);
 
-    // ~Interaction;
+  public:
+    Interaction(TEnvironment const& env, CORSIKA_ParticleCut const& cut);
 
     template <typename Particle>
     corsika::process::EProcessReturn DoInteraction(Particle&);
 
     template <typename TParticle>
     corsika::units::si::GrammageType GetInteractionLength(TParticle& p);
-
   };
 
-} // namespace corsika::process
+} // namespace corsika::process::proposal
 #endif