The Gaudi Framework  v41r0 (bdbe7744)
Loading...
Searching...
No Matches
Utils.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 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#pragma once
12
14#include <Gaudi/MonitoringHub.h>
16#include <TDirectory.h>
17#include <TFile.h>
18#include <TH1.h>
19#include <TH1D.h>
20#include <TH2D.h>
21#include <TH3D.h>
22#include <TProfile.h>
23#include <TProfile2D.h>
24#include <TProfile3D.h>
25#include <algorithm>
26#include <cmath>
27#include <functional>
28#include <gsl/span>
29#include <nlohmann/json.hpp>
30#include <range/v3/numeric/accumulate.hpp>
31#include <ranges>
32#include <string>
33#include <type_traits>
34#include <vector>
35
36#include <fmt/format.h>
37
39 inline std::string formatTitle( std::string_view title, unsigned int width ) {
40 if ( title.size() > width ) {
41 return fmt::format( "\"{:.{}s}...\"", title, width - 3 );
42 } else {
43 return fmt::format( "\"{:.{}s}\"", title, width );
44 }
45 }
46 inline std::string formatName( std::string_view name, unsigned int width ) {
47 if ( name.size() > width ) {
48 const auto preSize = ( width / 2 ) - 2;
49 const auto postSize = width - preSize - 3;
50 return fmt::format( "{:.{}s}...{:.{}s}", name.substr( 0, preSize ), preSize,
51 name.substr( name.size() - postSize, postSize ), postSize );
52 } else {
53 return std::string{ name };
54 }
55 }
56 constexpr std::string_view histo1DFormatting =
57 " | {:{}.{}s} | {:{}s} | {:10} |{:11.5g} | {:<#11.5g}|{:11.5g} |{:11.5g} |";
58 constexpr std::string_view histo2DFormatting =
59 " ID={:{}.{}s} {:{}s} Ents/All={:>5.0f}/{:<5.0f}<X>/sX={:.5g}/{:<.5g},<Y>/sY={:.5g}/{:<.5g}";
60 constexpr std::string_view histo3DFormatting =
61 " ID={:{}.{}s} {:{}s} "
62 "Ents/All={:>5.0f}/{:<5.0f}<X>/sX={:.5g}/{:<.5g},<Y>/sY={:.5g}/{:<.5g},<Z>/sZ={:.5g}/{:<.5g}";
63
66 unsigned int value{ 0 };
67 };
68
70 template <typename T>
71 inline T sqrt_or_zero( const T x ) {
72 return ( x > 0 ? std::sqrt( x ) : T{ 0 } );
73 }
74
75} // namespace Gaudi::Histograming::Sink::detail
76
87template <>
88struct fmt::formatter<Gaudi::Histograming::Sink::detail::IntWithFixedWidth> {
89 unsigned int width{ 10 };
90
91 constexpr auto parse( format_parse_context& ctx ) {
92 auto it = ctx.begin();
93 if ( it == ctx.end() || *it == '}' ) { return it; }
94 int w = fmt::detail::parse_nonnegative_int( it, ctx.end(), -1 );
95 if ( w == -1 ) throw fmt::format_error( "bad" );
96 width = (unsigned int)w;
97 if ( it == ctx.end() || *it != '}' ) throw fmt::format_error( "bad" );
98 return it;
99 }
100
102 auto s = fmt::format( "{:{}d}", n.value, width );
103 if ( s.size() > width ) { s = fmt::format( "{:{}.{}g}", (double)n.value, width, width - 5 ); }
104 return fmt::format_to( ctx.out(), "{:s}", s );
105 }
106};
107
109
122 template <bool isProfile, typename RootHisto, unsigned int N>
123 struct Traits;
124
131 template <typename Traits>
132 std::tuple<typename Traits::Histo, std::string> jsonToRootHistogram( std::string& dir, std::string& name,
133 nlohmann::json const& j );
134
140 template <typename Histo>
141 nlohmann::json rootHistogramTojson( Histo const& );
142
146 template <typename Traits>
147 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json const& j );
148
155 template <unsigned int N, bool isProfile, typename ROOTHisto>
156 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json const& j );
157
158 namespace details {
159
161 struct Axis {
162 unsigned int nBins{};
163 double minValue{};
164 double maxValue{};
165 std::string title;
166 };
167
169 inline Axis jsonToAxis( nlohmann::json& jAxis ) {
170 return { jAxis.at( "nBins" ).get<unsigned int>(), jAxis.at( "minValue" ).get<double>(),
171 jAxis.at( "maxValue" ).get<double>(),
172 ";" + jAxis.at( "title" ).get<std::string>() }; // ";" to prepare concatenations of titles
173 }
174
179 inline void fixNameAndDir( std::string& name, std::string& dir ) {
180 if ( name[0] == '/' ) {
181 dir = "";
182 name = name.substr( 1 );
183 }
184 // take into account the case where name contains '/'s (e.g. "Group/Name") by
185 // moving the prefix into dir
186 if ( auto pos = name.rfind( '/' ); pos != std::string::npos ) {
187 dir += '/' + name.substr( 0, pos );
188 name = name.substr( pos + 1 );
189 }
190 }
191
195 template <typename Traits, std::size_t... index>
196 std::tuple<typename Traits::Histo, std::string> jsonToRootHistogramInternal( std::string& dir, std::string& name,
197 nlohmann::json const& j,
198 std::index_sequence<index...> ) {
199 // extract data from json
200 auto jsonAxis = j.at( "axis" );
201 auto axis = std::array{ jsonToAxis( jsonAxis[index] )... };
202 auto weights = j.at( "bins" ).get<typename Traits::WeightType>();
203 auto title = j.at( "title" ).get<std::string>();
204 auto nentries = j.at( "nEntries" ).get<unsigned int>();
205 // weird way ROOT has to give titles to axis
206 title += ( axis[index].title + ... );
207 // compute total number of bins, multiplying bins per axis
208 auto totNBins = ( ( axis[index].nBins + 2 ) * ... );
209 // fix name and dir if needed
210 fixNameAndDir( name, dir );
211 // Create Root histogram calling constructors with the args tuple
212 auto histo = Traits::create( name, title, axis[index]... );
213 // fill Histo
214 Traits::fill( histo, totNBins, weights );
215 // in case we have sums, overwrite them in the histogram with our more precise values
216 // FIXME This is only supporting regular histograms. It won't work in case of weighted histograms
217 if constexpr ( sizeof...( index ) == 1 ) {
218 if ( j.find( "sum" ) != j.end() ) {
219 double s[13];
220 s[0] = j.at( "nTotEntries" ).get<double>();
221 s[1] = j.at( "nTotEntries" ).get<double>();
222 s[2] = j.at( "sum" ).get<double>();
223 s[3] = j.at( "sum2" ).get<double>();
224 histo.PutStats( s );
225 }
226 } else {
227 if ( j.find( "sumx" ) != j.end() ) {
228 double s[13];
229 s[0] = j.at( "nTotEntries" ).get<double>();
230 s[1] = j.at( "nTotEntries" ).get<double>();
231 s[2] = j.at( "sumx" ).get<double>();
232 s[3] = j.at( "sumx2" ).get<double>();
233 s[4] = j.at( "sumy" ).get<double>();
234 s[5] = j.at( "sumy2" ).get<double>();
235 s[6] = j.at( "sumxy" ).get<double>();
236 if constexpr ( sizeof...( index ) > 2 ) {
237 s[7] = j.at( "sumz" ).get<double>();
238 s[8] = j.at( "sumz2" ).get<double>();
239 s[9] = j.at( "sumxz" ).get<double>();
240 s[10] = j.at( "sumyz" ).get<double>();
241 }
242 histo.PutStats( s );
243 }
244 }
245 // fill histo metadata, e.g. bins and number of entries
246 Traits::fillMetaData( histo, jsonAxis, nentries );
247 return { histo, dir };
248 }
249
255 template <typename RootHisto, unsigned int N>
256 struct TraitsBase {
257 static constexpr unsigned int Dimension{ N };
258 // hleper method for the creation of the Root histogram, using an index_sequence for handling the axis
259 template <typename AxisArray, std::size_t... index>
260 static RootHisto create( std::string& name, std::string& title, AxisArray axis, std::index_sequence<index...> ) {
261 return std::make_from_tuple<RootHisto>(
262 std::tuple_cat( std::tuple{ name.c_str(), title.c_str() },
263 std::tuple{ std::get<index>( axis ).nBins, std::get<index>( axis ).minValue,
264 std::get<index>( axis ).maxValue }... ) );
265 }
266 // Generic creation of the Root histogram from name, title and a set of axis
267 template <typename... Axis>
268 static RootHisto create( std::string& name, std::string& title, Axis&... axis ) {
269 return create( name, title, std::make_tuple( axis... ), std::make_index_sequence<sizeof...( Axis )>() );
270 }
271 // Generic fill of the metadata of the Root histogram from json data
272 static void fillMetaData( RootHisto& histo, nlohmann::json const& jsonAxis, unsigned int nentries ) {
273 auto try_set_bin_labels = [&histo, &jsonAxis]( auto idx ) {
274 TAxis* axis = nullptr;
275 switch ( idx ) {
276 case 0:
277 axis = histo.GetXaxis();
278 break;
279 case 1:
280 axis = histo.GetYaxis();
281 break;
282 case 2:
283 axis = histo.GetZaxis();
284 break;
285 default:
286 break;
287 }
288 if ( axis && jsonAxis[idx].contains( "labels" ) ) {
289 const auto labels = jsonAxis[idx].at( "labels" );
290 for ( unsigned int i = 0; i < labels.size(); i++ ) {
291 axis->SetBinLabel( i + 1, labels[i].template get<std::string>().c_str() );
292 }
293 }
294 if ( axis && jsonAxis[idx].contains( "xbins" ) ) {
295 const auto xbins = jsonAxis[idx].at( "xbins" );
296 axis->Set( xbins.size() - 1, xbins.template get<std::vector<double>>().data() );
297 }
298 };
299 for ( unsigned int i = 0; i < jsonAxis.size(); i++ ) try_set_bin_labels( i );
300 // Fix the number of entries, wrongly computed by ROOT from the numer of calls to fill
301 histo.SetEntries( nentries );
302 }
303 };
304
306 template <typename TP>
307 struct ProfileWrapper : TP {
308 template <typename... Args>
309 ProfileWrapper( Args&&... args ) : TP( std::forward<Args>( args )... ) {
310 // When the static function TH1::SetDefaultSumw2 had been called (passing true), `Sumw2(true)` is automatically
311 // called by the constructor of TProfile. This is a problem because in the profiles in Gaudi::Accumulators we do
312 // not keep track of the sum of squares of weights and consequently don't set fBinSumw2 of the TProfile, which
313 // in turn leads to a self-inconsistent TProfile object. The "fix" is to disable sum of squares explicitly.
314 this->Sumw2( false );
315 }
316 ProfileWrapper( ProfileWrapper const& ) = delete;
318 ProfileWrapper( ProfileWrapper const&& ) = delete;
320 void setBinNEntries( Int_t i, Int_t n ) { this->fBinEntries.fArray[i] = n; }
321 void setBinW2( Int_t i, Double_t v ) { this->fSumw2.fArray[i] = v; }
322 Double_t getBinW2( Int_t i ) { return this->fSumw2.fArray[i]; }
323 };
324
329 inline TDirectory* changeDir( TFile& file, std::string_view dir ) {
330 // remember the current directory
331 auto previousDir = gDirectory;
332 // find or create the directory for the histogram
333 auto currentDir = ranges::accumulate(
334 dir | std::views::transform( []( char c ) { return c == '.' ? '/' : c; } ) | std::views::split( '/' ) |
335 std::views::transform( []<std::ranges::input_range R>( R&& r ) {
336 return std::string( std::ranges::begin( r ), std::ranges::end( r ) );
337 } ),
338 file.GetDirectory( "" ), []( TDirectory* current, std::string const& d ) -> TDirectory* {
339 if ( !current ) return current;
340 if ( auto next = current->GetDirectory( d.c_str() ); next ) return next;
341 return current->mkdir( d.c_str() );
342 } );
343 if ( !currentDir )
344 throw GaudiException( fmt::format( "Could not create directory {}", dir ), "Histogram::Sink::Root",
346 // switch to the directory
347 currentDir->cd();
348 return previousDir;
349 }
350
351 template <typename Histo>
352 nlohmann::json allAxisTojson( Histo const& h ) {
353 if constexpr ( std::is_base_of_v<TH3D, Histo> ) {
354 return { *h.GetXaxis(), *h.GetYaxis(), *h.GetZaxis() };
355 } else if constexpr ( std::is_base_of_v<TProfile2D, Histo> || std::is_base_of_v<TH2D, Histo> ) {
356 return { *h.GetXaxis(), *h.GetYaxis() };
357 } else {
358 return { *h.GetXaxis() };
359 }
360 }
361
362 template <typename Histo>
363 nlohmann::json binsTojson( Histo const& h ) {
364 if constexpr ( std::is_base_of_v<TProfile, Histo> || std::is_base_of_v<TProfile2D, Histo> ) {
365 nlohmann::json j;
366 // ROOT TProfile interface being completely inconsistent, we have to play
367 // with different ways to access values of the histogram... one per value !
368 auto* sums = h.GetArray();
369 auto* sums2 = h.GetSumw2();
370 for ( unsigned long n = 0; n < (unsigned long)h.GetSize(); n++ ) {
371 j.push_back( nlohmann::json{ { h.GetBinEntries( n ), sums[n] }, sums2->At( n ) } );
372 }
373 return j;
374 } else {
375 return gsl::span{ h.GetArray(), (unsigned long)h.GetSize() };
376 }
377 }
378
380 template <typename Histo>
381 nlohmann::json rootHistogramToJson( Histo const& h ) {
382 bool isProfile = std::is_base_of_v<TProfile, Histo> || std::is_base_of_v<TProfile2D, Histo>;
383 std::string type = isProfile ? "histogram:ProfileHistogram:double" : "histogram:Histogram:double";
384 auto j = nlohmann::json{ { "type", type },
385 { "title", h.GetTitle() },
386 { "dimension", h.GetDimension() },
387 { "empty", (int)h.GetEntries() == 0 },
388 { "nEntries", (int)h.GetEntries() },
389 { "axis", allAxisTojson( h ) },
390 { "bins", binsTojson( h ) } };
391 if ( !isProfile ) {
392 double s[13];
393 h.GetStats( s );
394 if ( h.GetDimension() == 1 ) {
395 j["nTotEntries"] = s[0];
396 j["sum"] = s[2];
397 j["sum2"] = s[3];
398 j["mean"] = s[2] / s[0];
399 } else {
400 j["nTotEntries"] = s[0];
401 j["sumx"] = s[2];
402 j["sumx2"] = s[3];
403 j["meanx"] = s[2] / s[0];
404 j["sumy"] = s[4];
405 j["sumy2"] = s[5];
406 j["sumxy"] = s[6];
407 j["meany"] = s[4] / s[0];
408 if ( h.GetDimension() >= 3 ) {
409 j["sumz"] = s[7];
410 j["sumz2"] = s[8];
411 j["sumxz"] = s[9];
412 j["sumyz"] = s[10];
413 j["meanz"] = s[7] / s[0];
414 }
415 }
416 }
417 return j;
418 }
419
420 } // namespace details
421
425 template <typename RootHisto, unsigned int N>
426 struct Traits<false, RootHisto, N> : details::TraitsBase<RootHisto, N> {
427 using Histo = RootHisto;
428 using WeightType = std::vector<double>;
429 static void fill( Histo& histo, unsigned int nbins, const WeightType& weight ) {
430 for ( unsigned int i = 0; i < nbins; i++ ) { histo.SetBinContent( i, weight[i] ); }
431 }
432 };
433
437 template <typename RootHisto, unsigned int N>
438 struct Traits<true, RootHisto, N> : details::TraitsBase<details::ProfileWrapper<RootHisto>, N> {
440 using WeightType = std::vector<std::tuple<std::tuple<unsigned int, double>, double>>;
441 static constexpr void fill( Histo& histo, unsigned int nbins, const WeightType& weight ) {
442 for ( unsigned int i = 0; i < nbins; i++ ) {
443 auto [c, sumWeight2] = weight[i];
444 auto [nEntries, sumWeight] = c;
445 histo.setBinNEntries( i, nEntries );
446 histo.SetBinContent( i, sumWeight );
447 histo.setBinW2( i, sumWeight2 );
448 }
449 }
450 };
451
452 template <typename Traits>
453 std::tuple<typename Traits::Histo, std::string> jsonToRootHistogram( std::string& dir, std::string& name,
454 nlohmann::json const& j ) {
455 return details::jsonToRootHistogramInternal<Traits>( dir, name, j, std::make_index_sequence<Traits::Dimension>() );
456 }
457
458 template <typename Traits>
459 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json const& j ) {
460 // get the Root histogram
461 auto [histo, newDir] = jsonToRootHistogram<Traits>( dir, name, j );
462 // Change to the proper directory in the ROOT file
463 auto previousDir = details::changeDir( file, newDir );
464 // write to file
465 histo.Write();
466 // switch back to the previous directory
467 previousDir->cd();
468 }
469
470 template <unsigned int N, bool isProfile, typename ROOTHisto>
471 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json const& j ) {
472 saveRootHisto<Traits<isProfile, ROOTHisto, N>>( file, std::move( dir ), std::move( name ), j );
473 }
474
476 template <Accumulators::atomicity Atomicity = Accumulators::atomicity::full, typename Arithmetic = double>
478 // get original histogram from the Entity
479 auto const& gaudiHisto =
481 // convert to Root
482 auto const& gaudiAxis = gaudiHisto.template axis<0>();
483 details::ProfileWrapper<TProfile> histo{ name.c_str(), gaudiHisto.title().c_str(), gaudiAxis.numBins(),
484 gaudiAxis.minValue(), gaudiAxis.maxValue() };
485 if ( !gaudiAxis.labels().empty() ) {
486 auto& axis = *histo.GetXaxis();
487 for ( unsigned int i = 0; i < gaudiAxis.labels().size(); i++ ) {
488 axis.SetBinLabel( i + 1, gaudiAxis.labels()[i].c_str() );
489 }
490 }
491 for ( unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) {
492 auto const& [tmp, sumw2] = gaudiHisto.binValue( i );
493 auto const& [nent, sumw] = tmp;
494 histo.SetBinContent( i, sumw );
495 histo.setBinNEntries( i, nent );
496 histo.setBinW2( i, sumw2 );
497 }
498 unsigned long totNEntries{ 0 };
499 for ( unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) { totNEntries += gaudiHisto.nEntries( i ); }
500 histo.SetEntries( totNEntries );
501 return histo;
502 }
503
505 template <Accumulators::atomicity Atomicity = Accumulators::atomicity::full, typename Arithmetic = double>
507 // get original histogram from the Entity
508 auto const& gaudiHisto =
510 // convert to Root
511 auto const& gaudiXAxis = gaudiHisto.template axis<0>();
512 auto const& gaudiYAxis = gaudiHisto.template axis<1>();
513 details::ProfileWrapper<TProfile2D> histo{ name.c_str(), gaudiHisto.title().c_str(), gaudiXAxis.numBins(),
514 gaudiXAxis.minValue(), gaudiXAxis.maxValue(), gaudiYAxis.numBins(),
515 gaudiYAxis.minValue(), gaudiYAxis.maxValue() };
516 if ( !gaudiXAxis.labels().empty() ) {
517 auto& axis = *histo.GetXaxis();
518 for ( unsigned int i = 0; i < gaudiXAxis.labels().size(); i++ ) {
519 axis.SetBinLabel( i + 1, gaudiXAxis.labels()[i].c_str() );
520 }
521 }
522 if ( !gaudiYAxis.labels().empty() ) {
523 auto& axis = *histo.GetYaxis();
524 for ( unsigned int i = 0; i < gaudiYAxis.labels().size(); i++ ) {
525 axis.SetBinLabel( i + 1, gaudiYAxis.labels()[i].c_str() );
526 }
527 }
528 for ( unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) {
529 auto const& [tmp, sumw2] = gaudiHisto.binValue( i );
530 auto const& [nent, sumw] = tmp;
531 histo.SetBinContent( i, sumw );
532 histo.setBinNEntries( i, nent );
533 histo.setBinW2( i, sumw2 );
534 }
535 unsigned long totNEntries{ 0 };
536 for ( unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) { totNEntries += gaudiHisto.nEntries( i ); }
537 histo.SetEntries( totNEntries );
538 return histo;
539 }
540
542 template <Accumulators::atomicity Atomicity = Accumulators::atomicity::full, typename Arithmetic = double>
544 // get original histogram from the Entity
545 auto const& gaudiHisto =
547 // convert to Root
548 auto const& gaudiXAxis = gaudiHisto.template axis<0>();
549 auto const& gaudiYAxis = gaudiHisto.template axis<1>();
550 auto const& gaudiZAxis = gaudiHisto.template axis<2>();
551 details::ProfileWrapper<TProfile3D> histo{ name.c_str(), gaudiHisto.title().c_str(), gaudiXAxis.numBins(),
552 gaudiXAxis.minValue(), gaudiXAxis.maxValue(), gaudiYAxis.numBins(),
553 gaudiYAxis.minValue(), gaudiYAxis.maxValue(), gaudiZAxis.numBins(),
554 gaudiZAxis.minValue(), gaudiZAxis.maxValue() };
555 if ( !gaudiXAxis.labels().empty() ) {
556 auto& axis = *histo.GetXaxis();
557 for ( unsigned int i = 0; i < gaudiXAxis.labels().size(); i++ ) {
558 axis.SetBinLabel( i + 1, gaudiXAxis.labels()[i].c_str() );
559 }
560 }
561 if ( !gaudiYAxis.labels().empty() ) {
562 auto& axis = *histo.GetYaxis();
563 for ( unsigned int i = 0; i < gaudiYAxis.labels().size(); i++ ) {
564 axis.SetBinLabel( i + 1, gaudiYAxis.labels()[i].c_str() );
565 }
566 }
567 if ( !gaudiZAxis.labels().empty() ) {
568 auto& axis = *histo.GetZaxis();
569 for ( unsigned int i = 0; i < gaudiZAxis.labels().size(); i++ ) {
570 axis.SetBinLabel( i + 1, gaudiZAxis.labels()[i].c_str() );
571 }
572 }
573 for ( unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) {
574 auto const& [tmp, sumw2] = gaudiHisto.binValue( i );
575 auto const& [nent, sumw] = tmp;
576 histo.SetBinContent( i, sumw );
577 histo.setBinNEntries( i, nent );
578 histo.setBinW2( i, sumw2 );
579 }
580 unsigned long totNEntries{ 0 };
581 for ( unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) { totNEntries += gaudiHisto.nEntries( i ); }
582 histo.SetEntries( totNEntries );
583 return histo;
584 }
585
586 template <unsigned int N, Accumulators::atomicity Atomicity = Accumulators::atomicity::full,
587 typename Arithmetic = double>
588 void saveProfileHisto( TFile& file, std::string dir, std::string name, Monitoring::Hub::Entity const& ent ) {
589 // fix name and dir if needed
590 details::fixNameAndDir( name, dir );
591 // Change to the proper directory in the ROOT file
592 auto previousDir = details::changeDir( file, dir );
593 // write to file
594 if constexpr ( N == 1 ) {
596 } else if constexpr ( N == 2 ) {
598 } else if constexpr ( N == 3 ) {
600 }
601 // switch back to the previous directory
602 previousDir->cd();
603 }
604
605 namespace details {
606 template <typename TYPE>
607 struct BinAvValue {
608 private:
609 TYPE m_min{ 0 }, m_max{ 0 }, m_binSize{ 0 };
610 bool m_isInt{ false };
611
612 public:
613 BinAvValue( const TYPE minV, const TYPE maxV, unsigned int nbins, const bool isInt )
614 : m_min( minV ), m_max( maxV ), m_isInt( isInt ) {
615 if ( nbins > 0 ) { m_binSize = ( maxV - minV ) / nbins; }
616 }
617 auto operator()( const unsigned int n ) const {
618 TYPE binAv{ 0 };
619 if ( m_isInt ) {
620 // Need to find all int values that are in range for this bin and form average
621 const auto binMin = m_min + ( n - 1.0 ) * m_binSize;
622 const auto binMax = binMin + m_binSize;
623 unsigned int nAv{ 0 };
624 for ( auto iv = std::floor( binMin ); iv < std::ceil( binMax ); iv += 1.0 ) {
625 if ( binMin <= iv && iv <= binMax ) {
626 binAv += iv;
627 ++nAv;
628 }
629 }
630 binAv = ( nAv > 0 ? binAv / nAv : 0 );
631 } else {
632 // For floats just use bin centre
633 binAv = m_min + ( n - 0.5 ) * m_binSize;
634 }
635 return binAv;
636 }
637 };
638 } // namespace details
639
641 typename Arithmetic = double>
642 std::string printProfileHisto1D( std::string_view name, Gaudi::Monitoring::Hub::Entity const& ent,
643 unsigned int stringsWidth = 45 ) {
644 using std::abs;
645 // Type to use for internal calculation. Use double to avoid precision issues across different builds.
646 using FPType = double;
647 // get original histogram from the Entity
648 auto const& gaudiHisto =
650 // compute min and max values, we actually display the axis limits
651 auto const& gaudiAxisX = gaudiHisto.template axis<0>();
652 const FPType minValueX = gaudiAxisX.minValue();
653 const FPType maxValueX = gaudiAxisX.maxValue();
654 const unsigned int nBinsX = gaudiAxisX.numBins();
655 // Compute fist and second momenta for normal dimension
656 // Compute 1st and 2nd momenta for the profile dimension
657 unsigned int nEntries{ 0 }, nAllEntries{ 0 };
658 FPType totalSumW{ 0 };
659 FPType sumX{ 0 }, sum2X{ 0 }, sum3X{ 0 }, sum4X{ 0 };
660 const details::BinAvValue xBinAv( minValueX, maxValueX, nBinsX, std::is_integral_v<Arithmetic> );
661 for ( unsigned int nx = 0; nx <= nBinsX + 1; ++nx ) {
662 auto const& [tmp, sumw2] = gaudiHisto.binValue( nx );
663 auto const& [nent, sumw] = tmp;
664 nAllEntries += nent;
665 if ( nx > 0 && nx <= nBinsX ) {
666 const FPType binXValue = xBinAv( nx );
667 nEntries += nent;
668 const auto sumw_abs = abs( sumw );
669 totalSumW += sumw_abs;
670 auto val = binXValue * sumw_abs;
671 sumX += val;
672 val *= binXValue;
673 sum2X += val;
674 val *= binXValue;
675 sum3X += val;
676 val *= binXValue;
677 sum4X += val;
678 }
679 }
680 const std::string ftitle = detail::formatTitle( gaudiHisto.title(), stringsWidth - 2 );
681 if ( nEntries == 0 || !( abs( totalSumW ) > 0 ) ) { return ""; }
682 const FPType meanX = sumX / totalSumW;
683 const FPType sigmaX2 = ( sum2X / totalSumW ) - std::pow( meanX, 2 );
684 const FPType stddevX = detail::sqrt_or_zero( sigmaX2 );
685 const FPType EX3 = sum3X / totalSumW;
686 const FPType A = sigmaX2 * stddevX;
687 const FPType skewnessX = ( abs( A ) > 0.0 ? ( EX3 - ( 3 * sigmaX2 + meanX * meanX ) * meanX ) / A : 0.0 );
688 const FPType B = sigmaX2 * sigmaX2;
689 const FPType kurtosisX =
690 ( abs( B ) > 0.0 && abs( A ) > 0.0
691 ? ( sum4X / totalSumW - meanX * ( 4 * EX3 - meanX * ( 6 * sigmaX2 + 3 * meanX * meanX ) ) ) / B
692 : 3.0 );
693 // print
694 return fmt::format( fmt::runtime( detail::histo1DFormatting ), detail::formatName( name, stringsWidth ),
695 stringsWidth, stringsWidth, ftitle, stringsWidth, detail::IntWithFixedWidth{ nEntries }, meanX,
696 stddevX, skewnessX, kurtosisX - FPType{ 3.0 } );
697 }
698
700 typename Arithmetic = double>
701 std::string printProfileHisto2D( std::string_view name, Gaudi::Monitoring::Hub::Entity const& ent,
702 unsigned int stringsWidth = 45 ) {
703 using std::abs;
704 // Type to use for internal calculation. Use double to avoid precision issues across different builds.
705 using FPType = double;
706 // get original histogram from the Entity
707 auto const& gaudiHisto =
709 // compute min and max values, we actually display the axis limits
710 auto const& gaudiAxisX = gaudiHisto.template axis<0>();
711 const FPType minValueX = gaudiAxisX.minValue();
712 const FPType maxValueX = gaudiAxisX.maxValue();
713 const unsigned int nBinsX = gaudiAxisX.numBins();
714 auto const& gaudiAxisY = gaudiHisto.template axis<1>();
715 const FPType minValueY = gaudiAxisY.minValue();
716 const FPType maxValueY = gaudiAxisY.maxValue();
717 const unsigned int nBinsY = gaudiAxisY.numBins();
718 // Compute fist and second momenta for normal dimenstion
719 // Compute 1st and 2nd momenta for the profile dimension
720 FPType nEntries{ 0 }, nAllEntries{ 0 };
721 FPType totalSumW{ 0 };
722 FPType sumX{ 0 }, sumY{ 0 };
723 FPType sum2X{ 0 }, sum2Y{ 0 };
724 const details::BinAvValue xBinAv( minValueX, maxValueX, nBinsX, std::is_integral_v<Arithmetic> );
725 const details::BinAvValue yBinAv( minValueY, maxValueY, nBinsY, std::is_integral_v<Arithmetic> );
726 for ( unsigned int ny = 0; ny <= nBinsY + 1; ++ny ) {
727 const auto offset = ny * ( nBinsX + 2 );
728 for ( unsigned int nx = 0; nx <= nBinsX + 1; ++nx ) {
729 auto const& [tmp, sumw2] = gaudiHisto.binValue( nx + offset );
730 auto const& [nent, sumw] = tmp;
731 nAllEntries += nent;
732 if ( nx > 0 && ny > 0 && nx <= nBinsX && ny <= nBinsY ) {
733 const FPType binXValue = xBinAv( nx );
734 const FPType binYValue = yBinAv( ny );
735 nEntries += nent;
736 const auto sumw_abs = abs( sumw );
737 totalSumW += sumw_abs;
738 sumX += binXValue * sumw_abs;
739 sum2X += binXValue * binXValue * sumw_abs;
740 sumY += binYValue * sumw_abs;
741 sum2Y += binYValue * binYValue * sumw_abs;
742 }
743 }
744 }
745 const FPType meanX = abs( totalSumW ) > 0 ? sumX / totalSumW : 0.0;
746 const FPType stddevX =
747 abs( totalSumW ) > 0 ? detail::sqrt_or_zero( ( sum2X - sumX * ( sumX / totalSumW ) ) / totalSumW ) : 0.0;
748 const FPType meanY = abs( totalSumW ) > 0 ? sumY / totalSumW : 0.0;
749 const FPType stddevY =
750 abs( totalSumW ) > 0 ? detail::sqrt_or_zero( ( sum2Y - sumY * ( sumY / totalSumW ) ) / totalSumW ) : 0.0;
751 // print
752 const std::string ftitle = detail::formatTitle( gaudiHisto.title(), stringsWidth - 2 );
753 return fmt::format( fmt::runtime( detail::histo2DFormatting ), detail::formatName( name, stringsWidth ),
754 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
755 stddevY );
756 }
757
759 typename Arithmetic = double>
760 std::string printProfileHisto3D( std::string_view name, Gaudi::Monitoring::Hub::Entity const& ent,
761 unsigned int stringsWidth = 45 ) {
762 using std::abs;
763 // Type to use for internal calculation. Use double to avoid precision issues across different builds.
764 using FPType = double;
765 // get original histogram from the Entity
766 auto const& gaudiHisto =
768 // compute min and max values, we actually display the axis limits
769 auto const& gaudiAxisX = gaudiHisto.template axis<0>();
770 const FPType minValueX = gaudiAxisX.minValue();
771 const FPType maxValueX = gaudiAxisX.maxValue();
772 const unsigned int nBinsX = gaudiAxisX.numBins();
773 auto const& gaudiAxisY = gaudiHisto.template axis<1>();
774 const FPType minValueY = gaudiAxisY.minValue();
775 const FPType maxValueY = gaudiAxisY.maxValue();
776 const unsigned int nBinsY = gaudiAxisY.numBins();
777 auto const& gaudiAxisZ = gaudiHisto.template axis<2>();
778 const FPType minValueZ = gaudiAxisZ.minValue();
779 const FPType maxValueZ = gaudiAxisZ.maxValue();
780 const unsigned int nBinsZ = gaudiAxisZ.numBins();
781 // Compute fist and second momenta for normal dimenstion
782 // Compute 1st and 2nd momenta for the profile dimension
783 FPType nEntries{ 0 }, nAllEntries{ 0 };
784 FPType totalSumW{};
785 FPType sumX{ 0 }, sumY{ 0 }, sumZ{ 0 };
786 FPType sum2X{ 0 }, sum2Y{ 0 }, sum2Z{ 0 };
787 const details::BinAvValue xBinAv( minValueX, maxValueX, nBinsX, std::is_integral_v<Arithmetic> );
788 const details::BinAvValue yBinAv( minValueY, maxValueY, nBinsY, std::is_integral_v<Arithmetic> );
789 const details::BinAvValue zBinAv( minValueZ, maxValueZ, nBinsZ, std::is_integral_v<Arithmetic> );
790 for ( unsigned int nz = 0; nz <= nBinsZ + 1; ++nz ) {
791 const auto offsetz = nz * ( nBinsY + 2 );
792 for ( unsigned int ny = 0; ny <= nBinsY; ++ny ) {
793 const auto offset = ( offsetz + ny ) * ( nBinsX + 2 );
794 for ( unsigned int nx = 0; nx <= nBinsX; ++nx ) {
795 auto const& [tmp, sumw2] = gaudiHisto.binValue( nx + offset );
796 auto const& [nent, sumw] = tmp;
797 nAllEntries += nent;
798 if ( nx > 0 && ny > 0 && nz > 0 && nx <= nBinsX && ny <= nBinsY && nz <= nBinsZ ) {
799 const FPType binXValue = xBinAv( nx );
800 const FPType binYValue = yBinAv( ny );
801 const FPType binZValue = zBinAv( nz );
802 nEntries += nent;
803 const auto sumw_abs = abs( sumw );
804 totalSumW += sumw_abs;
805 sumX += binXValue * sumw_abs;
806 sum2X += binXValue * binXValue * sumw_abs;
807 sumY += binYValue * sumw_abs;
808 sum2Y += binYValue * binYValue * sumw_abs;
809 sumZ += binZValue * sumw_abs;
810 sum2Z += binZValue * binZValue * sumw_abs;
811 }
812 }
813 }
814 }
815 const FPType meanX = abs( totalSumW ) > 0 ? sumX / totalSumW : 0.0;
816 const FPType stddevX =
817 abs( totalSumW ) > 0 ? detail::sqrt_or_zero( ( sum2X - sumX * ( sumX / totalSumW ) ) / totalSumW ) : 0.0;
818 const FPType meanY = abs( totalSumW ) > 0 ? sumY / totalSumW : 0.0;
819 const FPType stddevY =
820 abs( totalSumW ) > 0 ? detail::sqrt_or_zero( ( sum2Y - sumY * ( sumY / totalSumW ) ) / totalSumW ) : 0.0;
821 const FPType meanZ = abs( totalSumW ) > 0 ? sumZ / totalSumW : 0.0;
822 const FPType stddevZ =
823 abs( totalSumW ) > 0 ? detail::sqrt_or_zero( ( sum2Z - sumZ * ( sumZ / totalSumW ) ) / totalSumW ) : 0.0;
824 // print
825 const std::string ftitle = detail::formatTitle( gaudiHisto.title(), stringsWidth - 2 );
826 return fmt::format( fmt::runtime( detail::histo3DFormatting ), detail::formatName( name, stringsWidth ),
827 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
828 stddevY, meanZ, stddevZ );
829 }
830
831 struct BinAccessor {
832 std::function<double( unsigned int )> m_get;
833 BinAccessor( std::string_view type, const nlohmann::json& j ) {
834 auto subtype = std::string_view( type ).substr( 10 ); // remove "histogram:" in front
835 if ( subtype.substr( 0, 15 ) == "WeightedProfile" || subtype.substr( 0, 7 ) == "Profile" ) {
836 m_get = [bins = j.at( "bins" ).get<std::vector<std::tuple<std::tuple<unsigned int, double>, double>>>()](
837 unsigned int nx ) {
838 auto [c, sumWeight2] = bins[nx];
839 auto [n, sumWeight] = c;
840 return sumWeight;
841 };
842 } else {
843 m_get = [bins = j.at( "bins" ).get<std::vector<double>>()]( unsigned int nx ) { return bins[nx]; };
844 }
845 }
846 auto operator[]( const unsigned int n ) const {
847 using std::abs;
848 return abs( m_get( n ) );
849 }
850 };
851
853 static bool is_integral( const std::string_view type ) {
854 for ( const std::string s : { ":i", ":l" } ) {
855 if ( 0 == type.compare( type.length() - s.length(), s.length(), s ) ) { return true; }
856 }
857 return false;
858 }
859 };
860
861 inline std::string printHistogram1D( std::string_view type, std::string_view name, std::string_view title,
862 const nlohmann::json& j, unsigned int stringsWidth = 45 ) {
863 using std::abs;
864 const auto& jaxis = j.at( "axis" );
865 const auto minValueX = jaxis[0].at( "minValue" ).get<double>();
866 const auto maxValueX = jaxis[0].at( "maxValue" ).get<double>();
867 const auto nBinsX = jaxis[0].at( "nBins" ).get<unsigned int>();
868 const auto nAllEntries = j.at( "nEntries" ).get<unsigned int>();
869 // compute the various momenta
870 BinAccessor ba{ type, j };
871 double sumX{}, sum2X{}, sum3X{}, sum4X{}, nEntries{ 0 };
872 const details::BinAvValue xBinAv( minValueX, maxValueX, nBinsX, ArthTypeAccessor::is_integral( type ) );
873 for ( unsigned int nx = 1; nx <= nBinsX; ++nx ) {
874 const double binXValue = xBinAv( nx );
875 const auto n = ba[nx];
876 nEntries += n;
877 auto val = binXValue * n;
878 sumX += val;
879 val *= binXValue;
880 sum2X += val;
881 val *= binXValue;
882 sum3X += val;
883 val *= binXValue;
884 sum4X += val;
885 }
886 const std::string ftitle = detail::formatTitle( title, stringsWidth - 2 );
887 if ( !( abs( nEntries ) > 0.0 ) ) { return ""; }
888 const double meanX = sumX / nEntries;
889 const double sigmaX2 = ( sum2X / nEntries ) - std::pow( meanX, 2 );
890 const double stddevX = detail::sqrt_or_zero( sigmaX2 );
891 const double EX3 = sum3X / nEntries;
892 const double A = sigmaX2 * stddevX;
893 const double skewnessX = ( abs( A ) > 0.0 ? ( EX3 - ( 3 * sigmaX2 + meanX * meanX ) * meanX ) / A : 0.0 );
894 const double B = sigmaX2 * sigmaX2;
895 const double kurtosisX =
896 ( abs( B ) > 0.0 && abs( A ) > 0.0
897 ? ( sum4X / nEntries - meanX * ( 4 * EX3 - meanX * ( 6 * sigmaX2 + 3 * meanX * meanX ) ) ) / B
898 : 3.0 );
899 // print
900 return fmt::format( fmt::runtime( detail::histo1DFormatting ), detail::formatName( name, stringsWidth ),
901 stringsWidth, stringsWidth, ftitle, stringsWidth, detail::IntWithFixedWidth{ nAllEntries },
902 meanX, stddevX, skewnessX, kurtosisX - 3.0 );
903 }
904
905 inline std::string printHistogram2D( std::string_view type, std::string_view name, std::string_view title,
906 const nlohmann::json& j, unsigned int stringsWidth = 45 ) {
907 using std::abs;
908 const auto& jaxis = j.at( "axis" );
909 const auto minValueX = jaxis[0].at( "minValue" ).get<double>();
910 const auto maxValueX = jaxis[0].at( "maxValue" ).get<double>();
911 const auto nBinsX = jaxis[0].at( "nBins" ).get<unsigned int>();
912 const auto minValueY = jaxis[1].at( "minValue" ).get<double>();
913 const auto maxValueY = jaxis[1].at( "maxValue" ).get<double>();
914 const auto nBinsY = jaxis[1].at( "nBins" ).get<unsigned int>();
915 const auto nAllEntries = j.at( "nEntries" ).get<double>();
916 // compute the various memneta
917 BinAccessor ba{ type, j };
918 double nEntries{};
919 double sumX{}, sumY{};
920 double sum2X{}, sum2Y{};
921 const auto isInt = ArthTypeAccessor::is_integral( type );
922 const details::BinAvValue xBinAv( minValueX, maxValueX, nBinsX, isInt );
923 const details::BinAvValue yBinAv( minValueY, maxValueY, nBinsY, isInt );
924 for ( unsigned int ny = 1; ny <= nBinsY; ++ny ) {
925 const auto offset = ny * ( nBinsX + 2 );
926 for ( unsigned int nx = 1; nx <= nBinsX; ++nx ) {
927 const double binXValue = xBinAv( nx );
928 const double binYValue = yBinAv( ny );
929 const auto n = ba[offset + nx];
930 nEntries += n;
931 sumX += n * binXValue;
932 sum2X += n * binXValue * binXValue;
933 sumY += n * binYValue;
934 sum2Y += n * binYValue * binYValue;
935 }
936 }
937 const double meanX = abs( nEntries ) > 0 ? sumX / nEntries : 0.0;
938 const double stddevX =
939 abs( nEntries ) > 0 ? detail::sqrt_or_zero( ( sum2X - sumX * ( sumX / nEntries ) ) / nEntries ) : 0.0;
940 const double meanY = abs( nEntries ) > 0 ? sumY / nEntries : 0.0;
941 const double stddevY =
942 abs( nEntries ) > 0 ? detail::sqrt_or_zero( ( sum2Y - sumY * ( sumY / nEntries ) ) / nEntries ) : 0.0;
943 // print
944 const std::string ftitle = detail::formatTitle( title, stringsWidth - 2 );
945 return fmt::format( fmt::runtime( detail::histo2DFormatting ), detail::formatName( name, stringsWidth ),
946 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
947 stddevY );
948 }
949
950 inline std::string printHistogram3D( std::string_view type, std::string_view name, std::string_view title,
951 const nlohmann::json& j, unsigned int stringsWidth = 45 ) {
952 using std::abs;
953 const auto& jaxis = j.at( "axis" );
954 const auto minValueX = jaxis[0].at( "minValue" ).get<double>();
955 const auto maxValueX = jaxis[0].at( "maxValue" ).get<double>();
956 const auto nBinsX = jaxis[0].at( "nBins" ).get<unsigned int>();
957 const auto minValueY = jaxis[1].at( "minValue" ).get<double>();
958 const auto maxValueY = jaxis[1].at( "maxValue" ).get<double>();
959 const auto nBinsY = jaxis[1].at( "nBins" ).get<unsigned int>();
960 const auto minValueZ = jaxis[2].at( "minValue" ).get<double>();
961 const auto maxValueZ = jaxis[2].at( "maxValue" ).get<double>();
962 const auto nBinsZ = jaxis[2].at( "nBins" ).get<unsigned int>();
963 const auto nAllEntries = j.at( "nEntries" ).get<double>();
964 // compute the various memneta
965 BinAccessor ba{ type, j };
966 double nEntries{};
967 double sumX{}, sumY{}, sumZ{};
968 double sum2X{}, sum2Y{}, sum2Z{};
969 const auto isInt = ArthTypeAccessor::is_integral( type );
970 const details::BinAvValue xBinAv( minValueX, maxValueX, nBinsX, isInt );
971 const details::BinAvValue yBinAv( minValueY, maxValueY, nBinsY, isInt );
972 const details::BinAvValue zBinAv( minValueZ, maxValueZ, nBinsZ, isInt );
973 for ( unsigned int nz = 1; nz <= nBinsZ; ++nz ) {
974 const auto offsetz = nz * ( nBinsY + 2 );
975 for ( unsigned int ny = 1; ny <= nBinsY; ++ny ) {
976 const auto offset = ( offsetz + ny ) * ( nBinsX + 2 );
977 for ( unsigned int nx = 1; nx <= nBinsX; ++nx ) {
978 const double binXValue = xBinAv( nx );
979 const double binYValue = yBinAv( ny );
980 const double binZValue = zBinAv( nz );
981 const auto n = ba[offset + nx];
982 nEntries += n;
983 sumX += n * binXValue;
984 sum2X += n * binXValue * binXValue;
985 sumY += n * binYValue;
986 sum2Y += n * binYValue * binYValue;
987 sumZ += n * binZValue;
988 sum2Z += n * binZValue * binZValue;
989 }
990 }
991 }
992 const double meanX = abs( nEntries ) > 0 ? sumX / nEntries : 0.0;
993 const double stddevX =
994 abs( nEntries ) > 0 ? detail::sqrt_or_zero( ( sum2X - sumX * ( sumX / nEntries ) ) / nEntries ) : 0.0;
995 const double meanY = abs( nEntries ) > 0 ? sumY / nEntries : 0.0;
996 const double stddevY =
997 abs( nEntries ) > 0 ? detail::sqrt_or_zero( ( sum2Y - sumY * ( sumY / nEntries ) ) / nEntries ) : 0.0;
998 const double meanZ = abs( nEntries ) > 0 ? sumZ / nEntries : 0.0;
999 const double stddevZ =
1000 abs( nEntries ) > 0 ? detail::sqrt_or_zero( ( sum2Z - sumZ * ( sumZ / nEntries ) ) / nEntries ) : 0.0;
1001 // print
1002 const std::string ftitle = detail::formatTitle( title, stringsWidth - 2 );
1003 return fmt::format( fmt::runtime( detail::histo3DFormatting ), detail::formatName( name, stringsWidth ),
1004 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
1005 stddevY, meanZ, stddevZ );
1006 }
1007
1008} // namespace Gaudi::Histograming::Sink
1009
1010namespace nlohmann {
1012 inline void to_json( nlohmann::json& j, TAxis const& axis ) {
1013 j = nlohmann::json{ { "nBins", axis.GetNbins() },
1014 { "minValue", axis.GetXmin() },
1015 { "maxValue", axis.GetXmax() },
1016 { "title", axis.GetTitle() } };
1017 }
1018
1019 inline void to_json( nlohmann::json& j, TH1D const& h ) {
1021 }
1022 inline void to_json( nlohmann::json& j, TH2D const& h ) {
1024 }
1025 inline void to_json( nlohmann::json& j, TH3D const& h ) {
1027 }
1028 inline void to_json( nlohmann::json& j, TProfile const& h ) {
1030 }
1031 inline void to_json( nlohmann::json& j, TProfile2D const& h ) {
1033 }
1034
1035} // namespace nlohmann
Wrapper class for arbitrary monitoring objects.
void * id() const
unique identifier, actually mapped to internal pointer
Define general base for Gaudi exception.
constexpr static const auto FAILURE
Definition StatusCode.h:100
atomicity
Defines atomicity of the accumulators.
HistogramingCounterBase< ND, Atomicity, Arithmetic, naming::profilehistogramString, ProfileHistogramingAccumulator, AxisTupleType > StaticProfileHistogram
profile static histograming counter. See HistogramingCounterBase for details
constexpr std::string_view histo1DFormatting
Definition Utils.h:56
constexpr std::string_view histo2DFormatting
Definition Utils.h:58
std::string formatTitle(std::string_view title, unsigned int width)
Definition Utils.h:39
T sqrt_or_zero(const T x)
sqrt or zero
Definition Utils.h:71
std::string formatName(std::string_view name, unsigned int width)
Definition Utils.h:46
constexpr std::string_view histo3DFormatting
Definition Utils.h:60
TDirectory * changeDir(TFile &file, std::string_view dir)
changes to the ROOT directory given in the current ROOT file and returns the current directory before...
Definition Utils.h:329
nlohmann::json binsTojson(Histo const &h)
Definition Utils.h:363
void fixNameAndDir(std::string &name, std::string &dir)
handles cases where name includes '/' character(s) and move needed part of it to dir.
Definition Utils.h:179
nlohmann::json rootHistogramToJson(Histo const &h)
automatic translation of Root Histograms to json
Definition Utils.h:381
Axis jsonToAxis(nlohmann::json &jAxis)
extract an Axis from json data
Definition Utils.h:169
std::tuple< typename Traits::Histo, std::string > jsonToRootHistogramInternal(std::string &dir, std::string &name, nlohmann::json const &j, std::index_sequence< index... >)
generic function to convert json to a ROOT Histogram - internal implementation
Definition Utils.h:196
nlohmann::json allAxisTojson(Histo const &h)
Definition Utils.h:352
std::string printProfileHisto3D(std::string_view name, Gaudi::Monitoring::Hub::Entity const &ent, unsigned int stringsWidth=45)
Definition Utils.h:760
std::string printProfileHisto1D(std::string_view name, Gaudi::Monitoring::Hub::Entity const &ent, unsigned int stringsWidth=45)
Definition Utils.h:642
nlohmann::json rootHistogramTojson(Histo const &)
generic function to convert a ROOT Histogram to json
std::string printHistogram1D(std::string_view type, std::string_view name, std::string_view title, const nlohmann::json &j, unsigned int stringsWidth=45)
Definition Utils.h:861
std::tuple< typename Traits::Histo, std::string > jsonToRootHistogram(std::string &dir, std::string &name, nlohmann::json const &j)
generic function to convert json to a ROOT Histogram
Definition Utils.h:453
details::ProfileWrapper< TProfile2D > profileHisto2DToRoot(std::string name, Monitoring::Hub::Entity const &ent)
Direct conversion of 2D histograms from Gaudi to ROOT format.
Definition Utils.h:506
void saveProfileHisto(TFile &file, std::string dir, std::string name, Monitoring::Hub::Entity const &ent)
Definition Utils.h:588
void saveRootHisto(TFile &file, std::string dir, std::string name, nlohmann::json const &j)
generic method to save histograms to files, based on Traits
Definition Utils.h:459
std::string printHistogram2D(std::string_view type, std::string_view name, std::string_view title, const nlohmann::json &j, unsigned int stringsWidth=45)
Definition Utils.h:905
details::ProfileWrapper< TProfile > profileHisto1DToRoot(std::string name, Monitoring::Hub::Entity const &ent)
Direct conversion of 1D histograms from Gaudi to ROOT format.
Definition Utils.h:477
std::string printHistogram3D(std::string_view type, std::string_view name, std::string_view title, const nlohmann::json &j, unsigned int stringsWidth=45)
Definition Utils.h:950
details::ProfileWrapper< TProfile3D > profileHisto3DToRoot(std::string name, Monitoring::Hub::Entity const &ent)
Direct conversion of 3D histograms from Gaudi to ROOT format.
Definition Utils.h:543
std::string printProfileHisto2D(std::string_view name, Gaudi::Monitoring::Hub::Entity const &ent, unsigned int stringsWidth=45)
Definition Utils.h:701
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
void to_json(nlohmann::json &j, TAxis const &axis)
automatic translation of TAxis to json
Definition Utils.h:1012
STL namespace.
Gaudi::ParticleID abs(const Gaudi::ParticleID &p)
Return the absolute value for a PID.
Definition ParticleID.h:191
static bool is_integral(const std::string_view type)
Definition Utils.h:853
std::function< double(unsigned int)> m_get
Definition Utils.h:832
auto operator[](const unsigned int n) const
Definition Utils.h:846
BinAccessor(std::string_view type, const nlohmann::json &j)
Definition Utils.h:833
static void fill(Histo &histo, unsigned int nbins, const WeightType &weight)
Definition Utils.h:429
static constexpr void fill(Histo &histo, unsigned int nbins, const WeightType &weight)
Definition Utils.h:441
std::vector< std::tuple< std::tuple< unsigned int, double >, double > > WeightType
Definition Utils.h:440
details::ProfileWrapper< RootHisto > Histo
Definition Utils.h:439
templated Traits dealing with Root Histogram filling for standard histograms
Definition Utils.h:123
helper struct to print integers with fixed width
Definition Utils.h:65
Small helper struct representing the Axis of an Histogram.
Definition Utils.h:161
auto operator()(const unsigned int n) const
Definition Utils.h:617
BinAvValue(const TYPE minV, const TYPE maxV, unsigned int nbins, const bool isInt)
Definition Utils.h:613
helper Wrapper around TProfileX to be able to fill it
Definition Utils.h:307
ProfileWrapper(ProfileWrapper const &)=delete
ProfileWrapper(ProfileWrapper const &&)=delete
ProfileWrapper & operator=(ProfileWrapper const &&)=delete
ProfileWrapper & operator=(ProfileWrapper const &)=delete
Common base for Traits dealing with Histogram conversions to Root Provides generic implementation for...
Definition Utils.h:256
static RootHisto create(std::string &name, std::string &title, Axis &... axis)
Definition Utils.h:268
static RootHisto create(std::string &name, std::string &title, AxisArray axis, std::index_sequence< index... >)
Definition Utils.h:260
static void fillMetaData(RootHisto &histo, nlohmann::json const &jsonAxis, unsigned int nentries)
Definition Utils.h:272
static constexpr unsigned int Dimension
Definition Utils.h:257
constexpr auto parse(format_parse_context &ctx)
Definition Utils.h:91
auto format(Gaudi::Histograming::Sink::detail::IntWithFixedWidth n, format_context &ctx) const
Definition Utils.h:101