From 9512d7fc4edc79fae3522564433b451e1b12cc44 Mon Sep 17 00:00:00 2001
From: Maarten van Veghel <mvegh@nikhef.nl>
Date: Wed, 23 Jun 2021 10:56:33 +0200
Subject: [PATCH 1/3] th3 support

---
 GaudiUtils/include/GaudiUtils/Histo2String.h |  78 ++++++++
 GaudiUtils/include/GaudiUtils/HistoParsers.h |  31 +++
 GaudiUtils/src/Lib/H1.h                      |  58 ++++++
 GaudiUtils/src/Lib/Histo2String.cpp          | 193 +++++++++++++++++++
 GaudiUtils/src/Lib/HistoParsers.cpp          | 180 +++++++++++++++++
 5 files changed, 540 insertions(+)

diff --git a/GaudiUtils/include/GaudiUtils/Histo2String.h b/GaudiUtils/include/GaudiUtils/Histo2String.h
index b860bc1ad4..5d3560bd56 100644
--- a/GaudiUtils/include/GaudiUtils/Histo2String.h
+++ b/GaudiUtils/include/GaudiUtils/Histo2String.h
@@ -31,14 +31,17 @@
 namespace AIDA {
   class IHistogram1D;
   class IHistogram2D;
+  class IHistogram3D;
 } // namespace AIDA
 // ============================================================================
 // ROOT
 // ============================================================================
 class TH1D; // ROOT
 class TH2D; // ROOT
+class TH3D; // ROOT
 class TH1F; // ROOT
 class TH2F; // ROOT
+class TH3F; // ROOT
 // ============================================================================
 namespace Gaudi {
   // ===========================================================================
@@ -64,6 +67,16 @@ namespace Gaudi {
      */
     GAUDI_API std::ostream& toStream( const TH2D& histo, std::ostream& stream, const bool asXML = false );
     // =========================================================================
+    /** stream the ROOT histogram into output stream
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param stream (OUTPUT) the stream
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the updated stream
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::ostream& toStream( const TH3D& histo, std::ostream& stream, const bool asXML = false );
+    // =========================================================================
     /** stream the ROOT histogram into output stream
      *  @param histo  (INPUT)  the histogram to be streamed
      *  @param stream (OUTPUT) the stream
@@ -84,6 +97,16 @@ namespace Gaudi {
      */
     GAUDI_API std::ostream& toStream( const TH2F& histo, std::ostream& stream, const bool asXML = false );
     // ========================================================================
+    /** stream the AIDA histogram into output stream
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param stream (OUTPUT) the stream
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the updated stream
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::ostream& toStream( const TH3F& histo, std::ostream& stream, const bool asXML = false );
+    // ========================================================================
     /** stream the AIDA histogram into output stream
      *  @param histo  (INPUT)  the histogram to be streamed
      *  @param stream (OUTPUT) the stream
@@ -104,6 +127,16 @@ namespace Gaudi {
      */
     GAUDI_API std::ostream& toStream( const AIDA::IHistogram2D& histo, std::ostream& stream, const bool asXML = false );
     // ========================================================================
+    /** stream the AIDA histogram into output stream
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param stream (OUTPUT) the stream
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the updated stream
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::ostream& toStream( const AIDA::IHistogram3D& histo, std::ostream& stream, const bool asXML = false );
+    // ========================================================================
     /** convert the histogram into the string
      *  @param histo  (INPUT)  the histogram to be streamed
      *  @param asXML  (INPUT)  use XML-format
@@ -122,6 +155,15 @@ namespace Gaudi {
      */
     GAUDI_API std::string toString( const TH2D& histo, const bool asXML = false );
     // ========================================================================
+    /** convert the histogram into the string
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the string representation of the histogram
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::string toString( const TH3D& histo, const bool asXML = false );
+    // ========================================================================
     /** convert the histogram into the string
      *  @param histo  (INPUT)  the histogram to be streamed
      *  @param asXML  (INPUT)  use XML-format
@@ -140,6 +182,15 @@ namespace Gaudi {
      */
     GAUDI_API std::string toString( const TH2F& histo, const bool asXML = false );
     // ========================================================================
+    /** convert the histogram into the string
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the string representation of the histogram
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::string toString( const TH3F& histo, const bool asXML = false );
+    // ========================================================================
     /** convert the histogram into the string
      *  @param histo  (INPUT)  the histogram to be streamed
      *  @param asXML  (INPUT)  use XML-format
@@ -158,6 +209,15 @@ namespace Gaudi {
      */
     GAUDI_API std::string toString( const AIDA::IHistogram2D& histo, const bool asXML = false );
     // ========================================================================
+    /** convert the histogram into the string
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the string representation of the histogram
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::string toString( const AIDA::IHistogram3D& histo, const bool asXML = false );
+    // ========================================================================
     /** convert the histogram into the string
      *  @param histo  (INPUT)  the histogram to be streamed
      *  @param asXML  (INPUT)  use XML-format
@@ -212,6 +272,24 @@ namespace Gaudi {
      */
     GAUDI_API std::string toString( TH2D* histo );
     // ========================================================================
+    /** convert the histogram into the string
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the string representation of the histogram
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::string toString( const TH3D* histo );
+    // ========================================================================
+    /** convert the histogram into the string
+     *  @param histo  (INPUT)  the histogram to be streamed
+     *  @param asXML  (INPUT)  use XML-format
+     *  @return the string representation of the histogram
+     *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+     *  @date 2009-09-26
+     */
+    GAUDI_API std::string toString( TH3D* histo );
+    // ========================================================================
   } // namespace Utils
   // ==========================================================================
 } //                                                     end of namespace Gaudi
