From 018b2d30293977878dbc45fc64cb626ebf5adf20 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Thu, 9 Jun 2022 17:30:17 +0200
Subject: [PATCH] L1: add consistency checkers for L1Parameters, L1Station,
 L1UMeasurementInfo, L1XYMeasurementInfo, L1MaterialInfo, L1Material,
 L1FieldSlice, L1FieldRegion, L1FieldValue classes

---
 reco/L1/CbmL1.cxx                      |  23 +---
 reco/L1/CbmMvdTrackerIF.cxx            |   4 +-
 reco/L1/L1Algo/L1Algo.h                |   4 +-
 reco/L1/L1Algo/L1Field.cxx             |  69 ++++++++++--
 reco/L1/L1Algo/L1Field.h               |  22 +++-
 reco/L1/L1Algo/L1InitManager.cxx       |   7 +-
 reco/L1/L1Algo/L1InitManager.h         |   5 +-
 reco/L1/L1Algo/L1MaterialInfo.cxx      |  80 +++++++++++++-
 reco/L1/L1Algo/L1MaterialInfo.h        |  25 +++--
 reco/L1/L1Algo/L1Parameters.cxx        | 144 ++++++++++++++++++++-----
 reco/L1/L1Algo/L1Parameters.h          |   4 +-
 reco/L1/L1Algo/L1Station.cxx           |  83 +++++++++++++-
 reco/L1/L1Algo/L1Station.h             |  25 +++--
 reco/L1/L1Algo/L1UMeasurementInfo.cxx  |  21 +++-
 reco/L1/L1Algo/L1UMeasurementInfo.h    |   5 +
 reco/L1/L1Algo/L1Utils.h               |  27 ++++-
 reco/L1/L1Algo/L1XYMeasurementInfo.cxx |  10 +-
 reco/L1/L1Algo/L1XYMeasurementInfo.h   |   5 +-
 reco/L1/vectors/P4_F32vec4.h           |  20 ++++
 19 files changed, 484 insertions(+), 99 deletions(-)

diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index fd5bb314f2..1c1a77072d 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -28,8 +28,6 @@
 #include "CbmMuchModuleGem.h"
 #include "CbmMuchPad.h"
 #include "CbmMuchStation.h"
-#include "CbmMvdDetector.h"
-#include "CbmMvdStationPar.h"
 #include "CbmSetup.h" // TODO: To be replaced to the CbmStsTrackerIF !! (S.Zharko)
 #include "CbmMvdTrackerIF.h"
 #include "CbmStsTrackerIF.h"
@@ -491,28 +489,11 @@ InitStatus CbmL1::Init()
 
 
   /*** MVD and STS ***/
-  CbmStsSetup* stsSetup = CbmStsSetup::Instance();
-  if (!stsSetup->IsInit()) { stsSetup->Init(nullptr); }
-  if (!stsSetup->IsModuleParsInit()) { stsSetup->SetModuleParameters(fStsParSetModule); }
-  if (!stsSetup->IsSensorParsInit()) { stsSetup->SetSensorParameters(fStsParSetSensor); }
-  if (!stsSetup->IsSensorCondInit()) { stsSetup->SetSensorConditions(fStsParSetSensorCond); }
-
-  NMvdStationsGeom = 0;
-  if (fUseMVD) {
-    CbmMvdDetector* mvdDetector = CbmMvdDetector::Instance();
-    if (mvdDetector) {
-      CbmMvdStationPar* mvdStationPar = mvdDetector->GetParameterFile();
-      assert(mvdStationPar);
-      NMvdStationsGeom = mvdStationPar->GetStationCount();
-    }
-  }
-  //NStsStationsGeom = (fUseSTS) ? CbmStsSetup::Instance()->GetNofStations() : 0;
-  
   auto mvdInterface = CbmMvdTrackerIF::Instance();
   auto stsInterface = CbmStsTrackerIF::Instance();
 
-  //NMvdStationsGeom = mvdInterface->GetNstations();
-  NStsStationsGeom = stsInterface->GetNstations();
+  NMvdStationsGeom = (fUseMVD) ? mvdInterface->GetNstations() : 0;
+  NStsStationsGeom = (fUseSTS) ? stsInterface->GetNstations() : 0;
   NStationGeom     = NMvdStationsGeom + NStsStationsGeom + NMuchStationsGeom + NTrdStationsGeom + NTOFStationGeom;
 
   // Provide crosscheck number of stations for the fpInitManagera
diff --git a/reco/L1/CbmMvdTrackerIF.cxx b/reco/L1/CbmMvdTrackerIF.cxx
index d465dd58d0..9a855edbb0 100644
--- a/reco/L1/CbmMvdTrackerIF.cxx
+++ b/reco/L1/CbmMvdTrackerIF.cxx
@@ -81,7 +81,7 @@ double CbmMvdTrackerIF::GetRmax(int stationId) const
 //
 int CbmMvdTrackerIF::GetNstations() const 
 { 
-  return fMvdMaterial->size(); 
+  return fMvdStationPar->GetStationCount(); 
 }
 
 //-------------------------------------------------------------------------------------------------------------------------------------
@@ -140,7 +140,7 @@ InitStatus CbmMvdTrackerIF::Init()
   
   fMvdMaterial = &(CbmKF::Instance()->vMvdMaterial);
   fMvdStationPar = CbmMvdDetector::Instance()->GetParameterFile();
-
+  
   if (!fMvdMaterial) { return kFATAL; }
   if (!fMvdStationPar) { return kFATAL; }
 
diff --git a/reco/L1/L1Algo/L1Algo.h b/reco/L1/L1Algo/L1Algo.h
index 5a789389a9..ca2faa6fd2 100644
--- a/reco/L1/L1Algo/L1Algo.h
+++ b/reco/L1/L1Algo/L1Algo.h
@@ -395,8 +395,8 @@ public:
   L1InitManager* GetInitManager() { return &fInitManager; }
 
 private:
