diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc
index 49e2c11b77e2704c84297600a21f5e1933594227..1b428066812c63c2a1cad080e0010446fb69ac08 100644
--- a/Documentation/Examples/cascade_example.cc
+++ b/Documentation/Examples/cascade_example.cc
@@ -211,13 +211,15 @@ int main() {
       Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m},
       1_km * std::numeric_limits<double>::infinity());
 
+  // fraction of oxygen
+  const float fox = 0.20946;
   using MyHomogeneousModel =
       corsika::environment::HomogeneousMedium<corsika::environment::IMediumModel>;
   theMedium->SetModelProperties<MyHomogeneousModel>(
       1_kg / (1_m * 1_m * 1_m),
       corsika::environment::NuclearComposition(
-          std::vector<corsika::particles::Code>{corsika::particles::Code::Oxygen},
-          std::vector<float>{1.}));
+					       std::vector<corsika::particles::Code>{corsika::particles::Code::Nitrogen,corsika::particles::Code::Oxygen},
+					       std::vector<float>{(float)1.-fox, fox}));
 
   universe.AddChild(std::move(theMedium));
 
@@ -226,7 +228,7 @@ int main() {
   // setup processes, decays and interactions
   tracking_line::TrackingLine<setup::Stack> tracking(env);
   stack_inspector::StackInspector<setup::Stack> p0(true);
-  corsika::process::sibyll::Interaction sibyll;
+  corsika::process::sibyll::Interaction sibyll(env);
   corsika::process::sibyll::Decay decay;
   ProcessCut cut(8_GeV);
   corsika::process::TrackWriter::TrackWriter trackWriter("tracks.dat");
@@ -270,6 +272,8 @@ int main() {
 
   cout << "Result: E0=" << E0 / 1_GeV << endl;
   cut.ShowResults();
+  const HEPEnergyType Efinal = cut.GetCutEnergy() + cut.GetInvEnergy() + cut.GetEmEnergy();
   cout << "total energy (GeV): "
-       << (cut.GetCutEnergy() + cut.GetInvEnergy() + cut.GetEmEnergy()) / 1_GeV << endl;
+       << Efinal / 1_GeV << endl
+       << "relative difference (%): " << (Efinal / E0 - 1. ) * 100 << endl;
 }
diff --git a/Environment/CMakeLists.txt b/Environment/CMakeLists.txt
index c4083f6f391babff17c107475b287eef9fbac812..a476b89e8a7ada3f41152a9c0166aafa185a4d3f 100644
--- a/Environment/CMakeLists.txt
+++ b/Environment/CMakeLists.txt
@@ -22,6 +22,7 @@ target_link_libraries (
   CORSIKAgeometry
   CORSIKAparticles
   CORSIKAunits
+  CORSIKArandom
   )
 
 target_include_directories (
diff --git a/Environment/HomogeneousMedium.h b/Environment/HomogeneousMedium.h
index cc612d044cb8c1d3f2d96ec081894806e6ab6dad..4c9a03f366a52c68b96e3ffe90bca8421b8f7810 100644
--- a/Environment/HomogeneousMedium.h
+++ b/Environment/HomogeneousMedium.h
@@ -17,6 +17,7 @@
 #include <corsika/geometry/Trajectory.h>
 #include <corsika/particles/ParticleProperties.h>
 #include <corsika/units/PhysicalUnits.h>
+#include <corsika/random/RNGManager.h>
 
 /**
  * a homogeneous medium
@@ -41,6 +42,29 @@ namespace corsika::environment {
     }
     NuclearComposition const& GetNuclearComposition() const override { return fNuclComp; }
 
+    corsika::particles::Code const& GetTarget( std::vector<corsika::units::si::CrossSectionType> &sigma) const override {
+      using namespace corsika::units::si;
+      int i=-1;
+      corsika::units::si::CrossSectionType total_weighted_sigma = 0._mbarn;
+      std::vector<float> fractions;				 
+      for(auto w: fNuclComp.GetFractions() ){
+	i++;
+	std::cout << "HomogeneousMedium: fraction: " << w << std::endl;
+	total_weighted_sigma +=  w * sigma[i];
+	fractions.push_back( w * sigma[i] / 1_mbarn );
+      }
+					 
+      for(auto f: fractions){
+	f = f / ( total_weighted_sigma / 1_mbarn );
+	std::cout << "HomogeneousMedium: reweighted fraction: " << f << std::endl;
+      }
+      std::discrete_distribution channelDist( fractions.begin(), fractions.end() );
+      static corsika::random::RNG& kRNG =
+	corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
+      const int ichannel = channelDist(kRNG);
+      return fNuclComp.GetComponents()[ichannel];
+    }
+    
     corsika::units::si::GrammageType IntegratedGrammage(
         corsika::geometry::Trajectory<corsika::geometry::Line> const&,
         corsika::units::si::LengthType pTo) const override {
@@ -52,7 +76,7 @@ namespace corsika::environment {
         corsika::geometry::Trajectory<corsika::geometry::Line> const&,
         corsika::units::si::GrammageType pGrammage) const override {
       return pGrammage / fDensity;
-    }
+    }    
   };
 
 } // namespace corsika::environment
diff --git a/Environment/IMediumModel.h b/Environment/IMediumModel.h
index ddae0564200a1a97428a0791f8333feea8c8932b..24393e805eb46a90febe4ac568c2949334f88bfe 100644
--- a/Environment/IMediumModel.h
+++ b/Environment/IMediumModel.h
@@ -38,6 +38,8 @@ namespace corsika::environment {
         corsika::units::si::GrammageType) const = 0;
 
     virtual NuclearComposition const& GetNuclearComposition() const = 0;
+
+    virtual corsika::particles::Code const& GetTarget( std::vector<corsika::units::si::CrossSectionType> &) const = 0;
   };
 
 } // namespace corsika::environment
diff --git a/Processes/Sibyll/CMakeLists.txt b/Processes/Sibyll/CMakeLists.txt
index ab8f9b3e094a42b00a63899442774d6b42c1b1f7..bf89db756b5aaca2be901596c1015b5d724245e7 100644
--- a/Processes/Sibyll/CMakeLists.txt
+++ b/Processes/Sibyll/CMakeLists.txt
@@ -69,6 +69,7 @@ target_link_libraries (
   CORSIKAunits
   CORSIKAthirdparty
   CORSIKAgeometry
+  CORSIKAenvironment
   )
 
 target_include_directories (
diff --git a/Processes/Sibyll/Interaction.h b/Processes/Sibyll/Interaction.h
index fac0dd578b77cfea776b1b942b6a42b9e899f809..b8709216a75bd7a827fea1b063520fa615805553 100644
--- a/Processes/Sibyll/Interaction.h
+++ b/Processes/Sibyll/Interaction.h
@@ -21,6 +21,8 @@
 #include <corsika/particles/ParticleProperties.h>
 #include <corsika/random/RNGManager.h>
 #include <corsika/units/PhysicalUnits.h>
+#include <corsika/environment/Environment.h>
+#include <corsika/environment/NuclearComposition.h>
 
 namespace corsika::process::sibyll {
 
@@ -28,9 +30,8 @@ namespace corsika::process::sibyll {
 
     int fCount = 0;
     int fNucCount = 0;
-
   public:
-    Interaction() {}
+    Interaction(corsika::environment::Environment const& env) : fEnvironment(env) { }
     ~Interaction() {
       std::cout << "Sibyll::Interaction n=" << fCount << " Nnuc=" << fNucCount
                 << std::endl;
@@ -44,11 +45,38 @@ namespace corsika::process::sibyll {
 
       corsika::random::RNGManager& rmng = corsika::random::RNGManager::GetInstance();
       rmng.RegisterRandomStream("s_rndm");
-
+     
       // initialize Sibyll
       sibyll_ini_();
     }
 
+    std::tuple<corsika::units::si::CrossSectionType, int> GetCrossSection(const corsika::particles::Code &BeamId, const corsika::particles::Code & TargetId, const corsika::units::si::HEPEnergyType& CoMenergy)
+    {
+      using namespace corsika::units::si;
+      double sigProd, dummy, dum1, dum2, dum3, dum4;
+      double dumdif[3];
+      const int iBeam = process::sibyll::GetSibyllXSCode(BeamId);
+      const double dEcm = CoMenergy / 1_GeV;
+      if(corsika::particles::IsNucleus( TargetId )){
+	const int iTarget = corsika::particles::GetNucleusA( TargetId );
+	if(iTarget>18||iTarget==0)
+	  throw std::runtime_error("Sibyll target outside range. Only nuclei with A<18 are allowed.");
+	sib_sigma_hnuc_(iBeam, iTarget, dEcm, sigProd, dummy);
+	return std::make_tuple( sigProd * 1_mbarn, iTarget );
+      }
+      else
+	{
+	  if (TargetId == corsika::particles::Proton::GetCode()){
+	    sib_sigma_hp_(iBeam, dEcm, dum1, dum2, sigProd, dumdif, dum3, dum4);
+	    return std::make_tuple( sigProd * 1_mbarn, 1 );
+	  }
+	  else
+	    // no interaction in sibyll possible, return infinite cross section? or throw?
+	    sigProd = std::numeric_limits<double>::infinity();
+	  return std::make_tuple( sigProd * 1_mbarn, 0 );
+	}
+    }
+    
     template <typename Particle, typename Track>
     corsika::units::si::GrammageType GetInteractionLength(Particle& p, Track&) {
 
@@ -66,60 +94,65 @@ namespace corsika::process::sibyll {
 
       // beam particles for sibyll : 1, 2, 3 for p, pi, k
       // read from cross section code table
-      const int kBeam = process::sibyll::GetSibyllXSCode(corsikaBeamId);
       const bool kInteraction = process::sibyll::CanInteract(corsikaBeamId);
-
-      /*
-         the target should be defined by the Environment,
-         ideally as full particle object so that the four momenta
-         and the boosts can be defined..
-       */
-      // target nuclei: A < 18
-      // FOR NOW: assume target is oxygen
-      const int kTarget = corsika::particles::Oxygen::GetNucleusA();
-
+      
       const HEPMassType nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() +
-                                              corsika::particles::Neutron::GetMass());
-      HEPEnergyType const Elab = p.GetEnergy();
-      HEPEnergyType const Etot = Elab + nucleon_mass;
-      MomentumVector Ptot(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
+                                                corsika::particles::Neutron::GetMass());
+
       // FOR NOW: assume target is at rest
       MomentumVector pTarget(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
+
+      // total momentum and energy
+      HEPEnergyType Elab = p.GetEnergy() + nucleon_mass;
+      MomentumVector Ptot(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
       Ptot += p.GetMomentum();
       Ptot += pTarget;
       // calculate cm. energy
-      const HEPEnergyType sqs = sqrt(Etot * Etot - Ptot.squaredNorm());
-      const double Ecm = sqs / 1_GeV;
+      const HEPEnergyType ECoM = sqrt(Elab * Elab - Ptot.squaredNorm());
 
       std::cout << "Interaction: LambdaInt: \n"
-                << " input energy: " << Elab / 1_GeV << endl
-                << " beam can interact:" << kBeam << endl
-                << " beam XS code:" << kBeam << endl
-                << " beam pid:" << p.GetPID() << endl
-                << " target mass number:" << kTarget << std::endl;
-
-      if (kInteraction && Elab >= 8.5_GeV && sqs >= 10_GeV) {
-
-        double prodCrossSection, dummy, dum1, dum2, dum3, dum4;
-        double dumdif[3];
-
-        if (kTarget == 1)
-          sib_sigma_hp_(kBeam, Ecm, dum1, dum2, prodCrossSection, dumdif, dum3, dum4);
-        else
-          sib_sigma_hnuc_(kBeam, kTarget, Ecm, prodCrossSection, dummy);
-
-        std::cout << "Interaction: "
-                  << "MinStep: sibyll return: " << prodCrossSection << std::endl;
-        si::CrossSectionType sig = prodCrossSection * 1_mbarn;
-        std::cout << "Interaction: "
-                  << "MinStep: CrossSection (mb): " << sig / 1_mbarn << std::endl;
-
-        std::cout << "Interaction: "
-                  << "nucleon mass " << nucleon_mass << std::endl;
-        // calculate interaction length in medium
-        GrammageType int_length = kTarget * corsika::units::constants::u / sig;
-        std::cout << "Interaction: "
-                  << "interaction length (g/cm2): " << int_length << std::endl;
+                << " input energy: " << p.GetEnergy() / 1_GeV << endl
+                << " beam can interact:" << kInteraction << endl
+                << " beam pid:" << p.GetPID() << endl;
+
+      if (kInteraction && Elab >= 8.5_GeV && ECoM >= 10_GeV) {
+
+	// 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..
+	*/
+	const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition());
+	const auto mediumComposition = currentNode->GetModelProperties().GetNuclearComposition();
+	// determine average interaction length
+	// weighted sum
+	int i =-1;
+	double avgTargetMassNumber = 0.;
+	si::CrossSectionType weightedProdCrossSection = 0_mbarn;
+	// get weights of components from environment/medium
+	const auto w = mediumComposition.GetFractions();
+	// loop over components in medium
+	for (auto targetId: mediumComposition.GetComponents() ){
+	  i++;
+	  cout << "Interaction: get interaction length for target: " << targetId << endl;
+
+	  auto const [ productionCrossSection, numberOfNucleons ] = GetCrossSection( corsikaBeamId, targetId, ECoM);
+	  
+	  std::cout << "Interaction: "
+		    << " IntLength: sibyll return (mb): " << productionCrossSection / 1_mbarn << std::endl;
+	  weightedProdCrossSection += w[i] * productionCrossSection;
+	  avgTargetMassNumber += w[i] * numberOfNucleons;
+	}
+	cout << "Interaction: "
+	     << "IntLength: weighted CrossSection (mb): " << weightedProdCrossSection / 1_mbarn
+	     << endl;
+	
+	// calculate interaction length in medium
+#warning check interaction length units	
+	GrammageType int_length = avgTargetMassNumber * corsika::units::constants::u / weightedProdCrossSection;
+	std::cout << "Interaction: "
+		  << "interaction length (g/cm2): " << int_length / ( 0.001_kg ) * 1_cm * 1_cm << std::endl;
 
         return int_length;
       }
@@ -137,10 +170,11 @@ namespace corsika::process::sibyll {
       using std::cout;
       using std::endl;
 
+      const auto corsikaBeamId = p.GetPID();
       cout << "ProcessSibyll: "
-           << "DoInteraction: " << p.GetPID() << " interaction? "
-           << process::sibyll::CanInteract(p.GetPID()) << endl;
-      if (process::sibyll::CanInteract(p.GetPID())) {
+           << "DoInteraction: " << corsikaBeamId << " interaction? "
+           << process::sibyll::CanInteract( corsikaBeamId ) << endl;
+      if (process::sibyll::CanInteract(corsikaBeamId) ) {
         const CoordinateSystem& rootCS =
             RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
 
@@ -171,18 +205,8 @@ namespace corsika::process::sibyll {
         // double phi = asin( p.GetMomentum().GetComponents()[0]/pt(p.GetMomentum() ) );
         const CoordinateSystem tempCS = rootCS.rotate(zAxis, phi);
         const CoordinateSystem sibyllCS = tempCS.rotate(yAxis, theta);
-
-        /*
-           the target should be defined by the Environment,
-           ideally as full particle object so that the four momenta
-           and the boosts can be defined..
-
-           here we need: GetTargetMassNumber() or GetTargetPID()??
-                         GetTargetMomentum() (zero in EAS)
-        */
-        // FOR NOW: set target to oxygen
-        const int kTarget = corsika::particles::Oxygen::
-            GetNucleusA(); // env.GetTargetParticle().GetPID();
+	
+	
 
         // FOR NOW: target is always at rest
         auto constexpr nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() +
@@ -213,6 +237,39 @@ namespace corsika::process::sibyll {
         MomentumVector Ptot = p.GetMomentum();
         // invariant mass, i.e. cm. energy
         HEPEnergyType Ecm = sqrt(Etot * Etot - Ptot.squaredNorm());
+
+	
+	// sample target mass number
+	const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(pOrig);
+	const auto 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
+	std::vector<si::CrossSectionType> cross_section_of_components;
+	for(auto targetId: mediumComposition.GetComponents() ){
+	  const auto [sigProd, nNuc] = GetCrossSection( corsikaBeamId, targetId, Ecm);	  
+	  cross_section_of_components.push_back( sigProd );
+	}	
+
+	const auto targetCode = currentNode->GetModelProperties().GetTarget( cross_section_of_components);
+	cout << "Interaction: target selected: " << targetCode << endl;
+	/*
+	  FOR NOW: allow nuclei with A<18 or protons only. 
+	  when medium composition becomes more complex, approximations will have to be allowed
+	  air in atmosphere also contains some Argon.
+	*/
+	int targetSibCode = -1;
+	if( IsNucleus(targetCode))
+	  targetSibCode = GetNucleusA( targetCode );
+	if( targetCode == corsika::particles::Proton::GetCode())
+	  targetSibCode = 1;
+	cout << "Interaction: sibyll code: " << targetSibCode << endl;
+	if(targetSibCode>18||targetSibCode<1)
+	  throw std::runtime_error("Sibyll target outside range. Only nuclei with A<18 or protons are allowed.");
+	
         /*
          get transformation between Stack-frame and SibStack-frame
          for EAS Stack-frame is lab. frame, could be different for CRMC-mode
@@ -246,7 +303,7 @@ namespace corsika::process::sibyll {
 	cout << "Interaction: new boost: ebeam com: " << eProjectileCoM / 1_GeV << endl
 	     << "Interaction: new boost: pbeam com: " << pProjectileCoM / 1_GeV << endl;
 	
-        int kBeam = process::sibyll::ConvertToSibyllRaw(p.GetPID());
+        const int kBeam = process::sibyll::ConvertToSibyllRaw(corsikaBeamId);
 
         std::cout << "Interaction: "
                   << " DoInteraction: E(GeV):" << E / 1_GeV
@@ -260,7 +317,7 @@ namespace corsika::process::sibyll {
           // Sibyll does not know about units..
           const double sqs = Ecm / 1_GeV;
           // running sibyll, filling stack
-          sibyll_(kBeam, kTarget, sqs);
+          sibyll_(kBeam, targetSibCode, sqs);
           // running decays
           // setTrackedParticlesStable();
           decsib_();
@@ -334,6 +391,10 @@ namespace corsika::process::sibyll {
       }
       return process::EProcessReturn::eOk;
     }
+    
+  private:
+    corsika::environment::Environment const& fEnvironment;
+
   };
 
 } // namespace corsika::process::sibyll
diff --git a/Processes/Sibyll/testSibyll.cc b/Processes/Sibyll/testSibyll.cc
index 3d7d425d9c63aaacf5ffcef5723dfac730283b7e..eb3259e792aa86899f6569b7a1247dce8acd4cf6 100644
--- a/Processes/Sibyll/testSibyll.cc
+++ b/Processes/Sibyll/testSibyll.cc
@@ -74,25 +74,48 @@ TEST_CASE("Sibyll", "[processes]") {
 #include <corsika/setup/SetupTrajectory.h>
 #include <corsika/particles/ParticleProperties.h>
 
+#include <corsika/environment/Environment.h>
+#include <corsika/environment/HomogeneousMedium.h>
+#include <corsika/environment/NuclearComposition.h>
+
 using namespace corsika::units::si;
 using namespace corsika::units;
 
 TEST_CASE("SibyllInterface", "[processes]") {
 
-  auto const& cs =
-      geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
+    // setup environment, geometry
+  corsika::environment::Environment env;
+  auto& universe = *(env.GetUniverse());
+
+  auto theMedium = corsika::environment::Environment::CreateNode<geometry::Sphere>(
+									 geometry::Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m},
+      1_km * std::numeric_limits<double>::infinity());
+
+  using MyHomogeneousModel =
+      corsika::environment::HomogeneousMedium<corsika::environment::IMediumModel>;
+  theMedium->SetModelProperties<MyHomogeneousModel>(
+      1_kg / (1_m * 1_m * 1_m),
+      corsika::environment::NuclearComposition(
+          std::vector<corsika::particles::Code>{corsika::particles::Code::Oxygen},
+          std::vector<float>{1.}));
+
+  universe.AddChild(std::move(theMedium));
+
+  const geometry::CoordinateSystem& cs = env.GetCoordinateSystem();
+
   geometry::Point const origin(cs, {0_m, 0_m, 0_m});
   geometry::Vector<corsika::units::si::SpeedType::dimension_type> v(
       cs, 0_m / second, 0_m / second, 1_m / second);
   geometry::Line line(origin, v);
   geometry::Trajectory<geometry::Line> track(line, 10_s);
 
+  
   SECTION("InteractionInterface") {
 
     setup::Stack stack;
     auto particle = stack.NewParticle();
     
-    Interaction model;
+    Interaction model(env);
     
     model.Init();
     [[maybe_unused]] const process::EProcessReturn ret =