diff --git a/GaudiUtils/include/GaudiUtils/HistoParsers.h b/GaudiUtils/include/GaudiUtils/HistoParsers.h
index e2e831ec68..b920994403 100644
--- a/GaudiUtils/include/GaudiUtils/HistoParsers.h
+++ b/GaudiUtils/include/GaudiUtils/HistoParsers.h
@@ -24,14 +24,17 @@
 namespace AIDA {
   class IHistogram1D; // AIDA
   class IHistogram2D; // AIDA
+  class IHistogram3D;
 } // namespace AIDA
 // =============================================================================
 // ROOT
 // =============================================================================
 class TH1D; // ROOT
 class TH2D; // ROOT
+class TH3D; // ROOT
 class TH1F; // ROOT
 class TH2F; // ROOT
+class TH3F; // ROOT
 // =============================================================================
 namespace Gaudi {
   // ===========================================================================
@@ -51,6 +54,13 @@ namespace Gaudi {
      */
     GAUDI_API StatusCode parse( TH2D& result, const std::string& input );
     // =========================================================================
+    /** parse ROOT histogram from text representation
+     *  @param result (OUTPUT) the histogram
+     *  @param input  (INPUT)  the input to be parsed
+     *  @return status code
+     */
+    GAUDI_API StatusCode parse( TH3D& result, const std::string& input );
+    // =========================================================================
     /** parse ROOT histogram from text representation
      *  @param result (OUTPUT) the histogram
      *  @param input  (INPUT)  the input to be parsed
@@ -65,6 +75,13 @@ namespace Gaudi {
      */
     GAUDI_API StatusCode parse( TH2F& result, const std::string& input );
     // =========================================================================
+    /** parse AIDA histogram from text representation
+     *  @param result (OUTPUT) the histogram
+     *  @param input  (INPUT)  the input to be parsed
+     *  @return status code
+     */
+    GAUDI_API StatusCode parse( TH3F& result, const std::string& input );
+    // =========================================================================
     /** parse AIDA histogram from text representation
      *  @param result (OUTPUT) the histogram
      *  @param input  (INPUT)  the input to be parsed
@@ -79,6 +96,13 @@ namespace Gaudi {
      */
     GAUDI_API StatusCode parse( AIDA::IHistogram2D& result, const std::string& input );
     // =========================================================================
+    /** parse AIDA histogram from text representation
+     *  @param result (OUTPUT) the histogram
+     *  @param input  (INPUT)  the input to be parsed
+     *  @return status code
+     */
+    GAUDI_API StatusCode parse( AIDA::IHistogram3D& result, const std::string& input );
+    // =========================================================================
     /** parse ROOT histogram from text representation
      *  @param result (OUTPUT) the histogram
      *  @param input  (INPUT)  the input to be parsed
@@ -93,6 +117,13 @@ namespace Gaudi {
      */
     GAUDI_API StatusCode parse( TH2D*& result, const std::string& input );
     // =========================================================================
+    /** parse ROOT histogram from text representation
+     *  @param result (OUTPUT) the histogram
+     *  @param input  (INPUT)  the input to be parsed
+     *  @return status code
+     */
+    GAUDI_API StatusCode parse( TH3D*& result, const std::string& input );
+    // =========================================================================
   } // namespace Parsers
   // ===========================================================================
 } // end of namespace Gaudi
diff --git a/GaudiUtils/src/Lib/H1.h b/GaudiUtils/src/Lib/H1.h
index 6f89720d66..aacfcfc3cc 100644
--- a/GaudiUtils/src/Lib/H1.h
+++ b/GaudiUtils/src/Lib/H1.h
@@ -168,6 +168,64 @@ namespace {
     Bins        m_bins;
   };
   // ==========================================================================
