16#include <TDirectory.h>
23#include <TProfile2D.h>
24#include <TProfile3D.h>
29#include <nlohmann/json.hpp>
30#include <range/v3/numeric/accumulate.hpp>
36#include <fmt/format.h>
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 );
43 return fmt::format(
"\"{:.{}s}\"", title, width );
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 );
53 return std::string{ name };
57 " | {:{}.{}s} | {:{}s} | {:10} |{:11.5g} | {:<#11.5g}|{:11.5g} |{:11.5g} |";
59 " ID={:{}.{}s} {:{}s} Ents/All={:>5.0f}/{:<5.0f}<X>/sX={:.5g}/{:<.5g},<Y>/sY={:.5g}/{:<.5g}";
61 " ID={:{}.{}s} {:{}s} "
62 "Ents/All={:>5.0f}/{:<5.0f}<X>/sX={:.5g}/{:<.5g},<Y>/sY={:.5g}/{:<.5g},<Z>/sZ={:.5g}/{:<.5g}";
72 return ( x > 0 ? std::sqrt( x ) : T{ 0 } );
88struct fmt::formatter<
Gaudi::Histograming::Sink::detail::IntWithFixedWidth> {
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" );
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 );
122 template <
bool isProfile,
typename RootHisto,
unsigned int N>
131 template <
typename Traits>
132 std::tuple<typename Traits::Histo, std::string>
jsonToRootHistogram( std::string& dir, std::string& name,
133 nlohmann::json
const& j );
140 template <
typename Histo>
146 template <
typename Traits>
147 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json
const& j );
155 template <
unsigned int N,
bool isProfile,
typename ROOTHisto>
156 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json
const& j );
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>() };
180 if ( name[0] ==
'/' ) {
182 name = name.substr( 1 );
186 if (
auto pos = name.rfind(
'/' ); pos != std::string::npos ) {
187 dir +=
'/' + name.substr( 0, pos );
188 name = name.substr( pos + 1 );
195 template <
typename Traits, std::size_t... index>
197 nlohmann::json
const& j,
198 std::index_sequence<index...> ) {
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>();
206 title += ( axis[index].title + ... );
208 auto totNBins = ( ( axis[index].nBins + 2 ) * ... );
212 auto histo = Traits::create( name, title, axis[index]... );
214 Traits::fill( histo, totNBins, weights );
217 if constexpr (
sizeof...( index ) == 1 ) {
218 if ( j.find(
"sum" ) != j.end() ) {
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>();
227 if ( j.find(
"sumx" ) != j.end() ) {
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>();
246 Traits::fillMetaData( histo, jsonAxis, nentries );
247 return { histo, dir };
255 template <
typename RootHisto,
unsigned int N>
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 }... ) );
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 )>() );
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;
277 axis = histo.GetXaxis();
280 axis = histo.GetYaxis();
283 axis = histo.GetZaxis();
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() );
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() );
299 for (
unsigned int i = 0; i < jsonAxis.size(); i++ ) try_set_bin_labels( i );
301 histo.SetEntries( nentries );
306 template <
typename TP>
308 template <
typename... Args>
314 this->Sumw2(
false );
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]; }
329 inline TDirectory*
changeDir( TFile& file, std::string_view dir ) {
331 auto previousDir = gDirectory;
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 ) );
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() );
344 throw GaudiException( fmt::format(
"Could not create directory {}", dir ),
"Histogram::Sink::Root",
351 template <
typename Histo>
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() };
358 return { *h.GetXaxis() };
362 template <
typename Histo>
364 if constexpr ( std::is_base_of_v<TProfile, Histo> || std::is_base_of_v<TProfile2D, Histo> ) {
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 ) } );
375 return gsl::span{ h.GetArray(), (
unsigned long)h.GetSize() };
380 template <
typename Histo>
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() },
394 if ( h.GetDimension() == 1 ) {
395 j[
"nTotEntries"] = s[0];
398 j[
"mean"] = s[2] / s[0];
400 j[
"nTotEntries"] = s[0];
403 j[
"meanx"] = s[2] / s[0];
407 j[
"meany"] = s[4] / s[0];
408 if ( h.GetDimension() >= 3 ) {
413 j[
"meanz"] = s[7] / s[0];
425 template <
typename RootHisto,
unsigned int N>
430 for (
unsigned int i = 0; i < nbins; i++ ) { histo.SetBinContent( i, weight[i] ); }
437 template <
typename RootHisto,
unsigned int N>
440 using WeightType = std::vector<std::tuple<std::tuple<unsigned int, double>,
double>>;
442 for (
unsigned int i = 0; i < nbins; i++ ) {
443 auto [c, sumWeight2] = weight[i];
444 auto [nEntries, sumWeight] = c;
446 histo.SetBinContent( i, sumWeight );
452 template <
typename Traits>
454 nlohmann::json
const& j ) {
458 template <
typename Traits>
459 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json
const& j ) {
470 template <
unsigned int N,
bool isProfile,
typename ROOTHisto>
471 void saveRootHisto( TFile& file, std::string dir, std::string name, nlohmann::json
const& j ) {
476 template <Accumulators::atomicity Atomicity = Accumulators::atomicity::full,
typename Arithmetic =
double>
479 auto const& gaudiHisto =
482 auto const& gaudiAxis = gaudiHisto.template axis<0>();
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() );
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 );
498 unsigned long totNEntries{ 0 };
499 for (
unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) { totNEntries += gaudiHisto.nEntries( i ); }
500 histo.SetEntries( totNEntries );
505 template <Accumulators::atomicity Atomicity = Accumulators::atomicity::full,
typename Arithmetic =
double>
508 auto const& gaudiHisto =
511 auto const& gaudiXAxis = gaudiHisto.template axis<0>();
512 auto const& gaudiYAxis = gaudiHisto.template axis<1>();
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() );
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() );
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 );
535 unsigned long totNEntries{ 0 };
536 for (
unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) { totNEntries += gaudiHisto.nEntries( i ); }
537 histo.SetEntries( totNEntries );
542 template <Accumulators::atomicity Atomicity = Accumulators::atomicity::full,
typename Arithmetic =
double>
545 auto const& gaudiHisto =
548 auto const& gaudiXAxis = gaudiHisto.template axis<0>();
549 auto const& gaudiYAxis = gaudiHisto.template axis<1>();
550 auto const& gaudiZAxis = gaudiHisto.template axis<2>();
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() );
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() );
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() );
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 );
580 unsigned long totNEntries{ 0 };
581 for (
unsigned int i = 0; i < gaudiHisto.totNBins(); i++ ) { totNEntries += gaudiHisto.nEntries( i ); }
582 histo.SetEntries( totNEntries );
587 typename Arithmetic =
double>
594 if constexpr ( N == 1 ) {
596 }
else if constexpr ( N == 2 ) {
598 }
else if constexpr ( N == 3 ) {
606 template <
typename TYPE>
613 BinAvValue(
const TYPE minV,
const TYPE maxV,
unsigned int nbins,
const bool isInt )
615 if ( nbins > 0 ) {
m_binSize = ( maxV - minV ) / nbins; }
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 ) {
630 binAv = ( nAv > 0 ? binAv / nAv : 0 );
641 typename Arithmetic =
double>
643 unsigned int stringsWidth = 45 ) {
646 using FPType = double;
648 auto const& gaudiHisto =
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();
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;
665 if ( nx > 0 && nx <= nBinsX ) {
666 const FPType binXValue = xBinAv( nx );
668 const auto sumw_abs = abs( sumw );
669 totalSumW += sumw_abs;
670 auto val = binXValue * sumw_abs;
681 if ( nEntries == 0 || !( abs( totalSumW ) > 0 ) ) {
return ""; }
682 const FPType meanX = sumX / totalSumW;
683 const FPType sigmaX2 = ( sum2X / totalSumW ) - std::pow( meanX, 2 );
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
696 stddevX, skewnessX, kurtosisX - FPType{ 3.0 } );
700 typename Arithmetic =
double>
702 unsigned int stringsWidth = 45 ) {
705 using FPType = double;
707 auto const& gaudiHisto =
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();
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;
732 if ( nx > 0 && ny > 0 && nx <= nBinsX && ny <= nBinsY ) {
733 const FPType binXValue = xBinAv( nx );
734 const FPType binYValue = yBinAv( ny );
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;
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;
754 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
759 typename Arithmetic =
double>
761 unsigned int stringsWidth = 45 ) {
764 using FPType = double;
766 auto const& gaudiHisto =
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();
783 FPType nEntries{ 0 }, nAllEntries{ 0 };
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;
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 );
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;
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;
827 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
828 stddevY, meanZ, stddevZ );
832 std::function<double(
unsigned int )>
m_get;
834 auto subtype = std::string_view( type ).substr( 10 );
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>>>()](
838 auto [c, sumWeight2] = bins[nx];
839 auto [n, sumWeight] = c;
843 m_get = [bins = j.at(
"bins" ).get<std::vector<double>>()](
unsigned int nx ) {
return bins[nx]; };
848 return abs(
m_get( n ) );
854 for (
const std::string s : {
":i",
":l" } ) {
855 if ( 0 == type.compare( type.length() - s.length(), s.length(), s ) ) {
return true; }
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 ) {
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>();
871 double sumX{}, sum2X{}, sum3X{}, sum4X{}, nEntries{ 0 };
873 for (
unsigned int nx = 1; nx <= nBinsX; ++nx ) {
874 const double binXValue = xBinAv( nx );
875 const auto n = ba[nx];
877 auto val = binXValue * n;
887 if ( !( abs( nEntries ) > 0.0 ) ) {
return ""; }
888 const double meanX = sumX / nEntries;
889 const double sigmaX2 = ( sum2X / nEntries ) - std::pow( meanX, 2 );
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
902 meanX, stddevX, skewnessX, kurtosisX - 3.0 );
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 ) {
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>();
919 double sumX{}, sumY{};
920 double sum2X{}, sum2Y{};
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];
931 sumX += n * binXValue;
932 sum2X += n * binXValue * binXValue;
933 sumY += n * binYValue;
934 sum2Y += n * binYValue * binYValue;
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;
946 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
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 ) {
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>();
967 double sumX{}, sumY{}, sumZ{};
968 double sum2X{}, sum2Y{}, sum2Z{};
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];
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;
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;
1004 stringsWidth, stringsWidth, ftitle, stringsWidth, nEntries, nAllEntries, meanX, stddevX, meanY,
1005 stddevY, meanZ, stddevZ );
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() } };
1019 inline void to_json( nlohmann::json& j, TH1D
const& h ) {
1022 inline void to_json( nlohmann::json& j, TH2D
const& h ) {
1025 inline void to_json( nlohmann::json& j, TH3D
const& h ) {
1028 inline void to_json( nlohmann::json& j, TProfile
const& h ) {
1031 inline void to_json( nlohmann::json& j, TProfile2D
const& h ) {
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
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
constexpr std::string_view histo2DFormatting
std::string formatTitle(std::string_view title, unsigned int width)
T sqrt_or_zero(const T x)
sqrt or zero
std::string formatName(std::string_view name, unsigned int width)
constexpr std::string_view histo3DFormatting
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...
nlohmann::json binsTojson(Histo const &h)
void fixNameAndDir(std::string &name, std::string &dir)
handles cases where name includes '/' character(s) and move needed part of it to dir.
nlohmann::json rootHistogramToJson(Histo const &h)
automatic translation of Root Histograms to json
Axis jsonToAxis(nlohmann::json &jAxis)
extract an Axis from json data
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
nlohmann::json allAxisTojson(Histo const &h)
std::string printProfileHisto3D(std::string_view name, Gaudi::Monitoring::Hub::Entity const &ent, unsigned int stringsWidth=45)
std::string printProfileHisto1D(std::string_view name, Gaudi::Monitoring::Hub::Entity const &ent, unsigned int stringsWidth=45)
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)
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
details::ProfileWrapper< TProfile2D > profileHisto2DToRoot(std::string name, Monitoring::Hub::Entity const &ent)
Direct conversion of 2D histograms from Gaudi to ROOT format.
void saveProfileHisto(TFile &file, std::string dir, std::string name, Monitoring::Hub::Entity const &ent)
void saveRootHisto(TFile &file, std::string dir, std::string name, nlohmann::json const &j)
generic method to save histograms to files, based on Traits
std::string printHistogram2D(std::string_view type, std::string_view name, std::string_view title, const nlohmann::json &j, unsigned int stringsWidth=45)
details::ProfileWrapper< TProfile > profileHisto1DToRoot(std::string name, Monitoring::Hub::Entity const &ent)
Direct conversion of 1D histograms from Gaudi to ROOT format.
std::string printHistogram3D(std::string_view type, std::string_view name, std::string_view title, const nlohmann::json &j, unsigned int stringsWidth=45)
details::ProfileWrapper< TProfile3D > profileHisto3DToRoot(std::string name, Monitoring::Hub::Entity const &ent)
Direct conversion of 3D histograms from Gaudi to ROOT format.
std::string printProfileHisto2D(std::string_view name, Gaudi::Monitoring::Hub::Entity const &ent, unsigned int stringsWidth=45)
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
void to_json(nlohmann::json &j, TAxis const &axis)
automatic translation of TAxis to json
Gaudi::ParticleID abs(const Gaudi::ParticleID &p)
Return the absolute value for a PID.
static bool is_integral(const std::string_view type)
std::function< double(unsigned int)> m_get
auto operator[](const unsigned int n) const
BinAccessor(std::string_view type, const nlohmann::json &j)
std::vector< double > WeightType
static void fill(Histo &histo, unsigned int nbins, const WeightType &weight)
static constexpr void fill(Histo &histo, unsigned int nbins, const WeightType &weight)
std::vector< std::tuple< std::tuple< unsigned int, double >, double > > WeightType
details::ProfileWrapper< RootHisto > Histo
templated Traits dealing with Root Histogram filling for standard histograms
helper struct to print integers with fixed width
Small helper struct representing the Axis of an Histogram.
auto operator()(const unsigned int n) const
BinAvValue(const TYPE minV, const TYPE maxV, unsigned int nbins, const bool isInt)
helper Wrapper around TProfileX to be able to fill it
ProfileWrapper(ProfileWrapper const &)=delete
void setBinW2(Int_t i, Double_t v)
ProfileWrapper(ProfileWrapper const &&)=delete
ProfileWrapper & operator=(ProfileWrapper const &&)=delete
ProfileWrapper(Args &&... args)
Double_t getBinW2(Int_t i)
ProfileWrapper & operator=(ProfileWrapper const &)=delete
void setBinNEntries(Int_t i, Int_t n)
Common base for Traits dealing with Histogram conversions to Root Provides generic implementation for...
static RootHisto create(std::string &name, std::string &title, Axis &... axis)
static RootHisto create(std::string &name, std::string &title, AxisArray axis, std::index_sequence< index... >)
static void fillMetaData(RootHisto &histo, nlohmann::json const &jsonAxis, unsigned int nentries)
static constexpr unsigned int Dimension