From ccc303985276dac43bc980b45aa6d9726c248c7c Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Tue, 21 Jun 2022 15:08:59 +0200
Subject: [PATCH] L1: L1NaN.h introduced

---
 reco/L1/CMakeLists.txt               |  1 +
 reco/L1/L1Algo/L1MaterialInfo.cxx    |  2 +-
 reco/L1/L1Algo/L1MaterialInfo.h      | 30 +++++++++----
 reco/L1/L1Algo/L1NaN.h               | 66 ++++++++++++++++++++++++++++
 reco/L1/L1Algo/L1Station.h           | 22 +++++-----
 reco/L1/L1Algo/L1UMeasurementInfo.h  | 12 +++--
 reco/L1/L1Algo/L1Utils.h             |  4 +-
 reco/L1/L1Algo/L1XYMeasurementInfo.h | 13 ++++--
 8 files changed, 122 insertions(+), 28 deletions(-)
 create mode 100644 reco/L1/L1Algo/L1NaN.h

diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt
index 879ca5f061..cc8a444983 100644
--- a/reco/L1/CMakeLists.txt
+++ b/reco/L1/CMakeLists.txt
@@ -280,6 +280,7 @@ Install(FILES CbmL1Counters.h
               L1Algo/L1Parameters.h
               L1Algo/L1Constants.h
               L1Algo/L1Utils.h
+              L1Algo/L1NaN.h
               vectors/vec_arithmetic.h
               vectors/std_alloc.h
         DESTINATION include
diff --git a/reco/L1/L1Algo/L1MaterialInfo.cxx b/reco/L1/L1Algo/L1MaterialInfo.cxx
index bf3fea8630..13878ccbe4 100644
--- a/reco/L1/L1Algo/L1MaterialInfo.cxx
+++ b/reco/L1/L1Algo/L1MaterialInfo.cxx
@@ -3,7 +3,7 @@
    Authors: Sergey Gorbunov, Sergei Zharko [committer] */
 
 #include "L1MaterialInfo.h"
-
+#include "L1Utils.h"
 #include <FairLogger.h>
 
 #include <iomanip>
diff --git a/reco/L1/L1Algo/L1MaterialInfo.h b/reco/L1/L1Algo/L1MaterialInfo.h
index 9d8818a3b3..4f357f7e4a 100644
--- a/reco/L1/L1Algo/L1MaterialInfo.h
+++ b/reco/L1/L1Algo/L1MaterialInfo.h
@@ -11,20 +11,26 @@
 #include <vector>
 
 #include "L1Def.h"
-#include "L1Utils.h"
+#include "L1NaN.h"
 
 /// Class L1MaterialInfo contains SIMDized vector fields of the
 /// The fields of the structure should ONLY be initialized within L1BaseStationInfo::SetMaterial(double, double) method, when the
 /// stations sequence is initialized
 struct L1MaterialInfo {
-  fvec thick {L1Utils::kNaN};  ///< Average thickness of the station in arbitary length units
-  fvec RL {
-    L1Utils::kNaN};  ///< Average radiation length (X0) of the station material in THE SAME UNITS as the thickness
-  fvec RadThick {L1Utils::kNaN};  ///< Average thickness in units of radiation length (X/X0)
-  fvec logRadThick {L1Utils::kNaN};
+  fvec thick {L1NaN::SetNaN<decltype(thick)>()};  ///< Average thickness of the station in arbitary length units
+  /// Average radiation length (X0) of the station material in THE SAME UNITS as the thickness
+  fvec RL {L1NaN::SetNaN<decltype(RL)>()};
+  fvec RadThick {L1NaN::SetNaN<decltype(RadThick)>()};       ///< Average thickness in units of radiation length (X/X0)
+  fvec logRadThick {L1NaN::SetNaN<decltype(logRadThick)>()}; ///< Log of average thickness in units of radiation length
 
   /// Verifies class invariant consistency
   void CheckConsistency() const;
+  
+  /// Checks, if the fields are NaN
+  bool IsNaN() const
+  {
+    return L1NaN::IsNaN(thick) || L1NaN::IsNaN(RL) || L1NaN::IsNaN(RadThick) || L1NaN::IsNaN(logRadThick);
+  }
 
   /// String representation of class contents
   /// \param indentLevel    number of indent characters in the output
@@ -71,6 +77,12 @@ public:
   /// \param x  X coordinate of the point [cm] (SIMDized vector)
   /// \param y  Y coordinate of the point [cm] (SIMDized veotor)
   fvec GetRadThick(fvec x, fvec y) const;
+  
+  /// Checks, if the fields are NaN
+  bool IsNaN() const
+  {
+    return L1NaN::IsNaN(fNbins) || L1NaN::IsNaN(fRmax) || L1NaN::IsNaN(fFactor);
+  }
 
   /// Verifies class invariant consistency
   void CheckConsistency() const;
@@ -93,9 +105,9 @@ public:
   void Swap(L1Material& other) noexcept;
 
 private:
-  int fNbins {-1};                ///< Number of rows (columns) in the material budget table
-  float fRmax {L1Utils::kNaN};    ///< Size of the station in x and y dimensions [cm]
-  float fFactor {L1Utils::kNaN};  ///< Factor used in the recalculation of point coordinates to row/column id
+  int fNbins    {L1NaN::SetNaN<decltype(fNbins)>()};   ///< Number of rows (columns) in the material budget table
+  float fRmax   {L1NaN::SetNaN<decltype(fRmax)>()};    ///< Size of the station in x and y dimensions [cm]
+  float fFactor {L1NaN::SetNaN<decltype(fFactor)>()};  ///< Factor used in the recalculation of point coordinates to row/column id
   std::vector<float> fTable {};  ///< Material budget table
 } _fvecalignment;
 
diff --git a/reco/L1/L1Algo/L1NaN.h b/reco/L1/L1Algo/L1NaN.h
new file mode 100644
index 0000000000..b5a2349c13
--- /dev/null
+++ b/reco/L1/L1Algo/L1NaN.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/***************************************************************************************************
+ * @file   L1NaN.h
+ * @brief  Definition of setters and checkers for NaN values
+ * @since  21.06.2022
+ * @author S.Zharko <s.zharko@gsi.de>
+ ***************************************************************************************************/
+
+#ifndef L1NaN_h
+#define L1NaN_h 1
+
+#include <limits>
+#include <type_traits>
+#include <cmath>
+#include "vectors/P4_F32vec4.h"
+
+/// Namespace L1NaN defines functions to set variables to NaN and check wether they are NaN or not
+///
+namespace L1NaN {
+  /// Returns NaN value for a floating point variable
+  template <typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr>
+  constexpr auto SetNaN()
+  {
+    return std::numeric_limits<T>::signaling_NaN();
+  }
+
+  /// Returns MaN value for an intergral variable
+  template <typename T, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, T>::type* = nullptr>
+  constexpr auto SetNaN()
+  {
+    return T(-1); // -1 for signed integers and MAX_INT for unsigned integers
+  }
+  
+  /// Returns MaN value for fvec variable
+  template <typename T, typename std::enable_if<std::is_same<T, fvec>::value, T>::type* = nullptr>
+  constexpr auto SetNaN()
+  {
+    return fvec(SetNaN<fscal>());
+  }
+
+  /// Checks, if the floating point variable is NaN
+  template <typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr>
+  bool IsNaN(T value)
+  {
+    return std::isnan(value);
+  }
+
+  /// Checks, if the integral variable is NaN
+  template <typename T, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, T>::type* = nullptr>
+  bool IsNaN(T value)
+  {
+    return T(-1) == value;
+  }
+
+  /// Checks, if the fvec variable is NaN
+  template <typename T, typename std::enable_if<std::is_same<T, fvec>::value, T>::type* = nullptr>
+  bool IsNaN(T value) 
+  {
+    return value.IsNanAny(); // NOTE: Here we consider fvec a NaN if at least one of its words is NaN
+  }
+};
+
+#endif // L1NaN_h
diff --git a/reco/L1/L1Algo/L1Station.h b/reco/L1/L1Algo/L1Station.h
index 01b82ae659..803153a8e9 100644
--- a/reco/L1/L1Algo/L1Station.h
+++ b/reco/L1/L1Algo/L1Station.h
@@ -9,6 +9,7 @@
 
 #include "L1Field.h"
 #include "L1MaterialInfo.h"
+#include "L1NaN.h"
 #include "L1UMeasurementInfo.h"
 #include "L1Utils.h"
 #include "L1XYMeasurementInfo.h"
@@ -16,16 +17,17 @@
 /// Structure L1Station
 /// Contains a set of geometry parameters for a particular station
 ///
-struct L1Station {
-  int type {-1};
-  int timeInfo {-1};          ///< flag: if time information can be used
-  int fieldStatus {-1};       ///< flag: 1 - station is INSIDE the field, 0 - station is OUTSIDE the field
-  fvec z {L1Utils::kNaN};     ///< z position of station     [cm]
-  fvec Rmin {L1Utils::kNaN};  ///< min radius of the station [cm]
-  fvec Rmax {L1Utils::kNaN};  ///< max radius of the station [cm]
-  fvec dt {L1Utils::kNaN};    ///< time resolution [ns]
-  L1MaterialInfo
-    materialInfo {};  ///< structure containing station thickness(X), rad. length (X0), X/X0 and log(X/X0) values
+class L1Station {
+public:
+  int type        {L1NaN::SetNaN<decltype(type)>()};
+  int timeInfo    {L1NaN::SetNaN<decltype(timeInfo)>()};          ///< flag: if time information can be used
+  int fieldStatus {L1NaN::SetNaN<decltype(fieldStatus)>()};       ///< flag: 1 - station is INSIDE the field, 0 - station is OUTSIDE the field
+  fvec z          {L1NaN::SetNaN<decltype(z)>()};     ///< z position of station     [cm]
+  fvec Rmin       {L1NaN::SetNaN<decltype(Rmin)>()};  ///< min radius of the station [cm]
+  fvec Rmax       {L1NaN::SetNaN<decltype(Rmax)>()};  ///< max radius of the station [cm]
+  fvec dt         {L1NaN::SetNaN<decltype(dt)>()};    ///< time resolution [ns]
+  /// structure containing station thickness(X), rad. length (X0), X/X0 and log(X/X0) values
+  L1MaterialInfo materialInfo {};
   L1FieldSlice fieldSlice {};
   L1UMeasurementInfo frontInfo {};
   L1UMeasurementInfo backInfo {};
diff --git a/reco/L1/L1Algo/L1UMeasurementInfo.h b/reco/L1/L1Algo/L1UMeasurementInfo.h
index 4a8a6076ec..6383eebcee 100644
--- a/reco/L1/L1Algo/L1UMeasurementInfo.h
+++ b/reco/L1/L1Algo/L1UMeasurementInfo.h
@@ -8,14 +8,15 @@
 #include <string>
 
 #include "L1Def.h"
+#include "L1NaN.h"
 #include "L1Utils.h"
 
 class L1UMeasurementInfo {
 
 public:
-  fvec cos_phi {0.f};
-  fvec sin_phi {0.f};
-  fvec sigma2 {0.f};
+  fvec cos_phi {L1NaN::SetNaN<decltype(cos_phi)>()};
+  fvec sin_phi {L1NaN::SetNaN<decltype(sin_phi)>()};
+  fvec sigma2  {L1NaN::SetNaN<decltype(sigma2)>()};
 
   /// String representation of class contents
   /// \param indentLevel      number of indent characters in the output
@@ -24,6 +25,11 @@ public:
   /// Check consistency
   void CheckConsistency() const;
 
+  /// Checks, if the fields are NaN
+  bool IsNaN() const
+  {
+    return L1NaN::IsNaN(cos_phi) || L1NaN::IsNaN(sin_phi) || L1NaN::IsNaN(sigma2);
+  }
 } _fvecalignment;
 
 
diff --git a/reco/L1/L1Algo/L1Utils.h b/reco/L1/L1Algo/L1Utils.h
index 37256872c6..22c69e5720 100644
--- a/reco/L1/L1Algo/L1Utils.h
+++ b/reco/L1/L1Algo/L1Utils.h
@@ -15,6 +15,7 @@
 #include <map>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <unordered_map>
 
 #include <cmath>
@@ -31,10 +32,9 @@ struct L1Utils {
   /// \param  lhs  Left floating point to compare
   /// \param  rhs  Right floating point to compare
   /// \return      Comparison result: true - equals within epsilon
-  template<typename T>
+  template <typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr>
   static bool CmpFloats(T lhs, T rhs)
   {
-    static_assert(!std::numeric_limits<T>::is_integer, "L1Utils::CmpFloatingPoint does not work with integers");
     return fabs(lhs - rhs) < 2. * std::numeric_limits<T>::epsilon() * fabs(lhs + rhs)
            || fabs(lhs - rhs) < std::numeric_limits<T>::min();
   }
diff --git a/reco/L1/L1Algo/L1XYMeasurementInfo.h b/reco/L1/L1Algo/L1XYMeasurementInfo.h
index 57ef4b4d6e..85cdd745ea 100644
--- a/reco/L1/L1Algo/L1XYMeasurementInfo.h
+++ b/reco/L1/L1Algo/L1XYMeasurementInfo.h
@@ -8,13 +8,14 @@
 #include <string>
 
 #include "L1Def.h"
+#include "L1NaN.h"
 
 class L1XYMeasurementInfo {
 
 public:
-  fvec C00 {0};
-  fvec C10 {0};
-  fvec C11 {0};
+  fvec C00 {L1NaN::SetNaN<decltype(C00)>()};
+  fvec C10 {L1NaN::SetNaN<decltype(C10)>()};
+  fvec C11 {L1NaN::SetNaN<decltype(C11)>()};
 
   /// Consistency checker
   void CheckConsistency() const;
@@ -22,6 +23,12 @@ public:
   /// String representation of class contents
   /// \param indentLevel      number of indent characters in the output
   std::string ToString(int indentLevel = 0) const;
+
+  /// Checks, if the fields are NaN
+  bool IsNaN() const
+  {
+    return L1NaN::IsNaN(C00) || L1NaN::IsNaN(C10) || L1NaN::IsNaN(C11);
+  }
 } _fvecalignment;
 
 
-- 
GitLab