diff --git a/Documentation/Examples/boundary_example.cc b/Documentation/Examples/boundary_example.cc
index 9bf4e188ae18a1e668e86c9e8294d52a1c9642b1..e0451e9474155c7d2fbe47b21bb1bcd6238fc988 100644
--- a/Documentation/Examples/boundary_example.cc
+++ b/Documentation/Examples/boundary_example.cc
@@ -45,7 +45,6 @@ using namespace corsika::process;
 using namespace corsika::units;
 using namespace corsika::particles;
 using namespace corsika::random;
-using namespace corsika::setup;
 using namespace corsika::geometry;
 using namespace corsika::environment;
 
@@ -95,7 +94,7 @@ int main() {
   random::RNGManager::GetInstance().RegisterRandomStream("cascade");
 
   // setup environment, geometry
-  using EnvType = Environment<setup::IEnvironmentModel>;
+  using EnvType = setup::Environment;
   EnvType env;
   auto& universe = *(env.GetUniverse());
 
diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc
index b8551c87ac0e730014c65439825252b6c527866f..628109f9387278ccac6c12278c879095f5fc76f5 100644
--- a/Documentation/Examples/cascade_example.cc
+++ b/Documentation/Examples/cascade_example.cc
@@ -72,25 +72,25 @@ int main() {
 
   const CoordinateSystem& rootCS = env.GetCoordinateSystem();
 
-  auto outerMedium = setup::EnvironmentType::CreateNode<Sphere>(
+  auto outerMedium = setup::Environment::CreateNode<Sphere>(
       Point{rootCS, 0_m, 0_m, 0_m}, 1_km * std::numeric_limits<double>::infinity());
 
+  using MyHomogeneousModel =
+      environment::UniformMediumType<environment::UniformMagneticField<
+          environment::HomogeneousMedium<setup::EnvironmentInterface>>>;
 
-  using EnvironmentModel = environment::UniformMediumType<environment::UniformMagneticField<environment::HomogeneousMedium<setup::IEnvironment>>>;
-  
   // fraction of oxygen
   const float fox = 0.20946;
-  auto const props =
-      outerMedium
-    ->SetModelProperties<EnvironmentModel>(environment::EMediumType::eAir,
-					   Vector(rootCS, 0_T, 0_T, 0_T),
-					   1_kg / (1_m * 1_m * 1_m),
-					   environment::NuclearComposition(
-									   std::vector<particles::Code>{particles::Code::Nitrogen,
-													  particles::Code::Oxygen},
-									   std::vector<float>{1.f - fox, fox}));
-
-  auto innerMedium = setup::Environment::CreateNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m}, 5000_m);
+  auto const props = outerMedium->SetModelProperties<MyHomogeneousModel>(
+      environment::EMediumType::eAir, Vector(rootCS, 0_T, 0_T, 0_T),
+      1_kg / (1_m * 1_m * 1_m),
+      environment::NuclearComposition(
+          std::vector<particles::Code>{particles::Code::Nitrogen,
+                                       particles::Code::Oxygen},
+          std::vector<float>{1.f - fox, fox}));
+
+  auto innerMedium =
+      setup::Environment::CreateNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m}, 5000_m);
 
   innerMedium->SetModelProperties(props);
 
diff --git a/Documentation/Examples/cascade_proton_example.cc b/Documentation/Examples/cascade_proton_example.cc
index 4ca053f377d67d2aa597b8e377575c4f960cd305..51433db112959775fc222e5960826d4af6fbc50d 100644
--- a/Documentation/Examples/cascade_proton_example.cc
+++ b/Documentation/Examples/cascade_proton_example.cc
@@ -49,7 +49,6 @@ using namespace corsika::process;
 using namespace corsika::units;
 using namespace corsika::particles;
 using namespace corsika::random;
-using namespace corsika::setup;
 using namespace corsika::geometry;
 using namespace corsika::environment;
 
@@ -70,24 +69,27 @@ int main() {
   random::RNGManager::GetInstance().RegisterRandomStream("cascade");
 
   // setup environment, geometry
-  using EnvType = Environment<setup::IEnvironmentModel>;
+  using EnvType = setup::Environment;
   EnvType env;
   auto& universe = *(env.GetUniverse());
+  const CoordinateSystem& rootCS = env.GetCoordinateSystem();
 
   auto theMedium =
-      EnvType::CreateNode<Sphere>(Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m},
+      EnvType::CreateNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m},
                                   1_km * std::numeric_limits<double>::infinity());
 
-  using MyHomogeneousModel = HomogeneousMedium<IMediumModel>;
+  using MyHomogeneousModel =
+      environment::UniformMediumType<environment::UniformMagneticField<
+          environment::HomogeneousMedium<setup::EnvironmentInterface>>>;
+  
   theMedium->SetModelProperties<MyHomogeneousModel>(
+      environment::EMediumType::eAir, geometry::Vector(rootCS, 0_T, 0_T, 1_T),
       1_kg / (1_m * 1_m * 1_m),
       NuclearComposition(std::vector<particles::Code>{particles::Code::Hydrogen},
                          std::vector<float>{(float)1.}));
 
   universe.AddChild(std::move(theMedium));
 
-  const CoordinateSystem& rootCS = env.GetCoordinateSystem();
-
   // setup particle stack, and add primary particle
   setup::Stack stack;
   stack.Clear();