-  L1Parameters fParameters {};                ///< Object of L1Algo parameters class
-  L1InitManager fInitManager {&fParameters};  ///< Object of L1Algo initialization manager class
+  L1Parameters  fParameters {};                ///< Object of L1Algo parameters class
+  L1InitManager fInitManager {};  ///< Object of L1Algo initialization manager class
 
 
   /*********************************************************************************************/ /**
diff --git a/reco/L1/L1Algo/L1Field.cxx b/reco/L1/L1Algo/L1Field.cxx
index 8816d409ac..4f71d06cff 100644
--- a/reco/L1/L1Algo/L1Field.cxx
+++ b/reco/L1/L1Algo/L1Field.cxx
@@ -3,6 +3,7 @@
    Authors: Sergey Gorbunov, Sergei Zharko [committer] */
 
 #include "L1Field.h"
+#include "L1Utils.h"
 
 #include <iomanip>
 #include <iostream>
@@ -12,14 +13,16 @@
 // L1FieldValue methods
 //
 
-
 //----------------------------------------------------------------------------------------------------------------------
-// TODO: Should it be inline? (S.Zharko)
-void L1FieldValue::Combine(L1FieldValue& B, fvec w)
+//
+void L1FieldValue::CheckConsistency() const
 {
-  x += w * (B.x - x);
-  y += w * (B.y - y);
-  z += w * (B.z - z);
+  /* Check SIMD data vectors for consistent initialization */
+  L1Utils::CheckSimdVectorEquality(x, "L1FieldValue::x");
+  L1Utils::CheckSimdVectorEquality(y, "L1FieldValue::y");
+  L1Utils::CheckSimdVectorEquality(z, "L1FieldValue::z");
+
+  // TODO: Any other checks? (S.Zharko)
 }
 
 //----------------------------------------------------------------------------------------------------------------------
@@ -35,6 +38,8 @@ std::string L1FieldValue::ToString(int indentLevel) const
   return aStream.str();
 }
 
+//----------------------------------------------------------------------------------------------------------------------
+//
 std::ostream& operator<<(std::ostream& out, const L1FieldValue& B)
 {
   return out << B.x[0] << " | " << B.y[0] << " | " << B.z[0];
@@ -46,12 +51,38 @@ std::ostream& operator<<(std::ostream& out, const L1FieldValue& B)
 
 //----------------------------------------------------------------------------------------------------------------------
 //
-L1FieldSlice::L1FieldSlice() noexcept
+L1FieldSlice::L1FieldSlice()
+{
+  for (int i = 0; i < L1Constants::size::kMaxNFieldApproxCoefficients; ++i) {
+    cx[i] = L1Utils::kNaN;
+    cy[i] = L1Utils::kNaN;
+    cz[i] = L1Utils::kNaN;
+  }
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+//
+void L1FieldSlice::CheckConsistency() const
 {
+  /* Check SIMD data vectors for consistent initialization */
   for (int i = 0; i < L1Constants::size::kMaxNFieldApproxCoefficients; ++i) {
-    cx[i] = 0.f;
-    cy[i] = 0.f;
-    cz[i] = 0.f;
+    if (!cx[i].IsHorizontallyEqual()) {
+      std::stringstream msg;
+      msg << "L1FieldSlice: \"cx[" << i << "]\" SIMD vector is inconsistent not all of the words are equal each other: " << cx[i];
+      throw std::logic_error(msg.str());
+    }
+
+    if (!cy[i].IsHorizontallyEqual()) {
+      std::stringstream msg;
+      msg << "L1FieldSlice: \"cy[" << i << "]\" SIMD vector is inconsistent not all of the words are equal each other: " << cy[i];
+      throw std::logic_error(msg.str());
+    }
+
+    if (!cz[i].IsHorizontallyEqual()) {
+      std::stringstream msg;
+      msg << "L1FieldSlice: \"cz[" << i << "]\" SIMD vector is inconsistent not all of the words are equal each other: " << cz[i];
+      throw std::logic_error(msg.str());
+    }
   }
 }
 
@@ -133,6 +164,24 @@ L1FieldRegion::L1FieldRegion(float reg[10]) noexcept
 {
 }
 
+//----------------------------------------------------------------------------------------------------------------------
+//
+void L1FieldRegion::CheckConsistency() const
+{
+  /* Check SIMD data vectors for consistent initialization */
+  L1Utils::CheckSimdVectorEquality(cx0, "L1FieldRegion::cx0");
+  L1Utils::CheckSimdVectorEquality(cx1, "L1FieldRegion::cx1");
+  L1Utils::CheckSimdVectorEquality(cx2, "L1FieldRegion::cx2");
+  L1Utils::CheckSimdVectorEquality(cy0, "L1FieldRegion::cy0");
+  L1Utils::CheckSimdVectorEquality(cy1, "L1FieldRegion::cy1");
+  L1Utils::CheckSimdVectorEquality(cy2, "L1FieldRegion::cy2");
+  L1Utils::CheckSimdVectorEquality(cz0, "L1FieldRegion::cz0");
+  L1Utils::CheckSimdVectorEquality(cz1, "L1FieldRegion::cz1");
+  L1Utils::CheckSimdVectorEquality(cz2, "L1FieldRegion::cz2");
+  L1Utils::CheckSimdVectorEquality(z0, "L1FieldRegion::z0");
+  // TODO: Any other checks? (S.Zharko)
+}
+
 //----------------------------------------------------------------------------------------------------------------------
 // TODO: Should it be inline? (S.Zharko)
 L1FieldValue L1FieldRegion::Get(const fvec z)
diff --git a/reco/L1/L1Algo/L1Field.h b/reco/L1/L1Algo/L1Field.h
index b80cd4b7a7..b69ce7b8ff 100644
--- a/reco/L1/L1Algo/L1Field.h
+++ b/reco/L1/L1Algo/L1Field.h
@@ -21,6 +21,9 @@ public:
   /// \param w  weight from 0 to 1 // TODO: Do we need any checks here? (S.Zharko)
   void Combine(L1FieldValue& B, fvec w);  // TODO: Shouldn't the B parameter be const? (S.Zharko)
   
+  /// Consistency checker
+  void CheckConsistency() const;
+  
   /// Operator << overloading
   friend std::ostream& operator<<(std::ostream& out, const L1FieldValue& B);
   
@@ -29,18 +32,30 @@ public:
   std::string ToString(int indentLevel) const;
 } _fvecalignment;
 
+inline __attribute__((always_inline)) void L1FieldValue::Combine(L1FieldValue& B, fvec w)
+{
+  x += w * (B.x - x);
+  y += w * (B.y - y);
+  z += w * (B.z - z);
+}
 
 /// Class represents a set of magnetic field approximation coefficients
 ///
 // TODO: Crosscheck the default content (S.Zharko)
 class L1FieldSlice {
 public:
-  L1FieldSlice() noexcept;
+  /// Default constructor
+  L1FieldSlice();
+  
+  /// Consistency checker
+  void CheckConsistency() const;
+
   /// Gets field value from (x, y) fvec point
   /// \param x  x-coordinate of input
   /// \param y  y-coordinate of input
   /// \param B  the L1FieldValue output
   void GetFieldValue(const fvec& x, const fvec& y, L1FieldValue& B) const;
+  
   /// String representation of class contents
   /// \param indentLevel      number of indent characters in the output
   std::string ToString(int indentLevel = 0) const;
@@ -61,7 +76,10 @@ public:
   L1FieldRegion() = default;
   
   L1FieldRegion(float reg[10]) noexcept;
-
+  
+  /// Consistency checker
+  void CheckConsistency() const;
+  
   /// Gets the field vector at z
   // TODO: Probably we need a const specifier here, because the method does not change the fields
   L1FieldValue Get(const fvec z);
diff --git a/reco/L1/L1Algo/L1InitManager.cxx b/reco/L1/L1Algo/L1InitManager.cxx
index b4ac3de902..b621b83004 100644
--- a/reco/L1/L1Algo/L1InitManager.cxx
+++ b/reco/L1/L1Algo/L1InitManager.cxx
@@ -15,9 +15,6 @@
 #include <sstream>
 
 #include "L1Assert.h"
-//-----------------------------------------------------------------------------------------------------------------------
-//
-L1InitManager::L1InitManager(L1Parameters* pParameters) {}
 
 //-----------------------------------------------------------------------------------------------------------------------
 //
@@ -128,7 +125,9 @@ void L1InitManager::FormParametersContainer()
     fStationsInfo.insert(std::move(node));
     ++thickMapIt;
   }
-  //LOG(info) << "L1InitManager: L1Material vector was successfully transfered to L1Algo core";
+  
+  // Check the consistency of the parameters object. If object inconsistent, it throws std::logic_error
+  fParameters.CheckConsistency();
 }
 
 //-----------------------------------------------------------------------------------------------------------------------