+  /** @struct H3
+   *  the trivial representation of the 3D-histogram
+   *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+   *  @date 2009-10-21
+   */
+  struct H3 final {
+    //
+    void setName( std::string value ) { m_name = std::move( value ); }
+    void setTitle( std::string value ) { m_title = std::move( value ); }
+    void setXEdges( Edges value ) { m_xedges = std::move( value ); }
+    void setYEdges( Edges value ) { m_yedges = std::move( value ); }
+    void setZEdges( Edges value ) { m_zedges = std::move( value ); }
+    void setBins( Bins value ) { m_bins = std::move( value ); }
+    //
+    H3& operator*=( std::string value ) {
+      setName( std::move( value ) );
+      return *this;
+    }
+    H3& operator/=( std::string value ) {
+      setTitle( std::move( value ) );
+      return *this;
+    }
+    H3& operator&=( Edges value ) {
+      setXEdges( std::move( value ) );
+      return *this;
+    }
+    H3& operator|=( Edges value ) {
+      setYEdges( std::move( value ) );
+      return *this;
+    }
+    H3& operator-=( Edges value ) {
+      setZEdges( std::move( value ) );
+      return *this;
+    }
+    H3& operator+=( Bins value ) {
+      setBins( std::move( value ) );
+      return *this;
+    }
+    //
+    bool ok() const {
+      if ( m_bins.empty() ) { return false; }
+      if ( !m_xedges.ok() ) { return false; }
+      if ( !m_yedges.ok() ) { return false; }
+      if ( !m_zedges.ok() ) { return false; }
+      if ( m_bins.size() != ( m_xedges.nBins() + 2 ) * ( m_yedges.nBins() + 2 ) * ( m_zedges.nBins() + 2 ) ) { return false; }
+      return true;
+    }
+    //
+    //
+    std::string m_name;
+    std::string m_title;
+    Edges       m_xedges;
+    Edges       m_yedges;
+    Edges       m_zedges;
+    Bins        m_bins;
+  };
+
+  // ==========================================================================
 } // end of anonymous namespace
 // ============================================================================
 // The END
diff --git a/GaudiUtils/src/Lib/Histo2String.cpp b/GaudiUtils/src/Lib/Histo2String.cpp
index 5f42ebe2e0..b8250b0485 100644
--- a/GaudiUtils/src/Lib/Histo2String.cpp
+++ b/GaudiUtils/src/Lib/Histo2String.cpp
@@ -17,11 +17,14 @@
 #include "TH1F.h"
 #include "TH2D.h"
 #include "TH2F.h"
+#include "TH3D.h"
+#include "TH3F.h"
 // ============================================================================
 // AIDA
 // ============================================================================
 #include "AIDA/IHistogram1D.h"
 #include "AIDA/IHistogram2D.h"
+#include "AIDA/IHistogram3D.h"
 // ============================================================================
 // GaudiKernel
 // ============================================================================
@@ -156,6 +159,101 @@ namespace {
     return stream;
   }
   // ==========================================================================