diff --git a/Documentation/Examples/em_shower.cc b/Documentation/Examples/em_shower.cc
index c41d4574755db08489665f1bfde06fcded43d4c0..05863e5431c44100e84c7fa2b764a4811adb3b6b 100644
--- a/Documentation/Examples/em_shower.cc
+++ b/Documentation/Examples/em_shower.cc
@@ -42,7 +42,6 @@ using namespace corsika::process;
 using namespace corsika::units;
 using namespace corsika::particles;
 using namespace corsika::random;
-using namespace corsika::setup;
 using namespace corsika::geometry;
 using namespace corsika::environment;
 
@@ -55,6 +54,9 @@ void registerRandomStreams() {
   random::RNGManager::GetInstance().SeedAll();
 }
 
+template <typename T>
+using MEnv = environment::UniformMediumType<environment::UniformMagneticField<T>>;
+
 int main(int argc, char** argv) {
 
   logging::SetLevel(logging::level::info);
@@ -68,20 +70,30 @@ int main(int argc, char** argv) {
   registerRandomStreams();
 
   // setup environment, geometry
-  using EnvType = Environment<setup::IEnvironmentModel>;
+  using EnvType = setup::Environment;
   EnvType env;
   const CoordinateSystem& rootCS = env.GetCoordinateSystem();
   Point const center{rootCS, 0_m, 0_m, 0_m};
-  environment::LayeredSphericalAtmosphereBuilder builder{center};
+  environment::LayeredSphericalAtmosphereBuilder<setup::EnvironmentInterface> builder{
+      center};
   builder.setNuclearComposition(
       {{particles::Code::Nitrogen, particles::Code::Oxygen},
        {0.7847f, 1.f - 0.7847f}}); // values taken from AIRES manual, Ar removed for now
 
-  builder.addExponentialLayer(1222.6562_g / (1_cm * 1_cm), 994186.38_cm, 4_km);
-  builder.addExponentialLayer(1144.9069_g / (1_cm * 1_cm), 878153.55_cm, 10_km);
-  builder.addExponentialLayer(1305.5948_g / (1_cm * 1_cm), 636143.04_cm, 40_km);
-  builder.addExponentialLayer(540.1778_g / (1_cm * 1_cm), 772170.16_cm, 100_km);
-  builder.addLinearLayer(1e9_cm, 112.8_km);
+  builder.addExponentialLayer<MEnv>(1222.6562_g / (1_cm * 1_cm), 994186.38_cm, 4_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(1144.9069_g / (1_cm * 1_cm), 878153.55_cm, 10_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(1305.5948_g / (1_cm * 1_cm), 636143.04_cm, 40_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(540.1778_g / (1_cm * 1_cm), 772170.16_cm, 100_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addLinearLayer<MEnv>(1e9_cm, 112.8_km, environment::EMediumType::eAir,
+                               geometry::Vector(rootCS, 0_T, 0_T, 1_T));
 
   builder.assemble(env);
 
diff --git a/Documentation/Examples/vertical_EAS.cc b/Documentation/Examples/vertical_EAS.cc
index 14eeea8b94560f4f7233c8d385606702fd5e6294..6c602705bf54eeccceb0f736e0783c7ac2ab211c 100644
--- a/Documentation/Examples/vertical_EAS.cc
+++ b/Documentation/Examples/vertical_EAS.cc
@@ -53,7 +53,6 @@ using namespace corsika::process;
 using namespace corsika::units;
 using namespace corsika::particles;
 using namespace corsika::random;
-using namespace corsika::setup;
 using namespace corsika::geometry;
 using namespace corsika::environment;
 
@@ -76,6 +75,10 @@ void registerRandomStreams(const int seed) {
     random::RNGManager::GetInstance().SeedAll(seed);
 }
 
+template <typename T>
+using MEnv = environment::UniformMediumType<environment::UniformMagneticField<T>>;
+
+
 int main(int argc, char** argv) {
 
   logging::SetLevel(logging::level::info);
@@ -95,20 +98,29 @@ int main(int argc, char** argv) {
   registerRandomStreams(seed);
 
   // setup environment, geometry
-  using EnvType = Environment<setup::IEnvironmentModel>;
+  using EnvType = setup::Environment;
   EnvType env;
   const CoordinateSystem& rootCS = env.GetCoordinateSystem();
   Point const center{rootCS, 0_m, 0_m, 0_m};
-  environment::LayeredSphericalAtmosphereBuilder builder{center};
+  environment::LayeredSphericalAtmosphereBuilder<setup::EnvironmentInterface> builder{center};
   builder.setNuclearComposition(
       {{particles::Code::Nitrogen, particles::Code::Oxygen},
        {0.7847f, 1.f - 0.7847f}}); // values taken from AIRES manual, Ar removed for now
 
-  builder.addExponentialLayer(1222.6562_g / (1_cm * 1_cm), 994186.38_cm, 4_km);
-  builder.addExponentialLayer(1144.9069_g / (1_cm * 1_cm), 878153.55_cm, 10_km);
-  builder.addExponentialLayer(1305.5948_g / (1_cm * 1_cm), 636143.04_cm, 40_km);
-  builder.addExponentialLayer(540.1778_g / (1_cm * 1_cm), 772170.16_cm, 100_km);
-  builder.addLinearLayer(1e9_cm, 112.8_km);
+  builder.addExponentialLayer<MEnv>(1222.6562_g / (1_cm * 1_cm), 994186.38_cm, 4_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(1144.9069_g / (1_cm * 1_cm), 878153.55_cm, 10_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(1305.5948_g / (1_cm * 1_cm), 636143.04_cm, 40_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(540.1778_g / (1_cm * 1_cm), 772170.16_cm, 100_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addLinearLayer<MEnv>(1e9_cm, 112.8_km, environment::EMediumType::eAir,
+                               geometry::Vector(rootCS, 0_T, 0_T, 1_T));
 
   builder.assemble(env);
 
diff --git a/Processes/CONEXSourceCut/testCONEXSourceCut.cc b/Processes/CONEXSourceCut/testCONEXSourceCut.cc
index f70d54789319c8546d5bacd6da6b5e315c85e862..30831eed61e3e1f2e4168903a953366cf6dda674 100644
--- a/Processes/CONEXSourceCut/testCONEXSourceCut.cc
+++ b/Processes/CONEXSourceCut/testCONEXSourceCut.cc
@@ -10,8 +10,8 @@
 
 #include <corsika/environment/Environment.h>
 #include <corsika/environment/LayeredSphericalAtmosphereBuilder.h>
-#include <corsika/environment/UniformMediumType.h>
 #include <corsika/environment/UniformMagneticField.h>
+#include <corsika/environment/UniformMediumType.h>
 
 #include <corsika/geometry/Point.h>
 #include <corsika/geometry/RootCoordinateSystem.h>
@@ -35,6 +35,9 @@ using namespace corsika::environment;
 using namespace corsika::geometry;
 using namespace corsika::units::si;
 
+template <typename T>
+using MEnv = environment::UniformMediumType<environment::UniformMagneticField<T>>;
+
 TEST_CASE("CONEXSourceCut") {
   random::RNGManager::GetInstance().RegisterRandomStream("cascade");
   random::RNGManager::GetInstance().RegisterRandomStream("sibyll");
@@ -43,22 +46,30 @@ TEST_CASE("CONEXSourceCut") {
 
   // setup environment, geometry
   setup::Environment env;
-  auto& universe = *(env.GetUniverse());
-  using EnvironmentModel = environment::UniformMediumType<environment::UniformMagneticField<environment::InhomogeneousMedium<setup::IEnvironment>>>;
-
   const CoordinateSystem& rootCS = env.GetCoordinateSystem();
   Point const center{rootCS, 0_m, 0_m, 0_m};
-  environment::LayeredSphericalAtmosphereBuilder builder{center, conex::earthRadius};
-  
+
+  environment::LayeredSphericalAtmosphereBuilder<setup::EnvironmentInterface> builder{
+      center, conex::earthRadius};
+
   builder.setNuclearComposition(
       {{particles::Code::Nitrogen, particles::Code::Oxygen},
        {0.7847f, 1.f - 0.7847f}}); // values taken from AIRES manual, Ar removed for now
 
-  builder.addExponentialLayer(1222.6562_g / (1_cm * 1_cm), 994186.38_cm, 4_km);
-  builder.addExponentialLayer(1144.9069_g / (1_cm * 1_cm), 878153.55_cm, 10_km);
-  builder.addExponentialLayer(1305.5948_g / (1_cm * 1_cm), 636143.04_cm, 40_km);
-  builder.addExponentialLayer(540.1778_g / (1_cm * 1_cm), 772170.16_cm, 100_km);
-  builder.addLinearLayer(1e9_cm, 112.8_km);
+  builder.addExponentialLayer<MEnv>(1222.6562_g / (1_cm * 1_cm), 994186.38_cm, 4_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(1144.9069_g / (1_cm * 1_cm), 878153.55_cm, 10_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(1305.5948_g / (1_cm * 1_cm), 636143.04_cm, 40_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addExponentialLayer<MEnv>(540.1778_g / (1_cm * 1_cm), 772170.16_cm, 100_km,
+                                    environment::EMediumType::eAir,
+                                    geometry::Vector(rootCS, 0_T, 0_T, 1_T));
+  builder.addLinearLayer<MEnv>(1e9_cm, 112.8_km, environment::EMediumType::eAir,
+                               geometry::Vector(rootCS, 0_T, 0_T, 1_T));
 
   builder.assemble(env);
 
diff --git a/Processes/InteractionCounter/testInteractionCounter.cc b/Processes/InteractionCounter/testInteractionCounter.cc
index af43fe63eae05e941998fef7e180a47ca020e032..f8ded748cc33570c4b63284753cf7ebb71cda969 100644
--- a/Processes/InteractionCounter/testInteractionCounter.cc
+++ b/Processes/InteractionCounter/testInteractionCounter.cc
@@ -27,69 +27,6 @@ using namespace corsika::process::interaction_counter;
 using namespace corsika::units;
 using namespace corsika::units::si;
 
-auto setupEnvironment(particles::Code target_code) {
-  // setup environment, geometry
-  auto env = std::make_unique<environment::Environment<environment::IMediumModel>>();
-  auto& universe = *(env->GetUniverse());
-  const geometry::CoordinateSystem& cs = env->GetCoordinateSystem();
-
-  auto theMedium =
-      environment::Environment<environment::IMediumModel>::CreateNode<geometry::Sphere>(
-          geometry::Point{cs, 0_m, 0_m, 0_m},
-          1_km * std::numeric_limits<double>::infinity());
-
-  using MyHomogeneousModel = environment::HomogeneousMedium<environment::IMediumModel>;
-  theMedium->SetModelProperties<MyHomogeneousModel>(
-      1_kg / (1_m * 1_m * 1_m),
-      environment::NuclearComposition(std::vector<particles::Code>{target_code},
-                                      std::vector<float>{1.}));
-
-  auto const* nodePtr = theMedium.get();
-  universe.AddChild(std::move(theMedium));
-
-  return std::make_tuple(std::move(env), &cs, nodePtr);
-}
-
-template <typename TNodeType>
-auto setupStack(int vA, int vZ, HEPEnergyType vMomentum, TNodeType* vNodePtr,
-                geometry::CoordinateSystem const& cs) {
-  auto stack = std::make_unique<setup::Stack>();
-  auto constexpr mN = corsika::units::constants::nucleonMass;
-
-  geometry::Point const origin(cs, {0_m, 0_m, 0_m});
-  corsika::stack::MomentumVector const pLab(cs, {vMomentum, 0_GeV, 0_GeV});
-
-  HEPEnergyType const E0 = sqrt(units::static_pow<2>(mN * vA) + pLab.squaredNorm());
-  setup::Stack::StackIterator particle =
-      stack->AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
-                                    corsika::stack::MomentumVector, geometry::Point,
-                                    units::si::TimeType, unsigned short, unsigned short>{
-          particles::Code::Nucleus, E0, pLab, origin, 0_ns, vA, vZ});
-
-  particle.SetNode(vNodePtr);
-  return std::make_tuple(
-      std::move(stack), std::make_unique<decltype(setup::StackView(particle))>(particle));
-}
-
-template <typename TNodeType>
-auto setupStack(particles::Code vProjectileType, HEPEnergyType vMomentum,
-                TNodeType* vNodePtr, geometry::CoordinateSystem const& cs) {
-  auto stack = std::make_unique<setup::Stack>();
-
-  geometry::Point const origin(cs, {0_m, 0_m, 0_m});
-  corsika::stack::MomentumVector const pLab(cs, {vMomentum, 0_GeV, 0_GeV});
-
-  HEPEnergyType const E0 = sqrt(
-      units::static_pow<2>(particles::GetMass(vProjectileType)) + pLab.squaredNorm());
-  auto particle = stack->AddParticle(
-      std::tuple<particles::Code, units::si::HEPEnergyType,
-                 corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{
-          vProjectileType, E0, pLab, origin, 0_ns});
-
-  particle.SetNode(vNodePtr);
-  return std::make_tuple(
-      std::move(stack), std::make_unique<decltype(setup::StackView(particle))>(particle));
-}
 
 struct DummyProcess {
   template <typename TParticle>
@@ -114,12 +51,12 @@ TEST_CASE("InteractionCounter") {
     REQUIRE(countedProcess.GetInteractionLength(nullptr) == 100_g / 1_cm / 1_cm);
   }
 
-  auto [env, csPtr, nodePtr] = setupEnvironment(particles::Code::Oxygen);
+  auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Oxygen);
   [[maybe_unused]] auto& env_dummy = env;
 
   SECTION("DoInteraction nucleus") {
     unsigned short constexpr A = 14, Z = 7;
-    auto [stackPtr, secViewPtr] = setupStack(A, Z, 105_TeV, nodePtr, *csPtr);
+    auto [stackPtr, secViewPtr] = setup::testing::setupStack(particles::Code::Nucleus, A, Z, 105_TeV, nodePtr, *csPtr);
     REQUIRE(stackPtr->getEntries() == 1);
     REQUIRE(secViewPtr->getEntries() == 0);
 
@@ -139,7 +76,7 @@ TEST_CASE("InteractionCounter") {
   SECTION("DoInteraction Lambda") {
     auto constexpr code = particles::Code::Lambda0;
     auto constexpr codeInt = static_cast<particles::CodeIntType>(code);
-    auto [stackPtr, secViewPtr] = setupStack(code, 105_TeV, nodePtr, *csPtr);
+    auto [stackPtr, secViewPtr] = setup::testing::setupStack(code, 0,0, 105_TeV, nodePtr, *csPtr);
     REQUIRE(stackPtr->getEntries() == 1);
     REQUIRE(secViewPtr->getEntries() == 0);
 
diff --git a/Processes/OnShellCheck/testOnShellCheck.cc b/Processes/OnShellCheck/testOnShellCheck.cc
index 0d45b1e2946d814d47039d11f74249ace3282526..77c64e178da2726fabcd7c3792af60d270417c25 100644
--- a/Processes/OnShellCheck/testOnShellCheck.cc
+++ b/Processes/OnShellCheck/testOnShellCheck.cc
@@ -27,7 +27,7 @@ using namespace corsika::units::si;
 
 TEST_CASE("OnShellCheck", "[processes]") {
   feenableexcept(FE_INVALID);
-  using EnvType = environment::Environment<setup::IEnvironmentModel>;
+  using EnvType = setup::Environment;
   EnvType env;
   const geometry::CoordinateSystem& rootCS = env.GetCoordinateSystem();
 
diff --git a/Processes/ParticleCut/testParticleCut.cc b/Processes/ParticleCut/testParticleCut.cc
index 921eecc3ea2e59095f276bb03d7faec4ab43174a..adb0cef9fc0bb2af98d3de445bf17d35374795ce 100644
--- a/Processes/ParticleCut/testParticleCut.cc
+++ b/Processes/ParticleCut/testParticleCut.cc
@@ -26,7 +26,8 @@ using namespace corsika::units::si;
 
 TEST_CASE("ParticleCut", "[processes]") {
   feenableexcept(FE_INVALID);
-  using EnvType = environment::Environment<setup::IEnvironmentModel>;
+  using EnvType = setup::Environment;
+
   EnvType env;
   const geometry::CoordinateSystem& rootCS = env.GetCoordinateSystem();
 
diff --git a/Processes/Proposal/ContinuousProcess.cc b/Processes/Proposal/ContinuousProcess.cc
index 371f28262bd3b7a5e5f67fc2d2415c221cd43ffc..5d758be3b3033aad638928e72806a9b6c3ee97b4 100644
--- a/Processes/Proposal/ContinuousProcess.cc
+++ b/Processes/Proposal/ContinuousProcess.cc
@@ -44,7 +44,7 @@ namespace corsika::process::proposal {
   }
 
   template <>
-  ContinuousProcess::ContinuousProcess(setup::SetupEnvironment const& _env,
+  ContinuousProcess::ContinuousProcess(setup::Environment const& _env,
                                        corsika::units::si::HEPEnergyType _emCut)
       : ProposalProcessBase(_env, _emCut) {}
 
diff --git a/Processes/Proposal/Interaction.cc b/Processes/Proposal/Interaction.cc
index b2417b4260baec292ed779dbc912de9b1a5bd11e..f5ce68a800d56a2f855a46670638400b96fbffe5 100644
--- a/Processes/Proposal/Interaction.cc
+++ b/Processes/Proposal/Interaction.cc
@@ -22,7 +22,7 @@
 namespace corsika::process::proposal {
 
   template <>
-  Interaction::Interaction(setup::SetupEnvironment const& _env,
+  Interaction::Interaction(setup::Environment const& _env,
                            corsika::units::si::HEPEnergyType _emCut)
       : ProposalProcessBase(_env, _emCut) {}
 
diff --git a/Processes/Proposal/ProposalProcessBase.cc b/Processes/Proposal/ProposalProcessBase.cc
index 240c59d77f9977233e67e4017002407dfd3c2b52..66a749befab6a10785d365daae72a1fd3433214c 100644
--- a/Processes/Proposal/ProposalProcessBase.cc
+++ b/Processes/Proposal/ProposalProcessBase.cc
@@ -26,7 +26,7 @@ namespace corsika::process::proposal {
     return false;
   }
 
-  ProposalProcessBase::ProposalProcessBase(setup::SetupEnvironment const& _env,
+  ProposalProcessBase::ProposalProcessBase(setup::Environment const& _env,
                                            corsika::units::si::HEPEnergyType _emCut)
       : emCut_(_emCut)
       , fRNG(corsika::random::RNGManager::GetInstance().GetRandomStream("proposal")) {
diff --git a/Processes/Proposal/ProposalProcessBase.h b/Processes/Proposal/ProposalProcessBase.h
index 17c6b22d6c2142ca6ddd3b136ca47b71429dc6aa..6346721e77428db40666ad1765c0fd9052cb549d 100644
--- a/Processes/Proposal/ProposalProcessBase.h
+++ b/Processes/Proposal/ProposalProcessBase.h
@@ -89,7 +89,7 @@ namespace corsika::process::proposal {
     //! Store cut and  nuclear composition of the whole universe in media which are
     //! required for creating crosssections by proposal.
     //!
-    ProposalProcessBase(corsika::setup::SetupEnvironment const& _env,
+    ProposalProcessBase(corsika::setup::Environment const& _env,
                         corsika::units::si::HEPEnergyType _emCut);
 
     //!
diff --git a/Processes/Pythia/testPythia8.cc b/Processes/Pythia/testPythia8.cc
index a0af2a46a138e92c7d14032acb17400f5ebf8ca6..0019fdf0b1b5afe04d892ccff5b76ea93a00feaa 100644
--- a/Processes/Pythia/testPythia8.cc
+++ b/Processes/Pythia/testPythia8.cc
@@ -101,15 +101,19 @@ auto sumMomentum(TStackView const& view, geometry::CoordinateSystem const& vCS)
 
 TEST_CASE("pythia process") {
 
-  auto [env, csPtr, nodePtr] = testing::setupEnvironment(particles::Code::Oxygen);
+  auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Oxygen);
   auto const& cs = *csPtr;
   [[maybe_unused]] auto const& env_dummy = env;
   [[maybe_unused]] auto const& node_dummy = nodePtr;
   
   SECTION("pythia decay") {
     feenableexcept(FE_INVALID);
-    auto [stackPtr, secViewPtr] = testing::setupStack(code::PiPlus, 0, 0, 10_GeV, nodePtr, *csPtr);
-    auto projectile = secViewPtr->GetProjectile();
+    const HEPEnergyType P0 = 10_GeV;
+    auto [stackPtr, secViewPtr] = setup::testing::setupStack(particles::Code::PiPlus, 0, 0, P0, nodePtr, *csPtr);
+    const auto plab = corsika::stack::MomentumVector(cs, {P0, 0_eV, 0_eV}); // this is secret knowledge about setupStack
+    auto& stack = *stackPtr;
+    auto& view = *secViewPtr;
+    auto particle = stackPtr->first();
 
     random::RNGManager::GetInstance().RegisterRandomStream("pythia");
 
@@ -150,8 +154,9 @@ TEST_CASE("pythia process") {
   SECTION("pythia interaction") {
 
     feenableexcept(FE_INVALID);
-    auto [stackPtr, secViewPtr] = testing::setupStack(code::PiPlus, 0, 0, 100_GeV, nodePtr, *csPtr);
-    auto projectile = secViewPtr->GetProjectile();
+    auto [stackPtr, secViewPtr] = setup::testing::setupStack(particles::Code::PiPlus, 0, 0, 100_GeV, nodePtr, *csPtr);
+    auto& view = *secViewPtr;
+    auto particle = stackPtr->first();
 
     process::pythia::Interaction model;
 
diff --git a/Processes/QGSJetII/testQGSJetII.cc b/Processes/QGSJetII/testQGSJetII.cc
index 7f9af0675f759dce9b3b2a5293c062e45ca4503f..9a3fd1bc0d42d4226a900174732a0e3ba93cf3a3 100644
--- a/Processes/QGSJetII/testQGSJetII.cc
+++ b/Processes/QGSJetII/testQGSJetII.cc
@@ -122,10 +122,11 @@ TEST_CASE("QgsjetII", "[processes]") {
 
 using namespace corsika::units::si;
 using namespace corsika::units;
+using namespace corsika;
 
 TEST_CASE("QgsjetIIInterface", "[processes]") {
 
-  auto [env, csPtr, nodePtr] = testing::setupEnvironment(particles::Code::Oxygen);
+  auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Oxygen);
   auto const& cs = *csPtr;
   [[maybe_unused]] auto const& env_dummy = env;
   [[maybe_unused]] auto const& node_dummy = nodePtr;
@@ -135,13 +136,15 @@ TEST_CASE("QgsjetIIInterface", "[processes]") {
   SECTION("InteractionInterface") {
 
     auto [stackPtr, secViewPtr] =
-      testing::setupStack(particles::Code::Proton, 0,0, 110_GeV, nodePtr, *csPtr);
-    auto projectile = view.GetProjectile();
+      setup::testing::setupStack(particles::Code::Proton, 0,0, 110_GeV, nodePtr, *csPtr);
+    const auto& view = *secViewPtr;
+    auto particle = stackPtr->first();
+    auto projectile = secViewPtr->GetProjectile();
     auto const projectileMomentum = projectile.GetMomentum();
 
     Interaction model;
 
-    [[maybe_unused]] const process::EProcessReturn ret = model.DoInteraction(view);
+    [[maybe_unused]] const process::EProcessReturn ret = model.DoInteraction(*secViewPtr);
     [[maybe_unused]] const GrammageType length = model.GetInteractionLength(particle);
 
     CHECK(length / (1_g / square(1_cm)) == Approx(93.47).margin(0.1));
diff --git a/Processes/Sibyll/NuclearInteraction.cc b/Processes/Sibyll/NuclearInteraction.cc
index b87d02e5a9fb34d06524b6fa1a522bbac4c015a3..51d33a614c8b47b6bceca0c27129866e77a7680c 100644
--- a/Processes/Sibyll/NuclearInteraction.cc
+++ b/Processes/Sibyll/NuclearInteraction.cc
@@ -29,15 +29,14 @@ using std::tuple;
 using std::vector;
 
 using namespace corsika;
-using namespace corsika::setup;
 using Particle = corsika::setup::Stack::ParticleType; // StackIterator; // ParticleType;
 using View = corsika::setup::StackView;               // StackView::ParticleType;
-using Track = Trajectory;
+using Track = setup::Trajectory;
 
 namespace corsika::process::sibyll {
 
   template <>
-  NuclearInteraction<SetupEnvironment>::~NuclearInteraction() {
+  NuclearInteraction<setup::Environment>::~NuclearInteraction() {
     C8LOG_DEBUG(
         fmt::format("Nuclib::NuclearInteraction n={} Nnuc={}", count_, nucCount_));
   }
@@ -306,7 +305,7 @@ namespace corsika::process::sibyll {
 
   template <>
   template <>
-  process::EProcessReturn NuclearInteraction<SetupEnvironment>::DoInteraction(
+  process::EProcessReturn NuclearInteraction<setup::Environment>::DoInteraction(
       View& view) {
 
     // this routine superimposes different nucleon-nucleon interactions
diff --git a/Processes/Sibyll/testSibyll.cc b/Processes/Sibyll/testSibyll.cc
index ccdb4b651482f85fb1ef5b63f90f0c73c5eb731d..1a7722805cc075870991be20885fe38886bacb18 100644
--- a/Processes/Sibyll/testSibyll.cc
+++ b/Processes/Sibyll/testSibyll.cc
@@ -96,7 +96,7 @@ auto sumMomentum(TStackView const& view, geometry::CoordinateSystem const& vCS)
 
 TEST_CASE("SibyllInterface", "[processes]") {
 
-  auto [env, csPtr, nodePtr] = testing::setupEnvironment(particles::Code::Oxygen);
+  auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Oxygen);
   auto const& cs = *csPtr;
   [[maybe_unused]] auto const& env_dummy = env;
   [[maybe_unused]] auto const& node_dummy = nodePtr;
@@ -105,13 +105,16 @@ TEST_CASE("SibyllInterface", "[processes]") {
 
   SECTION("InteractionInterface - low energy") {
 
-    auto [stack, view] = testing::setupStack(particles::Code::Proton, 60_GeV, nodePtr, cs);
-    auto projectile = view.GetProjectile();
-
+    const HEPEnergyType P0 = 60_GeV;
+    auto [stack, view] = setup::testing::setupStack(particles::Code::Proton, 0,0, P0, nodePtr, cs);
+    const auto plab = corsika::stack::MomentumVector(cs, {P0, 0_eV, 0_eV}); // this is secret knowledge about setupStack
+    
+    auto particle = stack->first();
+    
     Interaction model;
 
-    [[maybe_unused]] const process::EProcessReturn ret = model.DoInteraction(view);
-    auto const pSum = sumMomentum(view, cs);
+    [[maybe_unused]] const process::EProcessReturn ret = model.DoInteraction(*view);
+    auto const pSum = sumMomentum(*view, cs);
 
     /*
       Interactions between hadrons (h) and nuclei (A) in Sibyll are treated in the
@@ -180,26 +183,27 @@ TEST_CASE("SibyllInterface", "[processes]") {
 
   SECTION("NuclearInteractionInterface") {
 
-    auto [stack, view] = testing::setupStack(particles::Code::Nucleus, 4, 2, 100_GeV, nodePtr, cs);
-    auto projectile = view.GetProjectile();
+    auto [stack, view] = setup::testing::setupStack(particles::Code::Nucleus, 4, 2, 100_GeV, nodePtr, cs);
+    auto particle = stack->first();
 
     Interaction hmodel;
-    NuclearInteraction model(hmodel, env);
+    NuclearInteraction model(hmodel, *env);
 
-    [[maybe_unused]] const process::EProcessReturn ret = model.DoInteraction(view);
+    [[maybe_unused]] const process::EProcessReturn ret = model.DoInteraction(*view);
     [[maybe_unused]] const GrammageType length = model.GetInteractionLength(particle);
   }
 
   SECTION("DecayInterface") {
 
-    auto [stack, view] = testing::setupStack(particles::Code::Lambda0, 0,0, 10_GeV, nodePtr, cs);
-    auto projectile = view.GetProjectile();
+    auto [stackPtr, view] = setup::testing::setupStack(particles::Code::Lambda0, 0,0, 10_GeV, nodePtr, cs);
+    auto& stack = *stackPtr; 
+    auto particle = stack.first();
 
     Decay model;
     model.PrintDecayConfig();
     [[maybe_unused]] const TimeType time = model.GetLifetime(particle);
 
-    /*[[maybe_unused]] const process::EProcessReturn ret =*/model.DoDecay(projectile);
+    /*[[maybe_unused]] const process::EProcessReturn ret =*/model.DoDecay(*view);
     // run checks
     // lambda decays into proton and pi- or neutron and pi+
     CHECK(stack.getEntries() == 3);
diff --git a/Processes/StackInspector/testStackInspector.cc b/Processes/StackInspector/testStackInspector.cc
index d76d9fd09b0bd57b37f81daa3f57106eea151910..9814efa02b7f9848eadb24cca7b0b508ac60a763 100644
--- a/Processes/StackInspector/testStackInspector.cc
+++ b/Processes/StackInspector/testStackInspector.cc
@@ -37,11 +37,9 @@ TEST_CASE("StackInspector", "[processes]") {
   stack.Clear();
   HEPEnergyType E0 = 100_GeV;
   stack.AddParticle(
-      std::tuple<particles::Code, units::si::HEPEnergyType,
-                 corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{
-          particles::Code::Electron, E0,
-          corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, -1_GeV}),
-          Point(rootCS, {0_m, 0_m, 10_km}), 0_ns});
+      std::make_tuple(particles::Code::Electron, E0,
+                      corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, -1_GeV}),
+                      Point(rootCS, {0_m, 0_m, 10_km}), 0_ns));
 
   SECTION("interface") {
 
diff --git a/Processes/UrQMD/testUrQMD.cc b/Processes/UrQMD/testUrQMD.cc
index 7bd929e3ec8c9177cb36af276fc9f4aaac5509f2..85616887e59305adab7284374973fd096e1aa4ce 100644
--- a/Processes/UrQMD/testUrQMD.cc
+++ b/Processes/UrQMD/testUrQMD.cc
@@ -67,7 +67,7 @@ TEST_CASE("UrQMD") {
   UrQMD urqmd;
 
   SECTION("interaction length") {
-    auto [env, csPtr, nodePtr] = testing::setupEnvironment(particles::Code::Nitrogen);
+    auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Nitrogen);
     auto const& cs = *csPtr;
     [[maybe_unused]] auto const& env_dummy = env;
     [[maybe_unused]] auto const& node_dummy = nodePtr;
@@ -78,7 +78,7 @@ TEST_CASE("UrQMD") {
         particles::Code::K0,      particles::Code::K0Bar,   particles::Code::K0Long};
 
     for (auto code : validProjectileCodes) {
-      auto [stack, view] = setupStack(code, 100_GeV, nodePtr, cs);
+      auto [stack, view] = setup::testing::setupStack(code, 0,0, 100_GeV, nodePtr, cs);
       REQUIRE(stack->getEntries() == 1);
       REQUIRE(view->getEntries() == 0);
 
@@ -89,12 +89,12 @@ TEST_CASE("UrQMD") {
   }
 
   SECTION("nucleus projectile") {
-    auto [env, csPtr, nodePtr] = testing::setupEnvironment(particles::Code::Oxygen);
+    auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Oxygen);
     [[maybe_unused]] auto const& env_dummy = env;      // against warnings
     [[maybe_unused]] auto const& node_dummy = nodePtr; // against warnings
 
     unsigned short constexpr A = 14, Z = 7;
-    auto [stackPtr, secViewPtr] = setupStack(code::Nucleus, A, Z, 400_GeV, nodePtr, *csPtr);
+    auto [stackPtr, secViewPtr] = setup::testing::setupStack(particles::Code::Nucleus, A, Z, 400_GeV, nodePtr, *csPtr);
     REQUIRE(stackPtr->getEntries() == 1);
     REQUIRE(secViewPtr->getEntries() == 0);
 
@@ -113,12 +113,12 @@ TEST_CASE("UrQMD") {
   }
 
   SECTION("\"special\" projectile") {
-    auto [env, csPtr, nodePtr] = testing::setupEnvironment(particles::Code::Oxygen);
+    auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Oxygen);
     [[maybe_unused]] auto const& env_dummy = env;      // against warnings
     [[maybe_unused]] auto const& node_dummy = nodePtr; // against warnings
 
     auto [stackPtr, secViewPtr] =
-      setupStack(particles::Code::PiPlus, 0,0, 400_GeV, nodePtr, *csPtr);
+      setup::testing::setupStack(particles::Code::PiPlus, 0,0, 400_GeV, nodePtr, *csPtr);
     REQUIRE(stackPtr->getEntries() == 1);
     REQUIRE(secViewPtr->getEntries() == 0);
 
@@ -139,12 +139,12 @@ TEST_CASE("UrQMD") {
   }
 
   SECTION("K0Long projectile") {
-    auto [env, csPtr, nodePtr] = testing::setupEnvironment(particles::Code::Oxygen);
+    auto [env, csPtr, nodePtr] = setup::testing::setupEnvironment(particles::Code::Oxygen);
     [[maybe_unused]] auto const& env_dummy = env;      // against warnings
     [[maybe_unused]] auto const& node_dummy = nodePtr; // against warnings
 
     auto [stackPtr, secViewPtr] =
-      setupStack(particles::Code::K0Long,0,0, 400_GeV, nodePtr, *csPtr);
+      setup::testing::setupStack(particles::Code::K0Long,0,0, 400_GeV, nodePtr, *csPtr);
     REQUIRE(stackPtr->getEntries() == 1);
     REQUIRE(secViewPtr->getEntries() == 0);
 
diff --git a/Setup/SetupEnvironment.h b/Setup/SetupEnvironment.h
index 3e141455db2e967d12af60ba4d911ee3e72a96dd..44b8ac261be7e799849b536dd506786a847e4bc8 100644
--- a/Setup/SetupEnvironment.h
+++ b/Setup/SetupEnvironment.h
@@ -39,7 +39,7 @@ namespace corsika::setup {
  */
 namespace corsika::setup::testing {
 
-  auto setupEnvironment(particles::Code vTargetCode) {
+  inline auto setupEnvironment(particles::Code vTargetCode) {
 
     using namespace corsika::units::si;
     using namespace corsika;
diff --git a/Setup/SetupStack.h b/Setup/SetupStack.h
index 91aa034179d2402e91bbdc429b6a711f347f9b1c..1431c5dd5cbe708f8aa3a43c8f9499f468800272 100644
--- a/Setup/SetupStack.h
+++ b/Setup/SetupStack.h
@@ -26,9 +26,8 @@ namespace corsika::setup {
     // the GeometryNode stack needs to know the type of geometry-nodes from the
     // environment:
     template <typename TStackIter>
-    using SetupGeometryDataInterface =
-        typename stack::node::MakeGeometryDataInterface<TStackIter,
-                                                        setup::SetupEnvironment>::type;
+    using SetupGeometryDataInterface = typename stack::node::MakeGeometryDataInterface<
+        TStackIter, corsika::setup::Environment>::type;
 
     // combine particle data stack with geometry information for tracking
     template <typename TStackIter>
@@ -38,7 +37,7 @@ namespace corsika::setup {
 
     using StackWithGeometry = corsika::stack::CombinedStack<
         typename corsika::stack::nuclear_extension::ParticleDataStack::StackImpl,
-        corsika::stack::node::GeometryData<setup::SetupEnvironment>,
+        corsika::stack::node::GeometryData<setup::Environment>,
         StackWithGeometryInterface>;
 
     // ------------------------------------------
@@ -132,16 +131,17 @@ namespace corsika::setup {
 
 } // namespace corsika::setup
 
-namespace corsika::setup::testing {
-
   /**
-   * standard setup for unit tests. This can be moved to "test"
+   * standard stack setup for unit tests. This can be moved to "test"
    * directory, when available.
    */
-  auto setupStack(particles::Code vProjectileType, int vA, int vZ,
-                  units::si::HEPEnergyType vMomentum,
-                  setup::Environment::BaseNodeType* vNodePtr,
-                  geometry::CoordinateSystem const& cs) {
+
+namespace corsika::setup::testing {
+
+  inline auto setupStack(particles::Code vProjectileType, int vA, int vZ,
+			 units::si::HEPEnergyType vMomentum,
+			 const setup::Environment::BaseNodeType* vNodePtr,
+			 geometry::CoordinateSystem const& cs) {
 
     using namespace corsika;
     using namespace corsika::units::si;