Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 08:34:39

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations *
0003 *                                                                                   *
0004 * This software is distributed under the terms of the Apache version 2 licence,     *
0005 * copied verbatim in the file "LICENSE".                                            *
0006 *                                                                                   *
0007 * In applying this licence, CERN does not waive the privileges and immunities       *
0008 * granted to it by virtue of its status as an Intergovernmental Organization        *
0009 * or submit itself to any jurisdiction.                                             *
0010 \***********************************************************************************/
0011 
0012 #include <Gaudi/BaseSink.h>
0013 #include <Gaudi/MonitoringHub.h>
0014 #include <TFile.h>
0015 #include <filesystem>
0016 #include <map>
0017 #include <nlohmann/json.hpp>
0018 #include <string>
0019 #include <vector>
0020 
0021 namespace Gaudi::Histograming::Sink {
0022 
0023   /*
0024    * a Base class for Root related Sinks dealing with Histograms.
0025    *
0026    * provides the common method plus a generic way of registering handler for different types
0027    */
0028   class Base : public Monitoring::BaseSink {
0029   public:
0030     using HistoIdentification = std::pair<std::string, int>;
0031     using HistoHandler        = std::function<void( TFile& file, std::string, std::string, nlohmann::json const& )>;
0032     using HistoRegistry       = std::map<HistoIdentification, HistoHandler>;
0033 
0034     using HistoBinIdentification = std::type_index;
0035     using HistoBinHandler =
0036         std::function<void( TFile& file, std::string, std::string, Monitoring::Hub::Entity const& )>;
0037     using HistoBinRegistry = std::map<HistoBinIdentification, HistoBinHandler>;
0038 
0039     Base( std::string name, ISvcLocator* svcloc ) : Monitoring::BaseSink( name, svcloc ) {
0040       // only deal with histograms
0041       setProperty( "TypesToSave", std::vector<std::string>{ "histogram:.*" } )
0042           .orThrow( "Unable to set typesToSaveProperty", "Histograming::Sink::Base" );
0043     }
0044 
0045     StatusCode initialize() override {
0046       return BaseSink::initialize().andThen( [&] {
0047         // empty output file if it exists, as we will update it at the end
0048         // This allows multiple Sinks to write to the same ROOT file
0049         std::filesystem::remove( m_fileName.value() );
0050         info() << "Writing ROOT histograms to: " << m_fileName.value() << endmsg;
0051       } );
0052     }
0053 
0054     void flush( bool ) override {
0055       // File is updated so that multiple sinks can write to the same file
0056       // As we are in stop, there is no multithreading so it is safe
0057       // As we dropped the file at initialization, no old data from a previous
0058       // run may be mixed with new one
0059       TFile histoFile( m_fileName.value().c_str(), "UPDATE" );
0060       // get all entities, sorted by component and name
0061       applyToAllSortedEntities( [this, &histoFile]( std::string const& component, std::string const& name,
0062                                                     Monitoring::Hub::Entity const& ent ) {
0063         // try first a dedicated flush, bypassing json (more efficient)
0064         auto typeIndex = ent.typeIndex();
0065         auto binSaver  = m_binRegistry.find( typeIndex );
0066         if ( binSaver != m_binRegistry.end() ) {
0067           binSaver->second( histoFile, component, name, ent );
0068           return;
0069         }
0070         // no fast track, let's use json intermediate format
0071         nlohmann::json j    = ent;
0072         auto           dim  = j.at( "dimension" ).template get<unsigned int>();
0073         auto           type = j.at( "type" ).template get<std::string>();
0074         // cut type after last ':' if there is one. The rest is precision parameter that we do not need here
0075         // as ROOT anyway treats everything as doubles in histograms
0076         type       = type.substr( 0, type.find_last_of( ':' ) );
0077         auto saver = m_registry.find( { type, dim } );
0078         if ( saver != m_registry.end() ) ( saver->second )( histoFile, component, name, j );
0079       } );
0080       info() << "Completed update of ROOT histograms in: " << m_fileName.value() << endmsg;
0081     }
0082 
0083     void registerHandler( HistoBinIdentification const& id, HistoBinHandler const& func ) {
0084       m_binRegistry.emplace( std::piecewise_construct, std::make_tuple( id ), std::make_tuple( func ) );
0085     }
0086 
0087     void registerHandler( HistoIdentification const& id, HistoHandler const& func ) {
0088       m_registry.emplace( std::piecewise_construct, std::make_tuple( id ), std::make_tuple( func ) );
0089     }
0090 
0091   private:
0092     /// map of supported type and the way to handle them
0093     HistoBinRegistry m_binRegistry{};
0094     /// map of supported type and the way to handle them
0095     HistoRegistry m_registry{};
0096 
0097     Gaudi::Property<std::string> m_fileName{ this, "FileName", "testHisto.root",
0098                                              "Name of file where to save histograms" };
0099   };
0100 
0101 } // namespace Gaudi::Histograming::Sink