+  template <class HISTO>
+  std::ostream& _toStream_3D_( const HISTO& histo, std::ostream& stream, const bool asXML ) {
+    if ( asXML ) { return Gaudi::Utils::Histos::toXml( histo, stream ); }
+    //
+    stream << "{ ";
+    //
+    stream << "'name'  : ";
+    Gaudi::Utils::toStream( std::string( histo.GetName() ), stream ) << " , ";
+    stream << "'title' : ";
+    Gaudi::Utils::toStream( std::string( histo.GetTitle() ), stream ) << " , ";
+    //
+    const TAxis* xaxis = histo.GetXaxis();
+    const int    xBins = xaxis->GetNbins();
+    //
+    stream << std::endl << "'X' : { ";
+    if ( xaxis->IsVariableBinSize() ) {
+      const TArrayD*      xbins = xaxis->GetXbins();
+      const unsigned int  xsize = xbins->GetSize();
+      std::vector<double> edges;
+      for ( unsigned int iBin = 0; iBin < xsize; ++iBin ) { edges.push_back( xbins->At( iBin ) ); }
+      // the edges
+      stream << "'edges' : ";
+      Gaudi::Utils::toStream( edges, stream ) << " }," << std::endl;
+    } else {
+      stream << "'nbins' : ";
+      Gaudi::Utils::toStream( xBins, stream ) << " , ";
+      stream << "'low'   : ";
+      Gaudi::Utils::toStream( xaxis->GetXmin(), stream ) << " , ";
+      stream << "'high'  : ";
+      Gaudi::Utils::toStream( xaxis->GetXmax(), stream ) << " }, " << std::endl;
+    }
+    //
+    const TAxis* yaxis = histo.GetYaxis();
+    const int    yBins = yaxis->GetNbins();
+    //
+    stream << std::endl << "'Y' : { ";
+    if ( yaxis->IsVariableBinSize() ) {
+      const TArrayD*      ybins = yaxis->GetXbins();
+      const unsigned int  ysize = ybins->GetSize();
+      std::vector<double> edges;
+      for ( unsigned int iBin = 0; iBin < ysize; ++iBin ) { edges.push_back( ybins->At( iBin ) ); }
+      // the edges
+      stream << " 'edges' : ";
+      Gaudi::Utils::toStream( edges, stream ) << " }," << std::endl;
+    } else {
+      stream << "'nbins' : ";
+      Gaudi::Utils::toStream( yBins, stream ) << " , ";
+      stream << "'low'   : ";
+      Gaudi::Utils::toStream( yaxis->GetXmin(), stream ) << " , ";
+      stream << "'high'  : ";
+      Gaudi::Utils::toStream( yaxis->GetXmax(), stream ) << " }, " << std::endl;
+    }
+    //
+    const TAxis* zaxis = histo.GetZaxis();
+    const int    zBins = zaxis->GetNbins();
+    //
+    stream << std::endl << "'Y' : { ";
+    if ( zaxis->IsVariableBinSize() ) {
+      const TArrayD*      zbins = zaxis->GetXbins();
+      const unsigned int  zsize = zbins->GetSize();
+      std::vector<double> edges;
+      for ( unsigned int iBin = 0; iBin < zsize; ++iBin ) { edges.push_back( zbins->At( iBin ) ); }
+      // the edges
+      stream << " 'edges' : ";
+      Gaudi::Utils::toStream( edges, stream ) << " }," << std::endl;
+    } else {
+      stream << "'nbins' : ";
+      Gaudi::Utils::toStream( zBins, stream ) << " , ";
+      stream << "'low'   : ";
+      Gaudi::Utils::toStream( zaxis->GetXmin(), stream ) << " , ";
+      stream << "'high'  : ";
+      Gaudi::Utils::toStream( zaxis->GetXmax(), stream ) << " }, " << std::endl;
+    }
+    //
+    // finally: the content
+    stream << "'bins' : " << std::endl << " [ ";
+    for ( int kBin = 0; kBin <= zBins + 1; ++kBin ) {
+      for ( int jBin = yBins + 1; jBin >= 0; --jBin ) {
+        if ( yBins + 1 != jBin ) { stream << std::endl; }
+        for ( int iBin = 0; iBin <= xBins + 1; ++iBin ) {
+          //
+          Gaudi::Utils::toStream( std::make_pair( histo.GetBinContent( iBin, jBin, kBin ), histo.GetBinError( iBin, jBin, kBin ) ),
+                                  stream );
+          //
+          if ( xBins + 1 != iBin || 0 != jBin || 0 != kBin ) { stream << " , "; }
+        }
+      }
+    }
+    stream << " ]";
+    //
+    stream << " }";
+    //
+    return stream;
+  }
+  // ==========================================================================
 } //                                                 end of anonymous namespace
 // ============================================================================
 /*  stream the ROOT histogram into output stream
@@ -198,6 +296,26 @@ std::ostream& Gaudi::Utils::toStream( const TH2F& histo, std::ostream& stream, c
   return _toStream_2D_( histo, stream, asXML );
 }
 // ============================================================================
+/*  stream the ROOT histogram into output stream
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param stream (OUTPUT) the stream
+ *  @param asXML  (INPUT)  use XML-format
+ */
+// ============================================================================
+std::ostream& Gaudi::Utils::toStream( const TH3D& histo, std::ostream& stream, const bool asXML ) {
+  return _toStream_3D_( histo, stream, asXML );
+}
+// ============================================================================
+/*  stream the ROOT histogram into output stream
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param stream (OUTPUT) the stream
+ *  @param asXML  (INPUT)  use XML-format
+ */
+// ============================================================================
+std::ostream& Gaudi::Utils::toStream( const TH3F& histo, std::ostream& stream, const bool asXML ) {
+  return _toStream_3D_( histo, stream, asXML );
+}
+// ============================================================================
 /*  stream the AIDA histogram into output stream
  *  @param histo  (INPUT)  the histogram to be streamed
  *  @param stream (OUTPUT) the stream
@@ -220,6 +338,19 @@ std::ostream& Gaudi::Utils::toStream( const AIDA::IHistogram2D& histo, std::ostr
   auto root = Gaudi::Utils::Aida2ROOT::aida2root( &histo );
   return root ? toStream( *root, stream, asXML ) : stream;
 }
+// ============================================================================
+/*  stream the AIDA histogram into output stream
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param stream (OUTPUT) the stream
+ *  @param asXML  (INPUT)  use XML-format
+ */
+// ============================================================================
+std::ostream& Gaudi::Utils::toStream( const AIDA::IHistogram3D& histo, std::ostream& stream, const bool asXML ) {
+  //
+  auto root = Gaudi::Utils::Aida2ROOT::aida2root( &histo );
+  return root ? toStream( *root, stream, asXML ) : stream;
+}
+
 // ============================================================================
 /*  convert the histogram into the string
  *  @param histo  (INPUT)  the histogram to be streamed
@@ -285,6 +416,34 @@ std::string Gaudi::Utils::toString( const TH2F& histo, const bool asXML ) {
  *  @date 2009-09-26
  */
 // ============================================================================