diff --git a/reco/L1/L1Algo/L1InitManager.h b/reco/L1/L1Algo/L1InitManager.h
index f98a03d640..2925d7cceb 100644
--- a/reco/L1/L1Algo/L1InitManager.h
+++ b/reco/L1/L1Algo/L1InitManager.h
@@ -94,10 +94,7 @@ private:
 
 public:
   /// Default constructor
-  L1InitManager() = delete;
-
-  /// Constructor from ptr to L1Paramters object
-  L1InitManager(L1Parameters* pParameters);
+  L1InitManager() = default;
 
   /// Destructor
   ~L1InitManager() = default;
diff --git a/reco/L1/L1Algo/L1MaterialInfo.cxx b/reco/L1/L1Algo/L1MaterialInfo.cxx
index 7a367a66fb..915c367311 100644
--- a/reco/L1/L1Algo/L1MaterialInfo.cxx
+++ b/reco/L1/L1Algo/L1MaterialInfo.cxx
@@ -7,6 +7,7 @@
 #include <iomanip>
 #include <sstream>
 #include <vector>
+#include <FairLogger.h>
 
 /************************
  * L1MaterialInfo class *
@@ -18,13 +19,49 @@ std::string L1MaterialInfo::ToString(int indentLevel) const
   // TODO: possibly it is better to place indentChar into L1Parameters (S.Zharko)
   constexpr char indentChar = '\t';
   std::string indent(indentLevel, indentChar);
-  aStream << indent << "Station thickness (X) [??]:  " << std::setw(12) << std::setfill(' ') << thick[0] << '\n';
-  aStream << indent << "Radiation length (X0) [??]:  " << std::setw(12) << std::setfill(' ') << RL[0] << '\n';
+  aStream << indent << "Station thickness (X) [cm]:  " << std::setw(12) << std::setfill(' ') << thick[0] << '\n';
+  aStream << indent << "Radiation length (X0) [cm]:  " << std::setw(12) << std::setfill(' ') << RL[0] << '\n';
   aStream << indent << "X/X0:                        " << std::setw(12) << std::setfill(' ') << RadThick[0] << '\n';
   aStream << indent << "log(X/X0):                   " << std::setw(12) << std::setfill(' ') << logRadThick[0];
   return aStream.str();
 }
 
+
+
+//------------------------------------------------------------------------------------------------------------------------------------
+//
+void L1MaterialInfo::CheckConsistency() const
+{
+  /* (i) Checks for the horizontal equality of elements */
+  L1Utils::CheckSimdVectorEquality(thick, "L1MaterialInfo::thick");
+  L1Utils::CheckSimdVectorEquality(RL, "L1MaterialInfo::RL");
+  L1Utils::CheckSimdVectorEquality(RadThick, "L1MaterialInfo::RadThick");
+  L1Utils::CheckSimdVectorEquality(logRadThick, "L1MaterialInfo::logRadThick");
+  
+  /* (ii) Checks for physical sence: thick and RL must be larger then 0. */
+  if (thick[0] < fscal(0.) || L1Utils::CmpFloats(thick[0], fscal(0.))) {
+    std::stringstream aStream;
+    aStream <<"L1MaterialInfo: illegal value for station thickness: (" << thick[0] << ", positive value expected) [cm]";
+    throw std::logic_error(aStream.str());
+  }
+
+  if (RL[0] < fscal(0.) || L1Utils::CmpFloats(RL[0], fscal(0.))) {
+    std::stringstream aStream;
+    aStream <<"L1MaterialInfo: illegal value for station radiation length: (" << RL[0] << ", positive value expected) [cm]";
+    throw std::logic_error(aStream.str());
+  }
+
+  /* (iii) Checks for RadThick and logRadThick */
+  if (!L1Utils::CmpFloats(RadThick[0] * RL[0], thick[0])) {
+    throw std::logic_error("L1MaterialInfo: illegal relation between thickness, radiation length and their ratio (RadThick)");
+  }
+
+  if (!L1Utils::CmpFloats(std::exp(logRadThick[0]), RadThick[0])) {
+    throw std::logic_error("L1MaterialInfo: illegal relation between RadThick and logRadThick data fields");
+  }
+}
+
+
 /********************
  * L1Material class *
  ********************/
