Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-26 09:01:07

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     template <unsigned int I>
0048     using AxisType = std::tuple_element_t<I, AxisTupleType>;
0049 
0050     /// constructor, only creates a set of Properties
0051     template <typename OWNER>
0052     HistogramWrapperInternal( OWNER* owner, std::string const& name, std::string const& title = "",
0053                               typename HistogramType::AxisTupleType axis = {}, bool doNotInitialize = false )
0054         : m_name{ name }, m_title{ title }, m_axis{ axis } {
0055       // Create associated properties
0056       owner->declareProperty( titlePropertyName(), m_title, fmt::format( "Title of histogram {}", name ) )
0057           ->template setOwnerType<OWNER>();
0058       ( owner
0059             ->declareProperty( axisPropertyName<ND>(), std::get<ND>( m_axis ),
0060                                fmt::format( "Axis {} of histogram {}", ND, name ) )
0061             ->template setOwnerType<OWNER>(),
0062         ... );
0063       // register creation of the Histogram at initialization time
0064       if ( !doNotInitialize ) {
0065         if ( owner->FSMState() >= Gaudi::StateMachine::INITIALIZED ) {
0066           // if the owner is already initialized (e.g. the histogram is being created during `start()`)
0067           // it is too late to register the callback
0068           createHistogram( *owner );
0069         } else {
0070           owner->registerCallBack( StateMachine::INITIALIZE, [this, owner]() { createHistogram( *owner ); } );
0071         }
0072       }
0073     }
0074     /// constructor with const owner (i.e. outside of constructor or initialize), equivalent to
0075     /// the StaticHistogram case (create immediately)
0076     template <typename OWNER>
0077     HistogramWrapperInternal( OWNER const* owner, std::string const& name, std::string const& title = "",
0078                               typename HistogramType::AxisTupleType axis = {} )
0079         : m_name{ name }, m_title{ title }, m_axis{ axis } {
0080       createHistogram( *owner );
0081     }
0082     /// constructor with more natural syntax for axis
0083     template <typename OWNER>
0084     HistogramWrapperInternal( OWNER* owner, std::string const& name, std::string const& title, AxisType<ND>... allAxis )
0085         : HistogramWrapperInternal( owner, name, title, std::make_tuple( allAxis... ) ) {}
0086 
0087     /// override of operator[] with extra checking that initialization happened
0088     [[nodiscard]] auto operator[]( typename HistogramType::AxisTupleArithmeticType&& v ) {
0089       if ( !m_histo ) {
0090         throw std::logic_error( fmt::format( "Histogram {} is used before being initialized", m_name ) );
0091       }
0092       return m_histo.value()[std::forward<typename HistogramType::AxisTupleArithmeticType>( v )];
0093     }
0094 
0095     /// creation of the internal histogram, from the properties
0096     template <typename OWNER>
0097     void createHistogram( OWNER& owner ) {
0098       m_histo.emplace( &owner, m_name, m_title, m_axis );
0099     }
0100 
0101     friend void to_json( nlohmann::json& j, HistogramWrapperInternal const& h ) {
0102       if ( !h.m_histo ) {
0103         throw std::logic_error( fmt::format( "Histogram {} is converted to json before being initialized", h.m_name ) );
0104       }
0105       j = h.m_histo.value();
0106     }
0107 
0108     // set directly some properties, only if histogram was not yet created
0109     void setTitle( std::string const& title ) {
0110       if ( m_histo )
0111         throw std::logic_error(
0112             fmt::format( "Cannot modify title of histogram {} after it has been initialized", m_name ) );
0113       m_title = title;
0114     }
0115     template <unsigned int N>
0116     void setAxis( std::tuple_element_t<N, typename HistogramType::AxisTupleType> const& axis ) {
0117       if ( m_histo )
0118         throw std::logic_error(
0119             fmt::format( "Cannot modify axis {} of histogram {} after it has been initialized", N, m_name ) );
0120       std::get<N>( m_axis ) = axis;
0121     }
0122 
0123     void reset() { m_histo.reset(); }
0124 
0125     // wrapping some methods of the underlyoing histogram
0126     auto buffer() {
0127       if ( !m_histo )
0128         throw std::logic_error( fmt::format( "`buffer()` called on histogram {} before being initialized", m_name ) );
0129       return m_histo->buffer();
0130     }
0131 
0132   private:
0133     std::string basePropertyName() const {
0134       // properties are used as identifiers in python and thus cannot anything alse than _, letters and numbers
0135       // we thus replace anything else with '_' in the property names
0136       std::string name = m_name;
0137       std::replace_if(
0138           begin( name ), end( name ), []( auto& c ) { return !std::isalnum( c ); }, '_' );
0139       return name;
0140     }
0141     std::string titlePropertyName() const { return fmt::format( "{}_Title", basePropertyName() ); }
0142     template <unsigned int N>
0143     std::string axisPropertyName() const {
0144       return fmt::format( "{}_Axis{}", basePropertyName(), N );
0145     }
0146 
0147     // Members of the custom histogrem
0148     std::string                           m_name{};
0149     std::string                           m_title{};
0150     typename HistogramType::AxisTupleType m_axis{};
0151     std::optional<HistogramType>          m_histo{};
0152   };
0153 
0154   template <typename HistogramType>
0155   using HistogramWrapper = HistogramWrapperInternal<HistogramType>;
0156 
0157 } // namespace Gaudi::Accumulators