diff --git a/Plume/PlumeReco/CMakeLists.txt b/Plume/PlumeReco/CMakeLists.txt index 9c755fddd4cc8a2cf770ca606a8460a3ba32ae01..03b06c445f0c4d4bdff57cc67e582c6649a61cef 100644 --- a/Plume/PlumeReco/CMakeLists.txt +++ b/Plume/PlumeReco/CMakeLists.txt @@ -19,6 +19,7 @@ gaudi_add_module(PlumeReco src/PlumeRawToDigits.cpp src/PlumeDigitMonitor.cpp src/PlumeTAEMonitor.cpp + src/PlumeLEDMonitor.cpp src/PlumeTuple.cpp LINK diff --git a/Plume/PlumeReco/src/PlumeDigitMonitor.cpp b/Plume/PlumeReco/src/PlumeDigitMonitor.cpp index acbf5db56370e30a1f83d35d07d008fd93ad8d04..8f492a934d295eb229ea45aa6d181a82334ebdca 100644 --- a/Plume/PlumeReco/src/PlumeDigitMonitor.cpp +++ b/Plume/PlumeReco/src/PlumeDigitMonitor.cpp @@ -86,7 +86,6 @@ public: private: Gaudi::Property m_timing_threshold{ "TimingThreshold", 9.5 }; - // DeCalorimeter* m_calo = nullptr; bool overThreshold( LHCb::PlumeAdc const& adc ) const { return ( adc.channelID().channelType() != ChannelID::ChannelType::TIME ) ? adc.overThreshold() @@ -103,8 +102,6 @@ private: std::unique_ptr m_fit_function_tf1; Gaudi::Property m_threshold_sshape{ this, "ThresholdSShape", 100.5 }; - mutable std::mutex m_lazy_lock; - mutable Gaudi::Accumulators::Histogram<1> m_over_thld_time{ this, "over_threshold_time", "#events OT per channel: TIME", axis1D{ 64, -0.5, 63.5 } }; @@ -112,10 +109,6 @@ private: AxisADC }; mutable Gaudi::Accumulators::Histogram<2> m_bcid_adc_time{ this, "bcid_adc_time", "BCID vs ADC time", AxisBCID, axis1D{ 256, -256, 4096 - 256 } }; - mutable Gaudi::Accumulators::Histogram<2> m_bcid_adc_pin{ this, "bcid_adc_pin", "BCID vs ADC pin", AxisBCID, - axis1D{ 256, -256, 4096 - 256 } }; - mutable Gaudi::Accumulators::Histogram<2> m_bcid_adc_mon{ this, "bcid_adc_mon", "BCID vs ADC mon", AxisBCID, - axis1D{ 256, -256, 4096 - 256 } }; mutable Gaudi::Accumulators::Histogram<2> m_bcid_adc_lumi_coarse{ this, "bcid_adc_coarse", "BCID vs ADC (LUMI)", AxisBCID, axis1D{ 410 + 26, -260, 4100 } }; @@ -192,9 +185,6 @@ private: // (in MONET, "freeze" references for all of the above and compare with current histos) mutable Gaudi::Accumulators::Histogram<1> m_calibType{ this, "odin_calib_type", "ODIN CalibrationType", { 16, -0.5, 15.5 } }; - // ADC histogram per channel type and BX type (only for calib triggers) - mutable std::map> m_mon_bx_adc; - mutable std::map> m_pin_bx_adc; // For physics monitoring // ADC histogram per channel type and BX type (excluding calib triggers) @@ -203,15 +193,12 @@ private: // ADC histogram for every channel per BB/EB/BE/EE (excluding calib triggers) mutable std::map, Gaudi::Accumulators::Histogram<1>> m_channel_bx_adc; - // ADC histogram for every channel per BB/EB/BE/EE (only calib triggers) - mutable std::map, Gaudi::Accumulators::Histogram<1>> m_channel_bx_adc_calib; // ADC vs BCID (TProfile1) for every channel mutable std::map> m_channel_bcid_adc; // Timing data mutable Gaudi::Accumulators::Histogram<1> m_time_adc{ this, "adc_TIME", "ADC for all timing channels", AxisADC }; - mutable std::map> m_channel_time; mutable unsigned long int m_runStartGps = 0; mutable unsigned int m_lastRun = 0; @@ -246,31 +233,24 @@ StatusCode PlumeDigitMonitor::initialize() { } for ( const auto& ch : channels ) { - if ( ch.channelType() != ChannelID::ChannelType::TIME_T ) { + const auto type = ch.channelType(); + if ( type != ChannelID::ChannelType::TIME_T && type != ChannelID::ChannelType::MON && + type != ChannelID::ChannelType::PIN ) { map_emplace( m_channel_bcid_adc, ch, this, "bcid_adc_" + ch.toString(), "ADC vs BCID for " + ch.toString(), AxisBCID ); } for ( auto bx : { BXTypes::NoBeam, BXTypes::Beam1, BXTypes::Beam2, BXTypes::BeamCrossing } ) { - map_emplace( m_channel_bx_adc, std::make_pair( ch, bx ), this, "adc_" + ch.toString() + "_" + to_string( bx ), - "ADC for " + ch.toString() + "/" + to_string( bx ), AxisADC ); - if ( ch.channelType() == ChannelID::ChannelType::LUMI && bx == BXTypes::NoBeam ) { - map_emplace( m_channel_bx_adc_calib, std::make_pair( ch, bx ), this, - "adc_" + ch.toString() + "_" + to_string( bx ) + "_calib_signals", - "ADC for " + ch.toString() + "/" + to_string( bx ) + "/calib signals", AxisADC ); + if ( type != ChannelID::ChannelType::MON && type != ChannelID::ChannelType::PIN ) { + map_emplace( m_channel_bx_adc, std::make_pair( ch, bx ), this, "adc_" + ch.toString() + "_" + to_string( bx ), + "ADC for " + ch.toString() + "/" + to_string( bx ), AxisADC ); } } - if ( ch.channelType() == ChannelID::ChannelType::TIME_T ) { - map_emplace( m_channel_time, ch, this, "time_" + ch.toString(), "Time for " + ch.toString(), - { 4096, 0, 4096 } ); - } } for ( auto bx : { BXTypes::NoBeam, BXTypes::Beam1, BXTypes::Beam2, BXTypes::BeamCrossing } ) { map_emplace( m_lumi_bx_adc, bx, this, "adc_LUMI_" + to_string( bx ), "ADC for LUMI/" + to_string( bx ), AxisADC ); map_emplace( m_time_bx_adc, bx, this, "adc_TIME_" + to_string( bx ), "ADC for TIME/" + to_string( bx ), AxisADC ); - map_emplace( m_mon_bx_adc, bx, this, "adc_MON_" + to_string( bx ), "ADC for MON/" + to_string( bx ), AxisADC ); - map_emplace( m_pin_bx_adc, bx, this, "adc_PIN_" + to_string( bx ), "ADC for PIN/" + to_string( bx ), AxisADC ); } for ( auto tchannel : { 5, 11, 29, 35 } ) { @@ -302,8 +282,6 @@ StatusCode PlumeDigitMonitor::initialize() { // ============================================================================ void PlumeDigitMonitor::operator()( const Input& adcs, const LHCb::ODIN& odin ) const { - // TODO: remove lock after migrating to new histograms - std::lock_guard guard_lock( m_lazy_lock ); if ( odin.runNumber() > m_lastRun ) { m_lastRun = odin.runNumber(); @@ -337,16 +315,11 @@ void PlumeDigitMonitor::monitor( const Input& adcs, const LHCb::ODIN& odin ) con const auto over_thld = overThreshold( *digit ); const auto key = std::make_pair( digit->channelID(), odin.bunchCrossingType() ); - m_channel_bcid_adc.at( digit->channelID() )[bcid] += adc; // Profile ADC vs BXID for each channel - - if ( calibType == 0 && type == ChannelType::LUMI ) { // lumi PMT, without requiring coincidence - ++m_channel_bx_adc.at( key )[adc]; - } else if ( calibType != 0 && type == ChannelType::LUMI && - bx == BXTypes::NoBeam ) { // lumi PMT, without requiring coincidence, but with the LED signals - ++m_channel_bx_adc_calib.at( key )[adc]; - } else if ( calibType == 0 && type == ChannelType::TIME ) { // timing PMT requires coincidence - ++m_channel_bx_adc.at( key )[adc]; + if ( calibType == 0 && type != ChannelID::ChannelType::MON && type != ChannelID::ChannelType::PIN ) { + m_channel_bcid_adc.at( digit->channelID() )[bcid] += adc; // Profile ADC vs BXID for each channel + ++m_channel_bx_adc.at( key )[adc]; // ADC distribution for each channel and bunch crossing type } + if ( type == ChannelType::TIME && channel_sub_id == 0 ) { if ( sshape_status.at( channel_id ) == true ) { ++m_time_channel.at( channel_id )[{ bcid, sshape_result.at( channel_id )[3].first }]; @@ -359,29 +332,11 @@ void PlumeDigitMonitor::monitor( const Input& adcs, const LHCb::ODIN& odin ) con ++m_sshape_amp_tot.at( channel_id )[sshape_result.at( channel_id )[1].first]; ++m_sshape_amp_err_tot.at( channel_id )[sshape_result.at( channel_id )[1].second]; } - } else if ( type == ChannelType::PIN || type == ChannelType::MON ) { - ++m_channel_bx_adc.at( key )[adc]; - } - - switch ( type ) { - case ChannelType::LUMI: - if ( calibType == 0 ) ++m_lumi_bx_adc.at( bx )[adc]; - break; - case ChannelType::TIME: - if ( calibType == 0 ) ++m_time_bx_adc.at( bx )[adc]; - break; - case ChannelType::PIN: - ++m_pin_bx_adc.at( bx )[adc]; - break; - case ChannelType::MON: - ++m_mon_bx_adc.at( bx )[adc]; - break; - default: - break; } switch ( type ) { case ChannelID::ChannelType::LUMI: { + ++m_lumi_bx_adc.at( bx )[adc]; // ADC distribution for each bunch crossing type, summed over all LUMI channels ++m_bcid_adc_lumi[{ bcid, adc }]; ++m_bcid_adc_lumi_coarse[{ bcid, adc }]; @@ -452,18 +407,11 @@ void PlumeDigitMonitor::monitor( const Input& adcs, const LHCb::ODIN& odin ) con } case ChannelID::ChannelType::TIME: + ++m_time_bx_adc.at( bx )[adc]; // ADC distribution for each bunch crossing type, summed over all TIME channels ++m_time_adc[adc]; if ( over_thld ) ++m_over_thld_time[channel_id]; ++m_bcid_adc_time[{ bcid, adc }]; break; - case ChannelID::ChannelType::PIN: - ++m_bcid_adc_pin[{ bcid, adc }]; - break; - case ChannelID::ChannelType::MON: - ++m_bcid_adc_mon[{ bcid, adc }]; - break; - case ChannelID::ChannelType::TIME_T: - ++m_channel_time.at( digit->channelID() )[digit->adc()]; default: break; } diff --git a/Plume/PlumeReco/src/PlumeLEDMonitor.cpp b/Plume/PlumeReco/src/PlumeLEDMonitor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77e2069dcfbc85d8a56b42d9cff678ffcc3f703e --- /dev/null +++ b/Plume/PlumeReco/src/PlumeLEDMonitor.cpp @@ -0,0 +1,120 @@ +/*****************************************************************************\ +* (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. * +\*****************************************************************************/ + +// Event +#include "Event/ODIN.h" +#include "Event/PlumeAdc.h" + +// Gaudi +#include "Gaudi/Accumulators/Histogram.h" +#include "LHCbAlgs/Consumer.h" + +#include + +using LHCb::Detector::Plume::ChannelID; +using Input = LHCb::PlumeAdcs; +using BXTypes = LHCb::ODIN::BXTypes; + +namespace { + template + using axis1D = Gaudi::Accumulators::Axis; + + template + void map_emplace( T& t, K&& key, OWNER* owner, std::string const& name, std::string const& title, + Gaudi::Accumulators::Axis axis1 ) { + t.emplace( std::piecewise_construct, std::forward_as_tuple( key ), + std::forward_as_tuple( owner, name, title, axis1 ) ); + } + template + std::string to_string( const T& streamable ) { + std::ostringstream oss; + oss << streamable; + return oss.str(); + } + + const auto AxisADC = axis1D( 1024 + 256, -256, 1024 ); +} // namespace + +class PlumeLEDMonitor final : public LHCb::Algorithm::Consumer { +public: + // Standart constructor + PlumeLEDMonitor( const std::string& name, ISvcLocator* pSvcLocator ) + : Consumer( name, pSvcLocator, { KeyValue{ "Input", "" }, KeyValue{ "ODIN", "" } } ){}; + + StatusCode initialize() override; + void operator()( const Input&, const LHCb::ODIN& odin ) const override; + +private: + void monitor( const Input& digits, const LHCb::ODIN& odin ) const; + + mutable Gaudi::Accumulators::Histogram<1> m_calibType{ + this, "odin_calib_type", "ODIN CalibrationType", { 16, -0.5, 15.5 } }; + + // ADC histogram for every channel (LUMI/PIN/...) only for calibration trigger (light) + mutable std::map> m_channel_adc_calib; +}; + +// ============================================================================= + +DECLARE_COMPONENT( PlumeLEDMonitor ) + +// ============================================================================= +// standard initialize method +// ============================================================================= + +StatusCode PlumeLEDMonitor::initialize() { + return Consumer::initialize().andThen( [&] { + // FIXME we should loop over the fiber-channel maps (once they're in the DB) in order to + // generate the full list of possible ChannelIDs. This would avoid hardcoding ranges here. + + std::vector channels; + for ( int i = 0; i < LHCb::Plume::nLumiPMTsPerBank * 2 + LHCb::Plume::nTimingPMTs; ++i ) { + channels.emplace_back( ChannelID::ChannelType::LUMI, i ); + } // this needs to be up to 48, because the indexing afterwards is done with the PMT index, that gets up to 47 + // (because the timing PMTs have a numbering mixed with the lumi PMTs and there are four of them) + for ( int i = 1; i <= LHCb::Plume::nPINChannels + 1; ++i ) { + channels.emplace_back( ChannelID::ChannelType::PIN, i ); + } // loops over PIN numbers, that are defined between 1 and 9 + for ( int i = 1; i <= LHCb::Plume::nMonitoringPMTs; ++i ) { + channels.emplace_back( ChannelID::ChannelType::MON, i ); + } // loops over Monitoring PMT numbers, that are defined between 1 and 4 + for ( int i : { 5, 29, 11, 35 } ) { + for ( int j = 0; j <= 15; ++j ) channels.emplace_back( ChannelID::ChannelType::TIME, i, j ); + } + + for ( const auto& ch : channels ) { + + map_emplace( m_channel_adc_calib, ch, this, "adc_" + ch.toString(), "ADC for " + ch.toString(), AxisADC ); + } + } ); +} + +// ============================================================================ +// standard execution method +// ============================================================================ + +void PlumeLEDMonitor::operator()( const Input& adcs, const LHCb::ODIN& odin ) const { monitor( adcs, odin ); } + +// ============================================================================ +// Fill histograms +// ============================================================================ +void PlumeLEDMonitor::monitor( const Input& adcs, const LHCb::ODIN& odin ) const { + auto calibType = odin.calibrationType(); + auto bx = odin.bunchCrossingType(); + + if ( calibType != 0 && bx == BXTypes::NoBeam ) { + ++m_calibType[calibType]; + for ( const auto& digit : adcs ) { + const auto adc = digit->adc(); + ++m_channel_adc_calib.at( digit->channelID() )[adc]; + } + } +} diff --git a/Plume/PlumeReco/src/PlumeTAEMonitor.cpp b/Plume/PlumeReco/src/PlumeTAEMonitor.cpp index d5ea2bbadcee265e5268c2a51fc759df0dcfc366..f10396acdc1a1fbf8521209fad0325c15b20856e 100644 --- a/Plume/PlumeReco/src/PlumeTAEMonitor.cpp +++ b/Plume/PlumeReco/src/PlumeTAEMonitor.cpp @@ -1,4 +1,4 @@ -/*****************************************************************************\ +/***************************************************************************** \ * (c) Copyright 2000-2024 CERN for the benefit of the LHCb Collaboration * * * * This software is distributed under the terms of the GNU General Public * @@ -19,7 +19,7 @@ #include "LHCbAlgs/MergingTransformer.h" namespace { - const auto axisADC = Gaudi::Accumulators::Axis( ( 4096 + 256 ) / 16, -256 / 16, 4096 / 16 ); + const auto axisADC = Gaudi::Accumulators::Axis( ( 1024 + 256 ), -256, 1024 ); } using LHCb::Detector::Plume::ChannelID; @@ -41,6 +41,11 @@ private: mutable Gaudi::Accumulators::Histogram<2> m_tae_adc{ this, "tae_adc", "ADC counts in lumi channels vs TAE offset", LHCb::TAE::defaultAxis, axisADC }; + mutable Gaudi::Accumulators::ProfileHistogram<1> m_profile_adc_tae{ + this, "tae_adc_profile", "average of ADC counts in lumi channels vs TAE offset", LHCb::TAE::defaultAxis }; + mutable Gaudi::Accumulators::ProfileHistogram<1> m_profile_adc_tae_zs{ + this, "tae_adc_profile_zs", "average of ADC counts in lumi channels vs TAE offset (zero suppressed)", + LHCb::TAE::defaultAxis }; }; DECLARE_COMPONENT( PlumeTAEMonitor ) @@ -59,9 +64,15 @@ void PlumeTAEMonitor::operator()( ODINVector const& odinVector, InputVector cons for ( const auto& digit : input ) { const auto adc = digit->adc(); const auto type = digit->channelID().channelType(); + if ( offset == 0 || odin.bunchCrossingType() == LHCb::ODIN::BXTypes::NoBeam ) { // one histogram that mixes together all channels and all TAE types (INDIVs and "fake TAEs") - if ( type == ChannelID::ChannelType::LUMI ) { ++m_tae_adc[{ offset, adc }]; } + if ( type == ChannelID::ChannelType::LUMI ) { + ++m_tae_adc[{ offset, adc }]; + m_profile_adc_tae[offset] += adc; + + if ( adc > 50 || offset != 0 ) { m_profile_adc_tae_zs[offset] += adc; } + } } } } diff --git a/Plume/PlumeReco/tests/options/plume_decoding.py b/Plume/PlumeReco/tests/options/plume_decoding.py index 552bedff7e4ecf106694ad1d5c4c3f2303509e5e..ecb3609ada4b15faedd3a91ff8e6c396b507726f 100644 --- a/Plume/PlumeReco/tests/options/plume_decoding.py +++ b/Plume/PlumeReco/tests/options/plume_decoding.py @@ -14,6 +14,7 @@ from Gaudi.Configuration import DEBUG, VERBOSE from PRConfig.TestFileDB import test_file_db from PyConf.Algorithms import ( PlumeDigitMonitor, + PlumeLEDMonitor, PlumeRawToDigits, PlumeTuple, PrintHeader, @@ -40,14 +41,13 @@ options = test_file_db["2024_raw_hlt1_290683"].make_lbexec_options( configure_input(options) # must call this before calling default_raw_event odin = make_odin() -digits = PlumeRawToDigits( - OutputLevel=DEBUG, RawBankLocation=default_raw_banks("Plume") -).Output +digits = PlumeRawToDigits(RawBankLocation=default_raw_banks("Plume")).Output monitor = PlumeDigitMonitor(Input=digits, ODIN=odin) plume_tuple = PlumeTuple(Input=digits, ODIN=odin) print_event = PrintHeader(ODINLocation=odin) +led = PlumeLEDMonitor(Input=digits, ODIN=odin) -top_node = CompositeNode("Top", [print_event, monitor, plume_tuple]) +top_node = CompositeNode("Top", [print_event, monitor, plume_tuple, led]) configure(options, top_node) from Configurables import LHCb__DetDesc__ReserveDetDescForEvent as reserveIOV