The Gaudi Framework  v36r9p1 (5c15b2bb)
RootHistogramSink.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2022 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 
12 #include "GaudiKernel/Service.h"
13 
15 
16 #include <TH1D.h>
17 #include <TH2D.h>
18 #include <TH3D.h>
19 #include <TProfile.h>
20 #include <TProfile2D.h>
21 #include <TProfile3D.h>
22 
23 namespace {
24 
25  template <typename RootHisto, unsigned int N>
26  struct TraitsBase {
27  static constexpr unsigned int Dimension{ N };
28  template <typename AxisArray, std::size_t... index>
29  static RootHisto create( std::string& name, std::string& title, AxisArray axis, std::index_sequence<index...> ) {
30  return std::make_from_tuple<RootHisto>(
31  std::tuple_cat( std::tuple{ name.c_str(), title.c_str() },
32  std::tuple{ std::get<index>( axis ).nBins, std::get<index>( axis ).minValue,
33  std::get<index>( axis ).maxValue }... ) );
34  }
35  template <typename... Axis>
36  static RootHisto create( std::string& name, std::string& title, Axis&... axis ) {
37  return create( name, title, std::make_tuple( axis... ), std::make_index_sequence<sizeof...( Axis )>() );
38  }
39  static void fillMetaData( RootHisto& histo, nlohmann::json const& jsonAxis, unsigned int nentries ) {
40  auto try_set_bin_labels = [&histo, &jsonAxis]( auto idx ) {
41  if ( jsonAxis[idx].contains( "labels" ) ) {
42  TAxis* axis = nullptr;
43  switch ( idx ) {
44  case 0:
45  axis = histo.GetXaxis();
46  break;
47  case 1:
48  axis = histo.GetYaxis();
49  break;
50  case 2:
51  axis = histo.GetZaxis();
52  break;
53  default:
54  break;
55  }
56  if ( axis ) {
57  const auto labels = jsonAxis[idx].at( "labels" );
58  for ( unsigned int i = 0; i < labels.size(); i++ ) {
59  axis->SetBinLabel( i + 1, labels[i].template get<std::string>().c_str() );
60  }
61  }
62  }
63  };
64  for ( unsigned int i = 0; i < jsonAxis.size(); i++ ) try_set_bin_labels( i );
65  // Fix the number of entries, wrongly computed by ROOT from the numer of calls to fill
66  histo.SetEntries( nentries );
67  }
68  };
69 
70  template <bool isProfile, typename RootHisto, unsigned int N>
71  struct Traits;
72 
73  template <typename RootHisto, unsigned int N>
74  struct Traits<false, RootHisto, N> : TraitsBase<RootHisto, N> {
75  using Histo = RootHisto;
76  using WeightType = double;
77  static void fill( Histo& histo, unsigned int i, const WeightType& weight ) { histo.SetBinContent( i, weight ); }
78  };
80  template <typename TP>
81  struct ProfileWrapper : TP {
82  template <typename... Args>
83  ProfileWrapper( Args&&... args ) : TP( std::forward<Args>( args )... ) {
84  // When the static function TH1::SetDefaultSumw2 had been called (passing true), `Sumw2(true)` is automatically
85  // called by the constructor of TProfile. This is a problem because in the profiles in Gaudi::Accumulators we do
86  // not keep track of the sum of squares of weights and consequently don't set fBinSumw2 of the TProfile, which in
87  // turn leads to a self-inconsistent TProfile object. The "fix" is to disable sum of squares explicitly.
88  this->Sumw2( false );
89  }
90  void setBinNEntries( Int_t i, Int_t n ) { this->fBinEntries.fArray[i] = n; }
91  void setBinW2( Int_t i, Double_t v ) { this->fSumw2.fArray[i] = v; }
92  };
93  template <typename RootHisto, unsigned int N>
94  struct Traits<true, RootHisto, N> : TraitsBase<ProfileWrapper<RootHisto>, N> {
95  using Histo = ProfileWrapper<RootHisto>;
96  using WeightType = std::tuple<std::tuple<unsigned int, double>, double>;
97  static constexpr void fill( Histo& histo, unsigned int i, const WeightType& weight ) {
98  auto [c, sumWeight2] = weight;
99  auto [nEntries, sumWeight] = c;
100  histo.setBinNEntries( i, nEntries );
101  histo.SetBinContent( i, sumWeight );
102  histo.setBinW2( i, sumWeight2 );
103  };
104  };
105 
106 } // namespace
107 
108 namespace Gaudi::Histograming::Sink {
109 
110  using namespace std::string_literals;
111 
112  template <unsigned int N, bool isProfile, typename ROOTHisto>
113  void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json& j ) {
114  details::saveRootHisto<Traits<isProfile, ROOTHisto, N>>( file, std::move( dir ), std::move( name ), j );
115  }
116 
117  struct Root : Base {
118 
119  using Base::Base;
120 
121  HistoRegistry registry = { { { "histogram:Histogram"s, 1 }, &saveRootHisto<1, false, TH1D> },
122  { { "histogram:WeightedHistogram"s, 1 }, &saveRootHisto<1, false, TH1D> },
123  { { "histogram:Histogram"s, 2 }, &saveRootHisto<2, false, TH2D> },
124  { { "histogram:WeightedHistogram"s, 2 }, &saveRootHisto<2, false, TH2D> },
125  { { "histogram:Histogram"s, 3 }, &saveRootHisto<3, false, TH3D> },
126  { { "histogram:WeightedHistogram"s, 3 }, &saveRootHisto<3, false, TH3D> },
127  { { "histogram:ProfileHistogram"s, 1 }, &saveRootHisto<1, true, TProfile> },
128  { { "histogram:WeightedProfileHistogram"s, 1 }, &saveRootHisto<1, true, TProfile> },
129  { { "histogram:ProfileHistogram"s, 2 }, &saveRootHisto<2, true, TProfile2D> },
130  { { "histogram:WeightedProfileHistogram"s, 2 }, &saveRootHisto<2, true, TProfile2D> },
131  { { "histogram:ProfileHistogram"s, 3 }, &saveRootHisto<3, true, TProfile3D> },
132  { { "histogram:WeightedProfileHistogram"s, 3 }, &saveRootHisto<3, true, TProfile3D> } };
133 
134  StatusCode initialize() override {
135  return Base::initialize().andThen( [&] {
136  for ( auto& [id, func] : registry ) { registerHandler( id, func ); }
137  } );
138  }
139  };
140 
141  DECLARE_COMPONENT( Root )
142 } // namespace Gaudi::Histograming::Sink
std::make_tuple
T make_tuple(T... args)
std::string
STL class.
GaudiPython.HistoUtils.nEntries
nEntries
Definition: HistoUtils.py:939
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:163
std::move
T move(T... args)
HistoEx.histo
histo
Definition: HistoEx.py:105
gaudirun.s
string s
Definition: gaudirun.py:346
Gaudi::Histograming::Sink::Base::initialize
StatusCode initialize() override
Definition: RootHistogramSinkBase.h:173
IOTest.N
int N
Definition: IOTest.py:115
std::tuple
Gaudi::Histograming::Sink::Base::Base
Base(std::string name, ISvcLocator *svcloc, std::function< bool(Monitoring::Hub::Entity const &)> const isRelevant=isHistogram)
Definition: RootHistogramSinkBase.h:169
gaudirun.c
c
Definition: gaudirun.py:525
jsonFromLHCbLog.json
dictionary json
Definition: jsonFromLHCbLog.py:87
GaudiPluginService.cpluginsvc.registry
def registry()
Definition: cpluginsvc.py:84
TimingHistograms.name
name
Definition: TimingHistograms.py:25
StatusCode
Definition: StatusCode.h:65
GaudiPluginService.cpluginsvc.func
func
Definition: cpluginsvc.py:236
Gaudi::Histograming::Sink
Definition: RootHistogramSinkBase.h:47
std::forward
T forward(T... args)
std::string::c_str
T c_str(T... args)
Gaudi::Histograming::Sink::Root
Definition: RootHistogramSink.cpp:117
GaudiPluginService.cpluginsvc.n
n
Definition: cpluginsvc.py:235
Service.h
HistoDumpEx.v
v
Definition: HistoDumpEx.py:27
RootHistogramSinkBase.h
gaudirun.args
args
Definition: gaudirun.py:336
std
STL namespace.
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:46
Gaudi::Histograming::Sink::Base
Definition: RootHistogramSinkBase.h:163
std::tuple_cat
T tuple_cat(T... args)
Gaudi::Histograming::Sink::saveRootHisto
void saveRootHisto(TFile &file, std::string dir, std::string name, nlohmann::json &j)
Definition: RootHistogramSink.cpp:113
std::size_t
Gaudi::Utils::Histos::fill
GAUDI_API void fill(AIDA::IHistogram1D *histo, const double value, const double weight=1.0)
simple function to fill AIDA::IHistogram1D objects
Definition: Fill.cpp:45
Gaudi::Histograming::Sink::Root::initialize
StatusCode initialize() override
Definition: RootHistogramSink.cpp:134