From a6fd70403e60c6592cbbde89e5ef4de4b141be86 Mon Sep 17 00:00:00 2001 From: Chris Jones <jonesc@hep.phy.cam.ac.uk> Date: Thu, 7 Nov 2024 10:50:08 +0000 Subject: [PATCH] RICH - Add support for using new histograms --- Rich/RichFutureKernel/CMakeLists.txt | 22 +- .../RichFutureKernel/RichHistoAlgBase.h | 11 +- .../include/RichFutureKernel/RichHistoBase.h | 536 +++++++++--------- .../include/RichFutureKernel/RichHistoUtils.h | 28 - Rich/RichFutureKernel/src/RichHistoBase.icpp | 269 --------- .../src/component/RichBaseTests.cpp | 136 +++++ .../src/{ => lib}/RichAlgBase.cpp | 0 .../src/{ => lib}/RichCommonBase.icpp | 0 .../src/{ => lib}/RichHistoAlgBase.cpp | 2 - .../src/lib/RichHistoBase.icpp | 61 ++ .../src/{ => lib}/RichHistoToolBase.cpp | 0 .../src/{ => lib}/RichToolBase.cpp | 0 .../src/{ => lib}/RichTupleAlgBase.cpp | 0 .../src/{ => lib}/RichTupleToolBase.cpp | 0 .../tests/options/Histograms.py | 62 ++ .../tests/qmtest/histograms.qmt | 22 + Rich/RichFutureKernel/tests/refs/empty.ref | 0 .../tests/refs/histograms.ref | 113 ++++ 18 files changed, 696 insertions(+), 566 deletions(-) delete mode 100644 Rich/RichFutureKernel/include/RichFutureKernel/RichHistoUtils.h delete mode 100644 Rich/RichFutureKernel/src/RichHistoBase.icpp create mode 100644 Rich/RichFutureKernel/src/component/RichBaseTests.cpp rename Rich/RichFutureKernel/src/{ => lib}/RichAlgBase.cpp (100%) rename Rich/RichFutureKernel/src/{ => lib}/RichCommonBase.icpp (100%) rename Rich/RichFutureKernel/src/{ => lib}/RichHistoAlgBase.cpp (94%) create mode 100644 Rich/RichFutureKernel/src/lib/RichHistoBase.icpp rename Rich/RichFutureKernel/src/{ => lib}/RichHistoToolBase.cpp (100%) rename Rich/RichFutureKernel/src/{ => lib}/RichToolBase.cpp (100%) rename Rich/RichFutureKernel/src/{ => lib}/RichTupleAlgBase.cpp (100%) rename Rich/RichFutureKernel/src/{ => lib}/RichTupleToolBase.cpp (100%) create mode 100644 Rich/RichFutureKernel/tests/options/Histograms.py create mode 100644 Rich/RichFutureKernel/tests/qmtest/histograms.qmt create mode 100644 Rich/RichFutureKernel/tests/refs/empty.ref create mode 100644 Rich/RichFutureKernel/tests/refs/histograms.ref diff --git a/Rich/RichFutureKernel/CMakeLists.txt b/Rich/RichFutureKernel/CMakeLists.txt index 9cfa4e65356..dda20128527 100644 --- a/Rich/RichFutureKernel/CMakeLists.txt +++ b/Rich/RichFutureKernel/CMakeLists.txt @@ -15,12 +15,12 @@ Rich/RichFutureKernel gaudi_add_library(RichFutureKernel SOURCES - src/RichAlgBase.cpp - src/RichHistoAlgBase.cpp - src/RichHistoToolBase.cpp - src/RichToolBase.cpp - src/RichTupleAlgBase.cpp - src/RichTupleToolBase.cpp + src/lib/RichAlgBase.cpp + src/lib/RichHistoAlgBase.cpp + src/lib/RichHistoToolBase.cpp + src/lib/RichToolBase.cpp + src/lib/RichTupleAlgBase.cpp + src/lib/RichTupleToolBase.cpp LINK PUBLIC AIDA::aida @@ -32,3 +32,13 @@ gaudi_add_library(RichFutureKernel PRIVATE Gaudi::GaudiUtilsLib ) + +gaudi_add_module(RichFutureKernelTests + SOURCES + src/component/RichBaseTests.cpp + LINK + LHCb::LHCbAlgsLib + LHCb::RichFutureKernel +) + +gaudi_add_tests(QMTest) diff --git a/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoAlgBase.h b/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoAlgBase.h index 30304f3a387..34444215be8 100644 --- a/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoAlgBase.h +++ b/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoAlgBase.h @@ -24,7 +24,6 @@ // Gaudi #include "Gaudi/Algorithm.h" #include "GaudiAlg/FixTESPath.h" -#include "GaudiAlg/GaudiHistoAlg.h" // local #include "RichFutureKernel/RichHistoBase.h" @@ -36,8 +35,10 @@ namespace Rich::Future { namespace Details { /// Basic algorithm class with minimum functionality from legacy GaudiAlg needed by GaudiHistos - struct GAUDI_API BaseAlg : FixTESPath<Gaudi::Algorithm> { + struct GAUDI_API HistoBaseAlg : FixTESPath<Gaudi::Algorithm> { using FixTESPath<Gaudi::Algorithm>::FixTESPath; + using FixTESPath<Gaudi::Algorithm>::initialize; + using FixTESPath<Gaudi::Algorithm>::finalize; StatusCode Print( const std::string& msg, // const StatusCode st = StatusCode::SUCCESS, // const MSG::Level lev = MSG::INFO ) const { @@ -55,12 +56,6 @@ namespace Rich::Future { return st; } }; - /// Histogramming base a la GaudiAlg, but based on Gaudi::Algorithm - struct GAUDI_API HistoBaseAlg : GaudiHistos<BaseAlg> { - using GaudiHistos<BaseAlg>::GaudiHistos; - using GaudiHistos<BaseAlg>::initialize; - using GaudiHistos<BaseAlg>::finalize; - }; } // namespace Details //----------------------------------------------------------------------------- diff --git a/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoBase.h b/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoBase.h index d0030a97669..e7d37a47c05 100644 --- a/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoBase.h +++ b/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoBase.h @@ -23,7 +23,6 @@ // Local #include "RichFutureKernel/RichCommonBase.h" -#include "RichFutureKernel/RichHistoUtils.h" // RichUtils #include "RichUtils/RichException.h" @@ -32,29 +31,234 @@ #include "RichUtils/RichMap.h" // Gaudi +#include "GAUDI_VERSION.h" #include "Gaudi/Property.h" - -// boost -#include "boost/array.hpp" - -// AIDA -#include "AIDA/IHistogram1D.h" -#include "AIDA/IHistogram2D.h" -//#include "AIDA/IHistogram3D.h" -#include "AIDA/IProfile1D.h" -#include "AIDA/IProfile2D.h" +#if GAUDI_MAJOR_VERSION < 39 +# include "Gaudi/Accumulators/Histogram.h" +#else +# include "Gaudi/Accumulators/StaticHistogram.h" +#endif // STL +#include <array> #include <cassert> +#include <cstdint> #include <mutex> +#include <optional> #include <string> +#include <tuple> +#include <type_traits> #include <utility> #include <vector> namespace Rich::Future { - // import histogram utils - using namespace Rich::Future::HistoUtils; + namespace Hist { + + namespace details { + /// Check if a given type is one of a given list. + template <typename T, typename... Types> + using is_one_of = std::disjunction<std::is_base_of<std::remove_pointer_t<T>, std::remove_pointer_t<Types>>...>; + template <typename T, typename... Types> + constexpr bool is_one_of_v = is_one_of<T, Types...>::value; + /// Check if it is 'OK' to cast a parameter From -> To + template <typename From, typename To> + constexpr bool is_safe_cast() { + // eventually would like to add proper 'narrowing' type traits here but for now do a few checks + constexpr bool is_fp_to_int = std::is_floating_point_v<From> && std::is_integral_v<To>; + constexpr bool is_big_to_small = ( sizeof( From ) > sizeof( To ) ); + constexpr bool is_signed_int_mismatch = + std::is_integral_v<From> && std::is_integral_v<To> && ( std::is_signed_v<From> != std::is_signed_v<To> ); + constexpr bool from_is_int_or_enum = std::is_arithmetic_v<From> || std::is_enum_v<From>; + return ( !is_fp_to_int && !is_big_to_small && !is_signed_int_mismatch && from_is_int_or_enum && + std::is_arithmetic_v<To> && std::is_convertible_v<From, To> ); + } + /// Check histogram dimensions + template <typename T, unsigned int ND, typename I = typename T::value_type::NumberDimensions::value_type> + constexpr bool is_dim_v = std::is_same_v<typename T::value_type::NumberDimensions, std::integral_constant<I, ND>>; + /// Check histogram types for various arthemtic emplate types + template <typename T, template <typename, Gaudi::Accumulators::atomicity> typename H, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + constexpr bool is_hist_type_v = + is_one_of_v<T, H<float, ATOMICITY>, H<double, ATOMICITY>, // + H<std::int64_t, ATOMICITY>, H<std::int32_t, ATOMICITY>, H<std::int16_t, ATOMICITY>, // + H<std::uint64_t, ATOMICITY>, H<std::uint32_t, ATOMICITY>, H<std::uint16_t, ATOMICITY>>; + template <typename T, template <typename, Gaudi::Accumulators::atomicity> typename... Hs> + constexpr bool is_one_of_hist_types_v = ( ... || is_hist_type_v<T, Hs> ); + /// Base class wrapper for all histograms, making them optional. + template <typename H> + struct BaseH : std::optional<H> { + using std::optional<H>::value; + using std::optional<H>::has_value; + using std::optional<H>::emplace; +#if GAUDI_MAJOR_VERSION < 39 + using X = typename H::AxisArithmeticType; + [[nodiscard]] auto operator[]( const X arg ) { return this->value()[arg]; } + [[nodiscard]] auto operator[]( const std::pair<X, X> arg ) { return this->value()[{arg.first, arg.second}]; } +#else + [[nodiscard]] auto operator[]( typename H::AxisTupleArithmeticType arg ) { + return this->value()[std::move( arg )]; + } +#endif + + template <unsigned int N> + [[nodiscard]] auto& axis() const { +#if GAUDI_MAJOR_VERSION < 39 + return this->value().axis()[N]; +#else + return this->value().template axis<N>(); +#endif + } + // Gaudi version here needs updating after + // https://gitlab.cern.ch/gaudi/Gaudi/-/merge_requests/1651 is in a release +#if GAUDI_VERSION >= CALC_GAUDI_VERSION( 39, 0 ) + template <typename B> + struct Buffer : std::optional<B> { + [[nodiscard]] auto operator[]( typename H::AxisTupleArithmeticType arg ) { + return this->value()[std::move( arg )]; + } + }; + [[nodiscard]] auto buffer() { + using BuffT = decltype( this->value().buffer() ); + return ( this->has_value() ? Buffer<BuffT>{this->value().buffer()} : Buffer<BuffT>{} ); + } +#else + // workaround for older v38 Gaudi release where there isa bug in the move semantics + // for histograms buffers, that prevents the use of std::optional with them. + // Just as a stop gap to allow builds to work here fake a buffer with just references to originals + template <typename B> + struct Buffer { + public: + Buffer() = default; + Buffer( B& b ) : m_b{&b} {} +# if GAUDI_MAJOR_VERSION < 39 + [[nodiscard]] auto operator[]( const X arg ) { return ( *m_b )[arg]; } + [[nodiscard]] auto operator[]( const std::pair<X, X> arg ) { return ( *m_b )[{arg.first, arg.second}]; } +# else + [[nodiscard]] auto operator[]( typename H::AxisTupleArithmeticType arg ) { + return ( *m_b )[std::move( arg )]; + } +# endif + + private: + B* m_b = nullptr; + }; + [[nodiscard]] auto buffer() { return ( this->has_value() ? Buffer<H>( this->value() ) : Buffer<H>() ); } +#endif + }; + } // namespace details + + using DefaultArithmeticType = double; + +// Use different gaudi histogram implementation in different Gaudi versions +#if GAUDI_MAJOR_VERSION < 39 + + // 1D histogram types + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using H1D = details::BaseH<Gaudi::Accumulators::Histogram<1, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WH1D = details::BaseH<Gaudi::Accumulators::WeightedHistogram<1, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using P1D = details::BaseH<Gaudi::Accumulators::ProfileHistogram<1, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WP1D = details::BaseH<Gaudi::Accumulators::WeightedProfileHistogram<1, ATOMICITY, TYPE>>; + + // 2D histogram types + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using H2D = details::BaseH<Gaudi::Accumulators::Histogram<2, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WH2D = details::BaseH<Gaudi::Accumulators::WeightedHistogram<2, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using P2D = details::BaseH<Gaudi::Accumulators::ProfileHistogram<2, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WP2D = details::BaseH<Gaudi::Accumulators::WeightedProfileHistogram<2, ATOMICITY, TYPE>>; + +#else + + // 1D histogram types + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using H1D = details::BaseH<Gaudi::Accumulators::StaticHistogram<1, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WH1D = details::BaseH<Gaudi::Accumulators::StaticWeightedHistogram<1, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using P1D = details::BaseH<Gaudi::Accumulators::StaticProfileHistogram<1, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WP1D = details::BaseH<Gaudi::Accumulators::StaticWeightedProfileHistogram<1, ATOMICITY, TYPE>>; + + // 2D histogram types + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using H2D = details::BaseH<Gaudi::Accumulators::StaticHistogram<2, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WH2D = details::BaseH<Gaudi::Accumulators::StaticWeightedHistogram<2, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using P2D = details::BaseH<Gaudi::Accumulators::StaticProfileHistogram<2, ATOMICITY, TYPE>>; + template <typename TYPE = DefaultArithmeticType, + Gaudi::Accumulators::atomicity ATOMICITY = Gaudi::Accumulators::atomicity::full> + using WP2D = details::BaseH<Gaudi::Accumulators::StaticWeightedProfileHistogram<2, ATOMICITY, TYPE>>; + +#endif + + // some type traits + + // Histogram Dimensionality + template <typename T> + constexpr bool is_1d_v = details::is_dim_v<T, 1>; + template <typename T> + constexpr bool is_2d_v = details::is_dim_v<T, 2>; + + // Profile versus regular histogram + template <typename T> + constexpr bool is_profile_v = details::is_one_of_hist_types_v<T, WP1D, WP2D, P1D, P2D>; + template <typename T> + constexpr bool is_hist_v = details::is_one_of_hist_types_v<T, WH1D, WH2D, H1D, H2D>; + + // Weighted versus non-weighted types + template <typename T> + constexpr bool is_weighted_v = details::is_one_of_hist_types_v<T, WH1D, WH2D, WP1D, WP2D>; + template <typename T> + constexpr bool is_not_weighted_v = details::is_one_of_hist_types_v<T, H1D, H2D, P1D, P2D>; + + /// Get histogram arithemtic type + template <typename T> + using param_t = typename T::value_type::AxisArithmeticType; + + template <typename PARAM, typename Z> + constexpr bool param_check_v = details::is_safe_cast<PARAM, Z>(); + + /// Array storage for histograms with buffer support + template <typename T, std::size_t N> + struct Array : public std::array<T, N> { + auto buffer() { + return std::apply( []( auto&... i ) { return std::array{i.buffer()...}; }, + static_cast<std::array<T, N>&>( *this ) ); + } + }; + + template <typename HIST> + using RadArray = Array<HIST, Rich::NRadiatorTypes>; + template <typename HIST> + using DetArray = Array<HIST, Rich::NRiches>; + template <typename HIST> + using PanelArray = Array<HIST, Rich::NPDPanelsPerRICH>; + template <typename HIST> + using PartArray = Array<HIST, Rich::NParticleTypes>; + + } // namespace Hist //----------------------------------------------------------------------------- /** @class HistoBase RichFutureKernel/RichHistoBase.h @@ -69,6 +273,14 @@ namespace Rich::Future { template <class PBASE> class HistoBase : public CommonBase<PBASE> { + protected: + // definitions + + /// short name for bin labels + using BinLabels = std::vector<std::string>; + /// short name for axis label + using AxisLabel = std::string; + public: // inherit constructors using CommonBase<PBASE>::CommonBase; @@ -76,18 +288,8 @@ namespace Rich::Future { protected: /// Histogram Constructor initisalisations inline void initRichHistoConstructor() { - const auto sc = - // Place all histograms under RICH/ sub-dir - this->setProperty( "HistoTopDir", "RICH/" ) && - // Expand printout table size a bit - this->setProperty( "ShortFormatFor1DHistoTable", " | %1$-45.45s %2%" ) && - this->setProperty( "FormatFor1DHistoTable", - "| %2$-75.75s | %3$=7d |%8$11.5g | %10$-11.5g|%12$11.5g |%14$11.5g |" ) && - this->setProperty( - "HeaderFor1DHistoTable", - "| Title | # | Mean | " - " RMS | Skewness | Kurtosis |" ); - if ( !sc ) { throw Rich::Exception( "Failed to set histogramming properties" ); } + // Nothing at the moment ... + // keep for now in case needed, but if not eventually should just remove. } /// Tuple Constructor initisalisations @@ -131,245 +333,73 @@ namespace Rich::Future { virtual StatusCode prebookHistograms(); protected: - // definitions + // Histogram initialisation - /// short name for bin labels - using BinLabels = std::vector<std::string>; - /// short name for axis label - using AxisLabel = std::string; - - protected: - /** Book a 1D histogram - * - * @param id Histogram identifier - * @param title Histogram title - * @param low Lower histogram edge - * @param high Upper histogram edge - * @param bins Number of bins - * @param xAxisLabel Label for the X Axis - * @param yAxisLabel Label for the Y Axis - * @param binLabels Labels for the X axis bins - * - * @return Pointer to booked histogram - */ - AIDA::IHistogram1D* richHisto1D( const Rich::HistogramID& id, // - const std::string& title, // - const double low, // - const double high, // - const unsigned int bins, // - const AxisLabel& xAxisLabel = "", // - const AxisLabel& yAxisLabel = "", // - const BinLabels& binLabels = BinLabels() ) const; - - /** Book a 2D histogram - * - * @param id Histogram identifier - * @param title Histogram title - * @param lowX Lower histogram edge in X - * @param highX Upper histogram edge in X - * @param binsX Number of bins in X - * @param lowY Lower histogram edge in Y - * @param highY Upper histogram edge in Y - * @param binsY Number of bins in Y - * @param xAxisLabel Label for the X Axis - * @param yAxisLabel Label for the Y Axis - * @param zAxisLabel Label for the Z Axis - * @param xBinLabels Labels for the X axis bins - * @param yBinLabels Labels for the Y axis bins - * - * @return Pointer to booked histogram - */ - AIDA::IHistogram2D* richHisto2D( const Rich::HistogramID& id, // - const std::string& title, // - const double lowX, // - const double highX, // - const unsigned int binsX, // - const double lowY, // - const double highY, // - const unsigned int binsY, // - const AxisLabel& xAxisLabel = "", // - const AxisLabel& yAxisLabel = "", // - const AxisLabel& zAxisLabel = "", // - const BinLabels& xBinLabels = BinLabels(), // - const BinLabels& yBinLabels = BinLabels() ) const; - - /** Book a 1D profile histogram - * - * @param id Histogram identifier - * @param title Histogram title - * @param low Lower hisstogram edge - * @param high Upper histogram edge - * @param bins Number of bins - * @param xAxisLabel Label for the X Axis - * @param yAxisLabel Label for the Y Axis - * €param binLabels Labels for the X axis bins - * - * @return Pointer to booked histogram - */ - AIDA::IProfile1D* richProfile1D( const Rich::HistogramID& id, // - const std::string& title, // - const double low, // - const double high, // - const unsigned int bins, // - const AxisLabel& xAxisLabel = "", // - const AxisLabel& yAxisLabel = "", // - const BinLabels& binLabels = BinLabels() ) const; - - /** Book a 2D profile histogram - * - * @param id Histogram identifier - * @param title Histogram title - * @param lowX Lower histogram edge in X - * @param highX Upper histogram edge in X - * @param binsX Number of bins in X - * @param lowY Lower histogram edge in Y - * @param highY Upper histogram edge in Y - * @param binsY Number of bins in Y - * @param xAxisLabel Label for the X Axis - * @param yAxisLabel Label for the Y Axis - * @param zAxisLabel Label for the Z Axis - * @param xBinLabels Labels for the X axis bins - * @param yBinLabels Labels for the Y axis bins - * - * @return Pointer to booked histogram - */ - AIDA::IProfile2D* richProfile2D( const Rich::HistogramID& id, // - const std::string& title, // - const double lowX, // - const double highX, // - const unsigned int binsX, // - const double lowY, // - const double highY, // - const unsigned int binsY, // - const AxisLabel& xAxisLabel = "", // - const AxisLabel& yAxisLabel = "", // - const AxisLabel& zAxisLabel = "", // - const BinLabels& xBinLabels = BinLabels(), // - const BinLabels& yBinLabels = BinLabels() ) const; - - //----------------------------------------------------------------------------------------- + template <typename H, typename... Args> + bool initHist( H& h, Args&&... args ) const { + if constexpr ( Hist::is_1d_v<H> ) { return init1D( h, std::forward<Args>( args )... ); } + if constexpr ( Hist::is_2d_v<H> ) { return init2D( h, std::forward<Args>( args )... ); } + } - protected: - /// Safe histogram filling - template <typename HIST, typename... Args> - inline void fillHisto( HIST* h, Args&&... args ) const { - if ( h ) { - h->fill( std::forward<Args>( args )... ); - } else { - throw Rich::Exception( "Attempt to fill NULL histogram pointer" ); + /// 1D histogram + template <typename H1D> + bool init1D( H1D& h, // + const Rich::HistogramID& id, // + std::string title, // + const Hist::param_t<H1D> low, // + const Hist::param_t<H1D> high, // + const unsigned int bins, // + AxisLabel xAxisLabel = "", // + AxisLabel yAxisLabel = "", // + BinLabels binLabels = {} ) const { + using Axis = Gaudi::Accumulators::Axis<Hist::param_t<H1D>>; + title = id.fullTitle( title ); + if ( !xAxisLabel.empty() ) { + title += ";" + xAxisLabel; + // Only allow y Axis label if we also have an X axis label + if ( !yAxisLabel.empty() ) { title += ";" + yAxisLabel; } } + h.emplace( this, "/RICH/" + this->name() + "/" + id.fullid(), std::move( title ), + Axis( bins, low, high, std::move( xAxisLabel ), std::move( binLabels ) ) ); + return h.has_value(); } - //----------------------------------------------------------------------------------------- - - private: - // Types for histogram lookup - - /** @class HistoMap RichFutureKernel/RichHistoBase.h - * - * Private class to implement mapping between RICH classes and histograms - * - * @author Chris Jones Christopher.Rob.Jones@cern.ch - * @date 2009-07-27 - */ - template <class HTYPE> - class HistoMap { - public: - using StringToHist = Rich::HashMap<std::string, HTYPE*>; - - private: - using Map = Rich::Map<Rich::PackedPIDInfo::Pack32_t, StringToHist>; - - private: - mutable Map m_map; - mutable std::mutex m_mutex; - - public: - inline StringToHist& getmap( const Rich::PackedPIDInfo& info ) const { - auto i = m_map.find( info.raw() ); - if ( i != m_map.end() ) { - return i->second; - } else { - // lock to create map - std::scoped_lock lock( m_mutex ); - // still missing ? - i = m_map.find( info.raw() ); - return ( i != m_map.end() ? i->second : m_map[info.raw()] ); + /// 2D histogram + template <typename H2D> + bool init2D( H2D& h, // + const Rich::HistogramID& id, // + std::string title, // + const Hist::param_t<H2D> lowX, // + const Hist::param_t<H2D> highX, // + const unsigned int binsX, // + const Hist::param_t<H2D> lowY, // + const Hist::param_t<H2D> highY, // + const unsigned int binsY, // + AxisLabel xAxisLabel = "", // + AxisLabel yAxisLabel = "", // + AxisLabel zAxisLabel = "", // + BinLabels xBinLabels = {}, // + BinLabels yBinLabels = {} ) const { + using Axis = Gaudi::Accumulators::Axis<Hist::param_t<H2D>>; + title = id.fullTitle( title ); + if ( !xAxisLabel.empty() ) { + title += ";" + xAxisLabel; + // Only allow y Axis label if we also have an X axis label + if ( !yAxisLabel.empty() ) { + title += ";" + yAxisLabel; + // Only allow z Axis label if we also have an X and Y axis labels + if ( !zAxisLabel.empty() ) { title += ";" + zAxisLabel; } } } - inline HTYPE*& gethist( const Rich::HistogramID& id ) const { return getmap( id.packedData() )[id.id()]; } - }; - - /// Mapping between IDs and 1D histogram pointers - using Map1DH = HistoMap<AIDA::IHistogram1D>; - - /// Mapping between IDs and 2D histogram pointers - using Map2DH = HistoMap<AIDA::IHistogram2D>; - - /// Mapping between IDs and 1D Profile histogram pointers - using Map1DP = HistoMap<AIDA::IProfile1D>; - - /// Mapping between IDs and 2D Profile histogram pointers - using Map2DP = HistoMap<AIDA::IProfile2D>; + h.emplace( this, "/RICH/" + this->name() + "/" + id.fullid(), std::move( title ), + Axis( binsX, lowX, highX, std::move( xAxisLabel ), std::move( xBinLabels ) ), + Axis( binsY, lowY, highY, std::move( yAxisLabel ), std::move( yBinLabels ) ) ); + return h.has_value(); + } private: /// Flag to indicate if histograms have been booked or not bool m_histosAreBooked{false}; - - /// 1D histo map - Map1DH m_1dhmap; - - /// 2D histo map - Map2DH m_2dhmap; - - /// 1D Profile map - Map1DP m_1dpmap; - - /// 2D Profile map - Map2DP m_2dpmap; - - /// Booking locks - mutable std::mutex m_mutex1DH; - mutable std::mutex m_mutex1DP; - mutable std::mutex m_mutex2DH; - mutable std::mutex m_mutex2DP; - - protected: - //----------------------------------------------------------------------------------------- - - /** Access 1D histogram by id - * - * @param id Histogram identifier - * - * @return Pointer to booked histogram - */ - AIDA::IHistogram1D* richHisto1D( const Rich::HistogramID& id ) const; - - /** Access 2D histogram by id - * - * @param id Histogram identifier - * - * @return Pointer to booked histogram - */ - AIDA::IHistogram2D* richHisto2D( const Rich::HistogramID& id ) const; - - /** Access 1D profile histogram by id - * - * @param id Histogram identifier - * - * @return Pointer to booked histogram - */ - AIDA::IProfile1D* richProfile1D( const Rich::HistogramID& id ) const; - - /** Access 2D profile histogram by id - * - * @param id Histogram identifier - * - * @return Pointer to booked histogram - */ - AIDA::IProfile2D* richProfile2D( const Rich::HistogramID& id ) const; - - //----------------------------------------------------------------------------------------- }; } // namespace Rich::Future diff --git a/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoUtils.h b/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoUtils.h deleted file mode 100644 index fea7291e677..00000000000 --- a/Rich/RichFutureKernel/include/RichFutureKernel/RichHistoUtils.h +++ /dev/null @@ -1,28 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * -* * -* This software is distributed under the terms of the GNU General Public * -* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * -* * -* In applying this licence, CERN does not waive the privileges and immunities * -* granted to it by virtue of its status as an Intergovernmental Organization * -* or submit itself to any jurisdiction. * -\*****************************************************************************/ - -#pragma once - -#include "RichUtils/RichException.h" -#include <cassert> - -namespace Rich::Future::HistoUtils { - - /// Utility method to save a histogram pointer with checks - template <typename HISTO> - [[nodiscard]] inline bool saveAndCheck( HISTO*& h1, HISTO* h2 ) { - // assert( h1 == nullptr ); // should never overwrite a previously cached valid pointer - if ( h1 && h1 != h2 ) { throw Rich::Exception( "Attempt to overwrite existing histogram '" + h1->title() + "'" ); } - h1 = h2; // save input - return ( h1 != nullptr ); // input should always be valid - } - -} // namespace Rich::Future::HistoUtils diff --git a/Rich/RichFutureKernel/src/RichHistoBase.icpp b/Rich/RichFutureKernel/src/RichHistoBase.icpp deleted file mode 100644 index c13fb3903b3..00000000000 --- a/Rich/RichFutureKernel/src/RichHistoBase.icpp +++ /dev/null @@ -1,269 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * -* * -* This software is distributed under the terms of the GNU General Public * -* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * -* * -* In applying this licence, CERN does not waive the privileges and immunities * -* granted to it by virtue of its status as an Intergovernmental Organization * -* or submit itself to any jurisdiction. * -\*****************************************************************************/ - -//----------------------------------------------------------------------------- -/** @file RichHistoBase.icpp - * - * Implementation file for RICH base class : Rich::HistoBase - * - * @author Chris Jones Christopher.Rob.Jones@cern.ch - * @date 2009-07-27 - */ -//----------------------------------------------------------------------------- - -#pragma once - -// local -#include "RichFutureKernel/RichHistoBase.h" - -// Utils -#include "RichUtils/RichException.h" - -// GaudiUtils -#include "GaudiUtils/HistoLabels.h" -using namespace Gaudi::Utils::Histos; - -// Base class methods -#include "RichCommonBase.icpp" - -//============================================================================= -// System Initialisation -//============================================================================= -template <class PBASE> -StatusCode Rich::Future::HistoBase<PBASE>::sysInitialize() { - // run base clase method - auto sc = CommonBase<PBASE>::sysInitialize(); - if ( sc ) { - // as last thing book any histos (only once) - if ( !m_histosAreBooked ) { - try { - sc = prebookHistograms(); - m_histosAreBooked = true; - } catch ( const Rich::Exception& excp ) { - this->error() << "Problem prebooking histograms : Error = '" << excp.message() << "'" << endmsg; - sc = StatusCode::FAILURE; - } - } - } - // return - return sc; -} -//============================================================================= - -template <class PBASE> -StatusCode Rich::Future::HistoBase<PBASE>::prebookHistograms() { - // Default implementation does nothing - return StatusCode::SUCCESS; -} - -//============================================================================= - -namespace { - template <typename MAP, typename ID> - decltype( auto ) findHistoImpl( const MAP& hmap, const ID& id ) { - const auto& map = hmap.getmap( id.packedData() ); - const auto iH = map.find( id.id() ); - if ( iH == map.end() ) { // - throw Rich::Exception( "Cannot find pre-booked histogram '" + id.fullid() + "'" ); - } - return iH->second; - } -} // namespace - -template <class PBASE> -AIDA::IHistogram1D* // -Rich::Future::HistoBase<PBASE>::richHisto1D( const Rich::HistogramID& id ) const { - return findHistoImpl( m_1dhmap, id ); -} - -template <class PBASE> -AIDA::IHistogram2D* // -Rich::Future::HistoBase<PBASE>::richHisto2D( const Rich::HistogramID& id ) const { - return findHistoImpl( m_2dhmap, id ); -} - -template <class PBASE> -AIDA::IProfile1D* // -Rich::Future::HistoBase<PBASE>::richProfile1D( const Rich::HistogramID& id ) const { - return findHistoImpl( m_1dpmap, id ); -} - -template <class PBASE> -AIDA::IProfile2D* // -Rich::Future::HistoBase<PBASE>::richProfile2D( const Rich::HistogramID& id ) const { - return findHistoImpl( m_2dpmap, id ); -} - -//============================================================================= - -namespace { - template <typename HISTO, typename LABEL> - void axisLabelsImpl( HISTO* h, // - const LABEL& xAxisLabel, // - const LABEL& yAxisLabel, // - const LABEL& zAxisLabel = "" ) { - if ( !zAxisLabel.empty() ) { - // Bug in GaudiUtils (to be fixed) with no way to set z axis. Ignore for the moment - //_ri_debug << "Setting Z axis label currently not supported : " << zAxisLabel << endmsg; - } - // set the axis labels - if ( !xAxisLabel.empty() || !yAxisLabel.empty() ) { - if ( !setAxisLabels( h, xAxisLabel, yAxisLabel ) ) { - throw Rich::Exception( "Problem Setting Histogram Axis Labels" ); - } - } - } - template <typename HISTO, typename LABELS> - void binLabelsImpl( HISTO* h, // - const LABELS& binLabels ) { - if ( !binLabels.empty() ) { - if ( !setBinLabels( h, binLabels ) ) { throw Rich::Exception( "Problem Setting Histogram Bin Labels" ); } - } - } - template <typename HISTO, typename LABELS> - void binLabelsImpl( HISTO* h, // - const LABELS& xBinLabels, // - const LABELS& yBinLabels ) { - if ( !xBinLabels.empty() || !yBinLabels.empty() ) { - if ( !setBinLabels( h, xBinLabels, yBinLabels ) ) { - throw Rich::Exception( "Problem Setting Histogram Bin Labels" ); - } - } - } -} // namespace - -template <class PBASE> -AIDA::IHistogram1D* // -Rich::Future::HistoBase<PBASE>::richHisto1D( const Rich::HistogramID& id, // - const std::string& title, // - const double low, // - const double high, // - const unsigned int bins, // - const AxisLabel& xAxisLabel, // - const AxisLabel& yAxisLabel, // - const BinLabels& binLabels ) const { - // Already been booked ? - auto*& h = m_1dhmap.gethist( id ); - if ( !h ) { - // Lock for new histo creation - std::scoped_lock lock( m_mutex1DH ); - // Still missing ? - h = m_1dhmap.gethist( id ); - if ( !h ) { - // Book the histo - h = PBASE::book1D( id.fullid(), id.fullTitle( title ), low, high, bins ); - // set the labels - axisLabelsImpl( h, xAxisLabel, yAxisLabel ); - binLabelsImpl( h, binLabels ); - } - } - // return the histo - return h; -} - -template <class PBASE> -AIDA::IHistogram2D* // -Rich::Future::HistoBase<PBASE>::richHisto2D( const Rich::HistogramID& id, // - const std::string& title, // - const double lowX, // - const double highX, // - const unsigned int binsX, // - const double lowY, // - const double highY, // - const unsigned int binsY, // - const AxisLabel& xAxisLabel, // - const AxisLabel& yAxisLabel, // - const AxisLabel& zAxisLabel, // - const BinLabels& xBinLabels, // - const BinLabels& yBinLabels ) const { - // Already been booked ? - auto*& h = m_2dhmap.gethist( id ); - if ( !h ) { - // Lock for new histo creation - std::scoped_lock lock( m_mutex2DH ); - // still missing ? - h = m_2dhmap.gethist( id ); - if ( !h ) { - // Book the histo - h = PBASE::book2D( id.fullid(), id.fullTitle( title ), lowX, highX, binsX, lowY, highY, binsY ); - // set the labels - axisLabelsImpl( h, xAxisLabel, yAxisLabel, zAxisLabel ); - binLabelsImpl( h, xBinLabels, yBinLabels ); - } - } - // return the histo - return h; -} - -template <class PBASE> -AIDA::IProfile1D* // -Rich::Future::HistoBase<PBASE>::richProfile1D( const Rich::HistogramID& id, // - const std::string& title, // - const double low, // - const double high, // - const unsigned int bins, // - const AxisLabel& xAxisLabel, // - const AxisLabel& yAxisLabel, // - const BinLabels& binLabels ) const { - // Already been booked ? - auto*& h = m_1dpmap.gethist( id ); - if ( !h ) { - // Lock for new histo creation - std::scoped_lock lock( m_mutex1DP ); - // still missing ? - h = m_1dpmap.gethist( id ); - if ( !h ) { - // Book the histo - h = PBASE::bookProfile1D( id.fullid(), id.fullTitle( title ), low, high, bins ); - // set the labels - axisLabelsImpl( h, xAxisLabel, yAxisLabel ); - binLabelsImpl( h, binLabels ); - } - } - // return the histo - return h; -} - -template <class PBASE> -AIDA::IProfile2D* // -Rich::Future::HistoBase<PBASE>::richProfile2D( const Rich::HistogramID& id, // - const std::string& title, // - const double lowX, // - const double highX, // - const unsigned int binsX, // - const double lowY, // - const double highY, // - const unsigned int binsY, // - const AxisLabel& xAxisLabel, // - const AxisLabel& yAxisLabel, // - const AxisLabel& zAxisLabel, // - const BinLabels& xBinLabels, // - const BinLabels& yBinLabels ) const { - // Already been booked ? - auto*& h = m_2dpmap.gethist( id ); - if ( !h ) { - // Lock for new histo creation - std::scoped_lock lock( m_mutex2DP ); - // still missing ? - h = m_2dpmap.gethist( id ); - if ( !h ) { - // Book the histo - h = PBASE::bookProfile2D( id.fullid(), id.fullTitle( title ), lowX, highX, binsX, lowY, highY, binsY ); - // set the labels - axisLabelsImpl( h, xAxisLabel, yAxisLabel, zAxisLabel ); - binLabelsImpl( h, xBinLabels, yBinLabels ); - } - } - // return the histo - return h; -} - -//============================================================================= diff --git a/Rich/RichFutureKernel/src/component/RichBaseTests.cpp b/Rich/RichFutureKernel/src/component/RichBaseTests.cpp new file mode 100644 index 00000000000..833e454731b --- /dev/null +++ b/Rich/RichFutureKernel/src/component/RichBaseTests.cpp @@ -0,0 +1,136 @@ +/*****************************************************************************\ +* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * +* * +* This software is distributed under the terms of the GNU General Public * +* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * +* * +* In applying this licence, CERN does not waive the privileges and immunities * +* granted to it by virtue of its status as an Intergovernmental Organization * +* or submit itself to any jurisdiction. * +\*****************************************************************************/ + +#include "GaudiKernel/RndmGenerators.h" +#include "LHCbAlgs/Consumer.h" +#include "RichFutureKernel/RichHistoAlgBase.h" + +#include <cmath> +#include <cstdint> +#include <type_traits> + +namespace Rich::Future::Tests { + + using namespace Rich::Future::Hist; + + template <typename HIST> + class HistoTestBase final + : public LHCb::Algorithm::Consumer<void(), Gaudi::Functional::Traits::BaseClass_t<HistoAlgBase>> { + public: + HistoTestBase( const std::string& name, ISvcLocator* pSvcLocator ) : Consumer( name, pSvcLocator ) { + setProperty( "HistoPrint", true ).ignore(); + } + auto shoot() const { + using T = param_t<HIST>; + static T var = 0; + if constexpr ( std::is_floating_point_v<T> ) { + return std::remainder( var++, T{100} ); + } else { + return var++ % T{100}; + } + } + void operator()() const override { + std::size_t iFill = 0; + auto h_b = m_h.buffer(); // test buffers + while ( iFill++ < 50 ) { + const auto i = ( iFill % 2 ); + if constexpr ( is_1d_v<HIST> ) { + if constexpr ( is_weighted_v<HIST> ) { + if constexpr ( is_profile_v<HIST> ) { + m_h[i][shoot()] += {shoot(), shoot()}; + h_b[i][shoot()] += {shoot(), shoot()}; + } else if constexpr ( is_hist_v<HIST> ) { + m_h[i][shoot()] += shoot(); + h_b[i][shoot()] += shoot(); + } + } else if constexpr ( is_not_weighted_v<HIST> ) { + if constexpr ( is_profile_v<HIST> ) { + m_h[i][shoot()] += shoot(); + h_b[i][shoot()] += shoot(); + } else if constexpr ( is_hist_v<HIST> ) { + ++m_h[i][shoot()]; + ++h_b[i][shoot()]; + } + } + } else if constexpr ( is_2d_v<HIST> ) { + if constexpr ( is_weighted_v<HIST> ) { + if constexpr ( is_profile_v<HIST> ) { + m_h[i][{shoot(), shoot()}] += {shoot(), shoot()}; + h_b[i][{shoot(), shoot()}] += {shoot(), shoot()}; + } else if constexpr ( is_hist_v<HIST> ) { + m_h[i][{shoot(), shoot()}] += shoot(); + h_b[i][{shoot(), shoot()}] += shoot(); + } + } else if constexpr ( is_not_weighted_v<HIST> ) { + if constexpr ( is_profile_v<HIST> ) { + m_h[i][{shoot(), shoot()}] += shoot(); + h_b[i][{shoot(), shoot()}] += shoot(); + } else if constexpr ( is_hist_v<HIST> ) { + ++m_h[i][{shoot(), shoot()}]; + ++h_b[i][{shoot(), shoot()}]; + } + } + } + } + } + + protected: + StatusCode prebookHistograms() override { + info() << "1D=" << is_1d_v<HIST> << " 2D=" << is_2d_v<HIST> // + << " H=" << is_hist_v<HIST> << " P=" << is_profile_v<HIST> // + << " W=" << is_weighted_v<HIST> << " NW=" << is_not_weighted_v<HIST> << endmsg; + bool ok = true; + if constexpr ( is_1d_v<HIST> ) { + ok &= initHist( m_h[0], HID( "testH1D0" ), "Test 1D Histogram 0", 0, 100, 100, "Rand Number", "Entries" ); + ok &= initHist( m_h[1], HID( "testH1D1" ), "Test 1D Histogram 1", 0, 100, 100, "Rand Number", "Entries" ); + } + if constexpr ( is_2d_v<HIST> ) { + ok &= initHist( m_h[0], HID( "testH2D0" ), "Test 2D Histogram 0", // + 0, 100, 100, 0, 100, 100, "Rand Number", "Rand Number", "Entries" ); + ok &= initHist( m_h[1], HID( "testH2D1" ), "Test 2D Histogram 1", // + 0, 100, 100, 0, 100, 100, "Rand Number", "Rand Number", "Entries" ); + } + return StatusCode{ok}; + } + + private: + /// test array of (optional) hists. + /// Note last entry is intentionally uninitialised to test handling this scenario. + mutable Hist::Array<HIST, 3> m_h; + }; + + DECLARE_COMPONENT_WITH_ID( HistoTestBase<H1D<>>, "RichTestH1DD" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WH1D<>>, "RichTestWH1DD" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<P1D<>>, "RichTestP1DD" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WP1D<>>, "RichTestWP1DD" ) + + DECLARE_COMPONENT_WITH_ID( HistoTestBase<H2D<>>, "RichTestH2DD" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WH2D<>>, "RichTestWH2DD" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<P2D<>>, "RichTestP2DD" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WP2D<>>, "RichTestWP2DD" ) + + DECLARE_COMPONENT_WITH_ID( HistoTestBase<H1D<float>>, "RichTestH1DF" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WH1D<float>>, "RichTestWH1DF" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<P1D<float>>, "RichTestP1DF" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WP1D<float>>, "RichTestWP1DF" ) + + DECLARE_COMPONENT_WITH_ID( HistoTestBase<H2D<float>>, "RichTestH2DF" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WH2D<float>>, "RichTestWH2DF" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<P2D<float>>, "RichTestP2DF" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<WP2D<float>>, "RichTestWP2DF" ) + + DECLARE_COMPONENT_WITH_ID( HistoTestBase<H1D<std::int32_t>>, "RichTestH1DI" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<P1D<std::int32_t>>, "RichTestP1DI" ) + + DECLARE_COMPONENT_WITH_ID( HistoTestBase<H2D<std::int32_t>>, "RichTestH2DI" ) + DECLARE_COMPONENT_WITH_ID( HistoTestBase<P2D<std::int32_t>>, "RichTestP2DI" ) + +} // namespace Rich::Future::Tests diff --git a/Rich/RichFutureKernel/src/RichAlgBase.cpp b/Rich/RichFutureKernel/src/lib/RichAlgBase.cpp similarity index 100% rename from Rich/RichFutureKernel/src/RichAlgBase.cpp rename to Rich/RichFutureKernel/src/lib/RichAlgBase.cpp diff --git a/Rich/RichFutureKernel/src/RichCommonBase.icpp b/Rich/RichFutureKernel/src/lib/RichCommonBase.icpp similarity index 100% rename from Rich/RichFutureKernel/src/RichCommonBase.icpp rename to Rich/RichFutureKernel/src/lib/RichCommonBase.icpp diff --git a/Rich/RichFutureKernel/src/RichHistoAlgBase.cpp b/Rich/RichFutureKernel/src/lib/RichHistoAlgBase.cpp similarity index 94% rename from Rich/RichFutureKernel/src/RichHistoAlgBase.cpp rename to Rich/RichFutureKernel/src/lib/RichHistoAlgBase.cpp index 7439f256d59..937183f5b40 100644 --- a/Rich/RichFutureKernel/src/RichHistoAlgBase.cpp +++ b/Rich/RichFutureKernel/src/lib/RichHistoAlgBase.cpp @@ -24,8 +24,6 @@ // ============================================================================ // Force creation of templated classes -#include "GaudiAlg/GaudiHistos.icpp" -template class GaudiHistos<Rich::Future::Details::BaseAlg>; #include "RichHistoBase.icpp" template class Rich::Future::CommonBase<Rich::Future::Details::HistoBaseAlg>; template class Rich::Future::HistoBase<Rich::Future::Details::HistoBaseAlg>; diff --git a/Rich/RichFutureKernel/src/lib/RichHistoBase.icpp b/Rich/RichFutureKernel/src/lib/RichHistoBase.icpp new file mode 100644 index 00000000000..d4bd4402b4b --- /dev/null +++ b/Rich/RichFutureKernel/src/lib/RichHistoBase.icpp @@ -0,0 +1,61 @@ +/*****************************************************************************\ +* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * +* * +* This software is distributed under the terms of the GNU General Public * +* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * +* * +* In applying this licence, CERN does not waive the privileges and immunities * +* granted to it by virtue of its status as an Intergovernmental Organization * +* or submit itself to any jurisdiction. * +\*****************************************************************************/ + +//----------------------------------------------------------------------------- +/** @file RichHistoBase.icpp + * + * Implementation file for RICH base class : Rich::HistoBase + * + * @author Chris Jones Christopher.Rob.Jones@cern.ch + * @date 2009-07-27 + */ +//----------------------------------------------------------------------------- + +#pragma once + +// local +#include "RichFutureKernel/RichHistoBase.h" + +// Utils +#include "RichUtils/RichException.h" + +// GaudiUtils +#include "GaudiUtils/HistoLabels.h" +using namespace Gaudi::Utils::Histos; + +// Base class methods +#include "RichCommonBase.icpp" + +template <class PBASE> +StatusCode Rich::Future::HistoBase<PBASE>::sysInitialize() { + // run base clase method + auto sc = CommonBase<PBASE>::sysInitialize(); + if ( sc ) { + // as last thing book any histos (only once) + if ( !m_histosAreBooked ) { + try { + sc = prebookHistograms(); + m_histosAreBooked = true; + } catch ( const Rich::Exception& excp ) { + this->error() << "Problem prebooking histograms : Error = '" << excp.message() << "'" << endmsg; + sc = StatusCode::FAILURE; + } + } + } + // return + return sc; +} + +template <class PBASE> +StatusCode Rich::Future::HistoBase<PBASE>::prebookHistograms() { + // Default implementation does nothing + return StatusCode::SUCCESS; +} diff --git a/Rich/RichFutureKernel/src/RichHistoToolBase.cpp b/Rich/RichFutureKernel/src/lib/RichHistoToolBase.cpp similarity index 100% rename from Rich/RichFutureKernel/src/RichHistoToolBase.cpp rename to Rich/RichFutureKernel/src/lib/RichHistoToolBase.cpp diff --git a/Rich/RichFutureKernel/src/RichToolBase.cpp b/Rich/RichFutureKernel/src/lib/RichToolBase.cpp similarity index 100% rename from Rich/RichFutureKernel/src/RichToolBase.cpp rename to Rich/RichFutureKernel/src/lib/RichToolBase.cpp diff --git a/Rich/RichFutureKernel/src/RichTupleAlgBase.cpp b/Rich/RichFutureKernel/src/lib/RichTupleAlgBase.cpp similarity index 100% rename from Rich/RichFutureKernel/src/RichTupleAlgBase.cpp rename to Rich/RichFutureKernel/src/lib/RichTupleAlgBase.cpp diff --git a/Rich/RichFutureKernel/src/RichTupleToolBase.cpp b/Rich/RichFutureKernel/src/lib/RichTupleToolBase.cpp similarity index 100% rename from Rich/RichFutureKernel/src/RichTupleToolBase.cpp rename to Rich/RichFutureKernel/src/lib/RichTupleToolBase.cpp diff --git a/Rich/RichFutureKernel/tests/options/Histograms.py b/Rich/RichFutureKernel/tests/options/Histograms.py new file mode 100644 index 00000000000..7ba7401402d --- /dev/null +++ b/Rich/RichFutureKernel/tests/options/Histograms.py @@ -0,0 +1,62 @@ +##################################################################################### +# (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations # +# # +# This software is distributed under the terms of the Apache version 2 licence, # +# copied verbatim in the file "LICENSE". # +# # +# In applying this licence, CERN does not waive the privileges and immunities # +# granted to it by virtue of its status as an Intergovernmental Organization # +# or submit itself to any jurisdiction. # +##################################################################################### + +from Gaudi.Configuration import * +from Configurables import FPEAuditor +from Configurables import Gaudi__Monitoring__MessageSvcSink as MessageSvcSink +from Configurables import Gaudi__Histograming__Sink__Root as RootHistoSink +from Configurables import RichTestH1DD, RichTestWH1DD, RichTestP1DD, RichTestWP1DD +from Configurables import RichTestH2DD, RichTestWH2DD, RichTestP2DD, RichTestWP2DD +from Configurables import RichTestH1DF, RichTestWH1DF, RichTestP1DF, RichTestWP1DF +from Configurables import RichTestH2DF, RichTestWH2DF, RichTestP2DF, RichTestWP2DF +from Configurables import RichTestH1DI, RichTestP1DI, RichTestH2DI, RichTestP2DI + +# Histo printout should be disabled if either of these is WARNING or above +outLevel = INFO +MessageSvc().OutputLevel = INFO + +algs = [ + # Double + RichTestH1DD(OutputLevel=outLevel), + RichTestWH1DD(OutputLevel=outLevel), + RichTestP1DD(OutputLevel=outLevel), + RichTestWP1DD(OutputLevel=outLevel), + RichTestH2DD(OutputLevel=outLevel), + RichTestWH2DD(OutputLevel=outLevel), + RichTestP2DD(OutputLevel=outLevel), + RichTestWP2DD(OutputLevel=outLevel), + # Float + RichTestH1DF(OutputLevel=outLevel), + RichTestWH1DF(OutputLevel=outLevel), + RichTestP1DF(OutputLevel=outLevel), + RichTestWP1DF(OutputLevel=outLevel), + RichTestH2DF(OutputLevel=outLevel), + RichTestWH2DF(OutputLevel=outLevel), + RichTestP2DF(OutputLevel=outLevel), + RichTestWP2DF(OutputLevel=outLevel), + # Int + RichTestH1DI(OutputLevel=outLevel), + RichTestP1DI(OutputLevel=outLevel), + RichTestH2DI(OutputLevel=outLevel), + RichTestP2DI(OutputLevel=outLevel), +] + +AuditorSvc().Auditors += ["FPEAuditor"] +FPEAuditor().EnableGlobal = True + +app = ApplicationMgr( + EvtMax=1000, + EvtSel="NONE", + HistogramPersistency="ROOT", + TopAlg=algs, + ExtSvc=[AuditorSvc(), MessageSvcSink(), + RootHistoSink()], + AuditAlgorithms=True) diff --git a/Rich/RichFutureKernel/tests/qmtest/histograms.qmt b/Rich/RichFutureKernel/tests/qmtest/histograms.qmt new file mode 100644 index 00000000000..85d8650959c --- /dev/null +++ b/Rich/RichFutureKernel/tests/qmtest/histograms.qmt @@ -0,0 +1,22 @@ +<?xml version="1.0" ?><!DOCTYPE extension PUBLIC '-//QM/2.3/Extension//EN' 'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'> +<!-- + (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations + + This software is distributed under the terms of the Apache version 2 licence, + copied verbatim in the file "LICENSE". + + In applying this licence, CERN does not waive the privileges and immunities + granted to it by virtue of its status as an Intergovernmental Organization + or submit itself to any jurisdiction. +--> +<extension class="GaudiTest.GaudiExeTest" kind="test"> +<argument name="program"><text>gaudirun.py</text></argument> +<argument name="args"><set><text>$RICHFUTUREKERNELROOT/tests/options/Histograms.py</text></set></argument> +<argument name="use_temp_dir"><enumeral>true</enumeral></argument> +<argument name="reference"><text>../refs/histograms.ref</text></argument> +<argument name="error_reference"><text>../refs/empty.ref</text></argument> +<argument name="validator"><text> +from GaudiConf.QMTest.LHCbExclusions import preprocessor +validateWithReference(preproc = preprocessor) +</text></argument> +</extension> diff --git a/Rich/RichFutureKernel/tests/refs/empty.ref b/Rich/RichFutureKernel/tests/refs/empty.ref new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Rich/RichFutureKernel/tests/refs/histograms.ref b/Rich/RichFutureKernel/tests/refs/histograms.ref new file mode 100644 index 00000000000..46daadf5c27 --- /dev/null +++ b/Rich/RichFutureKernel/tests/refs/histograms.ref @@ -0,0 +1,113 @@ +ApplicationMgr SUCCESS +==================================================================================================================================== +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +RichTestH1DD INFO 1D=1 2D=0 H=1 P=0 W=0 NW=1 +RichTestWH1DD INFO 1D=1 2D=0 H=1 P=0 W=1 NW=0 +RichTestP1DD INFO 1D=1 2D=0 H=0 P=1 W=0 NW=1 +RichTestWP1DD INFO 1D=1 2D=0 H=0 P=1 W=1 NW=0 +RichTestH2DD INFO 1D=0 2D=1 H=1 P=0 W=0 NW=1 +RichTestWH2DD INFO 1D=0 2D=1 H=1 P=0 W=1 NW=0 +RichTestP2DD INFO 1D=0 2D=1 H=0 P=1 W=0 NW=1 +RichTestWP2DD INFO 1D=0 2D=1 H=0 P=1 W=1 NW=0 +RichTestH1DF INFO 1D=1 2D=0 H=1 P=0 W=0 NW=1 +RichTestWH1DF INFO 1D=1 2D=0 H=1 P=0 W=1 NW=0 +RichTestP1DF INFO 1D=1 2D=0 H=0 P=1 W=0 NW=1 +RichTestWP1DF INFO 1D=1 2D=0 H=0 P=1 W=1 NW=0 +RichTestH2DF INFO 1D=0 2D=1 H=1 P=0 W=0 NW=1 +RichTestWH2DF INFO 1D=0 2D=1 H=1 P=0 W=1 NW=0 +RichTestP2DF INFO 1D=0 2D=1 H=0 P=1 W=0 NW=1 +RichTestWP2DF INFO 1D=0 2D=1 H=0 P=1 W=1 NW=0 +RichTestH1DI INFO 1D=1 2D=0 H=1 P=0 W=0 NW=1 +RichTestP1DI INFO 1D=1 2D=0 H=0 P=1 W=0 NW=1 +RichTestH2DI INFO 1D=0 2D=1 H=1 P=0 W=0 NW=1 +RichTestP2DI INFO 1D=0 2D=1 H=0 P=1 W=0 NW=1 +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramPersis... INFO Added successfully Conversion service RootHistSvc +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr INFO Application Manager Started successfully +RichTestH1DD INFO Booked 2 Histogram(s) : 1D=2 2D=0 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestH1DD INFO 1D histograms in directory "RichTestH1DD" : 2 +RichTestH1DF INFO Booked 2 Histogram(s) : 1D=2 2D=0 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestH1DF INFO 1D histograms in directory "RichTestH1DF" : 2 +RichTestH1DI INFO Booked 2 Histogram(s) : 1D=2 2D=0 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestH1DI INFO 1D histograms in directory "RichTestH1DI" : 2 +RichTestH2DD INFO Booked 2 Histogram(s) : 1D=0 2D=2 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestH2DD INFO 2D histograms in directory "RichTestH2DD" : 2 +RichTestH2DF INFO Booked 2 Histogram(s) : 1D=0 2D=2 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestH2DF INFO 2D histograms in directory "RichTestH2DF" : 2 +RichTestH2DI INFO Booked 2 Histogram(s) : 1D=0 2D=2 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestH2DI INFO 2D histograms in directory "RichTestH2DI" : 2 +RichTestP1DD INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=2 2DProf=0 3DProf=0 +RichTestP1DD INFO 1D profile histograms in directory "RichTestP1DD" : 2 +RichTestP1DF INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=2 2DProf=0 3DProf=0 +RichTestP1DF INFO 1D profile histograms in directory "RichTestP1DF" : 2 +RichTestP1DI INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=2 2DProf=0 3DProf=0 +RichTestP1DI INFO 1D profile histograms in directory "RichTestP1DI" : 2 +RichTestP2DD INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=0 2DProf=2 3DProf=0 +RichTestP2DD INFO 2D profile histograms in directory "RichTestP2DD" : 2 +RichTestP2DF INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=0 2DProf=2 3DProf=0 +RichTestP2DF INFO 2D profile histograms in directory "RichTestP2DF" : 2 +RichTestP2DI INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=0 2DProf=2 3DProf=0 +RichTestP2DI INFO 2D profile histograms in directory "RichTestP2DI" : 2 +RichTestWH1DD INFO Booked 2 Histogram(s) : 1D=2 2D=0 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestWH1DD INFO 1D histograms in directory "RichTestWH1DD" : 2 +RichTestWH1DF INFO Booked 2 Histogram(s) : 1D=2 2D=0 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestWH1DF INFO 1D histograms in directory "RichTestWH1DF" : 2 +RichTestWH2DD INFO Booked 2 Histogram(s) : 1D=0 2D=2 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestWH2DD INFO 2D histograms in directory "RichTestWH2DD" : 2 +RichTestWH2DF INFO Booked 2 Histogram(s) : 1D=0 2D=2 3D=0 1DProf=0 2DProf=0 3DProf=0 +RichTestWH2DF INFO 2D histograms in directory "RichTestWH2DF" : 2 +RichTestWP1DD INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=2 2DProf=0 3DProf=0 +RichTestWP1DD INFO 1D profile histograms in directory "RichTestWP1DD" : 2 +RichTestWP1DF INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=2 2DProf=0 3DProf=0 +RichTestWP1DF INFO 1D profile histograms in directory "RichTestWP1DF" : 2 +RichTestWP2DD INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=0 2DProf=2 3DProf=0 +RichTestWP2DD INFO 2D profile histograms in directory "RichTestWP2DD" : 2 +RichTestWP2DF INFO Booked 2 Histogram(s) : 1D=0 2D=0 3D=0 1DProf=0 2DProf=2 3DProf=0 +RichTestWP2DF INFO 2D profile histograms in directory "RichTestWP2DF" : 2 +ApplicationMgr INFO Application Manager Stopped successfully +EventLoopMgr INFO Histograms converted successfully according to request. +ApplicationMgr INFO Application Manager Finalized successfully +ApplicationMgr INFO Application Manager Terminated successfully +RichTestH1DD INFO 1D histograms in directory "RichTestH1DD" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestH1DD/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 25.52 | 14.143 | 0.0091834 | -1.1995 | + | /RICH/RichTestH1DD/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 25 | 14.975 | 0 | -1.2116 | +RichTestH1DF INFO 1D histograms in directory "RichTestH1DF" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestH1DF/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 25.52 | 14.143 | 0.0091834 | -1.1995 | + | /RICH/RichTestH1DF/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 25 | 14.975 | 0 | -1.2116 | +RichTestH1DI INFO 1D histograms in directory "RichTestH1DI" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestH1DI/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 51 | 28.849 | 0 | -1.2031 | + | /RICH/RichTestH1DI/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 49 | 28.849 | 0 | -1.2031 | +RichTestWH1DD INFO 1D histograms in directory "RichTestWH1DD" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestWH1DD/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 34.167 | 11.528 | -0.56675 | -0.60602 | + | /RICH/RichTestWH1DD/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 34.167 | 11.528 | -0.56675 | -0.60602 | +RichTestWH1DF INFO 1D histograms in directory "RichTestWH1DF" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestWH1DF/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 34.167 | 11.528 | -0.56675 | -0.60602 | + | /RICH/RichTestWH1DF/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 34.167 | 11.528 | -0.56675 | -0.60602 | +RichTestP1DD INFO 1D profile histograms in directory "RichTestP1DD" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestP1DD/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 25000 | 24.5 | 14.422 | 0 | -1.2038 | + | /RICH/RichTestP1DD/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 25000 | 24.5 | 14.422 | 0 | -1.2038 | +RichTestP1DF INFO 1D profile histograms in directory "RichTestP1DF" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestP1DF/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 25000 | 24.5 | 14.422 | 6.5108e-07 | -1.2039 | + | /RICH/RichTestP1DF/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 25000 | 24.5 | 14.422 | 6.5108e-07 | -1.2039 | +RichTestP1DI INFO 1D profile histograms in directory "RichTestP1DI" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestP1DI/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 50.5 | 28.862 | 0 | -1.201 | + | /RICH/RichTestP1DI/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 50.5 | 28.862 | 0 | -1.201 | +RichTestWP1DD INFO 1D profile histograms in directory "RichTestWP1DD" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestWP1DD/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 0.50456 | 0.41173 | 96.152 | 9617.8 | + | /RICH/RichTestWP1DD/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 34.539 | 11.674 | -0.55601 | -0.61011 | +RichTestWP1DF INFO 1D profile histograms in directory "RichTestWP1DF" : 2 + | ID | Title | # | Mean | RMS | Skewness | Kurtosis | + | /RICH/RichTestWP1DF/testH1D0 | "Test 1D Histogram 0;Rand Number;Entries" | 50000 | 0.50456 | 0.41173 | 96.152 | 9617.8 | + | /RICH/RichTestWP1DF/testH1D1 | "Test 1D Histogram 1;Rand Number;Entries" | 50000 | 34.539 | 11.674 | -0.55601 | -0.61011 | -- GitLab