The Gaudi Framework  v36r0 (4abb4d13)
RootHistogramSink.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 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 
14 #include <Gaudi/MonitoringHub.h>
15 
16 #include <TFile.h>
17 #include <TH1D.h>
18 #include <TH2D.h>
19 #include <TH3D.h>
20 #include <TProfile.h>
21 #include <TProfile2D.h>
22 #include <TProfile3D.h>
23 
24 #include <fmt/format.h>
25 
26 #include <algorithm>
27 #include <deque>
28 
29 namespace {
30 
31  struct Axis {
32  unsigned int nBins;
33  double minValue;
34  double maxValue;
35  std::string title;
36  };
37 
38  Axis toAxis( nlohmann::json& jAxis ) {
39  return {jAxis.at( "nBins" ).get<unsigned int>(), jAxis.at( "minValue" ).get<double>(),
40  jAxis.at( "maxValue" ).get<double>(),
41  ";" + jAxis.at( "title" ).get<std::string>()}; // ";" to prepare concatenations of titles
42  }
43 
44  template <typename Traits, std::size_t... index>
45  void saveRootHistoInternal( const std::string& component, const std::string& name, nlohmann::json& j,
46  std::index_sequence<index...> ) {
47  auto id = fmt::format( "{}/{}", component, name );
48  // extract data from json
49  auto jsonAxis = j.at( "axis" );
50  auto axis = std::array{toAxis( jsonAxis[index] )...};
51  auto weights = j.at( "bins" ).get<std::vector<typename Traits::WeightType>>();
52  auto title = j.at( "title" ).get<std::string>();
53  // weird way ROOT has to give titles to axis
54  title += ( axis[index].title + ... );
55  // compute total number of bins, multiplying bins per axis
56  auto totNBins = ( ( axis[index].nBins + 2 ) * ... );
57  assert( weights.size() == totNBins );
58  // Create Root histogram calling constructors with the args tuple
59  auto histo = std::make_from_tuple<typename Traits::Histo>(
60  std::tuple_cat( std::tuple{id.c_str(), title.c_str()},
61  std::tuple{axis[index].nBins, axis[index].minValue, axis[index].maxValue}... ) );
62  // fill Histo
63  for ( unsigned int i = 0; i < totNBins; i++ ) Traits::fill( histo, i, weights[i] );
64  // write to file
65  histo.Write();
66  }
67 
68  template <bool isProfile, typename RootHisto>
69  struct Traits;
70 
71  template <typename RootHisto>
72  struct Traits<false, RootHisto> {
73  using Histo = RootHisto;
74  using WeightType = double;
75  static auto fill( Histo& histo, unsigned int i, const WeightType& weight ) { histo.SetBinContent( i, weight ); }
76  };
77  template <typename RootHisto>
78  struct Traits<true, RootHisto> {
80  template <typename TP>
81  struct ProfileWrapper : TP {
82  using TP::TP;
83  void setBinNEntries( Int_t i, Int_t n ) { this->fBinEntries.fArray[i] = n; }
84  void setBinW2( Int_t i, Double_t v ) { this->fSumw2.fArray[i] = v; }
85  };
86  using Histo = ProfileWrapper<RootHisto>;
87  using WeightType = std::tuple<std::tuple<unsigned int, double>, double>;
88  static constexpr auto fill( Histo& histo, unsigned int i, const WeightType& weight ) {
89  auto [c, sumWeight2] = weight;
90  auto [nEntries, sumWeight] = c;
91  histo.setBinNEntries( i, nEntries );
92  histo.SetBinContent( i, sumWeight );
93  histo.setBinW2( i, sumWeight2 );
94  };
95  };
96 
97  template <unsigned int N, bool isProfile, typename ROOTHisto>
98  void saveRootHisto( const std::string& component, const std::string& name, nlohmann::json& j ) {
99  saveRootHistoInternal<Traits<isProfile, ROOTHisto>>( component, name, j, std::make_index_sequence<N>() );
100  }
101 
102  using namespace std::string_literals;
103  static const auto registry =
104  std::map{std::pair{std::pair{"histogram:Histogram"s, 1}, &saveRootHisto<1, false, TH1D>},
105  std::pair{std::pair{"histogram:WeightedHistogram"s, 1}, &saveRootHisto<1, false, TH1D>},
106  std::pair{std::pair{"histogram:Histogram"s, 2}, &saveRootHisto<2, false, TH2D>},
107  std::pair{std::pair{"histogram:WeightedHistogram"s, 2}, &saveRootHisto<2, false, TH2D>},
108  std::pair{std::pair{"histogram:Histogram"s, 3}, &saveRootHisto<3, false, TH3D>},
109  std::pair{std::pair{"histogram:WeightedHistogram"s, 3}, &saveRootHisto<3, false, TH3D>},
110  std::pair{std::pair{"histogram:ProfileHistogram"s, 1}, &saveRootHisto<1, true, TProfile>},
111  std::pair{std::pair{"histogram:WeightedProfileHistogram"s, 1}, &saveRootHisto<1, true, TProfile>},
112  std::pair{std::pair{"histogram:ProfileHistogram"s, 2}, &saveRootHisto<2, true, TProfile2D>},
113  std::pair{std::pair{"histogram:WeightedProfileHistogram"s, 2}, &saveRootHisto<2, true, TProfile2D>},
114  std::pair{std::pair{"histogram:ProfileHistogram"s, 3}, &saveRootHisto<3, true, TProfile3D>},
115  std::pair{std::pair{"histogram:WeightedProfileHistogram"s, 3}, &saveRootHisto<3, true, TProfile3D>}};
116 } // namespace
117 
119 
120  class Root : public Service, public Gaudi::Monitoring::Hub::Sink {
121 
122  public:
123  using Service::Service;
124 
125  StatusCode initialize() override {
126  return Service::initialize().andThen( [&] { serviceLocator()->monitoringHub().addSink( this ); } );
127  }
128 
129  StatusCode stop() override {
130  auto ok = Service::stop();
131  if ( !ok ) return ok;
132  std::sort( begin( m_monitoringEntities ), end( m_monitoringEntities ), []( const auto& a, const auto& b ) {
133  return std::tie( a.name, a.component ) > std::tie( b.name, b.component );
134  } );
135  TFile histoFile( m_fileName.value().c_str(), "RECREATE" );
137  auto j = ent.toJSON();
138  auto dim = j.at( "dimension" ).template get<unsigned int>();
139  auto type = j.at( "type" ).template get<std::string>();
140  // cut type after last ':' if there is one. The rest is precision parameter that we do not need here
141  // as ROOT anyway treats everything as doubles in histograms
142  type = type.substr( 0, type.find_last_of( ':' ) );
143  auto saver = registry.find( {type, dim} );
144  if ( saver == registry.end() )
145  throw GaudiException( "Unknown type : " + type + " dim : " + std::to_string( dim ), "Histogram::Sink::Root",
147  ( *saver->second )( ent.component, ent.name, j );
148  } );
149  return ok;
150  }
151 
153  if ( std::string_view( ent.type ).substr( 0, 10 ) == "histogram:" ) {
155  }
156  }
157 
158  void removeEntity( Monitoring::Hub::Entity const& ent ) override {
160  if ( it != m_monitoringEntities.end() ) { m_monitoringEntities.erase( it ); }
161  }
162 
163  private:
165 
166  Gaudi::Property<std::string> m_fileName{this, "FileName", "testHisto.root",
167  "Name of file where to save histograms"};
168  };
169 
170  DECLARE_COMPONENT( Root )
171 
172 } // namespace Gaudi::Histograming::Sink
Gaudi::Monitoring::Hub::Sink
Interface reporting services must implement.
Definition: MonitoringHub.h:78
std::for_each
T for_each(T... args)
Service::initialize
StatusCode initialize() override
Definition: Service.cpp:118
std::string
STL class.
Gaudi::Histograming::Sink::Root::removeEntity
void removeEntity(Monitoring::Hub::Entity const &ent) override
Definition: RootHistogramSink.cpp:158
GaudiPython.HistoUtils.nEntries
nEntries
Definition: HistoUtils.py:921
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:180
std::move
T move(T... args)
MonitoringHub.h
HistoEx.histo
histo
Definition: HistoEx.py:103
std::pair
gaudirun.s
string s
Definition: gaudirun.py:328
std::vector
STL class.
std::find
T find(T... args)
GaudiException
Definition: GaudiException.h:31
std::tuple
gaudirun.c
c
Definition: gaudirun.py:499
jsonFromLHCbLog.json
dictionary json
Definition: jsonFromLHCbLog.py:86
std::sort
T sort(T... args)
Service
Definition: Service.h:46
std::tie
T tie(T... args)
GaudiPluginService.cpluginsvc.registry
def registry()
Definition: cpluginsvc.py:82
Gaudi::Histograming::Sink::Root::m_fileName
Gaudi::Property< std::string > m_fileName
Definition: RootHistogramSink.cpp:166
TimingHistograms.name
name
Definition: TimingHistograms.py:23
StatusCode
Definition: StatusCode.h:65
std::string::at
T at(T... args)
Gaudi::Histograming::Sink::Root::stop
StatusCode stop() override
Definition: RootHistogramSink.cpp:129
Gaudi::Histograming::Sink::Root::initialize
StatusCode initialize() override
Definition: RootHistogramSink.cpp:125
Gaudi::Histograming::Sink
Definition: RootHistogramSink.cpp:118
CLHEP::begin
double * begin(CLHEP::HepVector &v)
Definition: TupleAlg.cpp:45
std::string::c_str
T c_str(T... args)
Gaudi::Property::value
const ValueType & value() const
Backward compatibility (.
Definition: Property.h:240
std::to_string
T to_string(T... args)
std::array
STL class.
std::deque::erase
T erase(T... args)
std::deque< Gaudi::Monitoring::Hub::Entity >
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
std::map
STL class.
Gaudi::Histograming::Sink::Root::registerEntity
void registerEntity(Monitoring::Hub::Entity ent) override
Definition: RootHistogramSink.cpp:152
GaudiPluginService.cpluginsvc.n
n
Definition: cpluginsvc.py:221
Service.h
HistoDumpEx.v
v
Definition: HistoDumpEx.py:27
gaudirun.type
type
Definition: gaudirun.py:154
std::deque::emplace_back
T emplace_back(T... args)
Service::stop
StatusCode stop() override
Definition: Service.cpp:181
Gaudi::Histograming::Sink::Root
Definition: RootHistogramSink.cpp:120
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:46
Service::Service
Service(std::string name, ISvcLocator *svcloc)
Standard Constructor
Definition: Service.cpp:339
std::tuple_cat
T tuple_cat(T... args)
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
std::deque::end
T end(T... args)
IOTest.end
end
Definition: IOTest.py:123
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:101
Gaudi::Monitoring::Hub::Entity
Wrapper class for arbitrary monitoring objects.
Definition: MonitoringHub.h:40
Gaudi::Property< std::string >
Gaudi::Histograming::Sink::Root::m_monitoringEntities
std::deque< Gaudi::Monitoring::Hub::Entity > m_monitoringEntities
Definition: RootHistogramSink.cpp:164
Service::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator
Definition: Service.cpp:335
Gaudi::Monitoring::Hub::Entity::type
std::string type
type of the entity, see comment above concerning its format and usage
Definition: MonitoringHub.h:55