+std::string Gaudi::Utils::toString( const TH3D& histo, const bool asXML ) {
+  std::ostringstream o;
+  toStream( histo, o, asXML );
+  return o.str();
+}
+// ============================================================================
+/*  convert the histogram into the string
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param asXML  (INPUT)  use XML-format
+ *  @return the string representation of the histogram
+ *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+ *  @date 2009-09-26
+ */
+// ============================================================================
+std::string Gaudi::Utils::toString( const TH3F& histo, const bool asXML ) {
+  std::ostringstream o;
+  toStream( histo, o, asXML );
+  return o.str();
+}
+// ============================================================================
+/*  convert the histogram into the string
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param asXML  (INPUT)  use XML-format
+ *  @return the string representation of the histogram
+ *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+ *  @date 2009-09-26
+ */
+// ============================================================================
 std::string Gaudi::Utils::toString( const AIDA::IHistogram1D& histo, const bool asXML ) {
   std::ostringstream o;
   toStream( histo, o, asXML );
@@ -305,6 +464,20 @@ std::string Gaudi::Utils::toString( const AIDA::IHistogram2D& histo, const bool
   return o.str();
 }
 // =============================================================================
+/*  convert the histogram into the string
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param asXML  (INPUT)  use XML-format
+ *  @return the string representation of the histogram
+ *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+ *  @date 2009-09-26
+ */
+// ============================================================================
+std::string Gaudi::Utils::toString( const AIDA::IHistogram3D& histo, const bool asXML ) {
+  std::ostringstream o;
+  toStream( histo, o, asXML );
+  return o.str();
+}
+// =============================================================================
 /*  convert the histogram into the string
  *  @param histo  (INPUT)  the histogram to be streamed
  *  @param asXML  (INPUT)  use XML-format
@@ -365,5 +538,25 @@ std::string Gaudi::Utils::toString( TH1D* histo ) { return histo ? toString( *hi
 // =============================================================================
 std::string Gaudi::Utils::toString( TH2D* histo ) { return histo ? toString( *histo ) : "{}"; }
 // ============================================================================
+/*  convert the histogram into the string
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param asXML  (INPUT)  use XML-format
+ *  @return the string representation of the histogram
+ *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+ *  @date 2009-09-26
+ */
+// =============================================================================
+std::string Gaudi::Utils::toString( const TH3D* histo ) { return histo ? toString( *histo ) : "{}"; }
+// ============================================================================
+/*  convert the histogram into the string
+ *  @param histo  (INPUT)  the histogram to be streamed
+ *  @param asXML  (INPUT)  use XML-format
+ *  @return the string representation of the histogram
+ *  @author Vanya BELYAEV Ivan.Belyaev@nikhef.nl
+ *  @date 2009-09-26
+ */
+// =============================================================================
+std::string Gaudi::Utils::toString( TH3D* histo ) { return histo ? toString( *histo ) : "{}"; }
+// ============================================================================
 // The END
 // ============================================================================
diff --git a/GaudiUtils/src/Lib/HistoParsers.cpp b/GaudiUtils/src/Lib/HistoParsers.cpp
index 7642a149c1..add4382e3b 100644
--- a/GaudiUtils/src/Lib/HistoParsers.cpp
+++ b/GaudiUtils/src/Lib/HistoParsers.cpp
@@ -161,6 +161,42 @@ namespace Gaudi {
     };
     REGISTER_GRAMMAR( H2, H2Grammar );
     // ========================================================================
+    template <typename Iterator, typename Skipper>
+    class H3Grammar : public qi::grammar<Iterator, H3(), qi::locals<char>, Skipper> {
+      // ======================================================================
+    public:
+      // ======================================================================
+      typedef H3 ResultT;
+      // ======================================================================
+    public:
+      // ======================================================================
+      H3Grammar() : H3Grammar::base_type( result ) {
+        inner = ( ( ( qi::lit( "name" ) | "'name'" | "\"name\"" ) >> ":" >> name[qi::_val *= qi::_1] ) |
+                  ( ( qi::lit( "title" ) | "'title'" | "\"title\"" ) >> ":" >> title[qi::_val /= qi::_1] ) |
+                  ( ( qi::lit( "X" ) | "'X'" | "\"X\"" | "x" | "'x'" | "\"x\"" ) >> ':' >> edges[qi::_val &= qi::_1] ) |
+                  ( ( qi::lit( "Y" ) | "'Y'" | "\"Y\"" | "y" | "'y'" | "\"y\"" ) >> ':' >> edges[qi::_val |= qi::_1] ) |
+                  ( ( qi::lit( "Z" ) | "'Z'" | "\"Z\"" | "z" | "'z'" | "\"z\"" ) >> ':' >> edges[qi::_val -= qi::_1] ) |
+                  ( ( qi::lit( "bins" ) | "'bins'" | "\"bins\"" ) >> ':' >> bins[qi::_val += qi::_1] ) ) %
+                ',';
+
+        begin =
+            enc::char_( '[' )[qi::_val = ']'] | enc::char_( '{' )[qi::_val = '}'] | enc::char_( '(' )[qi::_val = ')'];
+        end    = enc::char_( qi::_r1 );
+        result = ( begin[qi::_a = qi::_1] >> inner[qi::_val = qi::_1] >> end( qi::_a ) ) | inner[qi::_val = qi::_1];
+      }
+
+      StringGrammar<Iterator, Skipper>                                         name, title;
+      EdgeGrammar<Iterator, Skipper>                                           edges;
+      VectorGrammar<Iterator, std::vector<std::pair<double, double>>, Skipper> bins;
+      qi::rule<Iterator, H3(), qi::locals<char>, Skipper>                      result;
+      qi::rule<Iterator, H3(), Skipper>                                        inner;
+      qi::rule<Iterator, char()>                                               begin;
+      qi::rule<Iterator, void( char )>                                         end;
+
+      // ======================================================================
+    };
+    REGISTER_GRAMMAR( H3, H3Grammar );
+    // ========================================================================
   } // namespace Parsers
   // ==========================================================================
 } //                                                     end of namespace Gaudi