@@ -33,7 +70,8 @@ L1Material::L1Material() {}
 
 //------------------------------------------------------------------------------------------------------------------------------------
 //
-L1Material::~L1Material() noexcept {}
+L1Material::~L1Material()
+{}
 
 //------------------------------------------------------------------------------------------------------------------------------------
 //
@@ -101,14 +139,48 @@ fvec L1Material::GetRadThick(fvec x, fvec y) const
   return r;
 }
 
+
+//------------------------------------------------------------------------------------------------------------------------------------
+//
+void L1Material::CheckConsistency() const
+{
+  /* (i) Check, if the object was initialized */
+  if (fNbins < 1 || std::isnan(fRmax)) {
+    throw std::logic_error("L1Material: class was not initialized");
+  }
+
+  /* (ii) Check if the thickness values correct (non-negative) */
+  bool isThicknessOk = true;
+  for (int i = 0; i < int(fTable.size()); ++i) {
+    if (fTable[i] < 0) {
+      isThicknessOk = false;
+      LOG(error) << "L1Material: found illegal negative station thickness value " << fTable[i] << " at iBinX = " << (i % fNbins) 
+                 << ", iBin = " << (i / fNbins);
+    }
+  }
+  if (!isThicknessOk) { throw std::logic_error("L1Material: incorrect station thickness values found in the thickness map"); }
+}
+
 //------------------------------------------------------------------------------------------------------------------------------------
 //
 void L1Material::SetBins(int nBins, float stationSize)
 {
   fNbins  = nBins;
   fRmax   = stationSize;
-  fFactor = 0.5 * fNbins / fRmax;
+  
+  if (fNbins < 1) {
+    std::stringstream aStream;
+    aStream <<"L1Material: object cannot be initialized with non-positive nBins = " << nBins;
+    throw std::logic_error(aStream.str());
+  }
 
+  if (stationSize < 0 || L1Utils::CmpFloats(stationSize, 0.f)) {
+    std::stringstream aStream;
+    aStream << "L1Material: object cannot be initialized with non-positive stationStation = " << stationSize << " [cm]";
+    throw std::logic_error(aStream.str());
+  }
+
+  fFactor = 0.5 * fNbins / fRmax;
   fTable.resize(fNbins * fNbins);
 }
 
diff --git a/reco/L1/L1Algo/L1MaterialInfo.h b/reco/L1/L1Algo/L1MaterialInfo.h
index 762d048281..85f17a6f70 100644
--- a/reco/L1/L1Algo/L1MaterialInfo.h
+++ b/reco/L1/L1Algo/L1MaterialInfo.h
@@ -11,15 +11,19 @@
 #include <vector>
 
 #include "L1Def.h"
+#include "L1Utils.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 {0};     ///< Average thickness of the station in arbitary length units
-  fvec RL {0};        ///< Average radiation length (X0) of the station material in THE SAME UNITS as the thickness
-  fvec RadThick {0};  ///< Average thickness in units of radiation length (X/X0)
-  fvec logRadThick {0};
+  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};
+  
+  /// Verifies class invariant consistency
+  void CheckConsistency() const;
 
   /// String representation of class contents
   /// \param indentLevel    number of indent characters in the output
