From 8c6ecc16ab8287a50dbb7ef10eac2521017daf13 Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Wed, 16 Sep 2020 15:11:08 +0200
Subject: [PATCH] various changes towards history stack

---
 Framework/Cascade/History.h                   |  8 +++
 Framework/Cascade/testCascade.h               |  2 +-
 Framework/StackInterface/SecondaryView.h      |  3 +-
 .../TrackingLine/testTrackingLineStack.h      |  2 +-
 Setup/SetupStack.h                            | 28 +++++---
 Stack/DummyStack/DummyStack.h                 | 27 ++++----
 Stack/DummyStack/testDummyStack.cc            | 11 ++--
 .../GeometryNodeStackExtension.h              | 11 ++--
 .../testGeometryNodeStackExtension.cc         | 50 +++++++-------
 Stack/History/CMakeLists.txt                  |  5 ++
 Stack/History/Event.hpp                       | 34 ++++++++++
 Stack/History/HStackView.hpp                  | 39 +++++++++++
 Stack/History/HistoryStackExtension.h         | 65 ++++++++++---------
 Stack/History/SecondaryParticle.hpp           | 38 +++++++++++
 Stack/History/testHistory.cc                  | 15 ++++-
 Stack/SuperStupidStack/SuperStupidStack.h     |  4 +-
 16 files changed, 242 insertions(+), 100 deletions(-)
 create mode 100644 Stack/History/Event.hpp
 create mode 100644 Stack/History/HStackView.hpp
 create mode 100644 Stack/History/SecondaryParticle.hpp

diff --git a/Framework/Cascade/History.h b/Framework/Cascade/History.h
index 235767cb9..530e5917a 100644
--- a/Framework/Cascade/History.h
+++ b/Framework/Cascade/History.h
@@ -1,3 +1,11 @@
+/*
+ * (c) Copyright 2020 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.
+ */
+
 #include <memory>
 #include <utility>
 #include <variant>
diff --git a/Framework/Cascade/testCascade.h b/Framework/Cascade/testCascade.h
index 286318452..b876107de 100644
--- a/Framework/Cascade/testCascade.h
+++ b/Framework/Cascade/testCascade.h
@@ -10,9 +10,9 @@
 
 #include <corsika/environment/Environment.h>
 
+#include <corsika/stack/CombinedStack.h>
 #include <corsika/stack/node/GeometryNodeStackExtension.h>
 #include <corsika/stack/nuclear_extension/NuclearStackExtension.h>
-#include <corsika/stack/CombinedStack.h>
 
 using TestEnvironmentType =
     corsika::environment::Environment<corsika::environment::IMediumModel>;