@@ -183,6 +219,14 @@ namespace {
     return h2.ok() ? StatusCode::SUCCESS : StatusCode::FAILURE;
   }
   // ==========================================================================
+  /// parse the histogram
+  StatusCode _parse( H3& h3, const std::string& input ) {
+    // check the parsing
+    StatusCode sc = Gaudi::Parsers::parse_( h3, input );
+    if ( sc.isFailure() ) { return sc; } // RETURN
+    return h3.ok() ? StatusCode::SUCCESS : StatusCode::FAILURE;
+  }
+  // ==========================================================================
   template <class HISTO1>
   std::unique_ptr<HISTO1> _parse_1D( const std::string& input, std::string& name ) {
     //
@@ -283,6 +327,61 @@ namespace {
     return histo;
   }
   // ==========================================================================
+  template <class HISTO3>
+  std::unique_ptr<HISTO3> _parse_3D( const std::string& input, std::string& name ) {
+    //
+    typedef std::unique_ptr<HISTO3> H3P;
+    // 1) parse the custom format
+    //
+    H3         h3;
+    StatusCode sc = _parse( h3, input );
+    if ( sc.isFailure() || !h3.ok() ) { return H3P(); } // RETURN
+    //
+    // 2) create the histogram
+    //
+    H3P histo( h3.m_xedges.edges.empty() || h3.m_yedges.edges.empty() || h3.m_zedges.edges.empty()
+                   ?                               // FIXED binning?
+                   new HISTO3( "",                 // h3.m_name.c_str   ()         ,           // NAME
+                               h3.m_title.c_str(), // TITLE
+                               h3.m_xedges.nbins,  // #bins
+                               h3.m_xedges.low,    // low edge
+                               h3.m_xedges.high,   // high edge
+                               h3.m_yedges.nbins,  // #bins
+                               h3.m_yedges.low,    // low edge
+                               h3.m_yedges.high,   // high edge
+                               h3.m_zedges.nbins,  // #bins
+                               h3.m_zedges.low,    // low edge
+                               h3.m_zedges.high )
+                             :                                       // high edge
+                             new HISTO3( "",                         // h3.m_name.c_str   ()         ,           // NAME
+                                         h3.m_title.c_str(),         // TITLE
+                                         h3.m_xedges.nBins(),        // #bins
+                                         &h3.m_xedges.edges.front(), // vector of edges
+                                         h3.m_yedges.nBins(),        // #bins
+                                         &h3.m_yedges.edges.front(),
+                                         h3.m_zedges.nBins(),
+                                         &h3.m_zedges.edges.front() ) ); // vector of edges
+
+    int       ibin  = 0;
+    const int xBins = h3.m_xedges.nBins();
+    const int yBins = h3.m_yedges.nBins();
+    const int zBins = h3.m_yedges.nBins();
+
+    for ( int kBin = 0; kBin <= zBins + 1; ++kBin ) {
+      for ( int jBin = yBins + 1; jBin >= 0; --jBin ) {
+        for ( int iBin = 0; iBin <= xBins + 1; ++iBin ) {
+          histo->SetBinContent( iBin, jBin, kBin, h3.m_bins[ibin].first );
+          histo->SetBinError( iBin, jBin, kBin, h3.m_bins[ibin].second );
+          ++ibin;
+        }
+      }
+    }
+    //
+    name = h3.m_name;
+    //
+    return histo;
+  }
+  // ==========================================================================
 } //                                                 end of anonymous namespace
 // ============================================================================
 /*  parse ROOT histogram from text representation
@@ -382,6 +481,51 @@ StatusCode Gaudi::Parsers::parse( TH2F& result, const std::string& input ) {
  *  @return status code
  */
 // ============================================================================