@@ -29,7 +33,9 @@ struct L1MaterialInfo {
 /// Class L1Material describes a map of station thickness in units of radiation length (X0) to the specific point in XY plane
 class L1Material {
 public:
-  /// Default constructor
+  /// Constructor
+  /// \param  nBins        Number of rows or columns
+  /// \param  stationSize  Size of station in x and y dimensions [cm]
   L1Material();
 
   /// Copy constructor
@@ -64,6 +70,9 @@ 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;
+  
+  /// Verifies class invariant consistency
+  void CheckConsistency() const;
 
   /// Sets value of material thickness in units of X0 for a given cell of the material table
   /// WARNING: Indeces of rows and columns in the table runs from 0 to nBins-1 inclusively, where nBins is the number both of rows
@@ -83,9 +92,9 @@ public:
   void Swap(L1Material& other) noexcept;
 
 private:
-  int fNbins {0};                ///< Number of rows (columns) in the material budget table
-  float fRmax {0.f};             ///< Size of the station in x and y dimensions [cm]
-  float fFactor {0.f};           ///< Factor used in the recalculation of point coordinates to row/column id
+  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
   std::vector<float> fTable {};  ///< Material budget table
 } _fvecalignment;
 
diff --git a/reco/L1/L1Algo/L1Parameters.cxx b/reco/L1/L1Algo/L1Parameters.cxx
index d89191e183..8f395aedc6 100644
--- a/reco/L1/L1Algo/L1Parameters.cxx
+++ b/reco/L1/L1Algo/L1Parameters.cxx
@@ -14,7 +14,10 @@
 
 //------------------------------------------------------------------------------------------------------------------------------------
 //
-L1Parameters::L1Parameters() {}
+L1Parameters::L1Parameters() 
+{
+  fActiveStationGlobalIDs.fill(-1); // by default, all stations are inactive, thus all the IDs must be -1
+}
 
 //------------------------------------------------------------------------------------------------------------------------------------
 //
@@ -77,26 +80,118 @@ void L1Parameters::Swap(L1Parameters& other) noexcept
   std::swap(fNstationsActive, other.fNstationsActive);
   std::swap(fNstationsGeometry, other.fNstationsGeometry);
   std::swap(fActiveStationGlobalIDs, other.fActiveStationGlobalIDs);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------
+//
+void L1Parameters::CheckConsistency() const {
+  LOG(info) << "Consistency test for L1 parameters object... ";
+  /*
+   * Arrays containing numbers of stations
+   *
+   * In the fNstationsActive and fNstationsGeometry array first L1Constants::size::kMaxNdetectors elements are the numbers of stations
+   * in particular detector subsystem. The last element in both arrays corresponds to the total number of stations (geometry or 
+   * active). This fact applies restriction on the arrays: the last element must be equal to the sum of all previous elements.
+   *
+   */
+  
+  if (std::accumulate(fNstationsGeometry.cbegin(), fNstationsGeometry.cend() - 1, 0) != *(fNstationsGeometry.cend() - 1)) { 
+    throw std::logic_error("L1Parameters: invalid object condition: total number of stations provided by geometry "
+                           "differs from the sum of the station numbers for individual detector subsystems");
+  };
+  
+  if (std::accumulate(fNstationsActive.cbegin(), fNstationsActive.cend() - 1, 0) != *(fNstationsActive.cend() - 1)) { 
+    throw std::logic_error("L1Parameters: invalid object condition: total number of stations active in tracking "
+                           "differs from the sum of the station numbers for individual detector subsystems");
+  };
+
+  /*
+   * Array of active station IDs
+   *
+   * In the array of active station IDs, 
+   *   (i)   sum of elements, which are not equal -1, must be equal the number of stations,
+   *   (ii)  subsequence of all the elements, which are not equal -1, must be a gapless subset of integer numbers starting with 0
+   */
+
+  auto filterInactiveStationIDs = [](int x) {return x != -1;};
+  int nStationsCheck = std::count_if(fActiveStationGlobalIDs.cbegin(), fActiveStationGlobalIDs.cend(), filterInactiveStationIDs);
+  if (nStationsCheck != *(fNstationsActive.cend() - 1)) {
+    std::stringstream msg;
+    msg << "L1Parameters: invalid object condition: array of active station IDs is not consistent "
+        << "with the total number of stations (" << nStationsCheck << " vs. " << *(fNstationsActive.cend() - 1) << ' '
+        << "expected)";
+    throw std::logic_error(msg.str());
+  }
+
+  // Check, if the subsequence of all the elements, which are not equal -1, must be a gapless subset of integer numbers 
+  // starting from 0. If it is, the testValue in the end must be equal the number of non -1 elements
+
+  std::vector<int> idsCheck(nStationsCheck); // temporary vector containing a sequence of active station IDs without -1 elements
+  std::copy_if(fActiveStationGlobalIDs.cbegin(), fActiveStationGlobalIDs.cend(), idsCheck.begin(), filterInactiveStationIDs);
+  bool isStationIDsOk = true;
+  for (int id = 0; id < nStationsCheck; ++id) { 
+    isStationIDsOk = isStationIDsOk && idsCheck[id] == id; 
+  }
+  if (!isStationIDsOk) {
+    std::stringstream msg;
+    msg << "L1Parameters: invalid object condition: array of active station IDs is not a gapless subset "
+        << "of integer numbers starting from 0:\n\t";
+    for (auto id: fActiveStationGlobalIDs) { 
+      msg << std::setw(3) << std::setfill(' ') << id << ' '; 
+    }
+    throw std::logic_error(msg.str());
+  }
+
+  /*
+   * Check target position SIMD vector
+   */
+
+  L1Utils::CheckSimdVectorEquality(fTargetPos[0], "L1Parameters: target position x");
+  L1Utils::CheckSimdVectorEquality(fTargetPos[1], "L1Parameters: target position y");
+  L1Utils::CheckSimdVectorEquality(fTargetPos[2], "L1Parameters: target position z");
+  
+  /*
+   * Check vertex field region and value objects at primary vertex
+   */
+
+  fVertexFieldValue.CheckConsistency();
+  fVertexFieldRegion.CheckConsistency();
+
+
+  /*
+   * Check if each station object is consistent itself, and if all of them are placed after the target
+   * NOTE: If a station was not set up, it is accounted inconsistent (uninitialized). In the array of stations there are uninitialized
+   *       stations possible (with id > NstationsActiveTotal), thus one should NOT run the loop above over all the stations in array
+   *       but only until *(fNstationsActive.cend() - 1) (== NstationsActiveTotal).
+   * TODO: Probably, we should introduce methods, which check the consistency of fully initialized objects such as L1Station,
+   *       L1MaterialInfo, etc. (S.Zharko)
+   */
 
-  //for (int i = 0; i < int(L1Constants::size::kMaxNstations); ++i) {
-  //  int tmp = fActiveStationGlobalIDs[i];
-  //  fActiveStationGlobalIDs[i] = other.fActiveStationGlobalIDs[i];
-  //  other.fActiveStationGlobalIDs[i] = tmp;
-  //}
-
-  //for (int i = 0; i < int(L1Constants::size::kMaxNdetectors + 1); ++i) {
-  //  int tmp = fNstationsGeometry[i];
-  //  fNstationsGeometry[i] = other.fNstationsGeometry[i];
-  //  other.fNstationsGeometry[i] = tmp;
-  //}
-
-  //for (int i = 0; i < int(L1Constants::size::kMaxNdetectors + 1); ++i) {
-  //  int tmp = fNstationsActive[i];
-  //  fNstationsActive[i] = other.fNstationsActive[i];
-  //  other.fNstationsActive[i] = tmp;
-  //}
+  for (int iSt = 0; iSt < *(fNstationsActive.cend() - 1); ++iSt) {
+    fStations[iSt].CheckConsistency();
+    if (fStations[iSt].z[0] < fTargetPos[2][0]) {
+      std::stringstream msg;
+      msg << "L1Parameters: station with global ID = " << iSt << " is placed before target "
+          << "(z_st = " << fStations[iSt].z[0] << " [cm] < z_targ = " << fTargetPos[2][0] << " [cm])";
+      throw std::logic_error(msg.str());
+    }
+  }
+  
+  /*
+   * Check thickness maps
+   * NOTE: If a L1Material map was not set up, it is accounted inconsistent (uninitialized). In the array of thickness maps for each 
+   *       there are uninitialized elements possible (with id > NstationsActiveTotal), thus one should NOT run the loop above over 
+   *       all the stations in array but only until *(fNstationsActive.cend() - 1) (== NstationsActiveTotal).
+   */
+
+  for (int iSt = 0; iSt < *(fNstationsActive.cend() - 1); ++iSt) {
+    fThickMap[iSt].CheckConsistency();
+  }
+
+  LOG(info) << "Consistency test for L1 parameters object... \033[1;32mpassed\033[0m";
 }
 
+
 //------------------------------------------------------------------------------------------------------------------------------------
 //
 void L1Parameters::Print(int /*verbosityLevel*/) const
@@ -130,26 +225,25 @@ std::string L1Parameters::ToString(int verbosity, int indentLevel) const
   aStream << indent << "GEOMETRY:\n";
   
   aStream << indent << indentChar << "TARGET:\n";
-  aStream << indent << indentChar << indentChar << "Position (x [cm], y [cm], z[cm]): ";
+  aStream << indent << indentChar << indentChar << "Position:\n";
   for (int dim = 0; dim < 3 /*nDimensions*/; ++dim ) {
-    aStream << std::setw(12) << std::setfill(' ') << fTargetPos[dim][0] << ' ';
+    aStream << indent << indentChar << indentChar << indentChar << char(120 + dim) << " = " << fTargetPos[dim][0] << " [cm]\n";
   }
-  aStream << '\n';
   
   aStream << indent << indentChar << "NUMBER OF STATIONS:\n";
   aStream << indent << indentChar << indentChar << "Number of stations (Geometry): ";
   for (int idx = 0; idx < int(fNstationsGeometry.size()); ++idx ) {
-    if (int(fNstationsGeometry.size() - 2) == idx) { aStream << " | total = "; }
+    if (int(fNstationsGeometry.size() - 1) == idx) { aStream << " | total = "; }
     aStream << std::setw(2) << std::setfill(' ') << fNstationsGeometry[idx] << ' ';
   }
   aStream << '\n';
-  aStream << indent << indentChar << indentChar << "Number of stations (Active): ";
+  aStream << indent << indentChar << indentChar << "Number of stations (Active):   ";
   for (int idx = 0; idx < int(fNstationsActive.size()); ++idx ) {
-    if (int(fNstationsActive.size() - 2) == idx) { aStream << " | total = "; }
+    if (int(fNstationsActive.size() - 1) == idx) { aStream << " | total = "; }
     aStream << std::setw(2) << std::setfill(' ') << fNstationsActive[idx] << ' ';
   }
   aStream << '\n';
-  aStream << indent << indentChar << indentChar << "Active station index: ";
+  aStream << indent << indentChar << indentChar << "Active station indeces: ";
   for (int idx = 0; idx < *(fNstationsActive.end() - 1); ++idx ) {
     aStream << std::setw(3) << std::setfill(' ') << fActiveStationGlobalIDs[idx] << ' ';
   }
diff --git a/reco/L1/L1Algo/L1Parameters.h b/reco/L1/L1Algo/L1Parameters.h
index 5fc1873b66..59d869d81c 100644
--- a/reco/L1/L1Algo/L1Parameters.h
+++ b/reco/L1/L1Algo/L1Parameters.h
@@ -155,6 +155,8 @@ public:
   /// Gets L1FieldValue object at primary vertex
   const L1FieldValue& GetVertexFieldValue() const { return fVertexFieldValue; }
 
+  /// Class invariant checker
+  void CheckConsistency() const;
 
 private:
   
@@ -172,7 +174,7 @@ private:
   /// Field value object at primary vertex (between target and the first station)
   alignas(L1Constants::misc::kAlignment) L1FieldValue fVertexFieldValue {};
   
-  /// Field value object at primary vertex (between target and the first station)
+  /// Field region object at primary vertex (between target and the first station)
   alignas(L1Constants::misc::kAlignment) L1FieldRegion fVertexFieldRegion {};
 
   /// Array of stations 
diff --git a/reco/L1/L1Algo/L1Station.cxx b/reco/L1/L1Algo/L1Station.cxx
index 30941e3a5d..3d242286fe 100644
--- a/reco/L1/L1Algo/L1Station.cxx
+++ b/reco/L1/L1Algo/L1Station.cxx
@@ -9,9 +9,87 @@
 #include <iomanip>
 #include <sstream>
 
+//------------------------------------------------------------------------------------------------------------------------------------
+//
+void L1Station::CheckConsistency() const
+{
+  /*
+   * Integer fields initialization checks
+   */
+
+  if (type < 0) {
+    std::stringstream msg;
+    msg << "L1Station: station type was not initialized (type = " << type << ", type > 0)";
+    throw std::logic_error(msg.str());
+  }
+
+  if (timeInfo != 0 && timeInfo != 1) {
+    std::stringstream msg;
+    msg << "L1Station: illegal time information flag (timeInfo = " << timeInfo << ", " 
+        << "0 [time information is not used] or 1 [time information is used] expected)";
+    throw std::logic_error(msg.str());
+  }
+
+  if (fieldStatus != 0 && fieldStatus != 1) {
+    std::stringstream msg;
+    msg << "L1Station: illegal field status flag (fieldStatus = " << fieldStatus << ", "
+        << "0 [station is outside the field] or 1 [station is inside the field] expected";
+    throw std::logic_error(msg.str());
+  }
+  
+  /*
+   * SIMD vector checks: all the words in a SIMD vector must be equal
+   */
+
+  L1Utils::CheckSimdVectorEquality(z, "L1Station::z");
+  L1Utils::CheckSimdVectorEquality(Rmin, "L1Station::Rmin");
+  L1Utils::CheckSimdVectorEquality(Rmax, "L1Station::Rmax");
+  L1Utils::CheckSimdVectorEquality(dt, "L1Station::dt");
+  
+  /*
+   * Inner and outer radia checks:
+   *  (i)  both Rmin and Rmax must be >= 0
+   *  (ii) Rmax cannot be smaller or equal to Rmin
+   */
+
+  if (Rmin[0] < 0 || L1Utils::CmpFloats(Rmin[0], Rmax[0]) || Rmax[0] < Rmin[0]) {
+    std::stringstream msg;
+    msg << "L1Station: " << this->ToString() << " has incorrect radia values: "
+        << "Rmin = " << Rmin[0] << " [cm], Rmax = " << Rmax[0] << " [cm] (0 <= Rmin < Rmax expected)";
+    throw std::logic_error(msg.str());
+  }
+
+  /*
+   * Time resolution cannot be smaller then 0
+   */
+    
+  if (dt[0] < 0) {
+    std::stringstream msg;
+    msg << "L1Station: " << this->ToString() << " has incorrect time resolution value: "
+        << "dt = " << Rmin[0] << " [ns], Rmax = " << Rmax[0] << " [cm] (0 <= Rmin < Rmax expected)";
+    throw std::logic_error(msg.str());
+  }
+
+  /*
+   * Check consistency of other members
+   */
+  
+  materialInfo.CheckConsistency();
+  fieldSlice.CheckConsistency();
+  frontInfo.CheckConsistency();
+  backInfo.CheckConsistency();
+  xInfo.CheckConsistency();
+  yInfo.CheckConsistency();
+  XYInfo.CheckConsistency();
+}
+
 // TODO: Improve log style (S.Zh.)
+//------------------------------------------------------------------------------------------------------------------------------------
+//
 void L1Station::Print(int verbosity) const { LOG(info) << ToString(verbosity); }
 
+//------------------------------------------------------------------------------------------------------------------------------------
+//
 std::string L1Station::ToString(int verbosityLevel, int indentLevel) const
 {
   std::stringstream aStream {};
@@ -19,13 +97,12 @@ std::string L1Station::ToString(int verbosityLevel, int indentLevel) const
   std::string indent(indentLevel, indentChar);
   if (verbosityLevel > 1) {
     // TODO: probably we can have verbosity level and address for each underlying object (S.Zharko)
-    aStream << '\n' << indent << "Address: " << this << '\n';
   }
   if (verbosityLevel == 0) {
-    aStream << indent << "- <z [cm], typeID> = " << std::setw(12) << std::setfill(' ') << z[0] << ", " << std::setw(4)
-            << std::setfill(' ') << type;
+    aStream << "L1Station at z = " << z[0] << " [cm]" ;
   }
   else {
+    aStream << '\n' << indent << "Address: " << this << '\n';
     aStream << indent << "Station type ID:  " << std::setw(12) << std::setfill(' ') << type << '\n';
     aStream << indent << "Is time info used:           " << std::setw(12) << std::setfill(' ') << timeInfo << '\n';
     aStream << indent << "Is station placed in field:  " << std::setw(12) << std::setfill(' ') << fieldStatus << '\n';
diff --git a/reco/L1/L1Algo/L1Station.h b/reco/L1/L1Algo/L1Station.h
index 7b7d426288..8a8a51f706 100644
--- a/reco/L1/L1Algo/L1Station.h
+++ b/reco/L1/L1Algo/L1Station.h
@@ -11,20 +11,21 @@
 #include "L1MaterialInfo.h"
 #include "L1UMeasurementInfo.h"
 #include "L1XYMeasurementInfo.h"
+#include "L1Utils.h"
 
 /// Structure L1Station
 /// Contains a set of geometry parameters for a particular station
 ///
 struct L1Station {
-  int type {0};
-  int timeInfo {0};     ///< flag: if time information can be used
-  int fieldStatus {0};  ///< flag: 1 - station is INSIDE the field, 0 - station is OUTSIDE the field
-  fvec z {0};           ///< z position of station
-  fvec Rmin {0};        ///< min radius of the station
-  fvec Rmax {0};        ///< max radius of the station
-  fvec dt {0};
-  L1MaterialInfo materialInfo {};
-  L1FieldSlice fieldSlice {};
+  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
+  L1FieldSlice fieldSlice {};      
   L1UMeasurementInfo frontInfo {};
   L1UMeasurementInfo backInfo {};
   L1UMeasurementInfo xInfo {};
@@ -34,11 +35,17 @@ struct L1Station {
   /// Prints object fields
   /// \param verbosity  Verbosity level of the output
   void Print(int verbosity = 0) const;
+  
   /// String representation of class contents
   /// \param verbosityLevel  Verbosity level of the output
   /// \param indentLevel     Number of indent characters in the output
   std::string ToString(int verbosityLevel = 0, int indentLevel = 0) const;
 
+  /// Verifies class invariant consistency
+  /// \note Object is considered undefined in the creation time, so this function should be called after the object
+  /// initialization
+  void CheckConsistency() const;
+
 } _fvecalignment;
 
 #endif  // L1Station_h
diff --git a/reco/L1/L1Algo/L1UMeasurementInfo.cxx b/reco/L1/L1Algo/L1UMeasurementInfo.cxx
index a53f7a5b61..2f8992f2be 100644
--- a/reco/L1/L1Algo/L1UMeasurementInfo.cxx
+++ b/reco/L1/L1Algo/L1UMeasurementInfo.cxx
@@ -7,6 +7,8 @@
 #include <iomanip>
 #include <sstream>
 
+//----------------------------------------------------------------------------------------------------------------------
+//
 std::string L1UMeasurementInfo::ToString(int indentLevel) const
 {
   std::stringstream aStream {};
@@ -15,6 +17,23 @@ std::string L1UMeasurementInfo::ToString(int indentLevel) const
   std::string indent(indentLevel, indentChar);
   aStream << indent << "cos(phi):    " << std::setw(12) << std::setfill(' ') << cos_phi[0] << '\n';
   aStream << indent << "sin(phi):    " << std::setw(12) << std::setfill(' ') << sin_phi[0] << '\n';
-  aStream << indent << "sigma2 [??]: " << std::setw(12) << std::setfill(' ') << sigma2[0];
+  aStream << indent << "sigma2 [cm2]: " << std::setw(12) << std::setfill(' ') << sigma2[0];
   return aStream.str();
 }
+
+//----------------------------------------------------------------------------------------------------------------------
+//
+void L1UMeasurementInfo::CheckConsistency() const
+{
+  /* (i) Checks for the horizontal equality of SIMD vector elements */
+  L1Utils::CheckSimdVectorEquality(cos_phi, "L1UMeasurementsInfo::cos_phi");
+  L1Utils::CheckSimdVectorEquality(sin_phi, "L1UMeasurementsInfo::sin_phi");
+  L1Utils::CheckSimdVectorEquality(sigma2, "L1UMeasurementsInfo::sigma2");
+  
+  /*(ii) Sigma2 possible values*/
+  if (sigma2[0] < 0) {
+    std::stringstream msg;
+    msg << "L1UMeasurementsInfo: illegal value of sigma2: " << sigma2[0] << " [cm2] (sigma2 >= 0 excepted)";
+    throw std::logic_error(msg.str());
+  }
+}
diff --git a/reco/L1/L1Algo/L1UMeasurementInfo.h b/reco/L1/L1Algo/L1UMeasurementInfo.h
index 3e3423eaf2..3a33617d2a 100644
--- a/reco/L1/L1Algo/L1UMeasurementInfo.h
+++ b/reco/L1/L1Algo/L1UMeasurementInfo.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "L1Utils.h"
 #include "L1Def.h"
 
 class L1UMeasurementInfo {
@@ -15,10 +16,14 @@ public:
   fvec cos_phi {0.f};
   fvec sin_phi {0.f};
   fvec sigma2 {0.f};
+  
   /// String representation of class contents
   /// \param indentLevel      number of indent characters in the output
   std::string ToString(int indentLevel = 0) const;
 
+  /// Check consistency
+  void CheckConsistency() const;
+
 } _fvecalignment;
 
 
diff --git a/reco/L1/L1Algo/L1Utils.h b/reco/L1/L1Algo/L1Utils.h
index f47260906e..fee4f61e52 100644
--- a/reco/L1/L1Algo/L1Utils.h
+++ b/reco/L1/L1Algo/L1Utils.h
@@ -13,16 +13,41 @@
 #include <iomanip>
 #include <limits>
 #include <map>
+#include <cmath>
 #include <sstream>
 #include <string>
 #include <unordered_map>
 
+#include "vectors/P4_F32vec4.h"
+
 /// Class contains some utility functions for L1Algo
 struct L1Utils {
 
-  /// Some constants
+  /// NaN value for float
   static constexpr float kNaN {std::numeric_limits<float>::signaling_NaN()};
 
+  /// Comparison method for floats
+  /// \param  lhs  Left floating point to compare
+  /// \param  rhs  Right floating point to compare
+  /// \return      Comparison result: true - equals within epsilon 
+  template <typename T> 
+  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();
+  }
+
+
+  static __attribute__((always_inline)) void CheckSimdVectorEquality(fvec v, const char* name)
+  {
+    if (!v.IsHorizontallyEqual()) {
+      std::stringstream msg;
+      msg << name << " SIMD vector is inconsistent, not all of the words are equal each other: " << v;
+      throw std::logic_error(msg.str());
+    }
+  }
+
   /// Hash for unordered_map with enum class keys
   struct EnumClassHash {
     template<typename T>
diff --git a/reco/L1/L1Algo/L1XYMeasurementInfo.cxx b/reco/L1/L1Algo/L1XYMeasurementInfo.cxx
index 07e3cdc92e..b8eba31513 100644
--- a/reco/L1/L1Algo/L1XYMeasurementInfo.cxx
+++ b/reco/L1/L1Algo/L1XYMeasurementInfo.cxx
@@ -3,10 +3,18 @@
    Authors: Sergey Gorbunov, Sergei Zharko [committer] */
 
 #include "L1XYMeasurementInfo.h"
-
+#include "L1Utils.h"
 #include <iomanip>
 #include <sstream>  // for stringstream
 
+void L1XYMeasurementInfo::CheckConsistency() const
+{
+  /* (i) Checks for the horizontal equality of SIMD vector elements */
+  L1Utils::CheckSimdVectorEquality(C00, "L1XYMeasurementsInfo::C00");
+  L1Utils::CheckSimdVectorEquality(C10, "L1XYMeasurementsInfo::C10");
+  L1Utils::CheckSimdVectorEquality(C11, "L1XYMeasurementsInfo::C11");
+}
+
 std::string L1XYMeasurementInfo::ToString(int indentLevel) const
 {
   std::stringstream aStream {};
diff --git a/reco/L1/L1Algo/L1XYMeasurementInfo.h b/reco/L1/L1Algo/L1XYMeasurementInfo.h
index 569a80d6a2..d8b7ac0c6b 100644
--- a/reco/L1/L1Algo/L1XYMeasurementInfo.h
+++ b/reco/L1/L1Algo/L1XYMeasurementInfo.h
@@ -15,10 +15,13 @@ public:
   fvec C00 {0};
   fvec C10 {0};
   fvec C11 {0};
+  
+  /// Consistency checker
+  void CheckConsistency() const;
+
   /// String representation of class contents
   /// \param indentLevel      number of indent characters in the output
   std::string ToString(int indentLevel = 0) const;
-
 } _fvecalignment;
 
 
diff --git a/reco/L1/vectors/P4_F32vec4.h b/reco/L1/vectors/P4_F32vec4.h
index cefaa3dc7c..1d22e5e241 100644
--- a/reco/L1/vectors/P4_F32vec4.h
+++ b/reco/L1/vectors/P4_F32vec4.h
@@ -228,6 +228,26 @@ public:
     return strm;
   }
 
+  /// Checks, if all bands are equal
+  /// NOTE: two values defined as signaling_NaN() are not equal, thus if there are all or one 
+  /// of the words are kNaN, the function returns false
+  bool IsHorizontallyEqual() const
+  {
+    return v[0] == v[1] && v[1] == v[2] && v[2] == v[3];
+  }
+
+  /// Checks, if any of the bands is NaN
+  bool IsNanAny() const
+  {
+    return std::isnan(v[0]) || std::isnan(v[1]) || std::isnan(v[2]) || std::isnan(v[3]);
+  }
+
+  /// Checks, if all of the bands is NaN
+  bool IsNanAll() const
+  {
+    return std::isnan(v[0]) && std::isnan(v[1]) && std::isnan(v[2]) && std::isnan(v[3]);
+  }
+
 } __attribute__((aligned(16)));
 
 
-- 
GitLab