Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:57:31

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2024 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 #pragma once
0012 
0013 #include <Gaudi/Accumulators/StaticHistogram.h>
0014 
0015 namespace Gaudi::Accumulators {
0016 
0017   /**
0018    * A Wrapper of a static Histogram base class using Properties to define title and axis
0019    *
0020    * Practically, this is an optional of the underlying static Histogram with creation
0021    * on demand, via the createHistogram method so one can wait that properties' values
0022    * are known.
0023    * By default creation will happen at initialization of the owner, but this can be
0024    * disabled at construction time, in which case the user has to call createHistogram
0025    * manually.
0026    * Note that disabling automatic initialization requires using the plain
0027    * constructor and passing title and axis. They can of course be empty and overwritten
0028    * via Properties. But there was no easier way providing char* convert automagically
0029    * to bool in C++ creating potential confusion between title on doNotInitialize
0030    *
0031    * This wrapper expects the Axis type of the Histogram to be usable in a
0032    * Gaudi Property and thus to define the required Grammar, parse function and operator<<
0033    * It also requires the underlying Histogram type to define :
0034    *   - AxisTupleType : a tuple type of all Axis types
0035    *   - AxisTupleArithmeticType : a tuple type of all Axis Arithmetic types
0036    * FIXME : use concepts when available
0037    */
0038   template <typename HistogramType,
0039             typename Seq =
0040                 std::make_integer_sequence<unsigned int, std::tuple_size_v<typename HistogramType::AxisTupleType>>>
0041   class HistogramWrapperInternal;
0042   template <typename HistogramType, unsigned int... ND>
0043   class HistogramWrapperInternal<HistogramType, std::integer_sequence<unsigned int, ND...>> {
0044   public:
0045     using AxisTupleType      = typename HistogramType::AxisTupleType;
0046     using AxisArithmeticType = typename HistogramType::AxisArithmeticType;
0047     using BufferType         = typename HistogramType::BufferType;
0048     template <unsigned int I>
0049     using AxisType = std::tuple_element_t<I, AxisTupleType>;
0050 
0051     /// constructor, only creates a set of Properties
0052     template <typename OWNER>
0053     HistogramWrapperInternal( OWNER* owner, std::string const& name, std::string const& title = "",
0054                               typename HistogramType::AxisTupleType axis = {}, bool doNotInitialize = false )
0055         : m_name{ name }, m_title{ title }, m_axis{ axis } {
0056       // Create associated properties
0057       owner->declareProperty( titlePropertyName(), m_title, fmt::format( "Title of histogram {}", name ) )
0058           ->template setOwnerType<OWNER>();
0059       ( owner
0060             ->declareProperty( axisPropertyName<ND>(), std::get<ND>( m_axis ),
0061                                fmt::format( "Axis {} of histogram {}", ND, name ) )
0062             ->template setOwnerType<OWNER>(),
0063         ... );
0064       // register creation of the Histogram at initialization time
0065       if ( !doNotInitialize ) {
0066         if ( owner->FSMState() >= Gaudi::StateMachine::INITIALIZED ) {
0067           // if the owner is already initialized (e.g. the histogram is being created during `start()`)
0068           // it is too late to register the callback
0069           createHistogram( *owner );
0070         } else {
0071           owner->registerCallBack( StateMachine::INITIALIZE, [this, owner]() { createHistogram( *owner ); } );
0072         }
0073       }
0074     }
0075     /// constructor with const owner (i.e. outside of constructor or initialize), equivalent to
0076     /// the StaticHistogram case (create immediately)
0077     template <typename OWNER>
0078     HistogramWrapperInternal( OWNER const* owner, std::string const& name, std::string const& title = "",
0079                               typename HistogramType::AxisTupleType axis = {} )
0080         : m_name{ name }, m_title{ title }, m_axis{ axis } {
0081       createHistogram( *owner );
0082     }
0083     /// constructor with more natural syntax for axis
0084     template <typename OWNER>
0085     HistogramWrapperInternal( OWNER* owner, std::string const& name, std::string const& title, AxisType<ND>... allAxis )
0086         : HistogramWrapperInternal( owner, name, title, std::make_tuple( allAxis... ) ) {}
0087 
0088     /// override of operator[] with extra checking that initialization happened
0089     [[nodiscard]] auto operator[]( typename HistogramType::AxisTupleArithmeticType v ) {
0090       if ( !m_histo ) {
0091         throw std::logic_error( fmt::format( "Histogram {} is used before being initialized", m_name ) );
0092       }
0093       return m_histo.value()[v];
0094     }
0095 
0096     /// creation of the internal histogram, from the properties
0097     template <typename OWNER>
0098     void createHistogram( OWNER& owner ) {
0099       m_histo.emplace( &owner, m_name, m_title, m_axis );
0100     }
0101 
0102     friend void to_json( nlohmann::json& j, HistogramWrapperInternal const& h ) {
0103       if ( !h.m_histo ) {
0104         throw std::logic_error( fmt::format( "Histogram {} is converted to json before being initialized", h.m_name ) );
0105       }
0106       j = h.m_histo.value();
0107     }
0108 
0109     // set directly some properties, only if histogram was not yet created
0110     void setTitle( std::string const& title ) {
0111       if ( m_histo )
0112         throw std::logic_error(
0113             fmt::format( "Cannot modify title of histogram {} after it has been initialized", m_name ) );
0114       m_title = title;
0115     }
0116     template <unsigned int N>
0117     void setAxis( std::tuple_element_t<N, typename HistogramType::AxisTupleType> const& axis ) {
0118       if ( m_histo )
0119         throw std::logic_error(
0120             fmt::format( "Cannot modify axis {} of histogram {} after it has been initialized", N, m_name ) );
0121       std::get<N>( m_axis ) = axis;
0122     }
0123 
0124     template <unsigned int N>
0125     auto& axis() const {
0126       if ( !m_histo )
0127         throw std::logic_error(
0128             fmt::format( "Cannot get axis {} of histogram {} before it has been initialized", N, m_name ) );
0129       return m_histo->template axis<N>();
0130     }
0131 
0132     auto& axis() const {
0133       if ( !m_histo )
0134         throw std::logic_error(
0135             fmt::format( "Cannot get axis of histogram {} before it has been initialized", m_name ) );
0136       return m_histo->axis();
0137     }
0138 
0139     void reset() { m_histo.reset(); }
0140 
0141     // wrapping some methods of the underlyoing histogram
0142     auto buffer() {
0143       if ( !m_histo )
0144         throw std::logic_error( fmt::format( "`buffer()` called on histogram {} before being initialized", m_name ) );
0145       return m_histo->buffer();
0146     }
0147 
0148   private:
0149     std::string basePropertyName() const {
0150       // properties are used as identifiers in python and thus cannot anything alse than _, letters and numbers
0151       // we thus replace anything else with '_' in the property names
0152       std::string name = m_name;
0153       std::replace_if(
0154           begin( name ), end( name ), []( auto& c ) { return !std::isalnum( c ); }, '_' );
0155       return name;
0156     }
0157     std::string titlePropertyName() const { return fmt::format( "{}_Title", basePropertyName() ); }
0158     template <unsigned int N>
0159     std::string axisPropertyName() const {
0160       return fmt::format( "{}_Axis{}", basePropertyName(), N );
0161     }
0162 
0163     // Members of the custom histogrem
0164     std::string                           m_name{};
0165     std::string                           m_title{};
0166     typename HistogramType::AxisTupleType m_axis{};
0167     std::optional<HistogramType>          m_histo{};
0168   };
0169 
0170   template <typename HistogramType>
0171   using HistogramWrapper = HistogramWrapperInternal<HistogramType>;
0172 
0173 } // namespace Gaudi::Accumulators