14 #  pragma warning( disable : 2259 ) 
   20 #  pragma warning( disable : 4996 ) 
   23 #include <AIDA/IAnnotation.h> 
   24 #include <AIDA/IAxis.h> 
   25 #include <AIDA/IHistogram1D.h> 
   26 #include <AIDA/IProfile1D.h> 
   35 #include <fmt/format.h> 
   46   constexpr 
bool essentiallyEqual( 
double const a, 
double const b ) {
 
   67       Bin( 
const double h = 0, 
const double e = 0, 
const double l = -1 ) : height( 
h ), error( e ), lower( 
l ) {}
 
   76       Bin& operator+=( 
const Bin& right ) {
 
   77         height += 
right.height;
 
   78         const double e2 = error * error + 
right.error * 
right.error;
 
   86     double maxY( 
const bool withErr )
 const {
 
   89           [&]( 
double m, 
const Bin& b ) { return std::max( m, withErr ? b.height + b.error : b.height ); } );
 
   92     double minY( 
const bool withErr )
 const {
 
   95           [&]( 
double m, 
const Bin& b ) { return std::min( m, withErr ? b.height - b.error : b.height ); } );
 
   98     Histo rebin( 
const unsigned int bin )
 const {
 
  105       for ( 
unsigned int ibin = 0; ibin < bins.size(); ++ibin ) {
 
  106         const Bin& current = bins[ibin];
 
  107         if ( nh.bins.empty() ) {
 
  108           nh.bins.push_back( current );
 
  109         } 
else if ( 0 == ibin % bin ) {
 
  110           nh.bins.push_back( current );
 
  112           nh.bins.back() += current;
 
  118     int nullBin()
 const {
 
  119       for ( 
auto ib = bins.cbegin(); bins.cend() != ib + 1; ++ib ) {
 
  120         if ( ib->lower <= 0 && 0 < ( ib + 1 )->lower ) { 
return ib - bins.cbegin(); }
 
  148     const TAxis* axis = 
root->GetXaxis();
 
  150     const int nbins = axis->GetNbins();
 
  154     hist.under = Histo::Bin( 
root->GetBinContent( 0 ), 
root->GetBinError( 0 ), axis->GetXmin() );
 
  156     hist.over = Histo::Bin( 
root->GetBinContent( nbins + 1 ), 
root->GetBinError( nbins + 1 ), axis->GetXmax() );
 
  159     for ( 
int ibin = 1; ibin <= nbins; ++ibin ) {
 
  161       hist.bins.emplace_back( 
root->GetBinContent( ibin ), 
root->GetBinError( ibin ), axis->GetBinLowEdge( ibin ) );
 
  173   StatusCode _getHisto( 
const TProfile* 
root, Histo& hist, 
const bool  ) {
 
  174     const TH1* histo = 
root;
 
  175     return _getHisto( histo, hist );
 
  185   StatusCode _getHisto( 
const AIDA::IHistogram1D* aida, Histo& hist ) {
 
  191     const AIDA::IAxis& axis  = aida->axis();
 
  192     const int          nbins = axis.bins();
 
  195     hist.under = Histo::Bin( aida->binHeight( AIDA::IAxis::UNDERFLOW_BIN ),
 
  196                              aida->binError( AIDA::IAxis::UNDERFLOW_BIN ), axis.lowerEdge() );
 
  198     hist.over = Histo::Bin( aida->binHeight( AIDA::IAxis::OVERFLOW_BIN ), aida->binError( AIDA::IAxis::OVERFLOW_BIN ),
 
  201     for ( 
int ibin = 0; ibin < nbins; ++ibin ) {
 
  203       hist.bins.emplace_back( aida->binHeight( ibin ), aida->binError( ibin ), axis.binLowerEdge( ibin ) );
 
  215   StatusCode _getHisto( 
const AIDA::IProfile1D* aida, Histo& hist, 
const bool spread ) {
 
  221     const AIDA::IAxis& axis  = aida->axis();
 
  222     const int          nbins = axis.bins();
 
  226         Histo::Bin( aida->binHeight( AIDA::IAxis::UNDERFLOW_BIN ),
 
  227                     spread ? aida->binRms( AIDA::IAxis::UNDERFLOW_BIN ) : aida->binError( AIDA::IAxis::UNDERFLOW_BIN ),
 
  231         Histo::Bin( aida->binHeight( AIDA::IAxis::OVERFLOW_BIN ),
 
  232                     spread ? aida->binRms( AIDA::IAxis::OVERFLOW_BIN ) : aida->binError( AIDA::IAxis::OVERFLOW_BIN ),
 
  235     for ( 
int ibin = 0; ibin < nbins; ++ibin ) {
 
  237       hist.bins.emplace_back( aida->binHeight( ibin ), spread ? aida->binRms( ibin ) : aida->binError( ibin ),
 
  238                               axis.binLowerEdge( ibin ) );
 
  248   inline unsigned int rebin( 
const unsigned int bins, 
const unsigned int imax ) {
 
  249     if ( 0 == imax ) { 
return 1; } 
 
  250     unsigned int ibin = 1;
 
  251     while ( bins > imax * ibin ) { ++ibin; }
 
  264     else if ( essentiallyEqual( 1.0, 
v ) ) {
 
  268       auto r = decompose( -
v );
 
  269       return { -r.first, r.second }; 
 
  270     } 
else if ( 0.1 > 
v ) {
 
  277     } 
else if ( 1 < 
v ) {
 
  292   inline double _pow( 
double x, 
unsigned long n ) {
 
  293     double y = 
n % 2 ? x : 1;
 
  296       if ( 
n % 2 ) { y *= x; }
 
  301   inline double rValMin( 
double v );
 
  307   inline double rValMax( 
double v ) {
 
  308     if ( 0 > 
v ) { 
return -1 * rValMin( -
v ); } 
 
  312     const double f = 
std::ceil( 20 * r.first ) / 2; 
 
  313     const int    l = r.second - 1;
 
  314     return 0 < 
l ? f * _pow( 10, 
l ) : f / _pow( 10, -
l );
 
  321   inline double rValMin( 
double v ) {
 
  322     if ( 0 > 
v ) { 
return -1 * rValMax( -
v ); } 
 
  325     const double           f = 
std::floor( 20 * r.first ) / 2; 
 
  326     const int              l = r.second - 1;
 
  327     return 0 < 
l ? f * _pow( 10, 
l ) : f / _pow( 10, -
l );
 
  343   char symbBin( 
const Histo::Bin& bin, 
const double yLow, 
const double yHigh, 
const bool yNull, 
const bool errors ) {
 
  344     if ( errors && yLow <= bin.height && bin.height < yHigh ) {
 
  347     else if ( errors && yHigh < bin.height - bin.error ) {
 
  349     } 
else if ( errors && yLow >= bin.height + bin.error ) {
 
  351     } 
else if ( errors ) {
 
  353     } 
else if ( yLow <= bin.height && bin.height < yHigh ) {
 
  355     } 
else if ( 0 <= bin.height && yLow <= bin.height && 0 < yHigh && !yNull ) {
 
  358     else if ( 0 > bin.height && yHigh > bin.height && 0 >= yLow && !yNull ) {
 
  371     if ( 40 > width ) { 
return dumpText( histo, 40, height, errors, 
stream ); }
 
  372     if ( 200 < width ) { 
return dumpText( histo, 200, height, errors, 
stream ); }
 
  373     if ( 150 < height ) { 
return dumpText( histo, width, 150, errors, 
stream ); }
 
  374     if ( 20 > height ) { 
return dumpText( histo, width, 20, errors, 
stream ); }
 
  375     if ( height > width ) { 
return dumpText( histo, width, width, errors, 
stream ); }
 
  377     const unsigned int nBins = histo.bins.size();
 
  378     if ( nBins > width ) {
 
  380       Histo r = histo.rebin( rebin( nBins, width ) );
 
  381       return dumpText( r, width, height, errors, 
stream );
 
  385     double yMax = 
std::max( rValMax( histo.maxY( errors ) ), 0.0 );
 
  386     double yMin = 
std::min( rValMin( histo.minY( errors ) ), 0.0 );
 
  388     if ( essentiallyEqual( yMin, yMax ) ) { yMax = yMin + 1; }
 
  392     if ( 1 >= _ny ) { _ny = 10; }
 
  396     if ( 20 > yBins ) { yBins = 20; }
 
  397     const double yScale = ( yMax - yMin ) / yBins;
 
  400     const int ySkip = 0 == yBins % 13   ? 13
 
  401                       : 0 == yBins % 11 ? 11
 
  418     int iNull = histo.nullBin();
 
  428     for ( 
int yLine = -1; yLine < yBins; ++yLine ) {
 
  429       const double yHigh = yMax - yScale * yLine;
 
  431       const double yLow = yMax - yScale * ( yLine + 1 );
 
  435       const bool ynull  = ( yLow <= 0 && 0 < yHigh );
 
  436       const bool yfirst = -1 == yLine || yBins - 1 == yLine;
 
  437       const bool ylab   = ( 0 == ( yLine + 1 ) % ySkip ) || yfirst || ynull;
 
  440         line1 += yLabel( ( yLow <= 0 && 0 < yHigh ) ? 0.0 : yLow );
 
  448       line1 += symbBin( histo.under, yLow, yHigh, ynull, errors );
 
  450       line1 += ynull ? 
"-+" : ylab ? 
" +" : 
" |";
 
  454       for ( 
auto ibin = histo.bins.cbegin(); histo.bins.cend() != ibin; ++ibin ) {
 
  456         const int i = ibin - histo.bins.cbegin();
 
  458         const bool xnull = ibin->lower <= 0 && ( ibin + 1 ) != histo.bins.cend() && 0 < ( ibin + 1 )->lower;
 
  459         const bool xlab  = iNull == i % xSkip;
 
  461         char symb = symbBin( *ibin, yLow, yHigh, ynull, errors );
 
  464           if ( ( ynull || yfirst ) && xlab ) {
 
  466           } 
else if ( ynull || yfirst ) {
 
  470           else if ( ylab && xnull ) {
 
  472           } 
else if ( xnull ) {
 
  476           else if ( ylab || xlab ) {
 
  485       std::string line3 = ynull ? 
"->" : ylab ? 
"+ " : 
"| ";
 
  488       line3 += symbBin( histo.over, yLow, yHigh, ynull, errors );
 
  496     for ( 
auto ib = histo.bins.cbegin(); histo.bins.cend() != ib; ++ib ) { xlabels.
push_back( xLabel( ib->lower ) ); }
 
  498     const std::string oLabel = xLabel( histo.over.lower );
 
  499     const std::string uLabel = xLabel( histo.under.lower );
 
  501     static const std::string s_UNDERFLOW( 
"UNDERFLOW" );
 
  502     static const std::string s_OVERFLOW( 
" OVERFLOW" );
 
  505     for ( 
unsigned int yLine = 0; yLine < 12; ++yLine ) {
 
  508       if ( yLine < s_UNDERFLOW.size() ) {
 
  509         line += s_UNDERFLOW[yLine];
 
  516       if ( uLabel.
size() > yLine ) {
 
  517         line += uLabel[yLine];
 
  522       for ( 
auto ibin = histo.bins.cbegin(); histo.bins.cend() != ibin; ++ibin ) {
 
  523         int        ib   = ibin - histo.bins.cbegin();
 
  524         const bool xlab = ( iNull == ib % xSkip );
 
  525         if ( xlab && yLine < xlabels[ib].
size() ) {
 
  526           line += xlabels[ib][yLine];
 
  532       if ( oLabel.
size() > yLine ) {
 
  533         line += oLabel[yLine];
 
  540       if ( yLine < s_OVERFLOW.size() ) {
 
  541         line += s_OVERFLOW[yLine];
 
  569   if ( !histo ) { 
return stream.str(); } 
 
  577  Mean        : {:11.5g} +- {:<10.4g} 
  578  Rms         : {:11.5g} +- {:<10.4g} 
  579  Skewness    : {:11.5g} +- {:<10.4g} 
  580  Kurtosis    : {:11.5g} +- {:<10.4g} 
  583  |    All    |  In Range | Underflow |  Overflow | #Equivalent |   Integral  |    Total    | 
  584  | {:^9} | {:^9} | {:^9} | {:^9} | {:^11.5g} | {:^11.5g} | {:^11.5g} | 
  587                          path( histo ), histo->title(),  
  592                          histo->allEntries(), histo->entries(), histo->binEntries( AIDA::IAxis::UNDERFLOW_BIN ),
 
  593                          histo->binEntries( AIDA::IAxis::OVERFLOW_BIN ), histo->equivalentBinEntries(),
 
  594                          histo->sumBinHeights(), histo->sumAllBinHeights() );
 
  596   const AIDA::IAnnotation& a = histo->annotation();
 
  598     stream << 
" Annotation\n";
 
  599     for ( 
int i = 0; i < a.size(); ++i ) {
 
  600       stream << 
fmt::format( 
" | {:<25.25s} : {:<45.45s} |\n", a.key( i ), a.value( i ) );
 
  605   return dumpText( hist, width, height, errors, 
stream ).str();
 
  620   if ( !histo ) { 
return stream.str(); } 
 
  622   StatusCode sc = _getHisto( histo, hist, spread );
 
  632  |    All    |  In Range | Underflow |  Overflow |   Integral  |    Total    | 
  633  | {:^9} | {:^9} | {:^9} | {:^9} | {:^11.5g} | {:^11.5g} | 
  636                          path( histo ), histo->title(),  
  637                          histo->mean(), histo->rms(), histo->allEntries(), histo->entries(),
 
  638                          histo->binEntries( AIDA::IAxis::UNDERFLOW_BIN ),
 
  639                          histo->binEntries( AIDA::IAxis::OVERFLOW_BIN ), histo->sumBinHeights(),
 
  640                          histo->sumAllBinHeights() );
 
  642   const AIDA::IAnnotation& a = histo->annotation();
 
  644     stream << 
" Annotation\n";
 
  645     for ( 
int i = 0; i < a.size(); ++i ) {
 
  646       stream << 
fmt::format( 
" | {:<25.25s} : {:<45.45s} |\n", a.key( i ), a.value( i ) );
 
  651   return dumpText( hist, width, height, 
true, 
stream ).str();
 
  663                                              const bool errors ) {
 
  664   const TProfile* profile = 
dynamic_cast<const TProfile*
>( histo );
 
  665   if ( profile ) { 
return histoDump( profile, width, height ); }
 
  669   if ( !histo ) { 
return stream.str(); } 
 
  677  Mean        : {:11.5g} +- {:<10.4g} 
  678  Rms         : {:11.5g} +- {:<10.4g} 
  683  |     All     |  Underflow  |   Overflow  | #Equivalent |   Integral  | 
  684  | {:^11.5g} | {:^11.5g} | {:^11.5g} | {:^11.5g} | {:^11.5g} | 
  687                          histo->GetName(), histo->GetTitle(),  
  688                          histo->GetMean(), histo->GetMeanError(), histo->GetRMS(), histo->GetRMSError(),
 
  689                          histo->GetSkewness(), histo->GetKurtosis(), histo->GetEntries(), histo->GetBinContent( 0 ),
 
  690                          histo->GetBinContent( histo->GetNbinsX() + 1 ), histo->GetEffectiveEntries(),
 
  693   return dumpText( hist, width, height, errors, 
stream ).str();
 
  708   if ( !histo ) { 
return stream.str(); } 
 
  710   StatusCode sc = _getHisto( histo, hist, 
true );
 
  720  |     All     |  Underflow  |   Overflow  |   Integral  | 
  721  | {:^11.5g} | {:^11.5g} | {:^11.5g} | {:^11.5g} | 
  724                          histo->GetName(), histo->GetTitle(),  
  725                          histo->GetMean(), histo->GetRMS(), histo->GetSkewness(), histo->GetKurtosis(),
 
  726                          histo->GetEntries(), histo->GetBinContent( 0 ), histo->GetBinContent( histo->GetNbinsX() + 1 ),
 
  729   return dumpText( hist, width, height, 
true, 
stream ).str();