From 1d9929166a13cee41be2f2dc85d3e1b0047cd53a Mon Sep 17 00:00:00 2001
From: Maximilian Reininghaus <maximilian.reininghaus@tu-dortmund.de>
Date: Thu, 17 Mar 2022 23:33:45 +0100
Subject: [PATCH] setup::Stack with environment-type template

---
 corsika/detail/setup/SetupStack.hpp | 125 ++++++++++++++++------------
 corsika/setup/SetupStack.hpp        |   9 +-
 examples/em_shower.cpp              |   2 +-
 3 files changed, 77 insertions(+), 59 deletions(-)

diff --git a/corsika/detail/setup/SetupStack.hpp b/corsika/detail/setup/SetupStack.hpp
index 2b40ccbdb..bec6c0aa1 100644
--- a/corsika/detail/setup/SetupStack.hpp
+++ b/corsika/detail/setup/SetupStack.hpp
@@ -20,61 +20,76 @@
 namespace corsika {
 
   namespace setup::detail {
-
-    // ------------------------------------------
-    // add geometry node data to stack. This is fundamentally needed
-    // for robust tracking through multiple volumes.
-
-    // the GeometryNode stack needs to know the type of geometry-nodes from the
-    // environment:
-    template <typename TStackIter>
-    using SetupGeometryDataInterface =
-        typename node::MakeGeometryDataInterface<TStackIter, setup::Environment>::type;
-
-    // combine particle data stack with geometry information for tracking
-    template <typename TStackIter>
-    using StackWithGeometryInterface =
-        CombinedParticleInterface<VectorStack::pi_type, SetupGeometryDataInterface,
-                                  TStackIter>;
-
-    using StackWithGeometry =
-        CombinedStack<typename VectorStack::stack_data_type,
-                      node::GeometryData<setup::Environment>, StackWithGeometryInterface,
-                      DefaultSecondaryProducer>;
-
-    // ------------------------------------------
-    // add weight data to stack. This is fundamentally needed
-    // for thinning.
-
-    // the "pure" weight stack (interface)
-    template <typename TStackIter>
-    using SetupWeightDataInterface =
-        typename weights::MakeWeightDataInterface<TStackIter>::type;
-
-    // combine geometry-node-vector data stack with weight information for tracking
-    template <typename TStackIter>
-    using StackWithWeightInterface =
-        CombinedParticleInterface<StackWithGeometry::pi_type, SetupWeightDataInterface,
-                                  TStackIter>;
-
-    // the combined stack data: particle + geometry + weight
-    using StackWithWeight =
-        CombinedStack<typename StackWithGeometry::stack_data_type, weights::WeightData,
-                      StackWithWeightInterface, DefaultSecondaryProducer>;
-
-    // ------------------------------------------
-    // Add [OPTIONAL] history data to stack, too.
-    // This keeps the entire lineage of particles in memory.
-
-    template <typename TStackIter>
-    using StackWithHistoryInterface =
-        CombinedParticleInterface<StackWithWeight::pi_type,
-                                  history::HistoryEventDataInterface, TStackIter>;
-
-    using StackWithHistory =
-        CombinedStack<typename StackWithWeight::stack_data_type,
-                      history::HistoryEventData, StackWithHistoryInterface,
-                      history::HistorySecondaryProducer>;
+    template <typename TEnvironment = setup::Environment>
+    class StackGenerator {
+    private:
+      using env_type = TEnvironment;
+
+      // ------------------------------------------
+      // add geometry node data to stack. This is fundamentally needed
+      // for robust tracking through multiple volumes.
+
+      // the GeometryNode stack needs to know the type of geometry-nodes from the
+      // environment:
+
+      template <typename TStackIter>
+      using SetupGeometryDataInterface =
+          typename node::MakeGeometryDataInterface<TStackIter, env_type>::type;
+
+      // combine particle data stack with geometry information for tracking
+      template <typename TStackIter>
+      using StackWithGeometryInterface =
+          CombinedParticleInterface<VectorStack::pi_type, SetupGeometryDataInterface,
+                                    TStackIter>;
+
+      using StackWithGeometry =
+          CombinedStack<typename VectorStack::stack_data_type,
+                        node::GeometryData<env_type>, StackWithGeometryInterface,
+                        DefaultSecondaryProducer>;
+
+      template <class T>
+      using StackWithGeometry_PI_type = typename StackWithGeometry::template pi_type<T>;
+
+      // ------------------------------------------
+      // add weight data to stack. This is fundamentally needed
+      // for thinning.
+
+      // the "pure" weight stack (interface)
+      template <typename TStackIter>
+      using SetupWeightDataInterface =
+          typename weights::MakeWeightDataInterface<TStackIter>::type;
+
+      // combine geometry-node-vector data stack with weight information for tracking
+      template <typename TStackIter>
+      using StackWithWeightInterface =
+          CombinedParticleInterface<StackWithGeometry_PI_type, SetupWeightDataInterface,
+                                    TStackIter>;
+
+    public:
+      // the combined stack data: particle + geometry + weight
+      using StackWithWeight =
+          CombinedStack<typename StackWithGeometry::stack_data_type, weights::WeightData,
+                        StackWithWeightInterface, DefaultSecondaryProducer>;
+
+    private:
+      template <typename T>
+      using StackWithWeight_PI_type = typename StackWithWeight::template pi_type<T>;
+
+      // ------------------------------------------
+      // Add [OPTIONAL] history data to stack, too.
+      // This keeps the entire lineage of particles in memory.
+
+      template <typename TStackIter>
+      using StackWithHistoryInterface =
+          CombinedParticleInterface<StackWithWeight_PI_type,
+                                    history::HistoryEventDataInterface, TStackIter>;
+
+    public:
+      using StackWithHistory =
+          CombinedStack<typename StackWithWeight::stack_data_type,
+                        history::HistoryEventData, StackWithHistoryInterface,
+                        history::HistorySecondaryProducer>;
+    };
 
   } // namespace setup::detail
 
diff --git a/corsika/setup/SetupStack.hpp b/corsika/setup/SetupStack.hpp
index 9028c2ab1..7d1894e4c 100644
--- a/corsika/setup/SetupStack.hpp
+++ b/corsika/setup/SetupStack.hpp
@@ -24,18 +24,21 @@ namespace corsika::setup {
   /*
    * the version with history
    */
-  using Stack = detail::StackWithHistory;
+  template <typename TEnvironment>
+  using Stack = typename detail::StackGenerator<TEnvironment>::StackWithWeight;
 
 #else // WITH_HISTORY
 
   /*
    * the version without history (and geometry data and weights)
    */
-  using Stack = detail::StackWithWeight;
+  template <typename TEnvironment>
+  using Stack = typename detail::StackGenerator<TEnvironment>::StackWithWeight;
 
 #endif
 
   // the correct secondary stack view
-  using StackView = typename Stack::stack_view_type;
+  template <typename TEnvironment>
+  using StackView = typename Stack<TEnvironment>::stack_view_type;
 
 } // namespace corsika::setup
diff --git a/examples/em_shower.cpp b/examples/em_shower.cpp
index 615b840c1..fe67c6477 100644
--- a/examples/em_shower.cpp
+++ b/examples/em_shower.cpp
@@ -110,7 +110,7 @@ int main(int argc, char** argv) {
     set_energy_production_threshold(pcode, energy);
 
   // setup particle stack, and add primary particle
-  setup::Stack stack;
+  setup::Stack<EnvType> stack;
   stack.clear();
   const Code beamCode = Code::Electron;
   auto const mass = get_mass(beamCode);
-- 
GitLab