| # Gaudi Framework, version v21r6 |

Home |  | Generated: 11 Nov 2009

# GaudiHistos.icpp

Go to the documentation of this file.

    00001 // $Id: GaudiHistos.icpp,v 1.17 2008/10/10 12:39:04 marcocle Exp $
    00002 // ============================================================================
    00003 #ifndef GAUDIALG_GAUDIHISTOS_ICPP
    00004 #define GAUDIALG_GAUDIHISTOS_ICPP 1
    00005 // ============================================================================
    00006 /* @file
    00007  *
    00008  *  Implementation file for class : GaudiHistos
    00009  *
    00010  *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
    00011  *  @author Vanya BELYAEV Ivan.Belyaev@itep.ru
    00012  *  @date   2005-08-08
    00013  */
    00014 // ============================================================================
    00015 // STD & STL
    00016 // ============================================================================
    00017 #include <algorithm>
    00018 #include <string>
    00019 #include <vector>
    00020 #include <set>
    00021 // ============================================================================
    00022 // GaudiKernel
    00023 // ============================================================================
    00024 #include "GaudiKernel/MsgStream.h"
    00025 #include "GaudiKernel/IHistogramSvc.h"
    00026 // ============================================================================
    00027 // GaudiUtils
    00028 // ============================================================================
    00029 #include "GaudiUtils/HistoTableFormat.h"
    00030 // ============================================================================
    00031 // GaudiAlg
    00032 // ============================================================================
    00033 #include "GaudiAlg/GaudiHistos.h"
    00034 #include "GaudiAlg/CheckForNaN.h"
    00035 #include "GaudiAlg/Print.h"
    00036 #include "GaudiAlg/Fill.h"
    00037 // ============================================================================
    00038 // forward declarations from AIDA
    00039 // ============================================================================
    00040 namespace AIDA
    00041 {
    00042   class IBaseHistogram ;
    00043   class IHistogram     ;
    00044   class IHistogram1D   ;
    00045   class IHistogram2D   ;
    00046   class IHistogram3D   ;
    00047   class IProfile       ;
    00048   class IProfile1D     ;
    00049   class IProfile2D     ;
    00050 }
    00051 // ============================================================================
    00052 // Destructor
    00053 // ============================================================================
    00054 template <class PBASE>
    00055 GaudiHistos<PBASE>::~GaudiHistos() {}
    00056 // =============================================================================
    00057 // Constructor initialisation and job options
    00058 // =============================================================================
    00059 template <class PBASE>
    00060 void GaudiHistos<PBASE>::initGaudiHistosConstructor()
    00061 {
    00062   // SWITCH ON/OFF the histograms
    00063   this->declareProperty
    00064     ( "HistoProduce"          ,
    00065       m_produceHistos = true  ,
    00066       "Swith on/off the production of histograms "   ) ;
    00067   // print the histograms at finalization
    00068   this->declareProperty
    00069     ( "HistoPrint"            ,
    00070       m_histosPrint   = false ,
    00071       "Switch on/off the printout of histograms at finalization"    )
    00072     -> declareUpdateHandler ( &GaudiHistos<PBASE>::printHistoHandler, this ) ;
    00073   // check for NaN/Finite
    00074   this->declareProperty
    00075     ( "HistoCheckForNaN"      ,
    00076       m_checkForNaN   = true  ,
    00077       "Swicth on/off the checks for NaN and Infinity for histogram fill" ) ;
    00078   // for HBOOK persistency, 'true' can be useful
    00079   this->declareProperty
    00080     ( "HistoSplitDir"         ,
    00081       m_splitHistoDir = false ,
    00082       "Split long directory names into short pieces (suitable for HBOOK)" );
    00083   // general OffSet for histogram ID
    00084   this->declareProperty
    00085     ( "HistoOffSet"           ,
    00086       m_histoOffSet   =   0   ,
    00087       "OffSet for automatically assigned histogram numerical identifiers " ) ;
    00088   // top level histogram directory
    00089   this->declareProperty
    00090     ( "HistoTopDir"           ,
    00091       m_histoTopDir   =   ""  ,
    00092       "Top level histogram directory (take care that it ends with '/')" ) ;
    00093   // histogram directory
    00094   this->declareProperty
    00095     ( "HistoDir"             ,
    00096       m_histoDir      = this->name() ,
    00097       "Histogram Directory" ) ;
    00098   // control output level of histograms
    00099   this->declareProperty ( "FullDetail"            , m_fullDetail    = false ) ;
    00100   // monitor histograms
    00101   this->declareProperty ( "MonitorHistograms"     , m_declareMoniHists = true ) ;
    00102   // format for 1D-histograms printout
    00103   this->declareProperty
    00104     ( "FormatFor1DHistoTable" ,
    00105       m_histo1DTableFormat   = Gaudi::Utils::Histos::Formats::format () ,
    00106       "Format string for printout of 1D histograms"      ) ;
    00107   // "short" format for 1D-histograms printout
    00108   this->declareProperty
    00109     ( "ShortFormatFor1DHistoTable" ,
    00110       m_histo1DTableFormatShort   = " | %1$-25.25s %2%"  ,
    00111       "Format string for printout of 1D histograms"      ) ;
    00112   // the header for 1D-histogram tabkle
    00113   this->declareProperty
    00114     ( "HeaderFor1DHistoTable" ,
    00115       m_histo1DTableHeader   = Gaudi::Utils::Histos::Formats::header () ,
    00116       "The table header for printout of 1D histograms "  ) ;
    00117   this->declareProperty
    00118     ( "UseSequencialNumericAutoIDs", m_useNumericAutoIDs = false,
    00119       "Flag to allow users to switch back to the old style of creating numerical automatic IDs" );
    00120   m_idReplaceInfo.clear();
    00121   m_idReplaceInfo["/"] = "=SLASH=";
    00122   this->declareProperty
    00123     ( "AutoStringIDPurgeMap", m_idReplaceInfo,
    00124       "Map of strings to search and replace when using the title as the basis of automatically generated literal IDs" );
    00125 }
    00126 // ============================================================================
    00127 // Initialise Histogramming
    00128 // ============================================================================
    00129 template <class PBASE>
    00130 StatusCode GaudiHistos<PBASE>::initialize()
    00131 {
    00132   // initialize base class
    00133   const StatusCode sc = PBASE::initialize();
    00134   if ( sc.isFailure() ) return sc;
    00135
    00136   // produce histograms?
    00137   if ( !produceHistos() )
    00138   {
    00139     this->debug() << "Histogram production is switched OFF" << endmsg;
    00140     return sc;
    00141   }
    00142
    00143   // check the validity of histogram service
    00144   if ( this->histoSvc() == NULL )
    00145   { return this->Error("initialize():: IHistogramSvc* is invalid"); }
    00146
    00147   // Warn if the user has decided to use numerical automatic IDs
    00148   if ( useNumericAutoIDs() )
    00149   {
    00150     this ->
    00151       Warning( "Using numerical automatic IDs. These are not guaranteed to be totally deterministic. Use with care...",
    00152                StatusCode::SUCCESS );
    00153   }
    00154
    00155   // Finally, print the location histogram will be written to
    00156   Print
    00157     ( "The histogram path is set to be '" + histoPath() + "'",
    00158       StatusCode( StatusCode::SUCCESS, true )  , MSG::DEBUG );
    00159
    00160   return sc;
    00161 }
    00162 // ============================================================================
    00163 // Finalise Histogramming
    00164 // ============================================================================
    00165 template <class PBASE>
    00166 StatusCode GaudiHistos<PBASE>::finalize()
    00167 {
    00168
    00169   if ( produceHistos() )
    00170   {
    00171
    00172     // Count how many histos of each type
    00173     if ( !noHistos() )
    00174     {
    00175       const unsigned int n1D  = histo1DMapID   () . size () ;
    00176       const unsigned int n2D  = histo2DMapID   () . size () ;
    00177       const unsigned int n3D  = histo3DMapID   () . size () ;
    00178       const unsigned int n1DP = profile1DMapID () . size () ;
    00179       const unsigned int n2DP = profile2DMapID () . size () ;
    00180       const unsigned int total = n1D+n2D+n3D+n1DP+n2DP;
    00181       if ( total>0 )
    00182       {
    00183         this->always() << "Booked " << total << " Histogram(s) : ";
    00184         if ( n1D>0  ) this->always() << "1D=" << n1D << " ";
    00185         if ( n2D>0  ) this->always() << "2D=" << n2D << " ";
    00186         if ( n3D>0  ) this->always() << "3D=" << n3D << " ";
    00187         if ( n1DP>0 ) this->always() << "1DProf=" << n1DP << " ";
    00188         if ( n2DP>0 ) this->always() << "2DProf=" << n2DP << " ";
    00189         this->always() << endmsg;
    00190       }
    00191     }
    00192
    00193     // detailed printing
    00194     if ( histosPrint() ) { printHistos() ; }
    00195
    00196   }
    00197
    00198   // clear all maps
    00199   m_histo1DMapTitle   . clear () ;
    00200   m_histo2DMapTitle   . clear () ;
    00201   m_histo3DMapTitle   . clear () ;
    00202   m_histo1DMapID      . clear () ;
    00203   m_histo2DMapID      . clear () ;
    00204   m_histo3DMapID      . clear () ;
    00205   m_profile1DMapTitle . clear () ;
    00206   m_profile2DMapTitle . clear () ;
    00207   m_profile1DMapID    . clear () ;
    00208   m_profile2DMapID    . clear () ;
    00209
    00210   // finalize base class
    00211   return PBASE::finalize();
    00212 }
    00213 // ============================================================================
    00214 // perform the actual detailed printout of histograms
    00215 // ============================================================================
    00216 template <class PBASE>
    00217 int GaudiHistos<PBASE>::printHistos ( const MSG::Level level ) const
    00218 {
    00219   using namespace Gaudi::Utils::Histos ;
    00220
    00221   if ( noHistos() )
    00222   {
    00223     if ( this->msgLevel(MSG::DEBUG) )
    00224     { this->msgStream(level) << "No histograms are booked" << endmsg ; }
    00225     return 0 ;                                                        // RETURN
    00226   }
    00227
    00228   MsgStream & msg = this->msgStream(level);
    00229
    00230   // Printout all histograms
    00231
    00232   Gaudi::Utils::Histos::Table table
    00233     ( m_histo1DTableFormat ,
    00234       m_histo1DTableHeader ) ;
    00235
    00236   if ( !histo1DMapID().empty() )
    00237   {
    00238     msg << "List of booked 1D histograms in directory         "
    00239         << "\"" << histoPath() << "\" :-"  ;
    00240
    00241     if ( !table.header().empty() )
    00242     {
    00243       msg << std::endl << Gaudi::Utils::Histos::format
    00244         ( "ID" , table.header() , m_histo1DTableFormatShort ) ;
    00245     }
    00246     // temporary map to keep ordered IDs
    00247     typedef std::map<HistoID,const AIDA::IHistogram1D*> OrderedMapType;
    00248     OrderedMapType OrderedMap ( histo1DMapID().begin() , histo1DMapID().end() );
    00249     //
    00250     for ( OrderedMapType::const_iterator entry = OrderedMap.begin() ;
    00251           OrderedMap.end() != entry ; ++entry )
    00252     {
    00253       const AIDA::IHistogram1D* aida = entry->second ;
    00254       if ( NULL == aida )
    00255       { this->error() << "IHistogram1D points to NULL" << endmsg ; continue ; }
    00256       // format and print the row
    00257       msg << std::endl << table.toString
    00258         ( aida                      ,
    00259           HistoID ( entry->first )  ,
    00260           m_histo1DTableFormatShort ) ;
    00261     }
    00262     msg << endmsg ;
    00263   }
    00264   // ==========================================================================
    00265   if ( !histo2DMapID().empty() )
    00266   {
    00267     msg << "List of booked 2D histograms in directory         "
    00268         << "\"" << histoPath() << "\" :-" ;
    00269
    00270     // temporary map to keep ordered IDs
    00271     typedef std::map<HistoID,const AIDA::IHistogram2D*> OrderedMapType;
    00272     OrderedMapType OrderedMap ( histo2DMapID().begin() , histo2DMapID().end() ) ;
    00273     //
    00274     for ( OrderedMapType::const_iterator entry = OrderedMap.begin() ;
    00275           OrderedMap.end() != entry ; ++entry )
    00276     {
    00277       const AIDA::IHistogram2D* aida = entry->second ;
    00278       if ( NULL == aida )
    00279       { this->error() << "IHistogram2D points to NULL" << endmsg ; continue ; }
    00280       msg << std::endl
    00281           << GaudiAlg::Print2D::toString ( aida , entry->first );
    00282     }
    00283     msg << endmsg ;
    00284   }
    00285   // ==========================================================================
    00286   if ( !histo3DMapID().empty() )
    00287   {
    00288     msg << "List of booked 3D histograms in directory         "
    00289         << "\"" << histoPath() << "\" :-" ;
    00290     // temporary map to keep ordered IDs
    00291     typedef std::map<HistoID,const AIDA::IHistogram3D*> OrderedMapType;
    00292     OrderedMapType OrderedMap ( histo3DMapID().begin() , histo3DMapID().end() ) ;
    00293     //
    00294     for ( OrderedMapType::const_iterator entry = OrderedMap.begin() ;
    00295           OrderedMap.end() != entry ; ++entry )
    00296     {
    00297       const AIDA::IHistogram3D* aida = entry->second ;
    00298       if ( NULL == aida )
    00299       { this->error() << "IHistogram3D points to NULL" << endmsg ; continue ; }
    00300       msg << std::endl << GaudiAlg::Print3D::toString ( aida , entry->first );
    00301     }
    00302     msg << endmsg ;
    00303   }
    00304   // ==========================================================================
    00305   if ( !profile1DMapID().empty() )
    00306   {
    00307     msg << "List of booked 1D profile histograms in directory "
    00308         << "\"" << histoPath() << "\" :-" ;
    00309     // temporary map to keep ordered IDs
    00310     typedef std::map<HistoID,const AIDA::IProfile1D*> OrderedMapType;
    00311     OrderedMapType OrderedMap ( profile1DMapID().begin() , profile1DMapID().end() ) ;
    00312     //
    00313     for ( OrderedMapType::const_iterator entry = OrderedMap.begin() ;
    00314           OrderedMap.end() != entry ; ++entry )
    00315     {
    00316       const AIDA::IProfile1D*   aida = entry->second ;
    00317       if ( NULL == aida )
    00318       { this->error() << "IProfile1D points to NULL" << endmsg ; continue ; }
    00319       msg << std::endl << GaudiAlg::Print1DProf::toString  ( aida , entry->first );
    00320     }
    00321     msg << endmsg ;
    00322   }
    00323   // ==========================================================================
    00324   if ( !profile2DMapID().empty() )
    00325   {
    00326     msg << "List of booked 2D profile histograms in directory "
    00327         << "\"" << histoPath() << "\" :-" ;
    00328     // temporary map to keep ordered IDs
    00329     typedef std::map<HistoID,const AIDA::IProfile2D*> OrderedMapType;
    00330     OrderedMapType OrderedMap ( profile2DMapID().begin() , profile2DMapID().end() ) ;
    00331     //
    00332     for ( OrderedMapType::const_iterator entry = OrderedMap.begin() ;
    00333           OrderedMap.end() != entry ; ++entry )
    00334     {
    00335       const AIDA::IProfile2D*   aida = entry->second ;
    00336       if ( NULL == aida )
    00337       { this->error() << "IProfile2D points to NULL" << endmsg ; continue ; }
    00338       msg << std::endl << GaudiAlg::Print2DProf::toString ( aida , entry->first );
    00339     }
    00340     msg << endmsg ;
    00341   }
    00342   //
    00343   return this->totalNumberOfHistos() ;
    00344 }
    00345 // ============================================================================
    00346 // Check if all histogram maps are empty
    00347 // ============================================================================
    00348 template <class PBASE>
    00349 bool GaudiHistos<PBASE>::noHistos() const
    00350 {
    00351   return ( histo1DMapTitle   () . empty() &&
    00352            histo2DMapTitle   () . empty() &&
    00353            histo3DMapTitle   () . empty() &&
    00354            profile1DMapTitle () . empty() &&
    00355            profile2DMapTitle () . empty() &&
    00356            histo1DMapID      () . empty() &&
    00357            histo2DMapID      () . empty() &&
    00358            histo3DMapID      () . empty() &&
    00359            profile1DMapID    () . empty() &&
    00360            profile2DMapID    () . empty() );
    00361 }
    00362 // ============================================================================
    00363 // Declare a histogram to the monitor service
    00364 // ============================================================================
    00365 template <class PBASE>
    00366 void GaudiHistos<PBASE>::monitorHisto
    00367 ( const AIDA::IBaseHistogram* hist,
    00368   const HistoID& ID ) const
    00369 {
    00370   if ( hist && m_declareMoniHists )
    00371   {
    00372     if ( this->msgLevel(MSG::DEBUG) )
    00373     {
    00374       this->debug() << "Monitoring histogram '"
    00375                     << ID.idAsString() << "' desc = '"
    00376                     << Gaudi::Utils::Histos::htitle(hist) << "'" << endmsg;
    00377     }
    00378     this->declareInfo ( histoPath()+"/"+ID.idAsString() ,
    00379                         hist            ,
    00380                         Gaudi::Utils::Histos::htitle(hist) ) ;
    00381   }
    00382 }
    00383 // ============================================================================
    00384 // access the EXISTING 1D histogram by ID
    00385 // ============================================================================
    00386 template <class PBASE>
    00387 AIDA::IHistogram1D* GaudiHistos<PBASE>::histo1D ( const HistoID& ID )  const
    00388 {
    00389   AIDA::IHistogram1D * h(NULL);
    00390   //
    00391   Histo1DMapID::const_iterator found = histo1DMapID().find( ID ) ;
    00392   //
    00393   h = ( histo1DMapID().end() == found ? NULL : found->second );
    00394   //
    00395   return h ;
    00396 }
    00397 // ============================================================================
    00398 // access the EXISTING 2D histogram by ID
    00399 // ============================================================================
    00400 template <class PBASE>
    00401 AIDA::IHistogram2D* GaudiHistos<PBASE>::histo2D ( const HistoID& ID )  const
    00402 {
    00403   AIDA::IHistogram2D * h(NULL);
    00404   //
    00405   Histo2DMapID::const_iterator found = histo2DMapID().find( ID ) ;
    00406   //
    00407   h = ( histo2DMapID().end() == found ? NULL : found->second );
    00408   //
    00409   return h;
    00410 }
    00411 // ============================================================================
    00412 // access the EXISTING 3D histogram by ID
    00413 // ============================================================================
    00414 template <class PBASE>
    00415 AIDA::IHistogram3D* GaudiHistos<PBASE>::histo3D ( const HistoID& ID )  const
    00416 {
    00417   AIDA::IHistogram3D * h(NULL);
    00418   //
    00419   Histo3DMapID::const_iterator found = histo3DMapID().find( ID ) ;
    00420   h = ( histo3DMapID().end() == found ? NULL : found->second );
    00421   //
    00422   return h;
    00423 }
    00424 // ============================================================================
    00425 // access the EXISTING 1D profile histogram by ID
    00426 // ============================================================================
    00427 template <class PBASE>
    00428 AIDA::IProfile1D* GaudiHistos<PBASE>::profile1D ( const HistoID& ID )  const
    00429 {
    00430   AIDA::IProfile1D * h(NULL);
    00431   //
    00432   Profile1DMapID::const_iterator found = profile1DMapID().find( ID ) ;
    00433   //
    00434   h = ( profile1DMapID().end() == found ? NULL : found->second );
    00435   //
    00436   return h;
    00437 }
    00438 // ============================================================================
    00439 // access the EXISTING 2D profile histogram by ID
    00440 // ============================================================================
    00441 template <class PBASE>
    00442 AIDA::IProfile2D* GaudiHistos<PBASE>::profile2D ( const HistoID& ID )  const
    00443 {
    00444   AIDA::IProfile2D * h(NULL);
    00445   //
    00446   Profile2DMapID::const_iterator found = profile2DMapID().find( ID ) ;
    00447   //
    00448   h = ( profile2DMapID().end() == found ? NULL : found->second );
    00449   //
    00450   return h;
    00451 }
    00452 // ============================================================================
    00453 // Returns the total number of histograms (of all types) currently booked
    00454 // ============================================================================
    00455 template <class PBASE>
    00456 unsigned int GaudiHistos<PBASE>::totalNumberOfHistos() const
    00457 {
    00458   return
    00459     histo1DMapID   () . size () +
    00460     histo2DMapID   () . size () +
    00461     histo3DMapID   () . size () +
    00462     profile1DMapID () . size () +
    00463     profile2DMapID () . size () ;
    00464 }
    00465 // ============================================================================
    00466 // Create a new histogram ID using the given title
    00467 // ============================================================================
    00468 template <class PBASE>
    00469 void GaudiHistos<PBASE>::newHistoID
    00470 ( const std::string & title ,
    00471   HistoID&            ID    ) const
    00472 {
    00473   if ( useNumericAutoIDs() || title.empty() )
    00474   {
    00475     if ( !useNumericAutoIDs() )
    00476     {
    00477       this -> Warning( "Cannot generate automatic literal ID from an empty title ! Using numeric ID instead for histogram ID",
    00478                        StatusCode::SUCCESS );
    00479     }
    00480     // propose the histogram ID (always numeric)
    00481     ID = HistoID( totalNumberOfHistos() + 1 + histoOffSet() );
    00482     // adjust the proposed ID
    00483     while ( histoExists( ID ) ) { ID = HistoID ( ID.numeric() + 1 ) ; }
    00484   }
    00485   else
    00486   {
    00487     // use the title to create a unique literal ID
    00488     ID = HistoID( this->convertTitleToID(title) );
    00489     // Just in case ...
    00490     while ( histoExists( ID ) ) { ID = HistoID(ID.idAsString()+"_"); }
    00491   }
    00492 }
    00493 // ============================================================================
    00494 // Create an ID string from a title string
    00495 // ============================================================================
    00496 template <class PBASE>
    00497 std::string GaudiHistos<PBASE>::convertTitleToID( const std::string & title ) const
    00498 {
    00499   // clean up the ID string for all unwanted characters
    00500   std::string tmp_id = title;
    00501   for ( std::map<std::string,std::string>::const_iterator i =
    00502           m_idReplaceInfo.begin() ; i != m_idReplaceInfo.end(); ++i )
    00503   {
    00504     stringSearchReplace( tmp_id, i->first, i->second );
    00505   }
    00506   return tmp_id;
    00507 }
    00508 // ============================================================================
    00509 // Searches 'title' for all instancies of 'A' and replaces them with 'B'
    00510 // ============================================================================
    00511 template <class PBASE>
    00512 void GaudiHistos<PBASE>::stringSearchReplace
    00513 ( std::string       & title ,
    00514   const std::string & A     ,
    00515   const std::string & B     ) const
    00516 {
    00517   std::string::size_type slash = title.find_first_of ( A ) ;
    00518   while ( std::string::npos != slash )
    00519   {
    00520     title = title.substr(0,slash) + B + title.substr(slash+A.size());
    00521     slash = title.find_first_of( A );
    00522   }
    00523 }
    00524 // ============================================================================
    00525 // the handler for "HistoPrint" property
    00526 // ============================================================================
    00527 template < class PBASE >
    00528 void GaudiHistos<PBASE>::printHistoHandler( Property& )
    00529 {
    00530   // no action if not yet initialized
    00531   if ( this -> FSMState() < Gaudi::StateMachine::INITIALIZED ) { return ; }
    00532   if ( this -> histosPrint() ) { this -> printHistos ( MSG::ALWAYS ) ; }
    00533 }
    00534 // ============================================================================
    00535 // 1D
    00536 #include "GaudiAlg/GaudiHistos_1DFixedBinning.icpp"
    00537 #include "GaudiAlg/GaudiHistos_1DVariableBinning.icpp"
    00538 // 2D
    00539 #include "GaudiAlg/GaudiHistos_2DFixedBinning.icpp"
    00540 #include "GaudiAlg/GaudiHistos_2DVariableBinning.icpp"
    00541 // 3D
    00542 #include "GaudiAlg/GaudiHistos_3DFixedBinning.icpp"
    00543 #include "GaudiAlg/GaudiHistos_3DVariableBinning.icpp"
    00544 // 1D Profile
    00545 #include "GaudiAlg/GaudiHistos_1DProfFixedBinning.icpp"
    00546 #include "GaudiAlg/GaudiHistos_1DProfVariableBinning.icpp"
    00547 // 2D Profile
    00548 #include "GaudiAlg/GaudiHistos_2DProfFixedBinning.icpp"
    00549 #include "GaudiAlg/GaudiHistos_2DProfVariableBinning.icpp"
    00550 // ============================================================================
    00551 // The END
    00552 // ============================================================================
    00553 #endif // GAUDIALG_GAUDIHISTOS_ICPP
    00554 // ============================================================================