From b3d524da6a9b43eb26b6b731e6a0c7b81e31402b Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Thu, 2 Oct 2025 16:00:37 +0200 Subject: [PATCH 1/2] Major step towards making Boole algorithms functional This is not the end of it, but in this step, all Boole algorithms still modifying the RawEvent (actually only HCDigitCreator) are changed so that they actually create their own RawEvent, hidden for the others and output a View on the interesting RawBanks. The different views are then be used to build the final RawEvent in the configuration. --- Digi/Boole/python/Boole/Configuration.py | 257 ++++++---- Digi/Boole/tests/pytest/test_run3_trackers.py | 4 +- .../pytest/test_run3_trackers_and_ecal.py | 3 +- HC/HCDigitisation/src/HCDigitCreator.cpp | 456 ++++++++++-------- HC/HCDigitisation/src/HCDigitCreator.h | 92 ---- .../python/RichDigiSys/Configuration.py | 17 +- .../src/MCRichDigitsToRawBufferAlg.cpp | 128 ++--- 7 files changed, 469 insertions(+), 488 deletions(-) delete mode 100755 HC/HCDigitisation/src/HCDigitCreator.h diff --git a/Digi/Boole/python/Boole/Configuration.py b/Digi/Boole/python/Boole/Configuration.py index 6ce2a8e4a..cf1fa9605 100755 --- a/Digi/Boole/python/Boole/Configuration.py +++ b/Digi/Boole/python/Boole/Configuration.py @@ -19,6 +19,8 @@ from functools import cached_property import GaudiKernel.ProcessJobOptions from Configurables import ( ApplicationMgr, + BooleInit, + CombineRawBankViewsToRawEvent, DigiConf, EventSelector, GaudiSequencer, @@ -26,6 +28,7 @@ from Configurables import ( LHCb__UnpackRawEvent, LHCbApp, LHCbConfigurableUser, + ODINEncoder, OutputStream, ProcessPhase, RecordStream, @@ -204,10 +207,10 @@ class Boole(LHCbConfigurableUser): if self.getProp("TAENext") > 0 or self.getProp("TAEPrev") > 0: tae = True - self.enableTAE() + taeViews = self.enableTAE() else: tae = False - + taeViews = [] detListInit = [] detListDigi = [] detListLink = [] @@ -252,13 +255,17 @@ class Boole(LHCbConfigurableUser): if not (det in detListLink) and (det in detListMoni): detListLink += [det] + # add a fake detector "Combine" to host the gathering of Rawbanks created by the + # different Digi sub sequences. This has to come last + detListDigi.append("Combine") + initDets = self._setupPhase("Init", detListInit) digiDets = self._setupPhase("Digi", detListDigi) linkDets = self._setupPhase("Link", detListLink) moniDets = self._setupPhase("Moni", detListMoni) - self.configureInit(tae, initDets) - self.configureDigi(digiDets) + odinViews = self.configureInit(tae, initDets) + self.configureDigi(digiDets, [odinViews] + taeViews) self.configureLink(linkDets, moniDets) self.configureMoni(moniDets) self.configureFilter() @@ -275,7 +282,13 @@ class Boole(LHCbConfigurableUser): 0, "Boole" ) # Always run Boole initialisation first! initBoole = GaudiSequencer("InitBooleSeq") - initBoole.Members += ["BooleInit"] + booleInitAlg = BooleInit() + odinEncoder = ODINEncoder( + ODINLocation="DAQ/ODIN", + OdinRawEventLocation="DAQ/ODINEvent", + OdinBankViewLocation="DAQ/ODIN/View", + ) + initBoole.Members += [booleInitAlg, odinEncoder] if UseDD4Hep: from Configurables import LHCb__Det__LbDD4hep__IOVProducer as IOVProducer @@ -301,7 +314,7 @@ class Boole(LHCbConfigurableUser): level = self.getProp("OutputLevel") if level == ERROR or level == WARNING: # Additional information to be kept - getConfigurable("BooleInit").OutputLevel = INFO + booleInitAlg.OutputLevel = INFO # Do not print event number at every event (done already by BooleInit) EventSelector().PrintFreq = -1 @@ -356,65 +369,66 @@ class Boole(LHCbConfigurableUser): initMuonSeq.Members.append(MBG.makeLowEnergyBG(bg_suffix)) if not tae: initMuonSeq.Members.append(MBG.makeFlatSpilloverBG(bg_suffix)) + return odinEncoder.OdinBankViewLocation - def configureDigi(self, digiDets): + def configureDigi(self, digiDets, taeViews): """ Set up the digitization sequence """ importOptions("$STDOPTS/PreloadUnits.opts") # needed by VELO and ST + allViews = taeViews if "VP" in digiDets: - self.configureDigiVP(GaudiSequencer("DigiVPSeq"), "") + allViews += self.configureDigiVP(GaudiSequencer("DigiVPSeq"), "") if "UT" in digiDets: - self.configureDigiUT(GaudiSequencer("DigiUTSeq"), "") + allViews.append(self.configureDigiUT(GaudiSequencer("DigiUTSeq"), "")) if "FT" in digiDets: - self.configureDigiFT(GaudiSequencer("DigiFTSeq"), "") + allViews.append(self.configureDigiFT(GaudiSequencer("DigiFTSeq"), "")) if "Rich" in digiDets: self.configureDigiRich(GaudiSequencer("DigiRichSeq"), "") if "Calo" in digiDets: - self.configureDigiCalo(GaudiSequencer("DigiCaloSeq"), "") + allViews += self.configureDigiCalo(GaudiSequencer("DigiCaloSeq"), "") if "Muon" in digiDets: - self.configureDigiMuon(GaudiSequencer("DigiMuonSeq"), "") + allViews.append(self.configureDigiMuon(GaudiSequencer("DigiMuonSeq"), "")) if "HC" in digiDets: - self.configureDigiHC(GaudiSequencer("DigiHCSeq"), "") + allViews.append(self.configureDigiHC(GaudiSequencer("DigiHCSeq"), "")) + GaudiSequencer("DigiCombineSeq").Members.append( + CombineRawBankViewsToRawEvent( + RawBankViews=[dh.path() for dh in allViews], RawEvent="DAQ/RawEvent" + ) + ) def configureDigiVP(self, seq, tae): # VP digitisation and clustering if tae == "": from Configurables import VPDepositCreator, VPDigitCreator, VPEnsureBanks - seq.Members += [VPEnsureBanks(), VPDepositCreator(), VPDigitCreator()] + digitCreator = VPDigitCreator() + seq.Members += [VPEnsureBanks(), VPDepositCreator(), digitCreator] from Configurables import VPSuperPixelBankEncoder - superPixelEncoder = VPSuperPixelBankEncoder() + superPixelEncoder = VPSuperPixelBankEncoder( + DigitLocation=digitCreator.OutputLocation, + RawEventLocation="DAQ/VPRawEvent", + ViewLocation="DAQ/VP/View", + ) seq.Members += [superPixelEncoder] + allBanks = [superPixelEncoder.ViewLocation] if self.getProp("RetinaCluster"): from Configurables import RawEventSimpleCombiner, VPRetinaClusterCreator - unpacker = LHCb__UnpackRawEvent( - RawEventLocation="VeloSP/RawEvent", - RawBankLocations=["VeloSP/RawBanks"], - BankTypes=["VP"], - ) clusterCreator = VPRetinaClusterCreator( - RawBanks=unpacker.RawBankLocations[0], - RetinaRawBanks="VPRetina/RawBanks", - ) - superPixelEncoder.RawEventLocation = unpacker.RawEventLocation.path() - - Combiner = RawEventSimpleCombiner( - EnableIncrementalMode=True, - RawBanksToCopy=["VPRetinaCluster"], - InputRawEventLocations=[ - clusterCreator.RetinaClusterLocation.path() - ], + RawBanks=superPixelEncoder.ViewLocation, + RetinaClusterLocation="DAQ/RetinaRawEvent", + RetinaRawBanks="DAQ/Retina/View", ) if self.getProp("PreserveSP"): # want both the SuperPixel banks and Retina clusters in the output - Combiner.RawBanksToCopy += ["VP"] - Combiner.InputRawEventLocations += [ - unpacker.RawEventLocation.path() - ] - seq.Members += [unpacker, clusterCreator, Combiner] + allBanks.append(clusterCreator.RetinaRawBanks) + else: + # want only Retina clusters in the output + allBanks = [clusterCreator.RetinaRawBanks] + seq.Members += [clusterCreator] + return allBanks else: raise RuntimeError("TAE not implemented for VP") @@ -433,17 +447,17 @@ class Boole(LHCbConfigurableUser): toolName = "SiDepositedCharge" if self.getProp("SiG4EnergyDeposit"): toolName = "SiGeantDepositedCharge" - depCreator = MCUTDepositCreator() - depCreator.DepChargeTool = toolName - depCreator.ApplyScaling = False - seq.Members += [depCreator] - seq.Members += [MCUTDigitCreator()] - digitCreator = UTDigitCreator() - digitCreator.Saturation = 31 - digitCreator.simulatePedestal = True - digitCreator.addCommonMode = True - seq.Members += [digitCreator] - seq.Members += [UTDigitsToRawBankAlg()] + depCreator = MCUTDepositCreator(DepChargeTool=toolName, ApplyScaling=False) + digitCreator = UTDigitCreator( + Saturation=31, simulatePedestal=True, addCommonMode=True + ) + digitToRB = UTDigitsToRawBankAlg( + digitLocation=digitCreator.OutputLocation, + rawLocation="DAQ/UTDigitEvent", + ViewLocation="DAQ/UTDigit/View", + ) + seq.Members += [depCreator, MCUTDigitCreator(), digitCreator, digitToRB] + return digitToRB.ViewLocation else: raise RuntimeError("TAE not implemented for UT") @@ -459,22 +473,27 @@ class Boole(LHCbConfigurableUser): MCFTDigitCreator, ) - unpacker = LHCb__UnpackRawEvent( - "UnpackRawEvent", - BankTypes=["FTCluster"], - RawEventLocation="/Event/DAQ/RawEvent", - RawBankLocations=["/Event/DAQ/RawBanks/FTCluster"], + spillMerger = FTMCHitSpillMerger() + depositCreator = MCFTDepositCreator( + InputLocation=spillMerger.OutputLocation ) - + digitCreator = MCFTDigitCreator(InputLocation=depositCreator.OutputLocation) + clusterCreator = FTClusterCreator(InputLocation=digitCreator.OutputLocation) + encoder = FTRawBankEncoder( + rawLocation="DAQ/FTEvent", + viewLocation="DAQ/FT/View", + InputLocation=clusterCreator.OutputLocation, + ) + decoder = FTRawBankDecoder(RawBanks=encoder.viewLocation) seq.Members += [ - FTMCHitSpillMerger(), - MCFTDepositCreator(), - MCFTDigitCreator(), - FTClusterCreator(), - FTRawBankEncoder(), - unpacker, - FTRawBankDecoder(), + spillMerger, + depositCreator, + digitCreator, + clusterCreator, + encoder, + decoder, ] + return encoder.viewLocation else: raise RuntimeError("TAE not implemented for SCIFI") @@ -482,10 +501,10 @@ class Boole(LHCbConfigurableUser): if tae == "": from Configurables import RichDigiSysConf - self.setOtherProp(RichDigiSysConf(), "UseSpillover") - self.setOtherProp(RichDigiSysConf(), "DataType") - RichDigiSysConf().Sequencer = GaudiSequencer("DigiRichSeq") - + config = RichDigiSysConf(Sequencer=GaudiSequencer("DigiRichSeq")) + self.setOtherProp(config, "UseSpillover") + self.setOtherProp(config, "DataType") + return config.configure() else: raise RuntimeError("TAE not implemented for RICH") @@ -498,43 +517,75 @@ class Boole(LHCbConfigurableUser): CaloSignalAlg, ) + ecalSignal = CaloSignalAlg(f"EcalSignal{tae}", IsTAE=bool(tae)) + hcalSignal = CaloSignalAlg(f"HcalSignal{tae}", IsTAE=bool(tae)) + ecalDigits = CaloDigitAlgEcal(f"EcalDigit{tae}") + hcalDigits = CaloDigitAlgHcal(f"HcalDigit{tae}") + ecalDet = ( + "/world/DownstreamRegion/Ecal:DetElement-Info-IOV" + if UseDD4Hep + else "/dd/Structure/LHCb/DownstreamRegion/Ecal" + ) + hcalDet = ( + "/world/DownstreamRegion/Hcal:DetElement-Info-IOV" + if UseDD4Hep + else "/dd/Structure/LHCb/DownstreamRegion/Hcal" + ) + ecalEncoder = CaloFutureFillRawBuffer( + "EcalFillRawBuffer" + tae, + InputBank=ecalDigits.OutputData, + DetectorLocation=ecalDet, + RawEventLocation="DAQ/EcalEvent", + ViewLocation="DAQ/Ecal/View", + OptViewLocation="DAQ/Ecal/OptView", + DataCodingType=5, + ) # 4 for BigEndian, 5 for LittleEndian + hcalEncoder = CaloFutureFillRawBuffer( + "HcalFillRawBuffer" + tae, + InputBank=hcalDigits.OutputData, + DetectorLocation=hcalDet, + RawEventLocation="DAQ/HcalEvent", + ViewLocation="DAQ/Hcal/View", + OptViewLocation="DAQ/Hcal/OptView", + DataCodingType=5, + ) # 4 for BigEndian, 5 for LittleEndian seq.Members += [ - CaloSignalAlg(f"EcalSignal{tae}", IsTAE=bool(tae)), - CaloSignalAlg(f"HcalSignal{tae}", IsTAE=bool(tae)), + ecalSignal, + hcalSignal, + ecalDigits, + hcalDigits, + ecalEncoder, + hcalEncoder, ] - - seq.Members += [ - CaloDigitAlgEcal(f"EcalDigit{tae}"), - CaloDigitAlgHcal(f"HcalDigit{tae}"), + return [ + ecalEncoder.ViewLocation, + hcalEncoder.ViewLocation, + ecalEncoder.OptViewLocation, + hcalEncoder.OptViewLocation, ] - for cal in ["Ecal", "Hcal"]: - det = ( - "/world/DownstreamRegion/" + cal + ":DetElement-Info-IOV" - if UseDD4Hep - else "/dd/Structure/LHCb/DownstreamRegion/" + cal - ) - - encoder = CaloFutureFillRawBuffer( - cal + "FillRawBuffer" + tae, - InputBank="Raw/" + cal + "/FullAdcs", - DetectorLocation=det, - DataCodingType=5, - ) # 4 for BigEndian, 5 for LittleEndian - seq.Members += [encoder] - def configureDigiMuon(self, seq, tae): from Configurables import MuonDigitization, MuonDigitToTell40RawBuffer - seq.Members += [MuonDigitization(f"MuonDigitization{tae}")] - seq.Members += [MuonDigitToTell40RawBuffer(f"MuonDigitToTell40RawBuffer{tae}")] + muonDigits = MuonDigitization(f"MuonDigitization{tae}") + muonBuffer = MuonDigitToTell40RawBuffer( + f"MuonDigitToTell40RawBuffer{tae}", + RawEventLocation="DAQ/MuonEvent", + ViewLocation="DAQ/Muon/View", + ) + seq.Members += [muonDigits, muonBuffer] + return muonBuffer.ViewLocation def configureDigiHC(self, seq, tae): # HC digitisation if tae == "": from Configurables import HCDigitCreator - seq.Members += [HCDigitCreator()] + hcCreator = HCDigitCreator( + RawEventLocation="DAQ/HCEvent", ViewLocation="DAQ/HC/View" + ) + seq.Members += [hcCreator] + return hcCreator.ViewLocaiton else: raise RuntimeError("TAE not implemented for HC") @@ -689,29 +740,43 @@ class Boole(LHCbConfigurableUser): taeNext -= 1 GaudiSequencer("BooleSequencer").Members = mainSeq + allViews = [] for taeSlot in taeSlots: taePhase = ProcessPhase(f"Digi{taeSlot}") taeDets = self.getProp("TAESubdets") - taePhase.DetectorList = ["Init"] + taeDets + taePhase.DetectorList = ["Init"] + taeDets + ["Combine"] from Configurables import BooleInit slotInit = BooleInit(f"Init{taeSlot}", RootInTES=f"{taeSlot}/") GaudiSequencer(f"Digi{taeSlot}InitSeq").Members = [slotInit] if "VP" in taeDets: - self.configureDigiVP(GaudiSequencer(f"Digi{taeSlot}VPSeq"), taeSlot) + allViews.append( + self.configureDigiVP(GaudiSequencer(f"Digi{taeSlot}VPSeq"), taeSlot) + ) if "UT" in taeDets: - self.configureDigiUT( - GaudiSequencer(f"Digi{taeSlot}UTSeq"), "UT", taeSlot + allViews.append( + self.configureDigiUT( + GaudiSequencer(f"Digi{taeSlot}UTSeq"), "UT", taeSlot + ) ) if "Rich" in taeDets: self.configureDigiRich(GaudiSequencer(f"Digi{taeSlot}RichSeq"), taeSlot) if "Calo" in taeDets: - self.configureDigiCalo(GaudiSequencer(f"Digi{taeSlot}CaloSeq"), taeSlot) + allViews += self.configureDigiCalo( + GaudiSequencer(f"Digi{taeSlot}CaloSeq"), taeSlot + ) if "Muon" in taeDets: - self.configureDigiMuon(GaudiSequencer(f"Digi{taeSlot}MuonSeq"), taeSlot) + allViews.append( + self.configureDigiMuon( + GaudiSequencer(f"Digi{taeSlot}MuonSeq"), taeSlot + ) + ) if "HC" in taeDets: - self.configureDigiHC(GaudiSequencer(f"Digi{taeSlot}HCSeq"), taeSlot) + allViews.append( + self.configureDigiHC(GaudiSequencer(f"Digi{taeSlot}HCSeq"), taeSlot) + ) + return allViews def defineMonitors(self): # get all defined monitors @@ -978,7 +1043,7 @@ class Boole(LHCbConfigurableUser): GaudiSequencer("MoniVPSeq").Members += [ VPDepositMonitor(), - VPRetinaFullClusterDecoder(RawBanks="VPRetina/RawBanks"), + VPRetinaFullClusterDecoder(RawBanks="DAQ/Retina/View"), VPClusterEffSimDQ(), ] diff --git a/Digi/Boole/tests/pytest/test_run3_trackers.py b/Digi/Boole/tests/pytest/test_run3_trackers.py index 19a584641..02009533d 100644 --- a/Digi/Boole/tests/pytest/test_run3_trackers.py +++ b/Digi/Boole/tests/pytest/test_run3_trackers.py @@ -20,4 +20,6 @@ class Test(LHCbExeTest): ] def test_stdout(self, stdout: bytes): - find_sequence(stdout.decode(), ["DigiVPSeq", "DigiUTSeq", "DigiFTSeq"]) + find_sequence( + stdout.decode(), ["DigiVPSeq", "DigiUTSeq", "DigiFTSeq", "DigiCombineSeq"] + ) diff --git a/Digi/Boole/tests/pytest/test_run3_trackers_and_ecal.py b/Digi/Boole/tests/pytest/test_run3_trackers_and_ecal.py index 5ef185b3d..2b75eab7c 100644 --- a/Digi/Boole/tests/pytest/test_run3_trackers_and_ecal.py +++ b/Digi/Boole/tests/pytest/test_run3_trackers_and_ecal.py @@ -21,5 +21,6 @@ class Test(LHCbExeTest): def test_stdout(self, stdout: bytes): find_sequence( - stdout.decode(), ["DigiVPSeq", "DigiUTSeq", "DigiFTSeq", "DigiEcalSeq"] + stdout.decode(), + ["DigiVPSeq", "DigiUTSeq", "DigiFTSeq", "DigiEcalSeq", "DigiCombineSeq"], ) diff --git a/HC/HCDigitisation/src/HCDigitCreator.cpp b/HC/HCDigitisation/src/HCDigitCreator.cpp index eb4b869db..ce9336307 100644 --- a/HC/HCDigitisation/src/HCDigitCreator.cpp +++ b/HC/HCDigitisation/src/HCDigitCreator.cpp @@ -1,120 +1,244 @@ /*****************************************************************************\ -* (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. * + * (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. * \*****************************************************************************/ -// Gaudi -#include "GaudiKernel/PhysicalConstants.h" - -// LHCb -// Event/MCEvent -#include "Event/MCHit.h" -// Event/DAQEvent -#include "Event/GenCollision.h" -#include "Event/RawEvent.h" - -// Local -#include "HCDigitCreator.h" - -DECLARE_COMPONENT( HCDigitCreator ) - -//============================================================================= -// Constructor -//============================================================================= -HCDigitCreator::HCDigitCreator( const std::string& name, ISvcLocator* pSvcLocator ) - : GaudiTupleAlg( name, pSvcLocator ) { - - declareProperty( "HitLocation", m_hitLocation = LHCb::MCHitLocation::HC ); - declareProperty( "RawEventLocation", m_rawEventLocation = LHCb::RawEventLocation::Default ); - - declareProperty( "CrateB", m_crateB = 0 ); - declareProperty( "CrateF", m_crateF = 1 ); - - declareProperty( "ChannelsB0", m_channelsB0 ); - declareProperty( "ChannelsB1", m_channelsB1 ); - declareProperty( "ChannelsB2", m_channelsB2 ); - declareProperty( "ChannelsF1", m_channelsF1 ); - declareProperty( "ChannelsF2", m_channelsF2 ); - - declareProperty( "ZPositionsB", m_zB = { -7500., -19700., -114000. } ); - declareProperty( "ZPositionsF", m_zF = { 20000., 114000. } ); - - declareProperty( "PhotonsPerMeV", m_photonsPerMeV = 8000. ); - declareProperty( "CollectionEfficiency", m_collectionEfficiency = 0.025 ); - declareProperty( "QuantumEfficiency", m_quantumEfficiency = 0.25 ); - declareProperty( "Gain", m_gain = 1.e3 ); - declareProperty( "ElectronsPerADC", m_electronsPerADC = 5000. ); - declareProperty( "MaxADC", m_maxADC = 1023 ); - declareProperty( "Threshold", m_threshold = 2 ); - - declareProperty( "Monitoring", m_monitoring = false ); -} -//============================================================================= -// Destructor -//============================================================================= -HCDigitCreator::~HCDigitCreator() {} - -//============================================================================= -// Initialisation -//============================================================================= -StatusCode HCDigitCreator::initialize() { - - StatusCode sc = GaudiTupleAlg::initialize(); - if ( sc.isFailure() ) return sc; - - // Initialize the random number generators. - sc = m_gauss.initialize( randSvc(), Rndm::Gauss( 0., 1. ) ); - if ( sc.isFailure() ) { return Error( "Cannot initialize Gaussian random number generator.", sc ); } - sc = m_uniform.initialize( randSvc(), Rndm::Flat( 0., 1. ) ); - if ( sc.isFailure() ) { return Error( "Cannot initialize uniform random number generator.", sc ); } - // Set up the channel maps. - mapChannels( m_channelsB0, 0, true ); - mapChannels( m_channelsB1, 1, true ); - mapChannels( m_channelsB2, 2, true ); - mapChannels( m_channelsF1, 1, false ); - mapChannels( m_channelsF2, 2, false ); - - // Compute the conversion factor between energy deposit and photo electrons. - m_pePerMeV = m_photonsPerMeV * m_collectionEfficiency * m_quantumEfficiency; - setHistoTopDir( "HC/" ); - return StatusCode::SUCCESS; -} +#include +#include +#include + +#include + +#include +#include +#include +#include -//========================================================================= -// Main execution -//========================================================================= -StatusCode HCDigitCreator::execute() { - - // Pick up the MC hits. - const LHCb::MCHits* hits = getIfExists( m_hitLocation ); - if ( !hits ) { return Error( "No hits in " + m_hitLocation ); } - - // Check if the raw event exists. - LHCb::RawEvent* rawEvent = getIfExists( m_rawEventLocation ); - if ( !rawEvent ) { - // Create the raw event. - rawEvent = new LHCb::RawEvent(); - put( rawEvent, m_rawEventLocation ); +namespace { + + /// Raw bank encoding (PRS/SPD format) + void encode( const unsigned int card, const std::vector& adcs, std::vector& words, + unsigned int threshold ) { + // Add the header word. + const unsigned int headerIndex = words.size(); + words.push_back( card << 14 ); + unsigned int lenAdc = 0; + unsigned int lenTrig = 0; + // Add the trigger words. + const unsigned int nChannels = adcs.size(); + int offset = 0; + unsigned int word = 0; + for ( unsigned int i = 0; i < nChannels; ++i ) { + int mask = 0; + if ( adcs[i] > threshold ) mask |= 0x40; + // if (spd) mask |= 0x80; + if ( 0 == mask ) continue; + mask |= i; + mask = mask << offset; + word |= mask; + offset += 8; + if ( 32 == offset ) { + words.push_back( word ); + word = 0; + offset = 0; + } + ++lenTrig; + } + if ( 0 != word ) { + words.push_back( word ); + word = 0; + } + // Add the ADC words. + for ( unsigned int i = 0; i < nChannels; ++i ) { + if ( adcs[i] == 0 ) continue; + const unsigned int adc = ( adcs[i] & 0x3FF ) | ( i << 10 ); + if ( 0 == word ) { + word = adc; + } else { + word |= ( adc << 16 ); + words.push_back( word ); + word = 0; + } + ++lenAdc; + } + if ( 0 != word ) { + words.push_back( word ); + word = 0; + } + // Add the lengths of trigger and ADC parts to the header. + words[headerIndex] |= ( lenAdc << 7 ) + lenTrig; } +} // namespace + +namespace LHCb { + + /** + * This algorithm simulates the detector and front-end response + * of the Herschel forward shower counters and writes out raw banks. + */ + class HCDigitCreator + : public Algorithm::MultiTransformer( MCHits const&, GenCollisions const& ), + Algorithm::Traits::writeOnly> { + + public: + HCDigitCreator( const std::string& name, ISvcLocator* pSvcLocator ); + StatusCode initialize() override; + std::tuple operator()( MCHits const&, GenCollisions const& ) const override; + + private: + Gaudi::Property m_crateB{ this, "CrateB", 0, "Number of B-side crate" }; + Gaudi::Property m_crateF{ this, "CrateF", 1, "Number of F-side crate" }; + + Gaudi::Property> m_channelsB0{ this, "ChannelsB0", {}, "Channel mappings" }; + Gaudi::Property> m_channelsB1{ this, "ChannelsB1", {}, "Channel mappings" }; + Gaudi::Property> m_channelsB2{ this, "ChannelsB2", {}, "Channel mappings" }; + Gaudi::Property> m_channelsF1{ this, "ChannelsF1", {}, "Channel mappings" }; + Gaudi::Property> m_channelsF2{ this, "ChannelsF2", {}, "Channel mappings" }; + + /// Channel numbers for each quadrant + std::vector> m_channels; + + Gaudi::Property> m_zB{ + this, "ZPositionsB", { -7500., -19700., -114000. }, "Nominal z-positions of the backward stations" }; + Gaudi::Property> m_zF{ + this, "ZPositionsF", { 20000., 114000. }, "Nominal z-positions of the forward stations" }; + + Gaudi::Property m_photonsPerMeV{ this, "PhotonsPerMeV", 8000., + "Number of photons per MeV of deposited energy" }; + Gaudi::Property m_collectionEfficiency{ this, "CollectionEfficiency", 0.025, + "Average fraction of collected photons" }; + Gaudi::Property m_quantumEfficiency{ this, "QuantumEfficiency", 0.25, "Quantum efficiency" }; + Gaudi::Property m_gain{ this, "Gain", 1.e3, "PMT gain" }; + Gaudi::Property m_electronsPerADC{ this, "ElectronsPerADC", 5000., "ADC conversion factor" }; + Gaudi::Property m_maxADC{ this, "MaxADC", 1023, "Max. number of ADC counts" }; + Gaudi::Property m_threshold{ this, "Threshold", 2, "Trigger threshold in ADC counts" }; + + /// Overall conversion factor between deposited energy and photo electrons + double m_pePerMeV; + + Gaudi::Property m_monitoring{ this, "Monitoring", false, "Flag to activate monitoring histograms or not" }; + + /// Generator for Gaussian random variates + Rndm::Numbers m_gauss; + /// Generator for uniform random variates + Rndm::Numbers m_uniform; + + mutable Gaudi::Accumulators::BinomialCounter<> m_hardQCDCounter{ this, "HardScat" }; + mutable Gaudi::Accumulators::BinomialCounter<> m_elasticCounter{ this, "HardScat" }; + mutable Gaudi::Accumulators::BinomialCounter<> m_SDCounter{ this, "SD" }; + mutable Gaudi::Accumulators::BinomialCounter<> m_DDCounter{ this, "DD" }; + + mutable Gaudi::Accumulators::HistogramArray, 3> m_edepBHisto{ + this, + []( int n ) { return fmt::format( "HC/Edep/B{}", n ); }, + []( int ) { return "Deposited energy [MeV]"; }, + { 50, 0., 10. } }; + mutable Gaudi::Accumulators::HistogramArray, 2> m_edepFHisto{ + this, + []( int n ) { return fmt::format( "HC/Edep/F{}", n + 1 ); }, + []( int ) { return "Deposited energy [MeV]"; }, + { 50, 0., 10. } }; - const LHCb::GenCollisions* collisions = getIfExists( LHCb::GenCollisionLocation::Default ); - if ( !collisions ) { return Error( "Cannot retrieve collisions" ); } - for ( LHCb::GenCollisions::const_iterator it = collisions->begin(); it != collisions->end(); ++it ) { + mutable Gaudi::Accumulators::HistogramArray, 3> m_momentumBHisto{ + this, + []( int n ) { return fmt::format( "HC/Momentum/B{}", n ); }, + []( int ) { return "Momentum [MeV/c]"; }, + { 100, 0., 200. } }; + mutable Gaudi::Accumulators::HistogramArray, 2> m_momentumFHisto{ + this, + []( int n ) { return fmt::format( "HC/Momentum/F{}", n + 1 ); }, + []( int ) { return "Momentum [MeV/c]"; }, + { 100, 0., 200. } }; + + mutable Gaudi::Accumulators::HistogramArray, 3> m_etaPTBHisto{ + this, + []( int n ) { return fmt::format( "HC/EtaPTB{}", n ); }, + []( int ) { return "Pseudorapidity vs. pT"; }, + { 50, 0., 5000. }, + { 50, 0., 11. } }; + mutable Gaudi::Accumulators::HistogramArray, 2> m_etaPTFHisto{ + this, + []( int n ) { return fmt::format( "HC/EtaPTF{}", n + 1 ); }, + []( int ) { return "Pseudorapidity vs. pT"; }, + { 50, 0., 5000. }, + { 50, 0., 11. } }; + + mutable Gaudi::Accumulators::HistogramArray, 3> m_etaBHisto{ + this, + []( int n ) { return fmt::format( "HC/EtaB{}", n ); }, + []( int ) { return "Pseudorapidity"; }, + { 50, -11., 11. } }; + mutable Gaudi::Accumulators::HistogramArray, 2> m_etaFHisto{ + this, + []( int n ) { return fmt::format( "HC/EtaF{}", n + 1 ); }, + []( int ) { return "Pseudorapidity"; }, + { 50, -11., 11. } }; + + mutable Gaudi::Accumulators::HistogramArray, 5> m_sumHisto{ + this, + []( int i ) { + return fmt::format( "HC/Sum{}", i < 3 ? "B" + std::to_string( i ) : "F" + std::to_string( i - 2 ) ); + }, + []( int i ) { + return fmt::format( "HC/Sum{}", i < 3 ? "B" + std::to_string( i ) : "F" + std::to_string( i - 2 ) ); + }, + { 50, 0., 2.5e5 } }; + + /// Set up the channel map for one station. + bool mapChannels( const std::vector& channels, const unsigned int station, const bool bwd ); + }; + + DECLARE_COMPONENT_WITH_ID( HCDigitCreator, "HCDigitCreator" ) + +} // namespace LHCb + +LHCb::HCDigitCreator::HCDigitCreator( const std::string& name, ISvcLocator* pSvcLocator ) + : MultiTransformer( name, pSvcLocator, + { KeyValue{ "HitLocation", MCHitLocation::HC }, + KeyValue{ "GenCollisionLocation", GenCollisionLocation::Default } }, + { KeyValue{ "RawEventLocation", "" }, KeyValue{ "ViewLocation", "" } } ) {} + +StatusCode LHCb::HCDigitCreator::initialize() { + return MultiTransformer::initialize().andThen( [&]() -> StatusCode { + // Initialize the random number generators. + StatusCode sc = m_gauss.initialize( randSvc(), Rndm::Gauss( 0., 1. ) ); + if ( sc.isFailure() ) { + throw GaudiException( "HCDigitCreator", "Cannot initialize Gaussian random number generator.", sc ); + } + sc = m_uniform.initialize( randSvc(), Rndm::Flat( 0., 1. ) ); + if ( sc.isFailure() ) { + throw GaudiException( "HCDigitCreator", "Cannot initialize uniform random number generator.", sc ); + } + // Set up the channel maps. + mapChannels( m_channelsB0, 0, true ); + mapChannels( m_channelsB1, 1, true ); + mapChannels( m_channelsB2, 2, true ); + mapChannels( m_channelsF1, 1, false ); + mapChannels( m_channelsF2, 2, false ); + + // Compute the conversion factor between energy deposit and photo electrons. + m_pePerMeV = m_photonsPerMeV * m_collectionEfficiency * m_quantumEfficiency; + return StatusCode::SUCCESS; + } ); +} + +std::tuple +LHCb::HCDigitCreator::operator()( LHCb::MCHits const& hits, LHCb::GenCollisions const& collisions ) const { + + RawEvent rawEvent; + + for ( GenCollisions::const_iterator it = collisions.begin(); it != collisions.end(); ++it ) { const unsigned int collisionType = ( *it )->processType(); - const bool hardQCD = ( collisionType >= 110 ); - const bool iselastic = ( collisionType == 102 ); - const bool issd = ( collisionType == 103 || collisionType == 104 ); - const bool isdd = ( collisionType == 105 ); - counter( "HardScat" ) += hardQCD; - counter( "Elastic" ) += iselastic; - counter( "SD" ) += issd; - counter( "DD" ) += isdd; + m_hardQCDCounter += ( collisionType >= 110 ); + m_elasticCounter += ( collisionType == 102 ); + m_SDCounter += ( collisionType == 103 || collisionType == 104 ); + m_DDCounter += ( collisionType == 105 ); } // Loop over the hits and sum up the signals in each quadrant. constexpr unsigned int nChannelsPerBoard = 64; @@ -123,14 +247,14 @@ StatusCode HCDigitCreator::execute() { const unsigned int nStationsB = 3; const unsigned int nStationsF = 2; std::vector sumSignals( nStationsB + nStationsF, 0. ); - for ( const LHCb::MCHit* hit : *hits ) { + for ( const MCHit* hit : hits ) { // Determine the station number. const double z = hit->midPoint().z(); unsigned int station = 999; if ( z > 0. ) { // Forward stations (Muon side) for ( unsigned int i = 0; i < nStationsF; ++i ) { - const double dz = z - m_zF[i]; + const double dz = z - m_zF.value()[i]; if ( fabs( dz ) < 20. ) { station = i + 1; break; @@ -139,7 +263,7 @@ StatusCode HCDigitCreator::execute() { } else { // Backward stations (VELO side) for ( unsigned int i = 0; i < nStationsB; ++i ) { - const double dz = z - m_zB[i]; + const double dz = z - m_zB.value()[i]; if ( fabs( dz ) < 20. ) { station = i; break; @@ -171,40 +295,34 @@ StatusCode HCDigitCreator::execute() { signalsB[channel] += signal; sumSignals[station] += signal; } - if ( !m_monitoring ) continue; + if ( !m_monitoring.value() ) continue; // Get the particle which produced this hit. - const LHCb::MCParticle* particle = hit->mcParticle(); + const MCParticle* particle = hit->mcParticle(); if ( !particle ) continue; const double p = particle->p() / Gaudi::Units::MeV; const std::string st = std::to_string( station ); // Retrieve the mother particle. - const LHCb::MCParticle* mother = particle; - while ( mother->originVertex() && mother->originVertex()->type() != LHCb::MCVertex::MCVertexType::ppCollision ) { + const MCParticle* mother = particle; + while ( mother->originVertex() && mother->originVertex()->type() != MCVertex::MCVertexType::ppCollision ) { mother = mother->originVertex()->mother(); } if ( !mother ) continue; const double pt = mother->pt() / Gaudi::Units::MeV; const double pseudoRapidity = mother->pseudoRapidity(); if ( z > 0. ) { - plot( edep, "Edep/F" + st, "Deposited energy [MeV]", 0., 10., 50 ); - plot( p, "Momentum/F" + st, "Momentum [MeV/c]", 0., 200., 100 ); - plot2D( pt, fabs( pseudoRapidity ), "EtaPTF" + st, "Pseudorapidity vs. pT", 0., 5000., 0., 11., 50, 50, edep ); - plot( pseudoRapidity, "EtaF" + st, "Pseudorapidity", -11., 11., 50, edep ); + ++m_edepFHisto[station - 1][edep]; + ++m_momentumFHisto[station - 1][p]; + m_etaPTFHisto[station - 1][{ pt, fabs( pseudoRapidity ) }] += edep; + m_etaFHisto[station - 1][pseudoRapidity] += edep; } else { - plot( edep, "Edep/B" + st, "Deposited energy [MeV]", 0., 10., 50 ); - plot( p, "Momentum/B" + st, "Momentum [MeV/c]", 0., 200., 100 ); - plot2D( pt, fabs( pseudoRapidity ), "EtaPTB" + st, "Pseudorapidity vs. pT", 0., 5000., 0., 11., 50, 50, edep ); - plot( pseudoRapidity, "EtaB" + st, "Pseudorapidity", -11., 11., 50, edep ); + ++m_edepBHisto[station][edep]; + ++m_momentumBHisto[station][p]; + m_etaPTBHisto[station][{ pt, fabs( pseudoRapidity ) }] += edep; + m_etaBHisto[station][pseudoRapidity] += edep; } } - if ( m_monitoring ) { - for ( unsigned int i = 0; i < 5; ++i ) { - const double low = 0.; - const double high = 2.5e5; - const unsigned int bins = 50; - const std::string st1 = i < 3 ? "B" + std::to_string( i ) : "F" + std::to_string( i - 2 ); - plot( sumSignals[i], "Sum" + st1, low, high, bins ); - } + if ( m_monitoring.value() ) { + for ( unsigned int i = 0; i < 5; ++i ) { ++m_sumHisto[i][sumSignals[i]]; } } // Convert the signals to ADC counts. std::vector adcsB( nChannelsPerBoard, 0 ); @@ -223,75 +341,19 @@ StatusCode HCDigitCreator::execute() { } // Encode the data. std::vector words; - encode( m_crateB, adcsB, words ); - encode( m_crateF, adcsF, words ); + encode( m_crateB, adcsB, words, m_threshold ); + encode( m_crateF, adcsF, words, m_threshold ); // Add a new raw bank and pass memory ownership to the raw event. const unsigned int version = 2; - rawEvent->addBank( 0, LHCb::RawBank::BankType::HC, version, words ); - return StatusCode::SUCCESS; -} + rawEvent.addBank( 0, RawBank::HC, version, words ); -//========================================================================= -// Raw bank encoding (PRS/SPD format) -//========================================================================= -void HCDigitCreator::encode( const unsigned int card, const std::vector& adcs, - std::vector& words ) { - - // Add the header word. - const unsigned int headerIndex = words.size(); - words.push_back( card << 14 ); - unsigned int lenAdc = 0; - unsigned int lenTrig = 0; - // Add the trigger words. - const unsigned int nChannels = adcs.size(); - int offset = 0; - unsigned int word = 0; - for ( unsigned int i = 0; i < nChannels; ++i ) { - int mask = 0; - if ( adcs[i] > m_threshold ) mask |= 0x40; - // if (spd) mask |= 0x80; - if ( 0 == mask ) continue; - mask |= i; - mask = mask << offset; - word |= mask; - offset += 8; - if ( 32 == offset ) { - words.push_back( word ); - word = 0; - offset = 0; - } - ++lenTrig; - } - if ( 0 != word ) { - words.push_back( word ); - word = 0; - } - // Add the ADC words. - for ( unsigned int i = 0; i < nChannels; ++i ) { - if ( adcs[i] == 0 ) continue; - const unsigned int adc = ( adcs[i] & 0x3FF ) | ( i << 10 ); - if ( 0 == word ) { - word = adc; - } else { - word |= ( adc << 16 ); - words.push_back( word ); - word = 0; - } - ++lenAdc; - } - if ( 0 != word ) { - words.push_back( word ); - word = 0; - } - // Add the lengths of trigger and ADC parts to the header. - words[headerIndex] |= ( lenAdc << 7 ) + lenTrig; + auto view = rawEvent.banks( RawBank::HC ); + // without std::move here the RawEvent gets copied which would invalidate the view + // View creation must be after RawEvent is made + return { std::move( rawEvent ), std::move( view ) }; } -//========================================================================= -// Set up the channel map. -//========================================================================= -bool HCDigitCreator::mapChannels( const std::vector& channels, const unsigned int station, const bool bwd ) { - +bool LHCb::HCDigitCreator::mapChannels( const std::vector& channels, const unsigned int station, const bool bwd ) { const unsigned int offset = bwd ? 0 : 2; // Check if the input is valid. if ( channels.size() != 4 ) { diff --git a/HC/HCDigitisation/src/HCDigitCreator.h b/HC/HCDigitisation/src/HCDigitCreator.h deleted file mode 100755 index 1d533630c..000000000 --- a/HC/HCDigitisation/src/HCDigitCreator.h +++ /dev/null @@ -1,92 +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. * -\*****************************************************************************/ -#ifndef HCDIGITCREATOR_H -#define HCDIGITCREATOR_H 1 - -// Gaudi -#include "GaudiAlg/GaudiTupleAlg.h" -#include "GaudiKernel/RndmGenerators.h" - -/** @class HCDigitCreator HCDigitCreator.h HCDigitisation/HCDigitCreator.h - * - * This algorithm simulates the detector and front-end response - * of the Herschel forward shower counters and writes out raw banks. - * - */ - -class HCDigitCreator : public GaudiTupleAlg { - -public: - /// Standard constructor - HCDigitCreator( const std::string& name, ISvcLocator* pSvcLocator ); - /// Destructor - virtual ~HCDigitCreator(); - - StatusCode initialize() override; ///< Algorithm initialization - StatusCode execute() override; ///< Algorithm execution - -private: - /// Location of input container - std::string m_hitLocation; - /// Location of output container - std::string m_rawEventLocation; - - /// Number of B-side crate - unsigned int m_crateB; - /// Number of F-side crate - unsigned int m_crateF; - - /// Channel mappings - std::vector m_channelsB0; - std::vector m_channelsB1; - std::vector m_channelsB2; - std::vector m_channelsF1; - std::vector m_channelsF2; - - /// Channel numbers for each quadrant - std::vector> m_channels; - - /// Nominal z-positions of the backward stations - std::vector m_zB; - /// Nominal z-positions of the forward stations - std::vector m_zF; - - /// Number of photons per MeV of deposited energy - double m_photonsPerMeV; - /// Average fraction of collected photons - double m_collectionEfficiency; - /// Quantum efficiency - double m_quantumEfficiency; - /// Overall conversion factor between deposited energy and photo electrons - double m_pePerMeV; - /// PMT gain - double m_gain; - /// ADC conversion factor - double m_electronsPerADC; - /// Max. number of ADC counts - unsigned int m_maxADC; - /// Trigger threshold in ADC counts - unsigned int m_threshold; - - /// Flag to activate monitoring histograms or not - bool m_monitoring; - - /// Generator for Gaussian random variates - Rndm::Numbers m_gauss; - /// Generator for uniform random variates - Rndm::Numbers m_uniform; - - /// Set up the channel map for one station. - bool mapChannels( const std::vector& channels, const unsigned int station, const bool bwd ); - /// Raw bank encoding (PRS/SPD format) - void encode( const unsigned int card, const std::vector& adcs, std::vector& words ); -}; -#endif diff --git a/Rich/RichDigiSys/python/RichDigiSys/Configuration.py b/Rich/RichDigiSys/python/RichDigiSys/Configuration.py index 862b440e7..9b5c1fc4d 100755 --- a/Rich/RichDigiSys/python/RichDigiSys/Configuration.py +++ b/Rich/RichDigiSys/python/RichDigiSys/Configuration.py @@ -72,7 +72,8 @@ class RichDigiSysConf(LHCbConfigurableUser): ## @brief Apply the configuration to the given GaudiSequencer # @param sequence The GaudiSequencer to add the RICH digitisation to - def applyConf(self): + # returns the list of views on RawBanks to be put in the RawEvent + def configure(self): if (not self.getProp("DataType") == "Run3") and ( not self.getProp("DataType") == "Upgrade" ): @@ -167,21 +168,17 @@ class RichDigiSysConf(LHCbConfigurableUser): rawEvtFill = self.makeComponent( Rich__MC__Digi__MCRichDigitsToRawBufferAlg, "RichFillRawBuffer" ) + rawEvtFill.RawEventLocation = "DAQ/RichEvent" + rawEvtFill.ViewLocation = "DAQ/Rich/View" dataV = self.getProp("RawDataFormatVersion") if dataV > -1: rawEvtFill.DataVersion = dataV sequence.Members += [rawEvtFill] if self.getProp("TestRawFormatDecoding"): - from Configurables import LHCb__UnpackRawEvent from Configurables import Rich__Future__RawBankDecoder as RichDecoder - unpacker = LHCb__UnpackRawEvent( - "UnpackRawEvent", - BankTypes=["Rich"], - RawEventLocation="/Event/DAQ/RawEvent", - RawBankLocations=["/Event/DAQ/RawBanks/Rich"], - ) - testDecode = self.makeComponent(RichDecoder, "RichDecodeTest") - sequence.Members += [unpacker, testDecode] + testDecode.RawBanks = rawEvtFill.ViewLocation + sequence.Members += [testDecode] + return rawEvtFill.ViewLocation diff --git a/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp b/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp index 5b9b58317..65aae4069 100644 --- a/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp +++ b/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp @@ -13,31 +13,21 @@ #include "Gaudi/Parsers/Factory.h" #include "GaudiKernel/StdArrayAsProperty.h" -// base class -#include "RichFutureKernel/RichAlgBase.h" - -// Gaudi Functional -#include "LHCbAlgs/Consumer.h" - -// Event Model #include "Event/MCRichDigit.h" #include "Event/RawEvent.h" +#include "LHCbAlgs/Transformer.h" +#include "RichFutureKernel/RichAlgBase.h" -// RICH DAQ #include "RichFutureDAQ/EncodeTel40Data.h" #include "RichFutureDAQ/RichPDMDBEncodeMapping.h" #include "RichFutureDAQ/RichTel40CableMapping.h" - -// RICH Utils #include "RichUtils/RichDAQDefinitions.h" #include "RichUtils/RichException.h" #include "RichUtils/RichSmartIDSorter.h" -// Kernel #include "Kernel/RichSmartID.h" #include "Kernel/RichSmartID32.h" -// STL #include #include #include @@ -100,62 +90,39 @@ namespace Rich::MC::Digi { * @date 2003-11-06 */ class MCRichDigitsToRawBufferAlg final - : public LHCb::Algorithm::Consumer, // - Tel40CableMapping, // - PDMDBEncodeMapping>> { + : public LHCb::Algorithm::MultiTransformer< + std::tuple( const LHCb::MCRichDigits&, const Tel40CableMapping&, + const PDMDBEncodeMapping& ), + Gaudi::Functional::Traits::use_< + LHCb::DetDesc::usesBaseAndConditions, Tel40CableMapping, PDMDBEncodeMapping>, + LHCb::Algorithm::Traits::writeOnly>> { public: - // framework - MCRichDigitsToRawBufferAlg( const std::string& name, ISvcLocator* pSvcLocator ) - : Consumer( name, pSvcLocator, - { KeyValue{ "MCRichDigitsLocation", LHCb::MCRichDigitLocation::Default }, - KeyValue{ "RawEventLocation", LHCb::RawEventLocation::Default }, - KeyValue{ "Tel40CableMapping", Tel40CableMapping::DefaultConditionKey + "-" + name }, - KeyValue{ "PDMDBEncodeMapping", PDMDBEncodeMapping::DefaultConditionKey + "-" + name } } ) {} + : MultiTransformer( name, pSvcLocator, + { KeyValue{ "MCRichDigitsLocation", LHCb::MCRichDigitLocation::Default }, + KeyValue{ "Tel40CableMapping", Tel40CableMapping::DefaultConditionKey + "-" + name }, + KeyValue{ "PDMDBEncodeMapping", PDMDBEncodeMapping::DefaultConditionKey + "-" + name } }, + { KeyValue{ "RawEventLocation", "" }, KeyValue{ "ViewLocation", "" } } ) {} - /// Initialise StatusCode initialize() override { - - // base initialise - auto sc = Consumer::initialize(); - if ( !sc ) return sc; - - // Force enable debug messages. - // sc = setProperty( "OutputLevel", MSG::VERBOSE ); - - // derived conditions - Tel40CableMapping::addConditionDerivation( this ); - PDMDBEncodeMapping::addConditionDerivation( this ); - - // check for valid data format version - if ( Rich::DAQ::MaPMT1 != m_version && // - Rich::DAQ::StreamSmartIDs32 != m_version && // - Rich::DAQ::StreamSmartIDs64 != m_version ) { - error() << "Unknown data format version " << m_version.value() << endmsg; - sc = StatusCode::FAILURE; - } - - return sc; + return MultiTransformer::initialize().andThen( [&] { + Tel40CableMapping::addConditionDerivation( this ); + PDMDBEncodeMapping::addConditionDerivation( this ); + // check for valid data format version + if ( Rich::DAQ::MaPMT1 != m_version && // + Rich::DAQ::StreamSmartIDs32 != m_version && // + Rich::DAQ::StreamSmartIDs64 != m_version ) { + error() << "Unknown data format version " << m_version.value() << endmsg; + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; + } ); } - /// Execution - void operator()( const LHCb::MCRichDigits& digits, // - const LHCb::RawEvent& rawEv, // - const Tel40CableMapping& tel40Maps, // - const PDMDBEncodeMapping& pdmdbMaps ) const override { - - // Boole still operates in a configuration where algorithms need to modify a RawEvent - // object. So until this is changed need to arrange for non-const access to the input object.. - auto& rawEv_nonconst = *( const_cast( &rawEv ) ); - - // because of the above... - std::lock_guard lock( m_updateLock ); - + std::tuple operator()( const LHCb::MCRichDigits& digits, + const Tel40CableMapping& tel40Maps, + const PDMDBEncodeMapping& pdmdbMaps ) const override { // Extract the Smart IDs to fill LHCb::RichSmartID::Vector ids; ids.reserve( digits.size() ); @@ -186,71 +153,50 @@ namespace Rich::MC::Digi { } } + LHCb::RawEvent rawEvent; // Format to use if ( Rich::DAQ::MaPMT1 == ver ) { - // Primary format - // Data structure to form Tel40 banks EncodeTel40 encTel40( tel40Maps, this ); - // loop over IDs for ( const auto id : ids ) { - // Sanity check ID is valid. // Should really never ever fail but best to check to protect DB lookups below. if ( id.isValid() ) { - // get the anode data for this hit const auto& anodeData = pdmdbMaps.anodeData( id ); if ( anodeData.isValid() ) { - // Now get the tel40 link data const auto& tel40Data = tel40Maps.tel40Data( id, anodeData.pdmdb, anodeData.frame ); if ( tel40Data.isValid() ) { - - // print - // _ri_verbo << id << endmsg; - // _ri_verbo << " -> AnodeData " << anodeData << endmsg; - // _ri_verbo << " -> Tel40Data " << tel40Data << endmsg; - // collect the active frame bits per Tel40 data link encTel40.add( tel40Data.sourceID, tel40Data.connector, anodeData.bit ); - } else { ++m_invalidTel40Data; } - } else { ++m_invalidAnodeData; } - } else { ++m_invalidID; } - } // ID loop - // finally loop over the collected data and form the raw banks - encTel40.fill( rawEv_nonconst, ver ); - + encTel40.fill( rawEvent, ver ); } else if ( Rich::DAQ::StreamSmartIDs32 == ver ) { - - fillStreamFormat( rawEv_nonconst, ids ); - + fillStreamFormat( rawEvent, ids ); } else if ( Rich::DAQ::StreamSmartIDs64 == ver ) { - - fillStreamFormat( rawEv_nonconst, ids ); - + fillStreamFormat( rawEvent, ids ); } // version if + + auto view = rawEvent.banks( LHCb::RawBank::HC ); + // without std::move here the RawEvent gets copied which would invalidate the view + // View creation must be after RawEvent is made + return { std::move( rawEvent ), std::move( view ) }; } private: - // data - - /// mutex lock - mutable std::mutex m_updateLock; - /// Count instances when automatically version fallback is taken mutable WarningCounter m_fallbackWarn{ this, "DB tags too old to support realistic PMT data format, falling back to ID streaming format." }; -- GitLab From 842af80c4bc593dea5a1cedb414b886d48b80760 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Mon, 20 Oct 2025 10:19:31 +0200 Subject: [PATCH 2/2] Use newly created utility functions of RawEvent to create views on RawBanks --- HC/HCDigitisation/src/HCDigitCreator.cpp | 7 ++----- Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp | 5 +---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/HC/HCDigitisation/src/HCDigitCreator.cpp b/HC/HCDigitisation/src/HCDigitCreator.cpp index ce9336307..8fc6da5ed 100644 --- a/HC/HCDigitisation/src/HCDigitCreator.cpp +++ b/HC/HCDigitisation/src/HCDigitCreator.cpp @@ -345,12 +345,9 @@ LHCb::HCDigitCreator::operator()( LHCb::MCHits const& hits, LHCb::GenCollisions encode( m_crateF, adcsF, words, m_threshold ); // Add a new raw bank and pass memory ownership to the raw event. const unsigned int version = 2; - rawEvent.addBank( 0, RawBank::HC, version, words ); + rawEvent.addBank( 0, RawBank::BankType::HC, version, words ); - auto view = rawEvent.banks( RawBank::HC ); - // without std::move here the RawEvent gets copied which would invalidate the view - // View creation must be after RawEvent is made - return { std::move( rawEvent ), std::move( view ) }; + return viewFromRawEvent( std::move( rawEvent ), RawBank::BankType::HC ); } bool LHCb::HCDigitCreator::mapChannels( const std::vector& channels, const unsigned int station, const bool bwd ) { diff --git a/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp b/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp index 65aae4069..8c5178886 100644 --- a/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp +++ b/Rich/RichReadout/src/MCRichDigitsToRawBufferAlg.cpp @@ -190,10 +190,7 @@ namespace Rich::MC::Digi { fillStreamFormat( rawEvent, ids ); } // version if - auto view = rawEvent.banks( LHCb::RawBank::HC ); - // without std::move here the RawEvent gets copied which would invalidate the view - // View creation must be after RawEvent is made - return { std::move( rawEvent ), std::move( view ) }; + return viewFromRawEvent( std::move( rawEvent ), LHCb::RawBank::BankType::Rich ); } private: -- GitLab