diff --git a/Framework/StackInterface/SecondaryView.h b/Framework/StackInterface/SecondaryView.h
index 077e56ea2..546ae571a 100644
--- a/Framework/StackInterface/SecondaryView.h
+++ b/Framework/StackInterface/SecondaryView.h
@@ -70,12 +70,13 @@ namespace corsika::stack {
      * @{
      */
     using InnerStackTypeValue = Stack<StackDataType, ParticleInterface>;
+
+  public:
     using StackIteratorValue =
         StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
                                ParticleInterface, InnerStackTypeValue>;
     /// @}
 
-  public:
     using StackIterator =
         StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
                                ParticleInterface, ViewType>;
diff --git a/Processes/TrackingLine/testTrackingLineStack.h b/Processes/TrackingLine/testTrackingLineStack.h
index 52955a816..d727064eb 100644
--- a/Processes/TrackingLine/testTrackingLineStack.h
+++ b/Processes/TrackingLine/testTrackingLineStack.h
@@ -15,9 +15,9 @@
 
 #include <corsika/particles/ParticleProperties.h>
 
+#include <corsika/stack/CombinedStack.h>
 #include <corsika/stack/node/GeometryNodeStackExtension.h>
 #include <corsika/stack/nuclear_extension/NuclearStackExtension.h>
-#include <corsika/stack/CombinedStack.h>
 
 #include <corsika/units/PhysicalUnits.h>
 
diff --git a/Setup/SetupStack.h b/Setup/SetupStack.h
index b4c99c339..aeef45dce 100644
--- a/Setup/SetupStack.h
+++ b/Setup/SetupStack.h
@@ -8,11 +8,10 @@
 
 #pragma once
 
+#include <corsika/stack/CombinedStack.h>
 #include <corsika/stack/node/GeometryNodeStackExtension.h>
 #include <corsika/stack/nuclear_extension/NuclearStackExtension.h>
-//#include <corsika/history/HistoryStackExtension.h>
-
-#include <corsika/stack/CombinedStack.h>
+#include <corsika/history/HistoryStackExtension.h>
 
 #include <corsika/setup/SetupEnvironment.h>
 
@@ -20,15 +19,26 @@ namespace corsika::setup {
 
   namespace detail {
 
-    // the GeometryNode stack needs to know the type of geometry-nodes from the environment:
+    // 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,
+                                                        setup::SetupEnvironment>::type;
+
+    /*
+    template <typename TStackIter>
+    using SetupGeometryHistoryDataInterface =
+      typename stack::node::MakeHistoryDataInterface<TStackIter,
+                                    ...event... >::type;
+    */
+
     
     // combine particle data stack with geometry information for tracking
     template <typename TStackIter>
     using StackWithGeometryInterface = corsika::stack::CombinedParticleInterface<
-        stack::nuclear_extension::ParticleDataStack::PIType,
-    SetupGeometryDataInterface, TStackIter>;
+        stack::nuclear_extension::ParticleDataStack::PIType, SetupGeometryDataInterface,
+        TStackIter>;
 
     using StackWithGeometry = corsika::stack::CombinedStack<
         typename corsika::stack::nuclear_extension::ParticleDataStack::StackImpl,
@@ -54,8 +64,8 @@ namespace corsika::setup {
 #if defined(__clang__)
   using StackView =
       corsika::stack::SecondaryView<typename corsika::setup::Stack::StackImpl,
-    // CHECK with CLANG: corsika::setup::Stack::PIType>;
-    corsika::setup::detail::StackWithGeometryInterface>;
+                                    // CHECK with CLANG: corsika::setup::Stack::PIType>;
+                                    corsika::setup::detail::StackWithGeometryInterface>;
 #elif defined(__GNUC__) || defined(__GNUG__)
   using StackView = corsika::stack::MakeView<corsika::setup::Stack>::type;
 #endif
diff --git a/Stack/DummyStack/DummyStack.h b/Stack/DummyStack/DummyStack.h
index 5f584b016..8427475ab 100644
--- a/Stack/DummyStack/DummyStack.h
+++ b/Stack/DummyStack/DummyStack.h
@@ -23,14 +23,18 @@ namespace corsika::stack {
      */
 
     /**
-       however, conceptually we need to provide fake data. A stack without data does not work...
+       however, conceptually we need to provide fake data. A stack without data does not
+       work...
      */
 
-    struct NoData {/* nothing */ int nothing=0; };
-    
+    struct NoData { /* nothing */
+      int nothing = 0;
+    };
+
     template <typename StackIteratorInterface>
-      class ParticleInterface : public corsika::stack::ParticleBase<StackIteratorInterface> {
-      
+    class ParticleInterface
+        : public corsika::stack::ParticleBase<StackIteratorInterface> {
+
     protected:
       using corsika::stack::ParticleBase<StackIteratorInterface>::GetStack;
       using corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData;
@@ -40,7 +44,8 @@ namespace corsika::stack {
 
     public:
       void SetParticleData(const std::tuple<NoData>& /*v*/) {}
-      void SetParticleData(ParticleInterface<StackIteratorInterface>& /*parent*/, const std::tuple<NoData>& /*v*/) {}
+      void SetParticleData(ParticleInterface<StackIteratorInterface>& /*parent*/,
+                           const std::tuple<NoData>& /*v*/) {}
     };
 
     /**
@@ -51,9 +56,9 @@ namespace corsika::stack {
     class DummyStackImpl {
 
     public:
-      void Init() {entries_=0;}
+      void Init() { entries_ = 0; }
 
-      void Clear() {entries_=0;}
+      void Clear() { entries_ = 0; }
 
       int GetSize() const { return entries_; }
       int GetCapacity() const { return entries_; }
@@ -63,12 +68,12 @@ namespace corsika::stack {
        */
       void Copy(const int /*i1*/, const int /*i2*/) {}
 
-      void IncrementSize() {entries_++;}
-      void DecrementSize() {entries_--;}
+      void IncrementSize() { entries_++; }
+      void DecrementSize() { entries_--; }
 
     private:
       int entries_ = 0;
-      
+
     }; // end class DummyStackImpl
 
     typedef Stack<DummyStackImpl, ParticleInterface> DummyStack;
diff --git a/Stack/DummyStack/testDummyStack.cc b/Stack/DummyStack/testDummyStack.cc
index 64195ef65..179527055 100644
--- a/Stack/DummyStack/testDummyStack.cc
+++ b/Stack/DummyStack/testDummyStack.cc
@@ -20,7 +20,7 @@ TEST_CASE("DummyStack", "[stack]") {
   using TestStack = dummy::DummyStack;
 
   dummy::NoData noData;
-    
+
   SECTION("write node") {
 
     TestStack s;
@@ -28,17 +28,14 @@ TEST_CASE("DummyStack", "[stack]") {
     REQUIRE(s.GetSize() == 1);
   }
 
-
   SECTION("stack fill and cleanup") {
 
     TestStack s;
     // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2!
-    for (int i = 0; i < 99; ++i) {
-      s.AddParticle(std::tuple<dummy::NoData>{noData});
-    }
-      
+    for (int i = 0; i < 99; ++i) { s.AddParticle(std::tuple<dummy::NoData>{noData}); }
+
     REQUIRE(s.GetSize() == 99);
     for (int i = 0; i < 99; ++i) s.GetNextParticle().Delete();
     REQUIRE(s.GetSize() == 0);
-  }  
+  }
 }
diff --git a/Stack/GeometryNodeStackExtension/GeometryNodeStackExtension.h b/Stack/GeometryNodeStackExtension/GeometryNodeStackExtension.h
index 16b9e02d6..d33997b8e 100644
--- a/Stack/GeometryNodeStackExtension/GeometryNodeStackExtension.h
+++ b/Stack/GeometryNodeStackExtension/GeometryNodeStackExtension.h
@@ -36,7 +36,7 @@ namespace corsika::stack::node {
     using T::GetIndex;
     using BaseNodeType = typename TEnvType::BaseNodeType;
 
-    public:
+  public:
     // default version for particle-creation from input data
     void SetParticleData(const std::tuple<BaseNodeType const*> v) {
       SetNode(std::get<0>(v));
@@ -56,8 +56,6 @@ namespace corsika::stack::node {
     BaseNodeType const* GetNode() const { return GetStackData().GetNode(GetIndex()); }
   };
 
-
-  
   // definition of stack-data object to store geometry information
   template <typename TEnvType>
 
@@ -93,10 +91,9 @@ namespace corsika::stack::node {
     std::vector<const BaseNodeType*> fNode;
   };
 
-
   template <typename T, typename TEnv>
-    struct MakeGeometryDataInterface {
-      typedef GeometryDataInterface<T, TEnv> type;
-    };
+  struct MakeGeometryDataInterface {
+    typedef GeometryDataInterface<T, TEnv> type;
+  };
 
 } // namespace corsika::stack::node
diff --git a/Stack/GeometryNodeStackExtension/testGeometryNodeStackExtension.cc b/Stack/GeometryNodeStackExtension/testGeometryNodeStackExtension.cc
index f637540b6..bad486425 100644
--- a/Stack/GeometryNodeStackExtension/testGeometryNodeStackExtension.cc
+++ b/Stack/GeometryNodeStackExtension/testGeometryNodeStackExtension.cc
@@ -6,9 +6,9 @@
  * the license.
  */
 
-#include <corsika/stack/node/GeometryNodeStackExtension.h>
-#include <corsika/stack/dummy/DummyStack.h>
 #include <corsika/stack/CombinedStack.h>
+#include <corsika/stack/dummy/DummyStack.h>
+#include <corsika/stack/node/GeometryNodeStackExtension.h>
 
 using namespace corsika;
 using namespace corsika::stack;
@@ -26,19 +26,19 @@ public:
 
 // the GeometryNode stack needs to know the type of geometry-nodes from the DummyEnv:
 template <typename TStackIter>
-using DummyGeometryDataInterface = typename corsika::stack::node::MakeGeometryDataInterface<TStackIter, DummyEnv>::type;
+using DummyGeometryDataInterface =
+    typename corsika::stack::node::MakeGeometryDataInterface<TStackIter, DummyEnv>::type;
 
 // combine dummy stack with geometry information for tracking
 template <typename TStackIter>
-using StackWithGeometryInterface = corsika::stack::CombinedParticleInterface<
-  dummy::DummyStack::PIType,
-    DummyGeometryDataInterface, TStackIter>;
-
-using TestStack = corsika::stack::CombinedStack<
-  typename stack::dummy::DummyStack::StackImpl,
-  stack::node::GeometryData<DummyEnv>,
-  StackWithGeometryInterface>;
+using StackWithGeometryInterface =
+    corsika::stack::CombinedParticleInterface<dummy::DummyStack::PIType,
+                                              DummyGeometryDataInterface, TStackIter>;
 
+using TestStack =
+    corsika::stack::CombinedStack<typename stack::dummy::DummyStack::StackImpl,
+                                  stack::node::GeometryData<DummyEnv>,
+                                  StackWithGeometryInterface>;
 
 TEST_CASE("GeometryNodeStackExtension", "[stack]") {
 
@@ -47,25 +47,21 @@ TEST_CASE("GeometryNodeStackExtension", "[stack]") {
   SECTION("write node") {
 
     const int data = 5;
-    
+
     TestStack s;
-    s.AddParticle(
-		  std::tuple<dummy::NoData>{
-		    noData}, std::tuple<const int*>{&data});
-    
+    s.AddParticle(std::tuple<dummy::NoData>{noData}, std::tuple<const int*>{&data});
+
     CHECK(s.GetSize() == 1);
   }
 
   SECTION("write/read node") {
     const int data = 15;
-    
+
     TestStack s;
-    auto p = s.AddParticle(
-			   std::tuple<dummy::NoData>{
-			     noData});
+    auto p = s.AddParticle(std::tuple<dummy::NoData>{noData});
     p.SetNode(&data);
     CHECK(s.GetSize() == 1);
-    
+
     const auto pout = s.GetNextParticle();
     CHECK(*(pout.GetNode()) == 15);
   }
@@ -77,12 +73,10 @@ TEST_CASE("GeometryNodeStackExtension", "[stack]") {
     TestStack s;
     // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2!
     for (int i = 0; i < 99; ++i) {
-      auto p = s.AddParticle(
-			     std::tuple<dummy::NoData>{
-			       noData});
+      auto p = s.AddParticle(std::tuple<dummy::NoData>{noData});
       p.SetNode(&data);
     }
-      
+
     CHECK(s.GetSize() == 99);
     double v = 0;
     for (int i = 0; i < 99; ++i) {
@@ -90,7 +84,7 @@ TEST_CASE("GeometryNodeStackExtension", "[stack]") {
       v += *(p.GetNode());
       p.Delete();
     }
-    CHECK(v == 99*data);    
-    CHECK(s.GetSize() == 0);    
-  }  
+    CHECK(v == 99 * data);
+    CHECK(s.GetSize() == 0);
+  }
 }
diff --git a/Stack/History/CMakeLists.txt b/Stack/History/CMakeLists.txt
index 5bf3be2b0..8b327411f 100644
--- a/Stack/History/CMakeLists.txt
+++ b/Stack/History/CMakeLists.txt
@@ -1,6 +1,9 @@
 set (
   SETUP_HEADERS
+  Event.hpp
+  HStackView.hpp
   HistoryStackExtension.h
+  SecondaryParticle.hpp
   )
 
 set (
@@ -14,6 +17,8 @@ CORSIKA_COPY_HEADERS_TO_NAMESPACE (CORSIKAhistory ${SETUP_NAMESPACE} ${SETUP_HEA
 target_link_libraries (
   CORSIKAhistory
   INTERFACE
+  CORSIKAparticles
+  CORSIKAgeometry
   SuperStupidStack
   NuclearStackExtension
   )
diff --git a/Stack/History/Event.hpp b/Stack/History/Event.hpp
new file mode 100644
index 000000000..82d949a7b
--- /dev/null
+++ b/Stack/History/Event.hpp
@@ -0,0 +1,34 @@
+/*
+ * (c) Copyright 2020 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/particles/ParticleProperties.h>
+#include <corsika/stack/Stack.h>
+#include <corsika/history/SecondaryParticle.hpp>
+
+#include <optional>
+#include <vector>
+
+namespace corsika::history {
+
+  template <typename TStackIterator>
+  class Event {
+    TStackIterator const projectile_; //!< reference to projectile
+    std::vector<SecondaryParticle> secondaries;
+
+    // meta information, could also be in a separate class
+    std::optional<corsika::particles::Code>
+        targetCode; // cannot be const, value set only after construction
+
+  public:
+    Event(TStackIterator projectile)
+        : projectile_{projectile} {}
+  };
+
+} // namespace corsika::history
diff --git a/Stack/History/HStackView.hpp b/Stack/History/HStackView.hpp
new file mode 100644
index 000000000..c5a7e1048
--- /dev/null
+++ b/Stack/History/HStackView.hpp
@@ -0,0 +1,39 @@
+/*
+ * (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/stack/history/Event.hpp>
+
+#include <memory>
+
+namespace corsika::history {
+
+  template <typename TStackView>
+  class HStackView : public TStackView {
+    std::shared_ptr<Event<typename TStackView::StackIteratorValue>> event_;
+
+  public:
+    template <typename... Args>
+    EventBuilder(Args&&... args)
+        : TStackView{std::forward<Args>(args)}
+        , event_{std::make_shared<Event>()} {}
+
+    template <typename... Args>
+    void AddSecondary(Args&&... args) {
+      auto const s = TStackView::AddSecondary(
+          std::forward<Args>(args), event_); // what if event is not last argument?
+      event_->secondaries.emplace_back(s.GetEnergy(), s.GetMomentum(), s.GetParticleID());
+    }
+
+    void SetTarget(corsika::particles::ParticleCode targetCode) {
+      event_->targetCode = targetCode;
+    }
+  };
+
+} // namespace corsika::history
diff --git a/Stack/History/HistoryStackExtension.h b/Stack/History/HistoryStackExtension.h
index cfd5515d6..d12632d9e 100644
--- a/Stack/History/HistoryStackExtension.h
+++ b/Stack/History/HistoryStackExtension.h
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2020 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
@@ -9,10 +9,11 @@
 #pragma once
 
 #include <corsika/stack/Stack.h>
+#include <corsika/history/Event.hpp>
 
+#include <memory>
 #include <tuple>
 #include <vector>
-#include <memory>
 
 namespace corsika::history {
 
@@ -28,26 +29,27 @@ namespace corsika::history {
 
   public:
     // these functions are needed for the Stack interface
-    void Clear() { fEvent.clear(); }
-    unsigned int GetSize() const { return fEvent.size(); }
-    unsigned int GetCapacity() const { return fEvent.size(); }
-    void Copy(const int i1, const int i2) { fEvent[i2] = fEvent[i1]; }
-    void Swap(const int i1, const int i2) { std::swap(fEvent[i1], fEvent[i2]); }
+    void Clear() { event_.clear(); }
+    unsigned int GetSize() const { return event_.size(); }
+    unsigned int GetCapacity() const { return event_.size(); }
+    void Copy(const int i1, const int i2) { event_[i2] = event_[i1]; }
+    void Swap(const int i1, const int i2) { std::swap(event_[i1], event_[i2]); }
 
     // custom data access function
-    void SetEvent(const int i, std::shared_ptr<TEvent> v) { fEvent[i] = v; }
-    std::shared_ptr<TEvent> GetEvent(const int i) const { return fEvent[i]; }
+    void SetEvent(const int i, std::shared_ptr<TEvent> v) { event_[i] = std::move(v); }
+    std::shared_ptr<TEvent> GetEvent(const int i) const { return event_[i]; }
 
     // these functions are also needed by the Stack interface
-    void IncrementSize() { fEvent.push_back(nullptr); }
+    void IncrementSize() { event_.push_back(nullptr); }
     void DecrementSize() {
-      if (fEvent.size() > 0) { fEvent.pop_back(); }
+      if (event_.size() > 0) { event_.pop_back(); }
     }
 
     // custom private data section
   private:
-    std::vector<std::shared_ptr<TEvent>> fEvent;
+    std::vector<std::shared_ptr<TEvent>> event_;
   };
+  
 
   /**
    * @class HistoryDataInterface
@@ -59,34 +61,33 @@ namespace corsika::history {
    */
   template <typename T, typename TEvent>
   class HistoryDataInterface : public T {
-    protected:
-      using T::GetStack;
-      using T::GetStackData;
+  protected:
+    using T::GetStack;
+    using T::GetStackData;
 
-    public:
-      using T::GetIndex;
+  public:
+    using T::GetIndex;
 
   public:
-    // default version for particle-creation from input data
-    void SetParticleData(const std::tuple<TEvent const*> v) { SetEvent(std::get<0>(v)); }
-    void SetParticleData(HistoryDataInterface& parent,
-                         const std::tuple<std::shared_ptr<TEvent>>) {
-      SetEvent(parent.GetEvent()); // copy Event from parent particle!
-    }
-    void SetParticleData() { SetEvent(nullptr); }
+ 
+    // create a new particle from scratch
+    void SetParticleData() { } // nullptr, already by design 
+
+    // create a new particle as secondary of a parent
     void SetParticleData(HistoryDataInterface& parent) {
-      SetEvent(parent.GetEvent()); // copy Event from parent particle!
+      SetEvent(std::make_shared<TEvent>(parent.GetEvent()));
+      GetEvent().getParent().addSecondary(GetEvent());
     }
-    void SetEvent(std::shared_ptr<TEvent> v) { GetStackData().SetEvent(GetIndex(), v); }
+
+    void SetEvent(const std::shared_ptr<TEvent>& v) { GetStackData().SetEvent(GetIndex(), v); }
     std::shared_ptr<TEvent> GetEvent() const {
       return GetStackData().GetEvent(GetIndex());
     }
   };
-  
+
   template <typename T, typename TEvent>
-    struct MakeHistoryDataInterface {
-      typedef HistoryDataInterface<T, TEvent> type;
-    };
-  
-  
+  struct MakeHistoryDataInterface {
+    typedef HistoryDataInterface<T, TEvent> type;
+  };
+
 } // namespace corsika::history
diff --git a/Stack/History/SecondaryParticle.hpp b/Stack/History/SecondaryParticle.hpp
new file mode 100644
index 000000000..319eeaa24
--- /dev/null
+++ b/Stack/History/SecondaryParticle.hpp
@@ -0,0 +1,38 @@
+/*
+ * (c) Copyright 2020 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/geometry/Vector.h>
+#include <corsika/particles/ParticleProperties.h>
+#include <corsika/units/PhysicalUnits.h>
+
+#include <vector>
+
+namespace corsika::history {
+
+  /**
+   * This class stores the non-common properties of secondaries in an event. All
+   * other (common) properties are available via the event itself.
+   */
+  class SecondaryParticle {
+    units::si::HEPEnergyType const energy_;
+    geometry::Vector<units::si::hepmomentum_d> const momentum_;
+    particles::Code const pid_;
+
+    // what else...?
+    // - polarization?
+
+  public:
+    SecondaryParticle(units::si::HEPEnergyType energy, geometry::Vector<units::si::hepmomentum_d> momentum, particles::Code pid)
+        : energy_{energy}
+        , momentum_{momentum}
+        , pid_{pid} {}
+  };
+
+} // namespace corsika::history
diff --git a/Stack/History/testHistory.cc b/Stack/History/testHistory.cc
index 5dd6faf2b..468ca6415 100644
--- a/Stack/History/testHistory.cc
+++ b/Stack/History/testHistory.cc
@@ -21,7 +21,20 @@ using namespace std;
 // this is our dummy environment, it only knows its trivial BaseNodeType
 class DummyEvent {
 public:
-  int id;
+  DummyEvent() {}
+  DummyEvent(const std::shared_ptr<DummyEvent>& parent) {
+    parent_ = parent;
+    //parent.addSecondary();
+  }
+
+  std::shared_ptr<DummyEvent> getParent() { return parent_; }
+  void addSecondary(const std::shared_ptr<DummyEvent>& particle) { secondaries_.push_back(particle); }
+
+  int multiplicity() const { return secondaries_.size(); }
+  
+private:
+  std::shared_ptr<DummyEvent> parent_;
+  std::vector<std::shared_ptr<DummyEvent>> secondaries_;
 };
 
 // the GeometryNode stack needs to know the type of geometry-nodes from the DummyEnv:
diff --git a/Stack/SuperStupidStack/SuperStupidStack.h b/Stack/SuperStupidStack/SuperStupidStack.h
index c3b755bbb..7c88628b6 100644
--- a/Stack/SuperStupidStack/SuperStupidStack.h
+++ b/Stack/SuperStupidStack/SuperStupidStack.h
@@ -16,8 +16,8 @@
 #include <corsika/geometry/RootCoordinateSystem.h> // remove
 #include <corsika/geometry/Vector.h>
 
-#include <vector>
 #include <tuple>
+#include <vector>
 
 namespace corsika::stack {
 
@@ -224,7 +224,7 @@ namespace corsika::stack {
     }; // end class SuperStupidStackImpl
 
     typedef Stack<SuperStupidStackImpl, ParticleInterface> SuperStupidStack;
-     
+
   } // namespace super_stupid
 
 } // namespace corsika::stack
-- 
GitLab