From 8ab149dc49251362a227aaf9242a6882531a445a Mon Sep 17 00:00:00 2001
From: Dominik Baack <dominik.baack@tu-dortmund.de>
Date: Fri, 18 Sep 2020 14:22:30 +0200
Subject: [PATCH] fixed template class stuff added missing unit test

---
 Processes/DevTools/Analytics/CMakeLists.txt  |  31 ++--
 Processes/DevTools/Analytics/ExecTime.cc     | 113 ++++++++-----
 Processes/DevTools/Analytics/ExecTime.h      | 157 ++++++++++---------
 Processes/DevTools/Analytics/testExecTime.cc |  48 +++++-
 4 files changed, 220 insertions(+), 129 deletions(-)

diff --git a/Processes/DevTools/Analytics/CMakeLists.txt b/Processes/DevTools/Analytics/CMakeLists.txt
index 422175428..9818a5cca 100644
--- a/Processes/DevTools/Analytics/CMakeLists.txt
+++ b/Processes/DevTools/Analytics/CMakeLists.txt
@@ -13,11 +13,11 @@ set (
   corsika/process/devtools
   )
 
-add_library (ProcessDevTools STATIC ${MODEL_SOURCES})
-CORSIKA_COPY_HEADERS_TO_NAMESPACE (ProcessDevTools ${MODEL_NAMESPACE} ${MODEL_HEADERS})
+add_library (DevTools_Analytic STATIC ${MODEL_SOURCES})
+CORSIKA_COPY_HEADERS_TO_NAMESPACE (DevTools_Analytic ${MODEL_NAMESPACE} ${MODEL_HEADERS})
 
 set_target_properties (
-  ProcessDevTools
+  DevTools_Analytic
   PROPERTIES
   VERSION ${PROJECT_VERSION}
   SOVERSION 1
@@ -25,32 +25,39 @@ set_target_properties (
 
 # target dependencies on other libraries (also the header onlys)
 target_link_libraries (
-  ProcessDevTools
-  CORSIKAsetup
+  DevTools_Analytic
+  CORSIKAprocesssequence
+  CORSIKAunits
+  CORSIKAthirdparty  
   )
 
 target_include_directories (
-  ProcessDevTools 
+  DevTools_Analytic 
   INTERFACE 
   $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
   $<INSTALL_INTERFACE:include/include>
   )
 
 install (
-  TARGETS ProcessDevTools
+  TARGETS DevTools_Analytic
   LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  PUBLIC_HEADER DESTINATION include/${MODEL_NAMESPACE}
+  ARCHIVE DESTINATION lib 
   )
 
 
 # --------------------
 # code unit testing
-CORSIKA_ADD_TEST (testExecTime testExecTime.cc)
+CORSIKA_ADD_TEST (testExecTime
+ SOURCES
+ testExecTime.cc
+ ${MODEL_HEADERS}
+)
+
 target_link_libraries (
-  testExecTime  ProcessDevTools
-  CORSIKAsetup
+  testExecTime  
+  DevTools_Analytic  
   DevTools_Dummy
+  CORSIKAtesting
   CORSIKAthirdparty # for catch2
   )
 
diff --git a/Processes/DevTools/Analytics/ExecTime.cc b/Processes/DevTools/Analytics/ExecTime.cc
index 18c31b5a1..8b7199e68 100644
--- a/Processes/DevTools/Analytics/ExecTime.cc
+++ b/Processes/DevTools/Analytics/ExecTime.cc
@@ -14,51 +14,90 @@
 namespace corsika::process {
   namespace devtools {
 
-    template <class T>
-    void ExecTime<T>::start() {
-      fStart = std::chrono::steady_clock::now();
-    }
+ 
 
-    template <class T>
-    void ExecTime<T>::stop() {
-      auto end = std::chrono::steady_clock::now();
-      std::chrono::microseconds timeDiv =
-          std::chrono::duration_cast<std::chrono::microseconds>(end - start);
-
-      fElapsedSum += timeDiv;
-      fN++;
-
-      if (fMax < timeDiv) fMax = timeDiv;
-
-      if (timeDiv < fMin) fMin = timeDiv;
-
-      auto delta = timeDiv - fMean;
-      fMean += delta / fN;
-
-      auto delta2 = timeDiv - fMean;
+  } // namespace devtools
+} // namespace corsika::process
 
-      fMean2 += delta * delta2;
-    }
+/*
+ template <typename T, bool>
+    class ExecTime_BoundaryCrossing {};
 
     template <typename T>
-    double ExecTime<T>::mean() {
-      return fMean;
-    }
+    class ExecTime_BoundaryCrossing<T, true> : protected T {
+    public:
+      template <
+          typename Particle, typename VTNType,
+          typename std::enable_if_t<
+              std::is_base_of<BoundaryCrossingProcess<typename T::_TDerived>, T>::value,
+              int> = 0>
+      EProcessReturn DoBoundaryCrossing(Particle& p, VTNType const& from,
+                                        VTNType const& to) {
+
+        return T::DoBoundaryCrossing(p, from, to);
+      }
+    };
+
+    template <typename T, bool>
+    class ExecTime_Continuous {};
 
     template <typename T>
-    double ExecTime<T>::var() {
-      return fMean2 / count;
-    }
+    class ExecTime_Continuous<T, true> : protected T {
+    public:
+      template <typename Particle, typename Track>
+      EProcessReturn DoContinuous(Particle& p, Track const& t) const {
+        return T::DoContinous(p, t);
+      }
+
+      template <typename Particle, typename Track>
+      units::si::LengthType MaxStepLength(Particle const& p, Track const& track) const {
+        return T::MaxStepLength(p, track);
+      }
+    };
+
+    template <typename T, bool>
+    class ExecTime_Decay {};
 
     template <typename T>
-    double ExecTime<T>::min() {
-      return fMin;
-    }
+    class ExecTime_Decay<T, true> : protected T {
+    public:
+      template <typename Particle>
+      EProcessReturn DoDecay(Particle& p) {
+        return T::DoDecay(p);
+      }
+
+      template <typename Particle>
+      corsika::units::si::TimeType GetLifetime(Particle& p) {
+        return T::GetLifetime(p);
+      }
+    };
+
+    template <typename T, bool>
+    class ExecTime_Interaction {};
 
     template <typename T>
-    double ExecTime<T>::max() {
-      return fMax;
-    }
+    class ExecTime_Interaction<T, true> : protected T {
+    public:
+      template <typename Particle>
+      EProcessReturn DoInteraction(Particle& p) {
+        return T::DoInteraction(p);
+      }
+
+      template <typename Particle>
+      corsika::units::si::GrammageType GetInteractionLength(Particle& p) {
+        return T::GetInteractionLength(p);
+      }
+    };
+
+    template <typename T, bool>
+    class ExecTime_Secondaries {};
 
-  } // namespace devtools
-} // namespace corsika::process
\ No newline at end of file
+    template <typename T>
+    class ExecTime_Secondaries<T, true> : protected T {
+    public:
+      template <typename Secondaries>
+      inline EProcessReturn DoSecondaries(Secondaries& sec) {
+        return T::DoSecondaries(sec);
+      }
+    };
+    */
\ No newline at end of file
diff --git a/Processes/DevTools/Analytics/ExecTime.h b/Processes/DevTools/Analytics/ExecTime.h
index aef2c588d..25524c03e 100644
--- a/Processes/DevTools/Analytics/ExecTime.h
+++ b/Processes/DevTools/Analytics/ExecTime.h
@@ -21,117 +21,118 @@
 namespace corsika::process {
   namespace devtools {
 
-    template <typename T, bool>
-    class ExecTime_BoundaryCrossing {};
-
     template <typename T>
-    class ExecTime_BoundaryCrossing<T, true> : protected T {
+    class ExecTime : private T {
+    private:
+      std::chrono::high_resolution_clock::time_point fStart;
+      std::chrono::duration<double,std::micro> fElapsedSum;
+      double fMean;
+      double fMean2;
+      double fMin;
+      double fMax;
+      long long fN;
+
+    protected:
     public:
-      template <
-          typename Particle, typename VTNType,
-          typename std::enable_if_t<
-              std::is_base_of<BoundaryCrossingProcess<typename T::_TDerived>, T>::value,
-              int> = 0>
+      ExecTime() {
+        fMin = std::numeric_limits<long long>::max();
+        fMax = 0;
+        fMean = 0;
+        fMean2 = 0;
+        fN = 0;
+      }
+
+      void start() { fStart = std::chrono::high_resolution_clock::now(); }
+      void stop() {
+        auto end = std::chrono::high_resolution_clock::now();
+        std::chrono::duration<double,std::micro> timeDiv =
+            std::chrono::duration_cast< std::chrono::duration<double,std::micro> >(end - fStart);
+
+        fElapsedSum += timeDiv;
+        fN = fN + 1;
+
+        if (fMax < timeDiv.count()) fMax = timeDiv.count();
+
+        if (timeDiv.count() < fMin) fMin = timeDiv.count();
+
+        double delta = timeDiv.count() - fMean;
+        fMean += delta / static_cast<double>(fN);
+
+        double delta2 = timeDiv.count() - fMean;
+
+        fMean2 += delta * delta2;
+      }
+
+      double mean() const { return fMean; }
+      double min() const { return fMin; }
+      double max() const { return fMax; }
+      double var() const { return fMean2 / fN; }
+      double sumTime() const { return fElapsedSum.count(); }
+
+      template <typename Particle, typename VTNType>
       EProcessReturn DoBoundaryCrossing(Particle& p, VTNType const& from,
                                         VTNType const& to) {
-        return T::DoBoundaryCrossing(p, from, to);
+        this->start();
+        auto r = T::DoBoundaryCrossing(p, from, to);
+        this->stop();
+        return r;
       }
-    };
-
-    template <typename T, bool>
-    class ExecTime_Continuous {};
 
-    template <typename T>
-    class ExecTime_Continuous<T, true> : protected T {
-    public:
       template <typename Particle, typename Track>
       EProcessReturn DoContinuous(Particle& p, Track const& t) const {
-        return T::DoContinous(p, t);
+        this->start();
+        auto r = T::DoContinous(p, t);
+        this->stop();
+        return r;
       }
 
       template <typename Particle, typename Track>
       units::si::LengthType MaxStepLength(Particle const& p, Track const& track) const {
-        return T::MaxStepLength(p, track);
+        this->start();
+        auto r = T::MaxStepLength(p, track);
+        this->stop();
+        return r;
       }
-    };
 
-    template <typename T, bool>
-    class ExecTime_Decay {};
-
-    template <typename T>
-    class ExecTime_Decay<T, true> : protected T {
-    public:
       template <typename Particle>
       EProcessReturn DoDecay(Particle& p) {
-        return T::DoDecay(p);
+        this->start();
+        auto r = T::DoDecay(p);
+        this->stop();
+        return r;
       }
 
       template <typename Particle>
       corsika::units::si::TimeType GetLifetime(Particle& p) {
-        return T::GetLifetime(p);
+        this->start();
+        auto r = T::GetLifetime(p);
+        this->stop();
+        return r;
       }
-    };
-
-    template <typename T, bool>
-    class ExecTime_Interaction {};
 
-    template <typename T>
-    class ExecTime_Interaction<T, true> : protected T {
-    public:
       template <typename Particle>
       EProcessReturn DoInteraction(Particle& p) {
-        return T::DoInteraction(p);
+        this->start();
+        auto r = T::DoInteraction(p);
+        this->stop();
+        return r;
       }
 
       template <typename Particle>
       corsika::units::si::GrammageType GetInteractionLength(Particle& p) {
-        return T::GetInteractionLength(p);
+        this->start();
+        auto r = T::GetInteractionLength(p);
+        this->stop();
+        return r;
       }
-    };
 
-    template <typename T, bool>
-    class ExecTime_Secondaries {};
-
-    template <typename T>
-    class ExecTime_Secondaries<T, true> : protected T {
-    public:
       template <typename Secondaries>
       inline EProcessReturn DoSecondaries(Secondaries& sec) {
-        return T::DoSecondaries(sec);
+        this->start();
+        auto r = T::DoSecondaries(sec);
+        this->stop();
+        return r;
       }
-    };
-
-    template <typename T>
-    class ExecTime
-        : public ExecTime_BoundaryCrossing<
-              T,
-              std::is_base_of<BoundaryCrossingProcess<typename T::_TDerived>, T>::value>,
-          public ExecTime_Continuous<
-              T, std::is_base_of<ContinuousProcess<typename T::_TDerived>, T>::value>,
-          public ExecTime_Decay<
-              T, std::is_base_of<DecayProcess<typename T::_TDerived>, T>::value>,
-          public ExecTime_Interaction<
-              T, std::is_base_of<InteractionProcess<typename T::_TDerived>, T>::value>,
-          public ExecTime_Secondaries<
-              T, std::is_base_of<SecondariesProcess<typename T::_TDerived>, T>::value> {
-    private:
-      std::chrono::microseconds fStart;
-      std::chrono::microseconds fElapsedSum;
-      std::chrono::microseconds fMean;
-      std::chrono::microseconds fMean2;
-      std::chrono::microseconds fMin;
-      std::chrono::microseconds fMax;
-      long long fN;
-
-      void start();
-      void stop();
-
-    protected:
-    public:
-      double mean();
-      double min();
-      double max();
-      double var();
 
       /*
                   // Stack
diff --git a/Processes/DevTools/Analytics/testExecTime.cc b/Processes/DevTools/Analytics/testExecTime.cc
index 853ccd2d2..f5cd643f7 100644
--- a/Processes/DevTools/Analytics/testExecTime.cc
+++ b/Processes/DevTools/Analytics/testExecTime.cc
@@ -18,12 +18,14 @@
 #include <corsika/process/devtools/DummyInteractionProcess.h>
 #include <corsika/process/devtools/DummySecondariesProcess.h>
 
+#include <random>
+
 using namespace corsika::process;
 using namespace corsika::process::devtools;
 
 TEST_CASE("ContinuousProcess interface", "[proccesses][DevTools ExecTime]") {
 
-  ExecTime<DummyBoundaryCrossingProcess<100>> execTime;
+  ExecTime<DummyBoundaryCrossingProcess<50>> execTime;
   int tmp = 0;
 
   SECTION("BoundaryCrossing") {
@@ -31,6 +33,48 @@ TEST_CASE("ContinuousProcess interface", "[proccesses][DevTools ExecTime]") {
     REQUIRE(execTime.DoBoundaryCrossing(tmp, 0, 0) == EProcessReturn::eOk);
     auto end = std::chrono::steady_clock::now();
     REQUIRE(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() ==
-            Approx(100).margin(1));
+            Approx(50).margin(1));
+
+    for (int i = 0; i < 100; i++) execTime.DoBoundaryCrossing(tmp, 0, 0);
+
+    REQUIRE(execTime.mean() == Approx(50 * 1000).margin(1 * 1000));
+
+    REQUIRE(execTime.sumTime() == Approx(50 * 100 * 1000).margin(100 * 1000));
+
+    REQUIRE(execTime.var() == Approx(0).margin(20000));
+  }
+
+  SECTION("TestMeanAlgo") {
+    std::default_random_engine generator;
+    std::normal_distribution<double> distribution(10000.0, 200.0);
+
+    double fStart;
+    double fElapsedSum;
+    double fMean;
+    double fMean2;
+    long long fMin;
+    long long fMax;
+    long long fN;
+
+    for (int i = 0; i < 1000000; i++) {
+      auto timeDiv = distribution(generator);
+
+      fElapsedSum += timeDiv;
+      fN = fN + 1;
+
+      if (fMax < timeDiv) fMax = timeDiv;
+
+      if (timeDiv < fMin) fMin = timeDiv;
+
+      double delta = timeDiv - fMean;
+      fMean += delta / static_cast<double>(fN);
+
+      double delta2 = timeDiv - fMean;
+
+      fMean2 += delta * delta2;
+    }
+
+    REQUIRE(fMean2 / fN == Approx(200*200).margin(200)); // Varianz
+    REQUIRE(fMean == Approx(10000).margin(10));
   }
 }
-- 
GitLab