diff --git a/Digi/Boole/python/Boole/Configuration.py b/Digi/Boole/python/Boole/Configuration.py index 6ce2a8e4a9f8dcd8051deb238251c7c7dc2f3489..cf1fa9605ee358ea5dd6669e77d38d597c84d4c9 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 19a58464195be55165e60d9a5305d8affd94713a..02009533d62124c4207faac9d0b45ab9ade1eda2 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 5ef185b3de21f8df9aeddbad513b07673196d4f7..2b75eab7c6b12456c8cc4d675e38ccee7f746663 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 eb4b869db00b79ef6cf86f72092eec0b1eb97420..8fc6da5ed6df1c1c4a855bd0194fa7c2ab918163 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,16 @@ 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::BankType::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; + return viewFromRawEvent( std::move( rawEvent ), RawBank::BankType::HC ); } -//========================================================================= -// 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 1d533630c3c10ccb4656e4c654ea65f4eff8c507..0000000000000000000000000000000000000000 --- 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 862b440e733b219f72a46db16c400cfd06e456e7..9b5c1fc4dffb3e628bf64b0736265fa1b52d492e 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 5b9b583177923ddc62ec953fd0d6842bec085a86..8c51788864be13f91d71a4b514b143a2a1f0b4c3 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,47 @@ 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 + + return viewFromRawEvent( std::move( rawEvent ), LHCb::RawBank::BankType::Rich ); } 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." };