+StatusCode Gaudi::Parsers::parse( TH3D& result, const std::string& input ) {
+  // 1) check the parsing
+  std::string name;
+  auto        h3 = _parse_3D<TH3D>( input, name );
+  if ( h3 ) {
+    result.Reset();
+    h3->Copy( result ); // ASSIGN
+    result.SetName( name.c_str() );
+    return StatusCode::SUCCESS; // RETURN
+  }
+  //
+  // XML-like text?
+  return ( std::string::npos != input.find( '<' ) ) ? Gaudi::Utils::Histos::fromXml( result, input )
+                                                    : StatusCode::FAILURE;
+}
+// ============================================================================
+/*  parse ROOT histogram from text representation
+ *  @param result (OUTPUT) the histogram
+ *  @param input  (INPUT)  the input to be parsed
+ *  @return status code
+ */
+// ============================================================================
+StatusCode Gaudi::Parsers::parse( TH3F& result, const std::string& input ) {
+  // 1) check the parsing
+  std::string name;
+  auto        h3 = _parse_3D<TH3F>( input, name );
+  if ( h3 ) {
+    result.Reset();
+    h3->Copy( result ); // ASSIGN
+    result.SetName( name.c_str() );
+    return StatusCode::SUCCESS; // RETURN
+  }
+  //
+  // XML-like text?
+  if ( std::string::npos != input.find( '<' ) ) { return Gaudi::Utils::Histos::fromXml( result, input ); }
+  //
+  return StatusCode::FAILURE;
+}
+// ============================================================================
+/*  parse ROOT histogram from text representation
+ *  @param result (OUTPUT) the histogram
+ *  @param input  (INPUT)  the input to be parsed
+ *  @return status code
+ */
+// ============================================================================
 StatusCode Gaudi::Parsers::parse( TH1D*& result, const std::string& input ) {
   if ( result ) { return parse( *result, input ); } // RETURN
 
@@ -422,6 +566,29 @@ StatusCode Gaudi::Parsers::parse( TH2D*& result, const std::string& input ) {
                                                     : StatusCode::FAILURE;
 }
 // ============================================================================
+/*  parse ROOT histogram from text representation
+ *  @param result (OUTPUT) the histogram
+ *  @param input  (INPUT)  the input to be parsed
+ *  @return status code
+ */
+// ============================================================================
+StatusCode Gaudi::Parsers::parse( TH3D*& result, const std::string& input ) {
+  if ( result ) { return parse( *result, input ); } // RETURN
+
+  // 1) check the parsing
+  std::string name;
+  auto        h3 = _parse_3D<TH3D>( input, name );
+  if ( h3 ) {
+    result = h3.release();
+    result->SetName( name.c_str() );
+    return StatusCode::SUCCESS; // RETURN
+  }
+  //
+  // XML-like text?
+  return ( std::string::npos != input.find( '<' ) ) ? Gaudi::Utils::Histos::fromXml( result, input )
+                                                    : StatusCode::FAILURE;
+}
+// ============================================================================
 /*  parse AIDA histogram from text representation
  *  @param result (OUTPUT) the histogram
  *  @param input  (INPUT)  the input to be parsed
@@ -448,5 +615,18 @@ StatusCode Gaudi::Parsers::parse( AIDA::IHistogram2D& result, const std::string&
   return root ? parse( *root, input ) : StatusCode::FAILURE;
 }
 // ============================================================================
+/*  parse AIDA histogram from text representation
+ *  @param result (OUTPUT) the histogram
+ *  @param input  (INPUT)  the input to be parsed
+ *  @return status code
+ */
+// ============================================================================
+StatusCode Gaudi::Parsers::parse( AIDA::IHistogram3D& result, const std::string& input ) {
+  // 1) convert to ROOT
+  auto root = Gaudi::Utils::Aida2ROOT::aida2root( &result );
+  // 2) read ROOT histogram
+  return root ? parse( *root, input ) : StatusCode::FAILURE;
+}
+// ============================================================================
 // The END
 // ============================================================================
-- 
GitLab


From dd1d43abfcb533d75b7c92815931d721a035f14b Mon Sep 17 00:00:00 2001
From: Maarten van Veghel <mvegh@nikhef.nl>
Date: Thu, 24 Jun 2021 00:48:02 +0200
Subject: [PATCH 2/3] string syntax fix

---
 GaudiUtils/include/GaudiUtils/HistoParsers.h | 2 +-
 GaudiUtils/src/Lib/Histo2String.cpp          | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/GaudiUtils/include/GaudiUtils/HistoParsers.h b/GaudiUtils/include/GaudiUtils/HistoParsers.h
index b920994403..a470c7f92a 100644
--- a/GaudiUtils/include/GaudiUtils/HistoParsers.h
+++ b/GaudiUtils/include/GaudiUtils/HistoParsers.h
@@ -24,7 +24,7 @@
 namespace AIDA {
   class IHistogram1D; // AIDA
   class IHistogram2D; // AIDA
-  class IHistogram3D;
+  class IHistogram3D; // AIDA
 } // namespace AIDA
 // =============================================================================
 // ROOT
diff --git a/GaudiUtils/src/Lib/Histo2String.cpp b/GaudiUtils/src/Lib/Histo2String.cpp
index b8250b0485..50ca2ee663 100644
--- a/GaudiUtils/src/Lib/Histo2String.cpp
+++ b/GaudiUtils/src/Lib/Histo2String.cpp
@@ -215,7 +215,7 @@ namespace {
     const TAxis* zaxis = histo.GetZaxis();
     const int    zBins = zaxis->GetNbins();
     //
-    stream << std::endl << "'Y' : { ";
+    stream << std::endl << "'Z' : { ";
     if ( zaxis->IsVariableBinSize() ) {
       const TArrayD*      zbins = zaxis->GetXbins();
       const unsigned int  zsize = zbins->GetSize();
@@ -243,7 +243,7 @@ namespace {
           Gaudi::Utils::toStream( std::make_pair( histo.GetBinContent( iBin, jBin, kBin ), histo.GetBinError( iBin, jBin, kBin ) ),
                                   stream );
           //
-          if ( xBins + 1 != iBin || 0 != jBin || 0 != kBin ) { stream << " , "; }
+          if ( !( ( ( xBins + 1 ) == iBin ) && ( 0 == jBin ) && ( ( zBins + 1 ) == kBin ) ) ) { stream << " , "; }
         }
       }
     }
-- 
GitLab


From a78290d3d258ea632addd64906e875cfc8a305d6 Mon Sep 17 00:00:00 2001
From: Gitlab CI <noreply@cern.ch>
Date: Wed, 23 Jun 2021 22:52:15 +0000
Subject: [PATCH 3/3] Fixed formatting

patch generated by https://gitlab.cern.ch/lhcb/Gaudi/-/jobs/14708672
---
 GaudiUtils/src/Lib/H1.h             |  4 +++-
 GaudiUtils/src/Lib/Histo2String.cpp |  5 +++--
 GaudiUtils/src/Lib/HistoParsers.cpp | 20 +++++++++-----------
 3 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/GaudiUtils/src/Lib/H1.h b/GaudiUtils/src/Lib/H1.h
index aacfcfc3cc..1356af992c 100644
--- a/GaudiUtils/src/Lib/H1.h
+++ b/GaudiUtils/src/Lib/H1.h
@@ -212,7 +212,9 @@ namespace {
       if ( !m_xedges.ok() ) { return false; }
       if ( !m_yedges.ok() ) { return false; }
       if ( !m_zedges.ok() ) { return false; }
-      if ( m_bins.size() != ( m_xedges.nBins() + 2 ) * ( m_yedges.nBins() + 2 ) * ( m_zedges.nBins() + 2 ) ) { return false; }
+      if ( m_bins.size() != ( m_xedges.nBins() + 2 ) * ( m_yedges.nBins() + 2 ) * ( m_zedges.nBins() + 2 ) ) {
+        return false;
+      }
       return true;
     }
     //
diff --git a/GaudiUtils/src/Lib/Histo2String.cpp b/GaudiUtils/src/Lib/Histo2String.cpp
index 50ca2ee663..8e8af0d393 100644
--- a/GaudiUtils/src/Lib/Histo2String.cpp
+++ b/GaudiUtils/src/Lib/Histo2String.cpp
@@ -240,8 +240,9 @@ namespace {
         if ( yBins + 1 != jBin ) { stream << std::endl; }
         for ( int iBin = 0; iBin <= xBins + 1; ++iBin ) {
           //
-          Gaudi::Utils::toStream( std::make_pair( histo.GetBinContent( iBin, jBin, kBin ), histo.GetBinError( iBin, jBin, kBin ) ),
-                                  stream );
+          Gaudi::Utils::toStream(
+              std::make_pair( histo.GetBinContent( iBin, jBin, kBin ), histo.GetBinError( iBin, jBin, kBin ) ),
+              stream );
           //
           if ( !( ( ( xBins + 1 ) == iBin ) && ( 0 == jBin ) && ( ( zBins + 1 ) == kBin ) ) ) { stream << " , "; }
         }
diff --git a/GaudiUtils/src/Lib/HistoParsers.cpp b/GaudiUtils/src/Lib/HistoParsers.cpp
index add4382e3b..73d105c0a9 100644
--- a/GaudiUtils/src/Lib/HistoParsers.cpp
+++ b/GaudiUtils/src/Lib/HistoParsers.cpp
@@ -339,8 +339,7 @@ namespace {
     //
     // 2) create the histogram
     //
-    H3P histo( h3.m_xedges.edges.empty() || h3.m_yedges.edges.empty() || h3.m_zedges.edges.empty()
-                   ?                               // FIXED binning?
+    H3P histo( h3.m_xedges.edges.empty() || h3.m_yedges.edges.empty() || h3.m_zedges.edges.empty() ? // FIXED binning?
                    new HISTO3( "",                 // h3.m_name.c_str   ()         ,           // NAME
                                h3.m_title.c_str(), // TITLE
                                h3.m_xedges.nbins,  // #bins
@@ -352,15 +351,14 @@ namespace {
                                h3.m_zedges.nbins,  // #bins
                                h3.m_zedges.low,    // low edge
                                h3.m_zedges.high )
-                             :                                       // high edge
-                             new HISTO3( "",                         // h3.m_name.c_str   ()         ,           // NAME
-                                         h3.m_title.c_str(),         // TITLE
-                                         h3.m_xedges.nBins(),        // #bins
-                                         &h3.m_xedges.edges.front(), // vector of edges
-                                         h3.m_yedges.nBins(),        // #bins
-                                         &h3.m_yedges.edges.front(),
-                                         h3.m_zedges.nBins(),
-                                         &h3.m_zedges.edges.front() ) ); // vector of edges
+                                                                                                   : // high edge
+                   new HISTO3( "",                         // h3.m_name.c_str   ()         ,           // NAME
+                               h3.m_title.c_str(),         // TITLE
+                               h3.m_xedges.nBins(),        // #bins
+                               &h3.m_xedges.edges.front(), // vector of edges
+                               h3.m_yedges.nBins(),        // #bins
+                               &h3.m_yedges.edges.front(), h3.m_zedges.nBins(),
+                               &h3.m_zedges.edges.front() ) ); // vector of edges
 
     int       ibin  = 0;
     const int xBins = h3.m_xedges.nBins();
-- 
GitLab