diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/TrigT1CaloByteStream/ITrigT1CaloDataAccess.h b/Trigger/TrigT1/TrigT1CaloByteStream/TrigT1CaloByteStream/ITrigT1CaloDataAccess.h new file mode 100644 index 0000000000000000000000000000000000000000..cc4900fe76be5e6cda0b6d4cde6924b2c419d9cd --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/TrigT1CaloByteStream/ITrigT1CaloDataAccess.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_ITRIGT1CALODATAACCESS_H +#define TRIGT1CALOBYTESTREAM_ITRIGT1CALODATAACCESS_H + +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/IInterface.h" + +#include "DataModel/DataVector.h" + +namespace LVL1 { + class TriggerTower; + class JEMEtSums; + class JetElement; + class JetElementKey; +} + +namespace LVL1BS { + +static const InterfaceID IID_ITrigT1CaloDataAccess("LVL1BS::ITrigT1CaloDataAccess", 1, 0); + +class ITrigT1CaloDataAccess : virtual public IAlgTool { + + public: + static const InterfaceID& interfaceID(); + + virtual StatusCode loadCollection( + DataVector<LVL1::TriggerTower>::const_iterator& beg, + DataVector<LVL1::TriggerTower>::const_iterator& end, + double etaMin, double etaMax, + double phiMin, double phiMax, const bool full) = 0; + virtual StatusCode loadCollection( + DataVector<LVL1::JetElement>::const_iterator& beg, + DataVector<LVL1::JetElement>::const_iterator& end)=0; + + +}; + +inline const InterfaceID& ITrigT1CaloDataAccess::interfaceID() +{ + return IID_ITrigT1CaloDataAccess; +} + +} // end of namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/cmt/requirements b/Trigger/TrigT1/TrigT1CaloByteStream/cmt/requirements new file mode 100755 index 0000000000000000000000000000000000000000..f4ac237a64717189bcd26ce580051b676b1f814d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/cmt/requirements @@ -0,0 +1,34 @@ +package TrigT1CaloByteStream + +use AtlasPolicy AtlasPolicy-* +use DataModel DataModel-* Control +use GaudiInterface GaudiInterface-* External + +author Peter Faulkner <P.J.W.Faulkner@bham.ac.uk> + +# use this line to exclude test algorithms +library TrigT1CaloByteStream *.cxx components/*.cxx +# use this line to include test algorithms +#library TrigT1CaloByteStream *.cxx ../test/*.cxx +apply_pattern component_library + +apply_pattern declare_joboptions files="*.py" + +private +use AthenaBaseComps AthenaBaseComps-* Control +use ByteStreamCnvSvcBase ByteStreamCnvSvcBase-* Event +use ByteStreamData ByteStreamData-* Event +use DataCollection DataCollection-* External +use StoreGate StoreGate-* Control +use SGTools SGTools-* Control +use EventInfo EventInfo-* Event + +use TrigT1CaloEvent TrigT1CaloEvent-* Trigger/TrigT1 +use TrigT1CaloUtils TrigT1CaloUtils-* Trigger/TrigT1 +use TrigT1CaloMappingToolInterfaces TrigT1CaloMappingToolInterfaces-* Trigger/TrigT1 + +# Only needed for test algorithms +#use TrigT1Interfaces TrigT1Interfaces-* Trigger/TrigT1 +#use StoreGate StoreGate-* Control + +macro_append DOXYGEN_FILE_PATTERNS " *.icc" diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/doc/mainpage.h b/Trigger/TrigT1/TrigT1CaloByteStream/doc/mainpage.h new file mode 100755 index 0000000000000000000000000000000000000000..05edfc912aff585e904bb4a92146e7f7f882e513 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/doc/mainpage.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** +@mainpage TrigT1CaloByteStream Package + +@section intro Introduction +This package contains offline bytestream conversion code for the +Level-1 Calorimeter Trigger sub-detectors.<p> + +The code is based on the following documents/sources:<p> + +ATLAS Level-1 Calorimeter Trigger-Read-out Driver, version 1.09h<br> +Level-1 Calorimeter Trigger: Cable Mappings and Crate Layouts from Analogue +Inputs to Processors, version 1.6<br> +Steve Hillier's online decoder, mainly L1CaloBsDecoderTemplate.h as of +November 2005.<br> +Private communications from Steve Hillier.<br> +ATLAS L1Calo Pre-processor compressed Slink data formats, D.P.C.Sankey, +Version 1.1, October 17, 2006.<br> +ATLAS Level-1 Calorimeter Trigger: Jet/Energy Processor Module, +Project Specification, version 1.0<br> +ATLAS Level-1 Calorimeter Trigger: Cluster Processor Module, +Project Specification, version 2.03<br> +ATLAS Calorimeter First Level Trigger: Common Merger Module, +Project Specification, version 1.7.8<p> + +Implemented so far: PPM, CPM, JEM, CMM-CP, CMM-Jet, CMM-Energy DAQ; + CPM RoI, JEM Jet RoI, CMM-Jet-Et RoI, CMM-Energy RoI. + +@author Peter Faulkner + +@ref used_TrigT1CaloByteStream +@ref requirements_TrigT1CaloByteStream + +*/ + +/** +@page used_TrigT1CaloByteStream Used Packages +@htmlinclude used_packages.html +*/ + +/** +@page requirements_TrigT1CaloByteStream Requirements +@include requirements +*/ + + diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBSRun1_jobOptions.py b/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBSRun1_jobOptions.py new file mode 100755 index 0000000000000000000000000000000000000000..4a20894417f283a7d9641eb6f73de2df624daf9e --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBSRun1_jobOptions.py @@ -0,0 +1,70 @@ +# Bytestream to TrigT1Calo objects conversions for data with Run 1 formats +include.block("TrigT1CaloByteStream/ReadLVL1CaloBSRun1_jobOptions.py") + +# the following include is needed to load correctly the trigger towers on/off, TT/Cells maps +include( "CaloConditions/CaloConditions_jobOptions.py" ) +# To setup correctly the LArCablingService when doLAr is off in the top option. +from RecExConfig.RecFlags import rec +if not rec.doLArg(): + include( "LArConditionsCommon/LArIdMap_comm_jobOptions.py" ) + include( "LArIdCnv/LArIdCnv_joboptions.py" ) + +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpByteStreamV1Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmRoiByteStreamV1Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepByteStreamV1Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepRoiByteStreamV1Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__PpmByteStreamTool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__RodHeaderByteStreamTool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__L1CaloErrorByteStreamTool +ToolSvc = Service("ToolSvc") +ToolSvc += LVL1BS__CpByteStreamV1Tool("CpByteStreamV1Tool") +ToolSvc += LVL1BS__CpmRoiByteStreamV1Tool("CpmRoiByteStreamV1Tool") +ToolSvc += LVL1BS__JepByteStreamV1Tool("JepByteStreamV1Tool") +ToolSvc += LVL1BS__JepRoiByteStreamV1Tool("JepRoiByteStreamV1Tool") +ToolSvc += LVL1BS__PpmByteStreamTool("PpmByteStreamTool", + PpmMappingTool="LVL1::PpmCoolOrBuiltinMappingTool/PpmCoolOrBuiltinMappingTool") +ToolSvc += LVL1BS__RodHeaderByteStreamTool("RodHeaderByteStreamTool") +ToolSvc += LVL1BS__L1CaloErrorByteStreamTool("L1CaloErrorByteStreamTool") + +ByteStreamAddressProviderSvc = Service( "ByteStreamAddressProviderSvc" ) +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTower>/CPMTowers" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTower>/CPMTowersOverlap" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMHits>/CPMHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMMCPHits>/CMMCPHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMRoI>/CPMRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMRoI>/CPMRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JetElement>/JetElements" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JetElement>/JetElementsOverlap" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMHits>/JEMHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMEtSums>/JEMEtSums" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMMJetHits>/CMMJetHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMMEtSums>/CMMEtSums" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMRoI>/JEMRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMRoI>/JEMRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "LVL1::CMMRoI/CMMRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "LVL1::CMMRoI/CMMRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::TriggerTower>/TriggerTowers" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::TriggerTower>/TriggerTowersSpare" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::TriggerTower>/TriggerTowersMuon" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeaders" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersPP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCPRoI" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEPRoI" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCPRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEPRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "std::vector<unsigned int>/L1CaloUnpackingErrors" ] + +#from AthenaCommon.AlgSequence import AlgSequence +#topSequence = AlgSequence() +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmTesterV1 +#topSequence += LVL1BS__CpmTesterV1("CpmTesterV1") +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmTesterV2 +#topSequence += LVL1BS__CpmTesterV2("CpmTesterV2") +#topSequence += LVL1BS__CpmTesterV2("CpmTesterV2", CMXCPTobPrint=2, CMXCPHitsPrint=2) +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JemTesterV1 +#topSequence += LVL1BS__JemTesterV1("JemTesterV1") +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JemTesterV2 +#topSequence += LVL1BS__JemTesterV2("JemTesterV2") +#topSequence += LVL1BS__JemTesterV2("JemTesterV2", CMXJetTobPrint=1) diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBSRun2_jobOptions.py b/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBSRun2_jobOptions.py new file mode 100755 index 0000000000000000000000000000000000000000..603cfbe429f187bafdcdf214328acae46981675f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBSRun2_jobOptions.py @@ -0,0 +1,70 @@ +# Bytestream to TrigT1Calo objects conversions for data with Run 2 formats +include.block("TrigT1CaloByteStream/ReadLVL1CaloBSRun2_jobOptions.py") + +# the following include is needed to load correctly the trigger towers on/off, TT/Cells maps +include( "CaloConditions/CaloConditions_jobOptions.py" ) +# To setup correctly the LArCablingService when doLAr is off in the top option. +from RecExConfig.RecFlags import rec +if not rec.doLArg(): + include( "LArConditionsCommon/LArIdMap_comm_jobOptions.py" ) + include( "LArIdCnv/LArIdCnv_joboptions.py" ) + +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpByteStreamV2Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmRoiByteStreamV2Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepByteStreamV2Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepRoiByteStreamV2Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__PpmByteStreamTool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__RodHeaderByteStreamTool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__L1CaloErrorByteStreamTool +ToolSvc = Service("ToolSvc") +ToolSvc += LVL1BS__CpByteStreamV2Tool("CpByteStreamV2Tool") +ToolSvc += LVL1BS__CpmRoiByteStreamV2Tool("CpmRoiByteStreamV2Tool") +ToolSvc += LVL1BS__JepByteStreamV2Tool("JepByteStreamV2Tool") +ToolSvc += LVL1BS__JepRoiByteStreamV2Tool("JepRoiByteStreamV2Tool") +ToolSvc += LVL1BS__PpmByteStreamTool("PpmByteStreamTool", + PpmMappingTool="LVL1::PpmCoolOrBuiltinMappingTool/PpmCoolOrBuiltinMappingTool") +ToolSvc += LVL1BS__RodHeaderByteStreamTool("RodHeaderByteStreamTool") +ToolSvc += LVL1BS__L1CaloErrorByteStreamTool("L1CaloErrorByteStreamTool") + +ByteStreamAddressProviderSvc = Service( "ByteStreamAddressProviderSvc" ) +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTower>/CPMTowers" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTower>/CPMTowersOverlap" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMXCPTob>/CMXCPTobs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMXCPHits>/CMXCPHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTobRoI>/CPMTobRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTobRoI>/CPMTobRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JetElement>/JetElements" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JetElement>/JetElementsOverlap" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMEtSums>/JEMEtSums" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMXJetTob>/CMXJetTobs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMXJetHits>/CMXJetHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMXEtSums>/CMXEtSums" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMTobRoI>/JEMTobRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMTobRoI>/JEMTobRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "LVL1::CMXRoI/CMXRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "LVL1::CMXRoI/CMXRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::TriggerTower>/TriggerTowers" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::TriggerTower>/TriggerTowersSpare" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::TriggerTower>/TriggerTowersMuon" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeaders" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersPP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCPRoI" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEPRoI" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCPRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEPRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "std::vector<unsigned int>/L1CaloUnpackingErrors" ] + +#from AthenaCommon.AlgSequence import AlgSequence +#topSequence = AlgSequence() +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmTesterV1 +#topSequence += LVL1BS__CpmTesterV1("CpmTesterV1") +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmTesterV2 +#topSequence += LVL1BS__CpmTesterV2("CpmTesterV2") +#topSequence += LVL1BS__CpmTesterV2("CpmTesterV2", CMXCPTobPrint=2, CMXCPHitsPrint=2) +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JemTesterV1 +#topSequence += LVL1BS__JemTesterV1("JemTesterV1") +#from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JemTesterV2 +#topSequence += LVL1BS__JemTesterV2("JemTesterV2") +#topSequence += LVL1BS__JemTesterV2("JemTesterV2", CMXJetTobPrint=1) diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBS_jobOptions.py b/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBS_jobOptions.py new file mode 100755 index 0000000000000000000000000000000000000000..7f41cf3026c364c192c3d4fdc53ac56dd9481970 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/share/ReadLVL1CaloBS_jobOptions.py @@ -0,0 +1,17 @@ +# Bytestream to TrigT1Calo objects conversions +include.block("TrigT1CaloByteStream/ReadLVL1CaloBS_jobOptions.py") + +from AthenaCommon.AthenaCommonFlags import athenaCommonFlags +from AthenaCommon.GlobalFlags import globalflags +from RecExConfig.AutoConfiguration import GetRunNumber +# Need something better eventually +if athenaCommonFlags.isOnline: + run1 = False +elif globalflags.DataSource() == "data": + run1 = (GetRunNumber() < 230000) +else: # MC + run1 = False +if run1: + include ("TrigT1CaloByteStream/ReadLVL1CaloBSRun1_jobOptions.py") +else: + include ("TrigT1CaloByteStream/ReadLVL1CaloBSRun2_jobOptions.py") diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBSRun1_jobOptions.py b/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBSRun1_jobOptions.py new file mode 100755 index 0000000000000000000000000000000000000000..39dff520825ef25ac8da3c7b10550293d9a997c1 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBSRun1_jobOptions.py @@ -0,0 +1,29 @@ +# TrigT1Calo object containers to bytestream conversion +include.block("TrigT1CaloByteStream/WriteLVL1CaloBSRun1_jobOptions.py") + +# the following include is needed to load correctly the trigger towers on/off, TT/Cells maps +include( "CaloConditions/CaloConditions_jobOptions.py" ) +# To setup correctly the LArCablingService when doLAr is off in the top option. +if not rec.doLArg(): + include( "LArConditionsCommon/LArIdMap_comm_jobOptions.py" ) + include( "LArIdCnv/LArIdCnv_joboptions.py" ) + +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__PpmByteStreamTool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpByteStreamV1Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmRoiByteStreamV1Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepByteStreamV1Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepRoiByteStreamV1Tool +ToolSvc = Service("ToolSvc") +ToolSvc += LVL1BS__PpmByteStreamTool("PpmByteStreamTool", + PpmMappingTool="LVL1::PpmCoolOrBuiltinMappingTool/PpmCoolOrBuiltinMappingTool") +ToolSvc += LVL1BS__CpByteStreamV1Tool("CpByteStreamV1Tool") +ToolSvc += LVL1BS__CpmRoiByteStreamV1Tool("CpmRoiByteStreamV1Tool") +ToolSvc += LVL1BS__JepByteStreamV1Tool("JepByteStreamV1Tool") +ToolSvc += LVL1BS__JepRoiByteStreamV1Tool("JepRoiByteStreamV1Tool") + +StreamBS = AthenaOutputStream( "StreamBS" ) +StreamBS.ItemList += [ "6207#*" ] # TriggerTower +StreamBS.ItemList += [ "216508938#*" ] # CPMRoI +StreamBS.ItemList += [ "1270847938#*" ] # CPBSCollectionV1 +StreamBS.ItemList += [ "1243139661#*" ] # JEPBSCollectionV1 +StreamBS.ItemList += [ "1316106214#*" ] # JEPRoIBSCollectionV1 diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBSRun2_jobOptions.py b/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBSRun2_jobOptions.py new file mode 100755 index 0000000000000000000000000000000000000000..1d662e98f45f17a3f5152e377bee906759b94f58 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBSRun2_jobOptions.py @@ -0,0 +1,29 @@ +# TrigT1Calo object containers to bytestream conversion +include.block("TrigT1CaloByteStream/WriteLVL1CaloBSRun2_jobOptions.py") + +# the following include is needed to load correctly the trigger towers on/off, TT/Cells maps +include( "CaloConditions/CaloConditions_jobOptions.py" ) +# To setup correctly the LArCablingService when doLAr is off in the top option. +if not rec.doLArg(): + include( "LArConditionsCommon/LArIdMap_comm_jobOptions.py" ) + include( "LArIdCnv/LArIdCnv_joboptions.py" ) + +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__PpmByteStreamTool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpByteStreamV2Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__CpmRoiByteStreamV2Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepByteStreamV2Tool +from TrigT1CaloByteStream.TrigT1CaloByteStreamConf import LVL1BS__JepRoiByteStreamV2Tool +ToolSvc = Service("ToolSvc") +ToolSvc += LVL1BS__PpmByteStreamTool("PpmByteStreamTool", + PpmMappingTool="LVL1::PpmCoolOrBuiltinMappingTool/PpmCoolOrBuiltinMappingTool") +ToolSvc += LVL1BS__CpByteStreamV2Tool("CpByteStreamV2Tool") +ToolSvc += LVL1BS__CpmRoiByteStreamV2Tool("CpmRoiByteStreamV2Tool") +ToolSvc += LVL1BS__JepByteStreamV2Tool("JepByteStreamV2Tool") +ToolSvc += LVL1BS__JepRoiByteStreamV2Tool("JepRoiByteStreamV2Tool") + +StreamBS = AthenaOutputStream( "StreamBS" ) +StreamBS.ItemList += [ "6207#*" ] # TriggerTower +StreamBS.ItemList += [ "1270847937#*" ] # CPBSCollectionV2 +StreamBS.ItemList += [ "80981142#*" ] # CPMTobRoI +StreamBS.ItemList += [ "1243139662#*" ] # JEPBSCollectionV2 +StreamBS.ItemList += [ "1316106213#*" ] # JEPRoIBSCollectionV2 diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBS_jobOptions.py b/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBS_jobOptions.py new file mode 100755 index 0000000000000000000000000000000000000000..9fca7d37f122f884db96296416021a6723a7bfef --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/share/WriteLVL1CaloBS_jobOptions.py @@ -0,0 +1,18 @@ +# TrigT1Calo object containers to bytestream conversion +include.block("TrigT1CaloByteStream/WriteLVL1CaloBS_jobOptions.py") + +from AthenaCommon.AthenaCommonFlags import athenaCommonFlags +from AthenaCommon.GlobalFlags import globalflags +from RecExConfig.AutoConfiguration import GetRunNumber +# Need something better eventually +if athenaCommonFlags.isOnline: + run1 = False +elif globalflags.DataSource() == "data": + run1 = (GetRunNumber() < 230000) +else: # MC + run1 = False +if run1: + include ("TrigT1CaloByteStream/WriteLVL1CaloBSRun1_jobOptions.py") +else: + include ("TrigT1CaloByteStream/WriteLVL1CaloBSRun2_jobOptions.py") + #include ("TrigT1CaloByteStream/WriteLVL1CaloBSRun1Run2_jobOptions.py") diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/share/jobOfragment_ReadLVL1CaloBS.py b/Trigger/TrigT1/TrigT1CaloByteStream/share/jobOfragment_ReadLVL1CaloBS.py new file mode 100755 index 0000000000000000000000000000000000000000..c07ee30aa54381a871a86067833f85e57180059d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/share/jobOfragment_ReadLVL1CaloBS.py @@ -0,0 +1,27 @@ +# Bytestream to TrigT1Calo objects conversions +ByteStreamAddressProviderSvc = Service( "ByteStreamAddressProviderSvc" ) +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::TriggerTower>/TriggerTowers" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTower>/CPMTowers" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMTower>/CPMTowersOverlap" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMHits>/CPMHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMMCPHits>/CMMCPHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMRoI>/CPMRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CPMRoI>/CPMRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JetElement>/JetElements" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JetElement>/JetElementsOverlap" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMHits>/JEMHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMEtSums>/JEMEtSums" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMMJetHits>/CMMJetHits" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::CMMEtSums>/CMMEtSums" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMRoI>/JEMRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::JEMRoI>/JEMRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "LVL1::CMMRoI/CMMRoIs" ] +ByteStreamAddressProviderSvc.TypeNames += [ "LVL1::CMMRoI/CMMRoIsRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeaders" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersPP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCPRoI" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEP" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEPRoI" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersCPRoIB" ] +ByteStreamAddressProviderSvc.TypeNames += [ "DataVector<LVL1::RODHeader>/RODHeadersJEPRoIB" ] diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmCpSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmCpSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..2a9cfe2155c83f9b4ca8edc268746c6ff140cbb9 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmCpSubBlock.cxx @@ -0,0 +1,255 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CmmCpSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CmmCpSubBlock::s_wordLength; + +const int CmmCpSubBlock::s_threshBit; +const int CmmCpSubBlock::s_threshErrorBit; +const int CmmCpSubBlock::s_sourceIdBit; +const int CmmCpSubBlock::s_dataWordIdBit; +const int CmmCpSubBlock::s_dataWordId; +const int CmmCpSubBlock::s_maxHits; +const uint32_t CmmCpSubBlock::s_threshMask; +const uint32_t CmmCpSubBlock::s_errorMask; +const uint32_t CmmCpSubBlock::s_sourceIdMask; + +const int CmmCpSubBlock::s_hitsBits; +const int CmmCpSubBlock::s_hitsErrorBits; +const int CmmCpSubBlock::s_bunchCrossingBits; +const int CmmCpSubBlock::s_paddingBits; +const int CmmCpSubBlock::s_fifoOverflowPin; + + +CmmCpSubBlock::CmmCpSubBlock() +{ +} + +CmmCpSubBlock::~CmmCpSubBlock() +{ +} + +// Clear all data + +void CmmCpSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_hitsData.clear(); +} + +// Return hit counts for given CPM or source ID + +unsigned int CmmCpSubBlock::hits(const int slice, int source) const +{ + --source; + unsigned int hits = 0; + if (slice >= 0 && slice < timeslices() && + source >= 0 && source < s_maxHits && !m_hitsData.empty()) { + hits = (m_hitsData[index(slice, source)] >> s_threshBit) & s_threshMask; + } + return hits; +} + +// Return hit error for given CPM or source ID + +int CmmCpSubBlock::hitsError(const int slice, int source) const +{ + --source; + int error = 0; + if (slice >= 0 && slice < timeslices() && + source >= 0 && source < s_maxHits && !m_hitsData.empty()) { + error = (m_hitsData[index(slice, source)] >> s_threshErrorBit) + & s_errorMask; + } + return error; +} + +// Store hit counts for given CPM or source ID + +void CmmCpSubBlock::setHits(const int slice, int source, + const unsigned int hits, const int error) +{ + --source; + if (slice >= 0 && slice < timeslices() && + source >= 0 && source < s_maxHits && (hits || error)) { + resize(); + uint32_t word = m_hitsData[index(slice, source)]; + word |= (hits & s_threshMask) << s_threshBit; + word |= (error & s_errorMask) << s_threshErrorBit; + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= (s_dataWordId) << s_dataWordIdBit; + m_hitsData[index(slice, source)] = word; + } +} + +// Packing/Unpacking routines + +bool CmmCpSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CmmCpSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data index appropriate to format + +int CmmCpSubBlock::index(const int slice, const int source) const +{ + int ix = source; + if (format() == NEUTRAL) ix += slice * s_maxHits; + return ix; +} + +// Resize the hits vector according to format + +void CmmCpSubBlock::resize() +{ + if (m_hitsData.empty()) { + int size = s_maxHits; + if (format() == NEUTRAL) size *= timeslices(); + m_hitsData.resize(size); + } +} + +// Pack neutral data + +bool CmmCpSubBlock::packNeutral() +{ + resize(); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int source = 1; source < MAX_SOURCE_ID; ++source) { + const int pin = source - 1; + // CPM hits; remote(3), local and total hits; parity error + packerNeutral(pin, hits(slice, source), s_hitsBits); + packerNeutral(pin, hitsError(slice, source), s_hitsErrorBits); + // Bunch crossing number; Fifo overflow + if (pin < s_bunchCrossingBits) { + packerNeutral(pin, bunchCrossing() >> pin, 1); + } else if (pin == s_fifoOverflowPin) { + packerNeutral(pin, daqOverflow(), 1); + } else packerNeutral(pin, 0, 1); + // Padding + packerNeutral(pin, 0, s_paddingBits); + // G-Link parity + packerNeutralParity(pin); + } + } + return true; +} + +// Pack uncompressed data + +bool CmmCpSubBlock::packUncompressed() +{ + std::vector<uint32_t>::const_iterator pos; + for (pos = m_hitsData.begin(); pos != m_hitsData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CmmCpSubBlock::unpackNeutral() +{ + resize(); + int bunchCrossing = 0; + int overflow = 0; + int parity = 0; + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int source = 1; source < MAX_SOURCE_ID; ++source) { + const int pin = source - 1; + // CPM hits; remote(3), local and total hits; parity error + const unsigned int hits = unpackerNeutral(pin, s_hitsBits); + const int error = unpackerNeutral(pin, s_hitsErrorBits); + setHits(slice, source, hits, error); + // Bunch crossing number; Fifo overflow + if (pin < s_bunchCrossingBits) { + bunchCrossing |= unpackerNeutral(pin, 1) << pin; + } else if (pin == s_fifoOverflowPin) { + overflow |= unpackerNeutral(pin, 1); + } else unpackerNeutral(pin, 1); + // Padding + unpackerNeutral(pin, s_paddingBits); + // G-Link parity errors + parity |= unpackerNeutralParityError(pin); + } + } + setBunchCrossing(bunchCrossing); + setDaqOverflow(overflow); + setGlinkParity(parity); + + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CmmCpSubBlock::unpackUncompressed() +{ + resize(); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int source = sourceId(word); + if (source < s_maxHits && m_hitsData[source] == 0) m_hitsData[source] = word; + else { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmCpSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmCpSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..ab7645f54c1d284f05cb333586007ddae752485e --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmCpSubBlock.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMMCPSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMMCPSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "CmmSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMM-CP data. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class CmmCpSubBlock : public CmmSubBlock { + + public: + // Note - because CPMs are numbered 1-14 these are one more + // than the stored source ID and corresponding G-Link pin. + enum SourceId { REMOTE_0 = 15, REMOTE_1 = 16, REMOTE_2 = 17, + LOCAL = 18, TOTAL = 19, MAX_SOURCE_ID }; + + CmmCpSubBlock(); + ~CmmCpSubBlock(); + + /// Clear all data + void clear(); + + /// Return hit counts for given CPM or source ID + unsigned int hits(int slice, int source) const; + /// Return hit error for given CPM or source ID + int hitsError(int slice, int source) const; + + /// Store hit counts for given CPM or source ID + void setHits(int slice, int source, unsigned int hits, int error); + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Data word length + static const int s_wordLength = 32; + // Jet hit counts bit positions and masks + static const int s_threshBit = 0; + static const int s_threshErrorBit = 24; + static const int s_sourceIdBit = 25; + static const int s_dataWordIdBit = 30; + static const int s_dataWordId = 0; + static const int s_maxHits = 19; + static const uint32_t s_threshMask = 0xffffff; + static const uint32_t s_errorMask = 0x1; + static const uint32_t s_sourceIdMask = 0x1f; + // Neutral format + static const int s_hitsBits = 24; + static const int s_hitsErrorBits = 1; + static const int s_bunchCrossingBits = 12; + static const int s_paddingBits = 8; + static const int s_fifoOverflowPin = 13; + + int sourceId(uint32_t word) const; + int index(int slice, int source) const; + void resize(); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// CPM hits and sums data + std::vector<uint32_t> m_hitsData; + +}; + +inline int CmmCpSubBlock::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmEnergySubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmEnergySubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..0019e28681d53438712cb9de343932f710525209 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmEnergySubBlock.cxx @@ -0,0 +1,533 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <utility> + +#include "CmmEnergySubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CmmEnergySubBlock::s_wordLength; + +const int CmmEnergySubBlock::s_exBit; +const int CmmEnergySubBlock::s_eyBit; +const int CmmEnergySubBlock::s_etBit; +const int CmmEnergySubBlock::s_jemErrorBit; +const int CmmEnergySubBlock::s_errorBit; +const int CmmEnergySubBlock::s_etMissBit; +const int CmmEnergySubBlock::s_etHitsBit; +const int CmmEnergySubBlock::s_etMissSigBit; +const int CmmEnergySubBlock::s_sourceIdBit; +const int CmmEnergySubBlock::s_dataWordIdBit; +const int CmmEnergySubBlock::s_dataWordId; +const int CmmEnergySubBlock::s_maxSums; +const int CmmEnergySubBlock::s_maxJems; +const uint32_t CmmEnergySubBlock::s_exMask; +const uint32_t CmmEnergySubBlock::s_eyMask; +const uint32_t CmmEnergySubBlock::s_etMask; +const uint32_t CmmEnergySubBlock::s_errorMask; +const uint32_t CmmEnergySubBlock::s_remoteErrorMask; +const uint32_t CmmEnergySubBlock::s_etMissMask; +const uint32_t CmmEnergySubBlock::s_etHitsMask; +const uint32_t CmmEnergySubBlock::s_etHitsMaskV1; +const uint32_t CmmEnergySubBlock::s_etMissSigMask; +const uint32_t CmmEnergySubBlock::s_sumsMask; +const uint32_t CmmEnergySubBlock::s_sourceIdMask; + +const int CmmEnergySubBlock::s_jemSumBits; +const int CmmEnergySubBlock::s_sumBits; +const int CmmEnergySubBlock::s_bunchCrossingBits; +const int CmmEnergySubBlock::s_paddingBits; +const int CmmEnergySubBlock::s_fifoOverflowPin; + + +CmmEnergySubBlock::CmmEnergySubBlock() +{ +} + +CmmEnergySubBlock::~CmmEnergySubBlock() +{ +} + +// Clear all data + +void CmmEnergySubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_sumsData.clear(); +} + +// Return Ex subsum for given JEM or source ID + +unsigned int CmmEnergySubBlock::ex(const int slice, const int source) const +{ + unsigned int ex = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (source >= 0 && source < s_maxJems) { + ex = (m_sumsData[index(slice, source)] >> s_exBit) & s_exMask; + } else if (source == REMOTE || source == LOCAL || source == TOTAL) { + ex = m_sumsData[index(slice, source)] & s_sumsMask; + } + } + return ex; +} + +// Return Ey subsum for given JEM or source ID + +unsigned int CmmEnergySubBlock::ey(const int slice, const int source) const +{ + unsigned int ey = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (source >= 0 && source < s_maxJems) { + ey = (m_sumsData[index(slice, source)] >> s_eyBit) & s_eyMask; + } else if (source == REMOTE || source == LOCAL || source == TOTAL) { + ey = m_sumsData[index(slice, source+1)] & s_sumsMask; + } + } + return ey; +} + +// Return Et subsum for given JEM or source ID + +unsigned int CmmEnergySubBlock::et(const int slice, const int source) const +{ + unsigned int et = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (source >= 0 && source < s_maxJems) { + et = (m_sumsData[index(slice, source)] >> s_etBit) & s_etMask; + } else if (source == REMOTE || source == LOCAL || source == TOTAL) { + et = m_sumsData[index(slice, source+2)] & s_sumsMask; + } + } + return et; +} + +// Return Ex subsum error for given JEM or source ID + +int CmmEnergySubBlock::exError(const int slice, const int source) const +{ + int error = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (source >= 0 && source < s_maxJems) { + error = (m_sumsData[index(slice, source)] >> s_jemErrorBit) & s_errorMask; + } else if (source == REMOTE) { + error = (m_sumsData[index(slice, source)] >> s_errorBit) + & s_remoteErrorMask; + } else if (source == LOCAL || source == TOTAL) { + error = (m_sumsData[index(slice, source)] >> s_errorBit) & s_errorMask; + } + } + return error; +} + +// Return Ey subsum error for given JEM or source ID + +int CmmEnergySubBlock::eyError(const int slice, const int source) const +{ + int error = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (source >= 0 && source < s_maxJems) { + error = (m_sumsData[index(slice, source)] >> s_jemErrorBit) & s_errorMask; + } else if (source == REMOTE) { + error = (m_sumsData[index(slice, source+1)] >> s_errorBit) + & s_remoteErrorMask; + } else if (source == LOCAL || source == TOTAL) { + error = (m_sumsData[index(slice, source+1)] >> s_errorBit) & s_errorMask; + } + } + return error; +} + +// Return Et subsum error for given JEM or source ID + +int CmmEnergySubBlock::etError(const int slice, const int source) const +{ + int error = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (source >= 0 && source < s_maxJems) { + error = (m_sumsData[index(slice, source)] >> s_jemErrorBit) & s_errorMask; + } else if (source == REMOTE) { + error = (m_sumsData[index(slice, source+2)] >> s_errorBit) + & s_remoteErrorMask; + } else if (source == LOCAL || source == TOTAL) { + error = (m_sumsData[index(slice, source+2)] >> s_errorBit) & s_errorMask; + } + } + return error; +} + +// Return Missing-ET Hits map + +unsigned int CmmEnergySubBlock::missingEtHits(const int slice) const +{ + unsigned int map = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + map = (m_sumsData[index(slice, TOTAL+1)] >> s_etMissBit) & s_etMissMask; + } + return map; +} + +// Return Sum-ET Hits map + +unsigned int CmmEnergySubBlock::sumEtHits(const int slice) const +{ + unsigned int map = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + unsigned int mask = (version() > 1) ? s_etHitsMask : s_etHitsMaskV1; + map = (m_sumsData[index(slice, TOTAL+2)] >> s_etHitsBit) & mask; + } + return map; +} + +// Return Missing-ET-Sig Hits map + +unsigned int CmmEnergySubBlock::missingEtSigHits(const int slice) const +{ + unsigned int map = 0; + if (version() > 1 && slice >= 0 && slice < timeslices() + && !m_sumsData.empty()) { + map = (m_sumsData[index(slice, TOTAL)] >> s_etMissSigBit) & s_etMissSigMask; + } + return map; +} + +// Store energy subsums and errors for given JEM or source ID + +void CmmEnergySubBlock::setSubsums(const int slice, const int source, + const unsigned int ex, const unsigned int ey, + const unsigned int et, const int exError, + const int eyError, const int etError) +{ + if (slice >= 0 && slice < timeslices() && + source >= 0 && source < s_maxSums && + (ex || ey || et || exError || eyError || etError)) { + resize(); + if (source < s_maxJems) { + uint32_t word = 0; + word |= (ex & s_exMask) << s_exBit; + word |= (ey & s_eyMask) << s_eyBit; + word |= (et & s_etMask) << s_etBit; + word |= (exError & s_errorMask) << s_jemErrorBit; + word |= (eyError & s_errorMask) << s_jemErrorBit; + word |= (etError & s_errorMask) << s_jemErrorBit; + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= s_dataWordId << s_dataWordIdBit; + m_sumsData[index(slice, source)] = word; + } else { + unsigned int sum = ex; + int err = exError; + uint32_t mask = s_errorMask; + if (source == REMOTE) mask = s_remoteErrorMask; + for (int i = 0; i < 3; ++i) { + if (sum || err) { + uint32_t word = m_sumsData[index(slice, source+i)]; + word |= sum & s_sumsMask; + word |= (err & mask) << s_errorBit; + word |= ((source+i) & s_sourceIdMask) << s_sourceIdBit; + word |= s_dataWordId << s_dataWordIdBit; + m_sumsData[index(slice, source+i)] = word; + } + if (i == 0) { + sum = ey; + err = eyError; + } else { + sum = et; + err = etError; + } + } + } + } +} + +// Store Missing-ET Hits map + +void CmmEnergySubBlock::setMissingEtHits(const int slice, + const unsigned int map) +{ + if (slice >= 0 && slice < timeslices() && map) { + resize(); + const int source = TOTAL + 1; + uint32_t word = m_sumsData[index(slice, source)]; + word |= (map & s_etMissMask) << s_etMissBit; + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= s_dataWordId << s_dataWordIdBit; + m_sumsData[index(slice, source)] = word; + } +} + +// Store Sum-Et Hits map + +void CmmEnergySubBlock::setSumEtHits(const int slice, const unsigned int map) +{ + if (slice >= 0 && slice < timeslices() && map) { + resize(); + const int source = TOTAL + 2; + const unsigned int mask = (version() > 1) ? s_etHitsMask : s_etHitsMaskV1; + uint32_t word = m_sumsData[index(slice, source)]; + word |= (map & mask) << s_etHitsBit; + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= s_dataWordId << s_dataWordIdBit; + m_sumsData[index(slice, source)] = word; + } +} + +// Store Missing-ET-Sig Hits map + +void CmmEnergySubBlock::setMissingEtSigHits(const int slice, + const unsigned int map) +{ + if (version() > 1 && slice >= 0 && slice < timeslices() && map) { + resize(); + const int source = TOTAL; + uint32_t word = m_sumsData[index(slice, source)]; + word |= (map & s_etMissSigMask) << s_etMissSigBit; + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= s_dataWordId << s_dataWordIdBit; + m_sumsData[index(slice, source)] = word; + } +} + +// Packing/Unpacking routines + +bool CmmEnergySubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 2: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CmmEnergySubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + case 2: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data index appropriate to format + +int CmmEnergySubBlock::index(const int slice, const int source) const +{ + int ix = source; + if (format() == NEUTRAL) ix += slice * s_maxSums; + return ix; +} + +// Resize the sums vector according to format + +void CmmEnergySubBlock::resize() +{ + if (m_sumsData.empty()) { + int size = s_maxSums; + if (format() == NEUTRAL) size *= timeslices(); + m_sumsData.resize(size); + } +} + +// Pack neutral data + +bool CmmEnergySubBlock::packNeutral() +{ + resize(); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_maxJems; ++pin) { + // JEM energy sums (jem == pin); parity error + packerNeutral(pin, ex(slice, pin), s_jemSumBits); + packerNeutral(pin, ey(slice, pin), s_jemSumBits); + packerNeutral(pin, et(slice, pin), s_jemSumBits); + packerNeutral(pin, etError(slice, pin), 1); + // Bunch crossing number; Fifo overflow + if (pin < s_bunchCrossingBits) { + packerNeutral(pin, bunchCrossing() >> pin, 1); + // Padding + packerNeutral(pin, 0, s_paddingBits); + } else if (pin == s_fifoOverflowPin) { + packerNeutral(pin, daqOverflow(), 1); + } else packerNeutral(pin, 0, 1); + } + int pin = s_bunchCrossingBits - 1; + // Missing-ET-Sig Hits Map + packerNeutral(pin, missingEtSigHits(slice), s_paddingBits); + // Total Et + packerNeutral(++pin, et(slice, TOTAL), s_paddingBits); + packerNeutral(++pin, et(slice, TOTAL) >> s_paddingBits, s_paddingBits-1); + packerNeutral(pin, etError(slice, TOTAL), 1); + // Sum-Et Hits Map + packerNeutral(++pin, sumEtHits(slice), s_paddingBits); + // Missing-ET Hits Map + packerNeutral(++pin, missingEtHits(slice), s_paddingBits); + // Remote Ex, Ey + packerNeutral(++pin, ex(slice, REMOTE), s_sumBits); + packerNeutral(pin, exError(slice, REMOTE), 2); + packerNeutral(pin, ey(slice, REMOTE), s_sumBits); + packerNeutral(pin, eyError(slice, REMOTE), 2); + // Local Ex, Ey + packerNeutral(++pin, ex(slice, LOCAL), s_sumBits); + packerNeutral(pin, exError(slice, LOCAL), 2); + packerNeutral(pin, ey(slice, LOCAL), s_sumBits); + packerNeutral(pin, eyError(slice, LOCAL), 2); + // Total Ex, Ey + packerNeutral(++pin, ex(slice, TOTAL), s_sumBits); + packerNeutral(pin, exError(slice, TOTAL), 2); + packerNeutral(pin, ey(slice, TOTAL), s_sumBits); + packerNeutral(pin, eyError(slice, TOTAL), 2); + // Remote and Local Et + packerNeutral(++pin, et(slice, REMOTE), s_sumBits-1); + packerNeutral(pin, etError(slice, REMOTE), 3); + packerNeutral(pin, et(slice, LOCAL), s_sumBits-1); + packerNeutral(pin, etError(slice, LOCAL), 3); + // G-Link parity errors + for (int p = 0; p <= pin; ++p) packerNeutralParity(p); + } + return true; +} + +// Pack uncompressed data + +bool CmmEnergySubBlock::packUncompressed() +{ + std::vector<uint32_t>::const_iterator pos; + for (pos = m_sumsData.begin(); pos != m_sumsData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CmmEnergySubBlock::unpackNeutral() +{ + resize(); + int bunchCrossing = 0; + int overflow = 0; + int parity = 0; + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_maxJems; ++pin) { + // JEM energy sums (jem == pin); parity error + const unsigned int ex = unpackerNeutral(pin, s_jemSumBits); + const unsigned int ey = unpackerNeutral(pin, s_jemSumBits); + const unsigned int et = unpackerNeutral(pin, s_jemSumBits); + const int er = unpackerNeutral(pin, 1); + setSubsums(slice, pin, ex, ey, et, er, er, er); + // Bunch crossing number; Fifo overflow + if (pin < s_bunchCrossingBits) { + bunchCrossing |= unpackerNeutral(pin, 1) << pin; + // Padding + unpackerNeutral(pin, s_paddingBits); + } else if (pin == s_fifoOverflowPin) { + overflow |= unpackerNeutral(pin, 1); + } else unpackerNeutral(pin, 1); + } + int pin = s_bunchCrossingBits - 1; + // Missing-ET-Sig Hits Map + setMissingEtSigHits(slice, unpackerNeutral(pin, s_paddingBits)); + // Total Et + unsigned int etTot = unpackerNeutral(++pin, s_paddingBits); + etTot |= unpackerNeutral(++pin, s_paddingBits-1) << s_paddingBits; + const int etErrTot = unpackerNeutral(pin, 1); + // Sum-Et Hits Map + padding + setSumEtHits(slice, unpackerNeutral(++pin, s_paddingBits) & s_etHitsMask); + // Missing-ET Hits Map + setMissingEtHits(slice, unpackerNeutral(++pin, s_paddingBits)); + // Remote Ex, Ey + const unsigned int exRem = unpackerNeutral(++pin, s_sumBits); + const int exErrRem = unpackerNeutral(pin, 2); + const unsigned int eyRem = unpackerNeutral(pin, s_sumBits); + const int eyErrRem = unpackerNeutral(pin, 2); + // Local Ex, Ey + const unsigned int exLoc = unpackerNeutral(++pin, s_sumBits); + const int exErrLoc = unpackerNeutral(pin, 1); + unpackerNeutral(pin, 1); + const unsigned int eyLoc = unpackerNeutral(pin, s_sumBits); + const int eyErrLoc = unpackerNeutral(pin, 1); + unpackerNeutral(pin, 1); + // Total Ex, Ey + const unsigned int exTot = unpackerNeutral(++pin, s_sumBits); + const int exErrTot = unpackerNeutral(pin, 1); + unpackerNeutral(pin, 1); + const unsigned int eyTot = unpackerNeutral(pin, s_sumBits); + const int eyErrTot = unpackerNeutral(pin, 1); + unpackerNeutral(pin, 1); + // Remote and Local Et + const unsigned int etRem = unpackerNeutral(++pin, s_sumBits-1); + const int etErrRem = unpackerNeutral(pin, 2); + unpackerNeutral(pin, 1); + const unsigned int etLoc = unpackerNeutral(pin, s_sumBits-1); + const int etErrLoc = unpackerNeutral(pin, 1); + unpackerNeutral(pin, 2); + setSubsums(slice, REMOTE, exRem, eyRem, etRem, + exErrRem, eyErrRem, etErrRem); + setSubsums(slice, LOCAL, exLoc, eyLoc, etLoc, + exErrLoc, eyErrLoc, etErrLoc); + setSubsums(slice, TOTAL, exTot, eyTot, etTot, + exErrTot, eyErrTot, etErrTot); + // G-Link parity errors + for (int p = 0; p <= pin; ++p) parity |= unpackerNeutralParityError(p); + } + setBunchCrossing(bunchCrossing); + setDaqOverflow(overflow); + setGlinkParity(parity); + + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CmmEnergySubBlock::unpackUncompressed() +{ + resize(); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int source = sourceId(word); + if (source < s_maxSums && m_sumsData[source] == 0) m_sumsData[source] = word; + else { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmEnergySubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmEnergySubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..521a606f687549df06d0fdf535883b914d2eb799 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmEnergySubBlock.h @@ -0,0 +1,129 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMMENERGYSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMMENERGYSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "CmmSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMM-Energy data. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class CmmEnergySubBlock : public CmmSubBlock { + + public: + enum SourceId { REMOTE = 20, LOCAL = 23, TOTAL = 26, MAX_SOURCE_ID }; + + CmmEnergySubBlock(); + ~CmmEnergySubBlock(); + + /// Clear all data + void clear(); + + /// Return Ex subsum for given JEM or source ID + unsigned int ex(int slice, int source) const; + /// Return Ey subsum for given JEM or source ID + unsigned int ey(int slice, int source) const; + /// Return Et subsum for given JEM or source ID + unsigned int et(int slice, int source) const; + /// Return Ex subsum error for given JEM or source ID + int exError(int slice, int source) const; + /// Return Ey subsum error for given JEM or source ID + int eyError(int slice, int source) const; + /// Return Et subsum error for given JEM or source ID + int etError(int slice, int source) const; + /// Return Missing-ET Hits map + unsigned int missingEtHits(int slice) const; + /// Return Sum-Et Hits map + unsigned int sumEtHits(int slice) const; + /// Return Missing-ET-Sig Hits map + unsigned int missingEtSigHits(int slice) const; + + /// Store energy subsums and errors for given JEM or source ID + void setSubsums(int slice, int source, unsigned int ex, + unsigned int ey, unsigned int et, + int exError, int eyError, int etError); + /// Store Missing-ET Hits map + void setMissingEtHits(int slice, unsigned int map); + /// Store Sum-Et Hits map + void setSumEtHits(int slice, unsigned int map); + /// Store Missing-ET-Sig Hits map + void setMissingEtSigHits(int slice, unsigned int map); + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Data word length + static const int s_wordLength = 32; + // Energy subsums bit positions and masks + static const int s_exBit = 0; + static const int s_eyBit = 8; + static const int s_etBit = 16; + static const int s_jemErrorBit = 24; + static const int s_errorBit = 15; + static const int s_etMissBit = 16; + static const int s_etHitsBit = 16; + static const int s_etMissSigBit = 16; + static const int s_sourceIdBit = 25; + static const int s_dataWordIdBit = 30; + static const int s_dataWordId = 0; + static const int s_maxSums = 29; + static const int s_maxJems = 16; + static const uint32_t s_exMask = 0xff; + static const uint32_t s_eyMask = 0xff; + static const uint32_t s_etMask = 0xff; + static const uint32_t s_errorMask = 0x1; + static const uint32_t s_remoteErrorMask = 0x3; + static const uint32_t s_etMissMask = 0xff; + static const uint32_t s_etHitsMask = 0xff; + static const uint32_t s_etHitsMaskV1 = 0xf; + static const uint32_t s_etMissSigMask = 0xff; + static const uint32_t s_sumsMask = 0x7fff; + static const uint32_t s_sourceIdMask = 0x1f; + // Neutral format + static const int s_jemSumBits = 8; + static const int s_sumBits = 15; + static const int s_bunchCrossingBits = 12; + static const int s_paddingBits = 8; + static const int s_fifoOverflowPin = 15; + + int sourceId(uint32_t word) const; + int index(int slice, int source) const; + void resize(); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Energy subsums data + std::vector<uint32_t> m_sumsData; + +}; + +inline int CmmEnergySubBlock::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmJetSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmJetSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..37867c93e0fe46058115049cde7c322c9f52eced --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmJetSubBlock.cxx @@ -0,0 +1,325 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CmmJetSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CmmJetSubBlock::s_wordLength; + +const int CmmJetSubBlock::s_threshBit; +const int CmmJetSubBlock::s_fwdErrorBit; +const int CmmJetSubBlock::s_etMapBit; +const int CmmJetSubBlock::s_threshErrorBit; +const int CmmJetSubBlock::s_sourceIdBit; +const int CmmJetSubBlock::s_dataWordIdBit; +const int CmmJetSubBlock::s_dataWordId; +const int CmmJetSubBlock::s_maxHits; +const uint32_t CmmJetSubBlock::s_threshMask; +const uint32_t CmmJetSubBlock::s_fwdMask; +const uint32_t CmmJetSubBlock::s_etMapMask; +const uint32_t CmmJetSubBlock::s_errorMask; +const uint32_t CmmJetSubBlock::s_sourceIdMask; + +const int CmmJetSubBlock::s_jetHitsBits; +const int CmmJetSubBlock::s_jetHitsErrorBits; +const int CmmJetSubBlock::s_fwdHitsBits; +const int CmmJetSubBlock::s_bunchCrossingBits; +const int CmmJetSubBlock::s_paddingBits; +const int CmmJetSubBlock::s_rightBit; +const int CmmJetSubBlock::s_fifoOverflowPin; + + +CmmJetSubBlock::CmmJetSubBlock() +{ +} + +CmmJetSubBlock::~CmmJetSubBlock() +{ +} + +// Clear all data + +void CmmJetSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_hitsData.clear(); +} + +// Return jet hit counts for given jem or source ID + +unsigned int CmmJetSubBlock::jetHits(const int slice, const int source) const +{ + unsigned int hits = 0; + if (slice >= 0 && slice < timeslices() && + source >= 0 && source < s_maxHits && !m_hitsData.empty()) { + if (source <= TOTAL_MAIN) { + hits = (m_hitsData[index(slice, source)] >> s_threshBit) & s_threshMask; + } else if (source >= REMOTE_FORWARD) { + hits = (m_hitsData[index(slice, source)] >> s_threshBit) & s_fwdMask; + } + } + return hits; +} + +// Return jet hit error for given jem or source ID + +int CmmJetSubBlock::jetHitsError(const int slice, const int source) const +{ + int error = 0; + if (slice >= 0 && slice < timeslices() && + source >= 0 && source < s_maxHits && !m_hitsData.empty()) { + if (source <= TOTAL_MAIN) { + error = (m_hitsData[index(slice, source)] >> s_threshErrorBit) + & s_errorMask; + } else if (source == REMOTE_FORWARD) { + error = (m_hitsData[index(slice, source)] >> s_fwdErrorBit) & s_errorMask; + } + } + return error; +} + +// Return jet ET map + +unsigned int CmmJetSubBlock::jetEtMap(const int slice) const +{ + unsigned int map = 0; + if (slice >= 0 && slice < timeslices() && !m_hitsData.empty()) { + map = (m_hitsData[index(slice, TOTAL_FORWARD)] >> s_etMapBit) & s_etMapMask; + } + return map; +} + +// Store jet hit counts and error for given jem or source ID + +void CmmJetSubBlock::setJetHits(const int slice, const int source, + const unsigned int hits, const int error) +{ + if (slice >= 0 && slice < timeslices() && + source >= 0 && source < s_maxHits && (hits || error)) { + resize(); + uint32_t word = m_hitsData[index(slice, source)]; + if (source <= TOTAL_MAIN) { + word |= (hits & s_threshMask) << s_threshBit; + word |= (error & s_errorMask) << s_threshErrorBit; + } else { + word |= (hits & s_fwdMask) << s_threshBit; + word |= (error & s_errorMask) << s_fwdErrorBit; + } + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= (s_dataWordId) << s_dataWordIdBit; + m_hitsData[index(slice, source)] = word; + } +} + +// Store jet ET map + +void CmmJetSubBlock::setJetEtMap(const int slice, const unsigned int map) +{ + if (slice >= 0 && slice < timeslices() && map) { + resize(); + uint32_t word = m_hitsData[index(slice, TOTAL_FORWARD)]; + word |= (map & s_etMapMask) << s_etMapBit; + word |= (TOTAL_FORWARD & s_sourceIdMask) << s_sourceIdBit; + word |= (s_dataWordId) << s_dataWordIdBit; + m_hitsData[index(slice, TOTAL_FORWARD)] = word; + } +} + +// Packing/Unpacking routines + +bool CmmJetSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CmmJetSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data index appropriate to format + +int CmmJetSubBlock::index(const int slice, const int source) const +{ + int ix = source; + if (format() == NEUTRAL) ix += slice * s_maxHits; + return ix; +} + +// Resize the hits vector according to format + +void CmmJetSubBlock::resize() +{ + if (m_hitsData.empty()) { + int size = s_maxHits; + if (format() == NEUTRAL) size *= timeslices(); + m_hitsData.resize(size); + } +} + +// Pack neutral data + +bool CmmJetSubBlock::packNeutral() +{ + resize(); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin <= TOTAL_MAIN; ++pin) { + // Jem hits; remote, local and total main hits; parity error + packerNeutral(pin, jetHits(slice, pin), s_jetHitsBits); + packerNeutral(pin, jetHitsError(slice, pin), s_jetHitsErrorBits); + // Bunch crossing number; Fifo overflow + if (pin < s_bunchCrossingBits) { + packerNeutral(pin, bunchCrossing() >> pin, 1); + } else if (pin == s_fifoOverflowPin) { + packerNeutral(pin, daqOverflow(), 1); + } else packerNeutral(pin, 0, 1); + // Padding + if (pin < REMOTE_MAIN) packerNeutral(pin, 0, s_paddingBits); + } + // ET Map + padding + packerNeutral(REMOTE_MAIN, jetEtMap(slice), s_paddingBits); + // Total forward (left + right) + packerNeutral(LOCAL_MAIN, jetHits(slice, TOTAL_FORWARD), s_paddingBits); + packerNeutral(TOTAL_MAIN, jetHits(slice, TOTAL_FORWARD) >> s_rightBit, + s_paddingBits); + // Remote + Local forward + const int lastpin = TOTAL_MAIN + 1; + packerNeutral(lastpin, jetHits(slice, REMOTE_FORWARD), s_fwdHitsBits); + packerNeutral(lastpin, jetHitsError(slice, REMOTE_FORWARD), + s_jetHitsErrorBits); + packerNeutral(lastpin, 0, 1); + packerNeutral(lastpin, jetHits(slice, LOCAL_FORWARD), s_fwdHitsBits); + // G-Link parity + for (int pin = 0; pin <= lastpin; ++pin) packerNeutralParity(pin); + } + return true; +} + +// Pack uncompressed data + +bool CmmJetSubBlock::packUncompressed() +{ + std::vector<uint32_t>::const_iterator pos; + for (pos = m_hitsData.begin(); pos != m_hitsData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CmmJetSubBlock::unpackNeutral() +{ + resize(); + int bunchCrossing = 0; + int overflow = 0; + int parity = 0; + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + unsigned int hits = 0; + int error = 0; + for (int pin = 0; pin <= TOTAL_MAIN; ++pin) { + // Jem hits; remote, local and total main hits; parity error + hits = unpackerNeutral(pin, s_jetHitsBits); + error = unpackerNeutral(pin, s_jetHitsErrorBits); + setJetHits(slice, pin, hits, error); + // Bunch crossing number; Fifo overflow + if (pin < s_bunchCrossingBits) { + bunchCrossing |= unpackerNeutral(pin, 1) << pin; + } else if (pin == s_fifoOverflowPin) { + overflow |= unpackerNeutral(pin, 1); + } else unpackerNeutral(pin, 1); + // Padding + if (pin < REMOTE_MAIN) unpackerNeutral(pin, s_paddingBits); + } + // ET Map + padding + setJetEtMap(slice, unpackerNeutral(REMOTE_MAIN, s_paddingBits)); + // Total forward (left + right) + hits = unpackerNeutral(LOCAL_MAIN, s_paddingBits); + hits |= unpackerNeutral(TOTAL_MAIN, s_paddingBits) << s_rightBit; + setJetHits(slice, TOTAL_FORWARD, hits, 0); + // Remote + Local forward + const int lastpin = TOTAL_MAIN + 1; + hits = unpackerNeutral(lastpin, s_fwdHitsBits); + error = unpackerNeutral(lastpin, s_jetHitsErrorBits); + setJetHits(slice, REMOTE_FORWARD, hits, error); + unpackerNeutral(lastpin, 1); + setJetHits(slice, LOCAL_FORWARD, + unpackerNeutral(lastpin, s_fwdHitsBits), 0); + // G-Link parity errors + for (int pin = 0; pin <= lastpin; ++pin) { + parity |= unpackerNeutralParityError(pin); + } + } + setBunchCrossing(bunchCrossing); + setDaqOverflow(overflow); + setGlinkParity(parity); + + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CmmJetSubBlock::unpackUncompressed() +{ + resize(); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int source = sourceId(word); + if (source < s_maxHits && m_hitsData[source] == 0) m_hitsData[source] = word; + else { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmJetSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmJetSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..75a00b3cecad5dc73f51b55388241959be4dc671 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmJetSubBlock.h @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMMJETSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMMJETSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "CmmSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMM-Jet data. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class CmmJetSubBlock : public CmmSubBlock { + + public: + enum SourceId { REMOTE_MAIN = 16, LOCAL_MAIN = 17, TOTAL_MAIN = 18, + REMOTE_FORWARD = 20, LOCAL_FORWARD = 21, TOTAL_FORWARD = 22, + MAX_SOURCE_ID }; + + CmmJetSubBlock(); + ~CmmJetSubBlock(); + + /// Clear all data + void clear(); + + /// Return jet hit counts for given jem or source ID + unsigned int jetHits(int slice, int source) const; + /// Return jet hit error for given jem or source ID + int jetHitsError(int slice, int source) const; + /// Return jet ET map + unsigned int jetEtMap(int slice) const; + + /// Store jet hit counts and error for given jem or source ID + void setJetHits(int slice, int source, unsigned int hits, + int error); + /// Store jet ET map + void setJetEtMap(int slice, unsigned int map); + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Data word length + static const int s_wordLength = 32; + // Jet hit counts bit positions and masks + static const int s_threshBit = 0; + static const int s_fwdErrorBit = 16; + static const int s_etMapBit = 17; + static const int s_threshErrorBit = 24; + static const int s_sourceIdBit = 25; + static const int s_dataWordIdBit = 30; + static const int s_dataWordId = 0; + static const int s_maxHits = 23; + static const uint32_t s_threshMask = 0xffffff; + static const uint32_t s_fwdMask = 0xffff; + static const uint32_t s_etMapMask = 0xf; + static const uint32_t s_errorMask = 0x1; + static const uint32_t s_sourceIdMask = 0x1f; + // Neutral format + static const int s_jetHitsBits = 24; + static const int s_jetHitsErrorBits = 1; + static const int s_fwdHitsBits = 16; + static const int s_bunchCrossingBits = 12; + static const int s_paddingBits = 8; + static const int s_rightBit = 8; + static const int s_fifoOverflowPin = 15; + + int sourceId(uint32_t word) const; + int index(int slice, int source) const; + void resize(); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// JEM hits and sums data + std::vector<uint32_t> m_hitsData; + +}; + +inline int CmmJetSubBlock::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..48dd020e451e71fea3dc44fe4f4b748e275a3859 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmSubBlock.cxx @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CmmSubBlock.h" + +namespace LVL1BS { + +// Static constant definitions + +const int CmmSubBlock::s_wordIdVal; + +const int CmmSubBlock::s_cmmSummingBit; +const int CmmSubBlock::s_cmmFirmwareBit; +const int CmmSubBlock::s_cmmPositionBit; +const uint32_t CmmSubBlock::s_cmmSummingMask; +const uint32_t CmmSubBlock::s_cmmFirmwareMask; +const uint32_t CmmSubBlock::s_cmmPositionMask; + +const int CmmSubBlock::s_glinkBitsPerSlice; + +CmmSubBlock::CmmSubBlock() +{ +} + +CmmSubBlock::~CmmSubBlock() +{ +} + +// Store CMM header + +void CmmSubBlock::setCmmHeader(const int version, const int format, + const int slice, const int crate, + const int summing, const int firmware, + const int position, const int timeslices) +{ + int module = 0; + module |= (summing & s_cmmSummingMask) << s_cmmSummingBit; + module |= (firmware & s_cmmFirmwareMask) << s_cmmFirmwareBit; + module |= (position & s_cmmPositionMask) << s_cmmPositionBit; + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, + timeslices); +} + +// Return number of timeslices + +int CmmSubBlock::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Static function to determine CMM type + +CmmSubBlock::CmmFirmwareCode CmmSubBlock::cmmType(const uint32_t word) +{ + CmmFirmwareCode type; + const int module = L1CaloSubBlock::module(word); + const int code = (module >> s_cmmFirmwareBit) & s_cmmFirmwareMask; + switch (code) { + case CMM_CP: + type = CMM_CP; + break; + case CMM_JET: + type = CMM_JET; + break; + case CMM_ENERGY: + type = CMM_ENERGY; + break; + default: + type = CMM_UNKNOWN; + break; + } + return type; +} + +// Static function to determine if header word corresponds to CMM block + +bool CmmSubBlock::cmmBlock(const uint32_t word) +{ + return L1CaloSubBlock::wordId(word) == s_wordIdVal; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..71c009c5dfb1f9bc50fc4f54888bf820900f73cb --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmmSubBlock.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMMSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMMSUBBLOCK_H + +#include <stdint.h> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMM data. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class CmmSubBlock : public L1CaloSubBlock { + + public: + enum CmmFirmwareCode { CMM_CP = 0, CMM_JET = 1, CMM_ENERGY = 2, + CMM_UNKNOWN = 3 }; + enum CmmSummingCode { CRATE = 0, SYSTEM = 1 }; + enum CmmPositions { LEFT = 0, RIGHT = 1 }; + + CmmSubBlock(); + ~CmmSubBlock(); + + /// Store CMM header + void setCmmHeader(int version, int format, int slice, int crate, + int summing, int firmware, int position, int timeslices); + + // Return CMM specific header data + int cmmSumming() const; + int cmmFirmware() const; + int cmmPosition() const; + int timeslices() const; + + /// CMM differentiation (CMM_CP, CMM_JET, or CMM_ENERGY) + static CmmFirmwareCode cmmType(uint32_t word); + /// Determine if header word corresponds to CMM + static bool cmmBlock(uint32_t word); + + private: + /// CMM header word ID + static const int s_wordIdVal = 0xe; + // CMM fields packed in module field + static const int s_cmmSummingBit = 3; + static const int s_cmmFirmwareBit = 1; + static const int s_cmmPositionBit = 0; + static const uint32_t s_cmmSummingMask = 0x1; + static const uint32_t s_cmmFirmwareMask = 0x3; + static const uint32_t s_cmmPositionMask = 0x1; + /// Needed for neutral format + static const int s_glinkBitsPerSlice = 35; + +}; + +inline int CmmSubBlock::cmmSumming() const +{ + return (module() >> s_cmmSummingBit) & s_cmmSummingMask; +} + +inline int CmmSubBlock::cmmFirmware() const +{ + return (module() >> s_cmmFirmwareBit) & s_cmmFirmwareMask; +} + +inline int CmmSubBlock::cmmPosition() const +{ + return (module() >> s_cmmPositionBit) & s_cmmPositionMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxCpSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxCpSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..5ccd5ce3954c09f50cb44cab8443b250dc649608 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxCpSubBlock.cxx @@ -0,0 +1,618 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CmxCpSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CmxCpSubBlock::s_wordLength; + +const int CmxCpSubBlock::s_tobEnergyBit; +const int CmxCpSubBlock::s_tobIsolationBit; +const int CmxCpSubBlock::s_tobErrorBit; +const int CmxCpSubBlock::s_tobOverflowBit; +const int CmxCpSubBlock::s_tobCoordBit; +const int CmxCpSubBlock::s_tobChipBit; +const int CmxCpSubBlock::s_tobCpmBit; +const int CmxCpSubBlock::s_tobWordId; +const uint32_t CmxCpSubBlock::s_tobEnergyMask; +const uint32_t CmxCpSubBlock::s_tobIsolationMask; +const uint32_t CmxCpSubBlock::s_tobErrorMask; +const uint32_t CmxCpSubBlock::s_tobCoordMask; +const uint32_t CmxCpSubBlock::s_tobChipMask; +const uint32_t CmxCpSubBlock::s_tobCpmMask; + +const int CmxCpSubBlock::s_threshBit; +const int CmxCpSubBlock::s_threshErrorBit; +const int CmxCpSubBlock::s_hlFlagBit; +const int CmxCpSubBlock::s_sourceIdBit; +const int CmxCpSubBlock::s_dataWordIdBit; +const int CmxCpSubBlock::s_threshWordId; +const uint32_t CmxCpSubBlock::s_threshMask; +const uint32_t CmxCpSubBlock::s_errorMask; +const uint32_t CmxCpSubBlock::s_hlFlagMask; +const uint32_t CmxCpSubBlock::s_sourceIdMask; +const uint32_t CmxCpSubBlock::s_dataWordIdMask; + +const int CmxCpSubBlock::s_presenceBits; +const int CmxCpSubBlock::s_coordBits; +const int CmxCpSubBlock::s_isolationBits; +const int CmxCpSubBlock::s_parityErrorBits; +const int CmxCpSubBlock::s_parityErrorMask; +const int CmxCpSubBlock::s_energyBits; +const int CmxCpSubBlock::s_hitsBits; +const int CmxCpSubBlock::s_hitsErrorBits; +const int CmxCpSubBlock::s_roiOverflowBits; +const int CmxCpSubBlock::s_paddingBits; +const int CmxCpSubBlock::s_bunchCrossingBits; +const int CmxCpSubBlock::s_fifoOverflowBits; +const int CmxCpSubBlock::s_topoChecksumBits; +const int CmxCpSubBlock::s_topoMapBits; +const int CmxCpSubBlock::s_topoCountsBits; +const int CmxCpSubBlock::s_topoPaddingBits; +const int CmxCpSubBlock::s_glinkPins; +const int CmxCpSubBlock::s_modules; +const int CmxCpSubBlock::s_tobsPerModule; +const int CmxCpSubBlock::s_muxPhases; + + +CmxCpSubBlock::CmxCpSubBlock() +{ +} + +CmxCpSubBlock::~CmxCpSubBlock() +{ +} + +// Clear all data + +void CmxCpSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_tobData.clear(); + m_hitsData.clear(); + m_presenceMaps.clear(); + m_overflow.clear(); +} + +// Return presence map for given CPM + +unsigned int CmxCpSubBlock::presenceMap(const int slice, + const int cpm) const +{ + unsigned int map = 0; + const unsigned int ix = mapIndex(slice, cpm); + if (ix < m_presenceMaps.size()) map = m_presenceMaps[ix]; + return map; +} + +// Return chip for given cpm and tob + +int CmxCpSubBlock::chip(const int slice, const int cpm, const int tob) const +{ + int ch = 0; + const unsigned int ix = tobIndex(slice, cpm, tob); + if (ix < m_tobData.size()) { + ch = (m_tobData[ix] >> s_tobChipBit) & s_tobChipMask; + } + return ch; +} + +// Return Local coordinate for given cpm and tob + +int CmxCpSubBlock::localCoord(const int slice, const int cpm, const int tob) const +{ + int coord = 0; + const unsigned int ix = tobIndex(slice, cpm, tob); + if (ix < m_tobData.size()) { + coord = (m_tobData[ix] >> s_tobCoordBit) & s_tobCoordMask; + } + return coord; +} + +// Return isolation for given cpm and tob + +int CmxCpSubBlock::isolation(const int slice, const int cpm, const int tob) const +{ + int isol = 0; + const unsigned int ix = tobIndex(slice, cpm, tob); + if (ix < m_tobData.size()) { + isol = (m_tobData[ix] >> s_tobIsolationBit) & s_tobIsolationMask; + } + return isol; +} + +// Return energy for given cpm and tob + +int CmxCpSubBlock::energy(const int slice, const int cpm, const int tob) const +{ + int et = 0; + const unsigned int ix = tobIndex(slice, cpm, tob); + if (ix < m_tobData.size()) { + et = (m_tobData[ix] >> s_tobEnergyBit) & s_tobEnergyMask; + } + return et; +} + +// Return error bits for given cpm and tob + +int CmxCpSubBlock::tobError(int slice, int cpm, int tob) const +{ + int error = 0; + const unsigned int ix = tobIndex(slice, cpm, tob); + if (ix < m_tobData.size()) { + error = (m_tobData[ix] >> s_tobErrorBit) & s_tobErrorMask; + } + return error; +} + +// Return hit/topo counts for given source ID and HL flag + +unsigned int CmxCpSubBlock::hits(const int slice, const int source, + const int flag) const +{ + unsigned int hits = 0; + const unsigned int ix = hitIndex(slice, source, flag); + if (ix < m_hitsData.size()) { + hits = (m_hitsData[ix] >> s_threshBit) & s_threshMask; + } + return hits; +} + +// Return hit error for given source ID and HL flag + +int CmxCpSubBlock::hitsError(const int slice, const int source, + const int flag) const +{ + int error = 0; + const unsigned int ix = hitIndex(slice, source, flag); + if (ix < m_hitsData.size()) { + error = (m_hitsData[ix] >> s_threshErrorBit) & s_errorMask; + } + return error; +} + +// Return RoI overflow for given source ID + +int CmxCpSubBlock::roiOverflow(const int slice, const int source) const +{ + int overflow = 0; + const unsigned int ix = ovfIndex(slice, source); + if (ix < m_overflow.size()) overflow = m_overflow[ix]; + return overflow; +} + +// Store presence map + +void CmxCpSubBlock::setPresenceMap(const int slice, const int cpm, + const unsigned int map) +{ + resize(); + if (map) { + const unsigned int ix = mapIndex(slice, cpm); + if (ix < m_presenceMaps.size()) m_presenceMaps[ix] = map; + } +} + +// Store TOB (RoI) data for given CPM, chip, local coord + +void CmxCpSubBlock::setTob(const int slice, const int cpm, const int chip, + const int loc, const int energy, const int isol, + const int error) +{ + resize(); + if (energy || isol || error) { + uint32_t word = 0; + word |= (energy & s_tobEnergyMask) << s_tobEnergyBit; + word |= (isol & s_tobIsolationMask) << s_tobIsolationBit; + word |= (error & s_tobErrorMask) << s_tobErrorBit; + word |= (loc & s_tobCoordMask) << s_tobCoordBit; + word |= (chip & s_tobChipMask) << s_tobChipBit; + word |= (cpm & s_tobCpmMask) << s_tobCpmBit; + word |= (s_tobWordId) << s_dataWordIdBit; + // Order by chip == presence bit // <<== CHECK + for (int tob = 0; tob < s_tobsPerModule; ++tob) { + const unsigned int ix = tobIndex(slice, cpm, tob); + if (m_tobData[ix] == 0) { + m_tobData[ix] = word; + break; + } else { + const int chipOld = (m_tobData[ix]>>s_tobChipBit)&s_tobChipMask; + if (chip < chipOld) { + for (int i = s_tobsPerModule-tob-1; i > 0; --i) { + m_tobData[ix + i] = m_tobData[ix + i - 1]; + } + m_tobData[ix] = word; + break; + } + } + } + } +} + +// Store hit counts for given source ID and HL flag + +void CmxCpSubBlock::setHits(const int slice, const int source, const int flag, + const unsigned int hits, const int error) +{ + resize(); + const unsigned int ix = hitIndex(slice, source, flag); + if (ix < m_hitsData.size() && (hits || error)) { + uint32_t word = m_hitsData[ix]; + word |= (hits & s_threshMask) << s_threshBit; + word |= (error & s_errorMask) << s_threshErrorBit; + word |= (flag & s_hlFlagMask) << s_hlFlagBit; + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= (s_threshWordId) << s_dataWordIdBit; + m_hitsData[ix] = word; + } +} + +// Store RoI overflow for given source ID + +void CmxCpSubBlock::setRoiOverflow(const int slice, const int source, + const int overflow) +{ + resize(); + if (overflow) { + const unsigned int ix = ovfIndex(slice, source); + if (ix < m_overflow.size()) m_overflow[ix] = overflow; + } +} + +// Packing/Unpacking routines + +bool CmxCpSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CmxCpSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return presence map index appropriate to format + +unsigned int CmxCpSubBlock::mapIndex(const int slice, + const int cpm) const +{ + unsigned int ix = cpm - 1; + if (format() == NEUTRAL) ix += slice * s_modules; + return ix; +} + +// Return tob data index appropriate to format + +unsigned int CmxCpSubBlock::tobIndex(const int slice, const int cpm, + const int tob) const +{ + unsigned int ix = (cpm - 1) * s_tobsPerModule + tob; + if (format() == NEUTRAL) ix += slice * s_modules * s_tobsPerModule; + return ix; +} + +// Return hits data index appropriate to format + +unsigned int CmxCpSubBlock::hitIndex(const int slice, const int source, + const int flag) const +{ + unsigned int ix = (source<<1)|flag; + if (format() == NEUTRAL) ix += slice * 2 * MAX_SOURCE_ID; + return ix; +} + +// Return overflow index appropriate to format + +unsigned int CmxCpSubBlock::ovfIndex(const int slice, const int source) const +{ + unsigned int ix = source; + if (format() == NEUTRAL) ix += slice * MAX_SOURCE_ID; + return ix; +} + +// Resize the data vectors according to format + +void CmxCpSubBlock::resize() +{ + if (m_tobData.empty()) { + int size1 = s_modules * s_tobsPerModule; + int size2 = 2 * MAX_SOURCE_ID; + int size3 = s_modules; + int size4 = MAX_SOURCE_ID; + if (format() == NEUTRAL) { + size1 *= timeslices(); + size2 *= timeslices(); + size3 *= timeslices(); + size4 *= timeslices(); + } + m_tobData.resize(size1); + m_hitsData.resize(size2); + m_presenceMaps.resize(size3); + m_overflow.resize(size4); + } +} + +// Pack neutral data + +bool CmxCpSubBlock::packNeutral() +{ + resize(); + std::vector<int> locVec(s_tobsPerModule); + std::vector<int> isolVec(s_tobsPerModule); + std::vector<int> parityVec(s_muxPhases); + std::vector<int> energyVec(s_tobsPerModule); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (pin < s_modules) { // TOB data + const int cpm = pin + 1; + // Presence map + packerNeutral(pin, presenceMap(slice, cpm), s_presenceBits); + // Get tob data for this cpm + locVec.clear(); + isolVec.clear(); + parityVec.clear(); + energyVec.clear(); + int parityMerge = 0; + for (int tob = 0; tob < s_tobsPerModule; ++tob) { + locVec.push_back(localCoord(slice, cpm, tob)); + isolVec.push_back(isolation(slice, cpm, tob)); + energyVec.push_back(energy(slice, cpm, tob)); + if (tob == 0) { + const int err = tobError(slice, cpm, tob); + parityMerge = err&s_parityErrorMask; + for (int mux = 0; mux < s_muxPhases; ++mux) { + parityVec.push_back((err>>(mux+s_parityErrorBits))&s_parityErrorMask); + } + } + } + // And pack + int locCount = 0; + int isolCount = 0; + int parityCount = 0; + int energyCount = 0; + for (int tob = 0; tob < s_tobsPerModule-2; ++tob) { + // Local coordinates (2 bit) + packerNeutral(pin, locVec[locCount++], s_coordBits); + // isolation + packerNeutral(pin, isolVec[isolCount++], s_isolationBits); + // backplane parity error + packerNeutral(pin, parityVec[parityCount++], s_parityErrorBits); + // energy + packerNeutral(pin, energyVec[energyCount++], s_energyBits); + if (tob < s_tobsPerModule-3) { + packerNeutral(pin, energyVec[energyCount++], s_energyBits); + } else { + packerNeutral(pin, locVec[locCount++], s_coordBits); + packerNeutral(pin, isolVec[isolCount++], s_isolationBits); + packerNeutral(pin, parityMerge, s_parityErrorBits); + packerNeutral(pin, locVec[locCount++], s_coordBits); + packerNeutral(pin, isolVec[isolCount++], s_isolationBits); + packerNeutral(pin, parityVec[parityCount++], s_parityErrorBits); + } + } + } else { // Hits and Topo data + if (pin < s_glinkPins-1) { + // Remote(3), local and total hits; parity error + const int source = pin - s_modules; + packerNeutral(pin, hits(slice, source, 0), s_hitsBits); + packerNeutral(pin, hitsError(slice, source, 0), s_hitsErrorBits); + packerNeutral(pin, hits(slice, source, 1), s_hitsBits); + packerNeutral(pin, hitsError(slice, source, 1), s_hitsErrorBits); + packerNeutral(pin, roiOverflow(slice, source), s_hitsErrorBits); + packerNeutral(pin, 0, s_paddingBits); + } else { + // Bunch crossing number, Fifo overflow and Topo data + packerNeutral(pin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(pin, daqOverflow(), s_fifoOverflowBits); + packerNeutral(pin, hits(slice, TOPO_CHECKSUM, 0), s_topoChecksumBits); + packerNeutral(pin, hits(slice, TOPO_OCCUPANCY_MAP, 0), s_topoMapBits); + packerNeutral(pin, hits(slice, TOPO_OCCUPANCY_COUNTS, 0), s_topoCountsBits); + packerNeutral(pin, hits(slice, TOPO_OCCUPANCY_COUNTS, 1), s_topoCountsBits); + packerNeutral(pin, 0, s_topoPaddingBits); + } + } + // G-Link parity + packerNeutralParity(pin); + } + } + return true; +} + +// Pack uncompressed data + +bool CmxCpSubBlock::packUncompressed() +{ + std::vector<uint32_t>::const_iterator pos; + for (pos = m_tobData.begin(); pos != m_tobData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + for (pos = m_hitsData.begin(); pos != m_hitsData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CmxCpSubBlock::unpackNeutral() +{ + resize(); + int bunchCrossing = 0; + int fifoOverflow = 0; + int glinkParity = 0; + std::vector<int> locVec(s_tobsPerModule); + std::vector<int> isolVec(s_tobsPerModule); + std::vector<int> parityVec(s_muxPhases); + std::vector<int> energyVec(s_tobsPerModule); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (pin < s_modules) { // TOB data + // Presence map + const unsigned int map = unpackerNeutral(pin, s_presenceBits); + locVec.clear(); + isolVec.clear(); + parityVec.clear(); + energyVec.clear(); + int parityMerge = 0; + for (int tob = 0; tob < s_tobsPerModule-2; ++tob) { + // Local coordinates (2 bit) + locVec.push_back(unpackerNeutral(pin, s_coordBits)); + // isolation + isolVec.push_back(unpackerNeutral(pin, s_isolationBits)); + // backplane parity error + parityVec.push_back(unpackerNeutral(pin, s_parityErrorBits)); + // energy + energyVec.push_back(unpackerNeutral(pin, s_energyBits)); + if (tob < s_tobsPerModule-3) { + energyVec.push_back(unpackerNeutral(pin, s_energyBits)); + } else { + locVec.push_back(unpackerNeutral(pin, s_coordBits)); + isolVec.push_back(unpackerNeutral(pin, s_isolationBits)); + parityMerge = unpackerNeutral(pin, s_parityErrorBits); + locVec.push_back(unpackerNeutral(pin, s_coordBits)); + isolVec.push_back(unpackerNeutral(pin, s_isolationBits)); + parityVec.push_back(unpackerNeutral(pin, s_parityErrorBits)); + } + } + int ntobs = 0; + for (int bit = 0; bit < s_presenceBits; ++bit) ntobs += (map>>bit)&1; + int error = parityMerge; + for (int mux = 0; mux < s_muxPhases; ++mux) { + error |= (parityVec[mux]<<(mux+s_parityErrorBits)); + } + if (ntobs > s_tobsPerModule) error |= (1<<(s_muxPhases+s_parityErrorBits)); // overflow + int tob = 0; + const int cpm = pin + 1; + for (int chip = 0; chip < s_presenceBits && tob < s_tobsPerModule; ++chip) { // <<== CHECK - assuming bit==chip + if ((map>>chip)&1) { + setTob(slice, cpm, chip, locVec[tob], energyVec[tob], isolVec[tob], error); + ++tob; + } + } + setPresenceMap(slice, cpm, map); + } else { // Hits and Topo data + if (pin < s_glinkPins-1) { + // Remote(3), local and total hits; parity error + const int source = pin - s_modules; + unsigned int hits = unpackerNeutral(pin, s_hitsBits); + int error = unpackerNeutral(pin, s_hitsErrorBits); + setHits(slice, source, 0, hits, error); + hits = unpackerNeutral(pin, s_hitsBits); + error = unpackerNeutral(pin, s_hitsErrorBits); + setHits(slice, source, 1, hits, error); + error = unpackerNeutral(pin, s_hitsErrorBits); + setRoiOverflow(slice, source, error); + unpackerNeutral(pin, s_paddingBits); + } else { + // Bunch crossing number, Fifo overflow and Topo data + bunchCrossing = unpackerNeutral(pin, s_bunchCrossingBits); + fifoOverflow |= unpackerNeutral(pin, s_fifoOverflowBits); + unsigned int hits = unpackerNeutral(pin, s_topoChecksumBits); + int error = 0; + setHits(slice, TOPO_CHECKSUM, 0, hits, error); + hits = unpackerNeutral(pin, s_topoMapBits); + setHits(slice, TOPO_OCCUPANCY_MAP, 0, hits, error); + hits = unpackerNeutral(pin, s_topoCountsBits); + setHits(slice, TOPO_OCCUPANCY_COUNTS, 0, hits, error); + hits = unpackerNeutral(pin, s_topoCountsBits); + setHits(slice, TOPO_OCCUPANCY_COUNTS, 1, hits, error); + unpackerNeutral(pin, s_topoPaddingBits); + } + } + // G-Link parity errors + glinkParity |= unpackerNeutralParityError(pin); + } + } + setBunchCrossing(bunchCrossing); + setDaqOverflow(fifoOverflow); + setGlinkParity(glinkParity); + + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CmxCpSubBlock::unpackUncompressed() +{ + resize(); + const int maxHits = m_hitsData.size(); + m_cpmTobCount.assign(s_modules, 0); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataWordId(word); + if (id == s_tobWordId) { // TOB data + const int index = cpm(word)-1; + const int count = m_cpmTobCount[index]; + const int index2 = index*s_tobsPerModule + count; + if (count < s_tobsPerModule) { + m_tobData[index2] = word; + ++m_cpmTobCount[index]; + } else { + setUnpackErrorCode(UNPACK_EXCESS_TOBS); // New code. Check consequences + return false; + } + } else if (id == s_threshWordId) { // Hits and Topo data + const int index = (sourceId(word)<<1) | hlFlag(word); + if (index < maxHits && m_hitsData[index] == 0) { + m_hitsData[index] = word; + } else { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + } else { + setUnpackErrorCode(UNPACK_DATA_ID); // New code + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxCpSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxCpSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..87b886a94d9f498af3c6041f8c3fe625daee9c34 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxCpSubBlock.h @@ -0,0 +1,178 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMXCPSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMXCPSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "CmxSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMX-CP data post LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx <<== CHECK + * + * @author Peter Faulkner + */ + +class CmxCpSubBlock : public CmxSubBlock { + + public: + + /// Sources of threshold sums + enum SourceId { REMOTE_0, REMOTE_1, REMOTE_2, LOCAL, TOTAL, + TOPO_CHECKSUM, TOPO_OCCUPANCY_MAP, TOPO_OCCUPANCY_COUNTS, + MAX_SOURCE_ID }; + + CmxCpSubBlock(); + ~CmxCpSubBlock(); + + /// Clear all data + void clear(); + + /// Return presence map for given CPM + unsigned int presenceMap(int slice, int cpm) const; + /// Return chip for given cpm and tob + int chip(int slice, int cpm, int tob) const; + /// Return Local coordinate for given cpm and tob + int localCoord(int slice, int cpm, int tob) const; + /// Return isolation for given cpm and tob + int isolation(int slice, int cpm, int tob) const; + /// Return energy for given cpm and tob + int energy(int slice, int cpm, int tob) const; + /// Return error bits for given cpm and tob + int tobError(int slice, int cpm, int tob) const; + /// Return hit/topo counts for given source ID and HL flag + unsigned int hits(int slice, int source, int flag) const; + /// Return hit error for given source ID and HL flag + int hitsError(int slice, int source, int flag) const; + /// Return RoI overflow for given source ID + int roiOverflow(int slice, int source) const; + + /// Store presence map + void setPresenceMap(int slice, int cpm, unsigned int map); + /// Store TOB (RoI) data for given CPM, chip, local coord + void setTob(int slice, int cpm, int chip, int loc, // NB chip and loc 4 and 2 bits here, as in diagram + int energy, int isol, int error); + /// Store hit counts for given source ID and HL flag + void setHits(int slice, int source, int flag, unsigned int hits, int error); + /// Store RoI overflow for given source ID + void setRoiOverflow(int slice, int source, int overflow); + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Data word length + static const int s_wordLength = 32; + // TOB bit positions and masks + static const int s_tobEnergyBit = 0; + static const int s_tobIsolationBit = 8; + static const int s_tobErrorBit = 13; + static const int s_tobOverflowBit = 18; + static const int s_tobCoordBit = 19; + static const int s_tobChipBit = 21; + static const int s_tobCpmBit = 25; + static const int s_tobWordId = 0; + static const uint32_t s_tobEnergyMask = 0xff; + static const uint32_t s_tobIsolationMask = 0x1f; + static const uint32_t s_tobErrorMask = 0x3f; // includes RoI overflow + static const uint32_t s_tobCoordMask = 0x3; + static const uint32_t s_tobChipMask = 0xf; + static const uint32_t s_tobCpmMask = 0xf; + // EM/Tau hit and topo counts bit positions and masks + static const int s_threshBit = 0; + static const int s_threshErrorBit = 24; + static const int s_hlFlagBit = 25; + static const int s_sourceIdBit = 26; + static const int s_dataWordIdBit = 29; + static const int s_threshWordId = 1; + static const uint32_t s_threshMask = 0xffffff; + static const uint32_t s_errorMask = 0x1; + static const uint32_t s_hlFlagMask = 0x1; + static const uint32_t s_sourceIdMask = 0x7; + static const uint32_t s_dataWordIdMask = 0x7; + // Neutral format + static const int s_presenceBits = 16; + static const int s_coordBits = 2; + static const int s_isolationBits = 5; + static const int s_parityErrorBits = 1; + static const int s_parityErrorMask = 0x1; + static const int s_energyBits = 8; + static const int s_hitsBits = 24; + static const int s_hitsErrorBits = 1; + static const int s_roiOverflowBits = 1; + static const int s_paddingBits = 45; + static const int s_bunchCrossingBits = 12; + static const int s_fifoOverflowBits = 1; + static const int s_topoChecksumBits = 16; + static const int s_topoMapBits = 14; + static const int s_topoCountsBits = 21; + static const int s_topoPaddingBits = 11; + static const int s_glinkPins = 20; + static const int s_modules = 14; + static const int s_tobsPerModule = 5; + static const int s_muxPhases = 4; + + int dataWordId(uint32_t word) const; + int sourceId(uint32_t word) const; + int cpm(uint32_t word) const; + int hlFlag(uint32_t word) const; + unsigned int mapIndex(int slice, int cpm) const; + unsigned int tobIndex(int slice, int cpm, int tob) const; + unsigned int hitIndex(int slice, int source, int flag) const; + unsigned int ovfIndex(int slice, int source) const; + void resize(); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// TOB data + std::vector<uint32_t> m_tobData; + /// Hits and topo data + std::vector<uint32_t> m_hitsData; + /// Presence maps + std::vector<unsigned int> m_presenceMaps; + /// CPM TOB count vector for unpacking + std::vector<int> m_cpmTobCount; + /// RoI overflows for neutral data + std::vector<int> m_overflow; + +}; + +inline int CmxCpSubBlock::dataWordId(const uint32_t word) const +{ + return (word >> s_dataWordIdBit) & s_dataWordIdMask; +} + +inline int CmxCpSubBlock::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +inline int CmxCpSubBlock::cpm(const uint32_t word) const +{ + return (word >> s_tobCpmBit) & s_tobCpmMask; +} + +inline int CmxCpSubBlock::hlFlag(const uint32_t word) const +{ + return (word >> s_hlFlagBit) & s_hlFlagMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxEnergySubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxEnergySubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..384af45046ba4b6a83d500406f9f9d45848b9afe --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxEnergySubBlock.cxx @@ -0,0 +1,597 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <utility> + +#include "CmxEnergySubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CmxEnergySubBlock::s_wordLength; + +const int CmxEnergySubBlock::s_overflowBit; +const int CmxEnergySubBlock::s_errorBit; +const int CmxEnergySubBlock::s_etHitsBit; +const int CmxEnergySubBlock::s_energyTypeJemBit; +const int CmxEnergySubBlock::s_jemBit; +const int CmxEnergySubBlock::s_energyTypeBit; +const int CmxEnergySubBlock::s_sumTypeBit; +const int CmxEnergySubBlock::s_sourceBit; +const int CmxEnergySubBlock::s_wordIdBit; +const int CmxEnergySubBlock::s_maxJems; +const int CmxEnergySubBlock::s_maxSums; +const uint32_t CmxEnergySubBlock::s_energyJemMask; +const uint32_t CmxEnergySubBlock::s_energySumMask; +const uint32_t CmxEnergySubBlock::s_errorMask; +const uint32_t CmxEnergySubBlock::s_overflowMask; +const uint32_t CmxEnergySubBlock::s_etHitsMask; +const uint32_t CmxEnergySubBlock::s_jemMask; +const uint32_t CmxEnergySubBlock::s_energyTypeMask; +const uint32_t CmxEnergySubBlock::s_sumTypeMask; +const uint32_t CmxEnergySubBlock::s_sourceMask; +const uint32_t CmxEnergySubBlock::s_wordIdMask; + +const int CmxEnergySubBlock::s_jemSumBits; +const int CmxEnergySubBlock::s_jemPaddingBits; +const int CmxEnergySubBlock::s_sumBitsEtCrate; +const int CmxEnergySubBlock::s_sumBitsEtSys; +const int CmxEnergySubBlock::s_sumBitsExEy; +const int CmxEnergySubBlock::s_bunchCrossingBits; +const int CmxEnergySubBlock::s_etHitMapsBits; +const int CmxEnergySubBlock::s_paddingBits; + + +CmxEnergySubBlock::CmxEnergySubBlock() +{ +} + +CmxEnergySubBlock::~CmxEnergySubBlock() +{ +} + +// Clear all data + +void CmxEnergySubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_sumsData.clear(); +} + +// Return energy subsum for given JEM and energy type + +unsigned int CmxEnergySubBlock::energy(const int slice, const int jem, + const EnergyType eType) const +{ + unsigned int e = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (jem >= 0 && jem < s_maxJems) { + e = m_sumsData[index(slice, jem) + eType] & s_energyJemMask; + } + } + return e; +} + +// Return energy subsum error for given JEM and energy type + +int CmxEnergySubBlock::error(const int slice, const int jem, + const EnergyType eType) const +{ + int parity = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + if (jem >= 0 && jem < s_maxJems) { + parity = (m_sumsData[index(slice, jem) + eType] >> s_errorBit) + & s_errorMask; + } + } + return parity<<1; +} + +// Return energy subsum for given source, sum type and energy type + +unsigned int CmxEnergySubBlock::energy(const int slice, + const SourceType source, + const SumType sType, + const EnergyType eType) const +{ + unsigned int e = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + const int pos = s_maxJems + 2*source + sType; + e = m_sumsData[index(slice, pos) + eType] & s_energySumMask; + } + return e; +} + +// Return energy subsum error for given source, sum type and energy type + +int CmxEnergySubBlock::error(const int slice, + const SourceType source, + const SumType sType, + const EnergyType eType) const +{ + int parity = 0; + int overflow = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + const int pos = s_maxJems + 2*source + sType; + const uint32_t word = m_sumsData[index(slice, pos) + eType]; + overflow = (word >> s_overflowBit) & s_overflowMask; + if (source == REMOTE) parity = (word >> s_errorBit) & s_errorMask; + } + return (parity<<1) + overflow; +} + +// Return hits map for given hits type and sum type + +unsigned int CmxEnergySubBlock::hits(const int slice, + const HitsType hType, + const SumType sType) const +{ + unsigned int map = 0; + if (slice >= 0 && slice < timeslices() && !m_sumsData.empty()) { + const int pos = s_maxJems + 2*TOTAL + sType; + map = (m_sumsData[index(slice, pos) + hType] >> s_etHitsBit) + & s_etHitsMask; + } + return map; +} + +// Store energy subsums and errors for given JEM + +void CmxEnergySubBlock::setSubsums(const int slice, const int jem, + const unsigned int ex, const unsigned int ey, + const unsigned int et, const int exError, + const int eyError, const int etError) +{ + if (slice >= 0 && slice < timeslices() && jem >= 0 && jem < s_maxJems) { + resize(); + const int ix = index(slice, jem); + unsigned int energy = 0; + int error = 0; + int parity = 0; + uint32_t word = 0; + for (int eType = 0; eType < MAX_ENERGY_TYPE; ++eType) { + if (eType == ENERGY_EX) { + energy = ex; + error = exError; + } else if (eType == ENERGY_EY) { + energy = ey; + error = eyError; + } else { + energy = et; + error = etError; + } + parity = (error >> 1) & s_errorMask; + if (energy || parity) { + word = energy & s_energyJemMask; + word |= parity << s_errorBit; + word |= eType << s_energyTypeJemBit; + word |= jem << s_jemBit; + word |= MODULE_ID << s_wordIdBit; + m_sumsData[ix + eType] = word; + } + } + } +} + +// Store energy subsums and errors for given source and sum type + +void CmxEnergySubBlock::setSubsums(const int slice, const SourceType source, + const SumType sType, + const unsigned int ex, const unsigned int ey, + const unsigned int et, const int exError, + const int eyError, const int etError) +{ + if (slice >= 0 && slice < timeslices()) { + resize(); + const int pos = s_maxJems + 2*source + sType; + const int ix = index(slice, pos); + unsigned int energy = 0; + int error = 0; + int overflow = 0; + int parity = 0; + uint32_t word = 0; + uint32_t baseword = (CRATE_SYSTEM_ID << s_wordIdBit) + + (source << s_sourceBit) + + (sType << s_sumTypeBit); + for (int eType = 0; eType < MAX_ENERGY_TYPE; ++eType) { + if (eType == ENERGY_EX) { + energy = ex; + error = exError; + } else if (eType == ENERGY_EY) { + energy = ey; + error = eyError; + } else { + energy = et; + error = etError; + } + overflow = error & s_overflowMask; + parity = (source == REMOTE) ? ((error >> 1) & s_errorMask) : 0; + if (energy || overflow || parity) { + word = m_sumsData[ix + eType]; + word |= energy & s_energySumMask; + word |= overflow << s_overflowBit; + word |= parity << s_errorBit; + word |= eType << s_energyTypeBit; + word |= baseword; + m_sumsData[ix + eType] = word; + } + } + } +} + +// Store hits map for given hits type and sum type + +void CmxEnergySubBlock::setEtHits(const int slice, const HitsType hType, + const SumType sType, const unsigned int map) +{ + if (map && slice >= 0 && slice < timeslices()) { + resize(); + const int pos = s_maxJems + 2*TOTAL + sType; + const int ix = index(slice, pos); + uint32_t word = m_sumsData[ix + hType]; + word |= (map & s_etHitsMask) << s_etHitsBit; + word |= hType << s_energyTypeBit; + word |= sType << s_sumTypeBit; + word |= TOTAL << s_sourceBit; + word |= CRATE_SYSTEM_ID << s_wordIdBit; + m_sumsData[ix + hType] = word; + } +} + +// Packing/Unpacking routines + +bool CmxEnergySubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 3: //<<== CHECK + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CmxEnergySubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 3: //<<== CHECK + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data index appropriate to format + +int CmxEnergySubBlock::index(const int slice, const int pos) const +{ + int ix = 3*pos; + if (format() == NEUTRAL) ix += slice * s_maxSums; + return ix; +} + +// Resize the sums vector according to format + +void CmxEnergySubBlock::resize() +{ + if (m_sumsData.empty()) { + int size = s_maxSums; + if (format() == NEUTRAL) size *= timeslices(); + m_sumsData.resize(size); + } +} + +// Pack neutral data + +bool CmxEnergySubBlock::packNeutral() +{ + resize(); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_maxJems; ++pin) { + // JEM energy sums (jem == pin); parity errors + packerNeutral(pin, energy(slice, pin, ENERGY_EX), s_jemSumBits); + packerNeutral(pin, 0, s_jemPaddingBits); + packerNeutral(pin, (error(slice, pin, ENERGY_EX)>>1), 1); + packerNeutral(pin, energy(slice, pin, ENERGY_EY), s_jemSumBits); + packerNeutral(pin, 0, s_jemPaddingBits); + packerNeutral(pin, (error(slice, pin, ENERGY_EY)>>1), 1); + packerNeutral(pin, energy(slice, pin, ENERGY_ET), s_jemSumBits); + packerNeutral(pin, 0, s_jemPaddingBits); + packerNeutral(pin, (error(slice, pin, ENERGY_ET)>>1), 1); + packerNeutral(pin, 0, s_jemSumBits); + packerNeutral(pin, 0, s_jemPaddingBits); + packerNeutral(pin, 0, 1); + } + // Remote Ex, Ey, Et + int pin = s_maxJems; + packerNeutral(pin, energy(slice, REMOTE, STANDARD, ENERGY_EX), + s_sumBitsExEy); + packerNeutral(pin, (error(slice, REMOTE, STANDARD, ENERGY_EX)>>1), 1); + packerNeutral(pin, energy(slice, REMOTE, RESTRICTED_WEIGHTED, ENERGY_EX), + s_sumBitsExEy); + packerNeutral(pin, (error(slice, REMOTE, RESTRICTED_WEIGHTED, + ENERGY_EX)>>1), 1); + packerNeutral(pin, (error(slice, REMOTE, STANDARD, ENERGY_EX)&0x1), 1); // Seems inconsistent with SLink? + packerNeutral(pin, energy(slice, REMOTE, STANDARD, ENERGY_EY), + s_sumBitsExEy); + packerNeutral(pin, (error(slice, REMOTE, STANDARD, ENERGY_EY)>>1), 1); + packerNeutral(pin, energy(slice, REMOTE, RESTRICTED_WEIGHTED, ENERGY_EY), + s_sumBitsExEy); + packerNeutral(pin, (error(slice, REMOTE, RESTRICTED_WEIGHTED, + ENERGY_EY)>>1), 1); + packerNeutral(pin, (error(slice, REMOTE, STANDARD, ENERGY_EY)&0x1), 1); + packerNeutral(pin, energy(slice, REMOTE, STANDARD, ENERGY_ET), + s_sumBitsEtCrate); + packerNeutral(pin, 0, 1); + packerNeutral(pin, energy(slice, REMOTE, RESTRICTED_WEIGHTED, ENERGY_ET), + s_sumBitsEtCrate); + packerNeutral(pin, (error(slice, REMOTE, STANDARD, ENERGY_ET)&0x1), 1); + // Local Ex, Ey, Et + ++pin; + packerNeutral(pin, energy(slice, LOCAL, STANDARD, ENERGY_EX), + s_sumBitsExEy); + packerNeutral(pin, 0, 1); + packerNeutral(pin, energy(slice, LOCAL, RESTRICTED_WEIGHTED, ENERGY_EX), + s_sumBitsExEy); + packerNeutral(pin, 0, 1); + packerNeutral(pin, (error(slice, LOCAL, STANDARD, ENERGY_EX)&0x1), 1); + packerNeutral(pin, energy(slice, LOCAL, STANDARD, ENERGY_EY), + s_sumBitsExEy); + packerNeutral(pin, 0, 1); + packerNeutral(pin, energy(slice, LOCAL, RESTRICTED_WEIGHTED, ENERGY_EY), + s_sumBitsExEy); + packerNeutral(pin, 0, 1); + packerNeutral(pin, (error(slice, LOCAL, STANDARD, ENERGY_EY)&0x1), 1); + packerNeutral(pin, energy(slice, LOCAL, STANDARD, ENERGY_ET), + s_sumBitsEtCrate); + packerNeutral(pin, 0, 1); + packerNeutral(pin, energy(slice, LOCAL, RESTRICTED_WEIGHTED, ENERGY_ET), + s_sumBitsEtCrate); + packerNeutral(pin, (error(slice, LOCAL, STANDARD, ENERGY_ET)&0x1), 1); + // Total Ex, Ey, Et + ++pin; + packerNeutral(pin, energy(slice, TOTAL, STANDARD, ENERGY_EX), + s_sumBitsExEy); + packerNeutral(pin, 0, 1); + packerNeutral(pin, energy(slice, TOTAL, RESTRICTED_WEIGHTED, ENERGY_EX), + s_sumBitsExEy); + packerNeutral(pin, 0, 1); + packerNeutral(pin, (error(slice, TOTAL, STANDARD, ENERGY_EX)&0x1), 1); + packerNeutral(pin, energy(slice, TOTAL, STANDARD, ENERGY_EY), + s_sumBitsExEy); + packerNeutral(pin, 0, 1); + packerNeutral(pin, energy(slice, TOTAL, RESTRICTED_WEIGHTED, ENERGY_EY), + s_sumBitsExEy); + packerNeutral(pin, (error(slice, TOTAL, STANDARD, ENERGY_ET)&0x1), 1); + packerNeutral(pin, (error(slice, TOTAL, STANDARD, ENERGY_EY)&0x1), 1); + packerNeutral(pin, energy(slice, TOTAL, STANDARD, ENERGY_ET), + s_sumBitsEtSys); + packerNeutral(pin, energy(slice, TOTAL, RESTRICTED_WEIGHTED, ENERGY_ET), + s_sumBitsEtSys); + // Bunchcrossing number, Fifo overflow + ++pin; + packerNeutral(pin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(pin, daqOverflow(), 1); + // Et hit maps + packerNeutral(pin, hits(slice, SUM_ET, STANDARD), s_etHitMapsBits); + packerNeutral(pin, hits(slice, MISSING_ET, STANDARD), s_etHitMapsBits); + packerNeutral(pin, hits(slice, MISSING_ET_SIG, STANDARD), s_etHitMapsBits); + packerNeutral(pin, hits(slice, SUM_ET, RESTRICTED_WEIGHTED), + s_etHitMapsBits); + packerNeutral(pin, hits(slice, MISSING_ET, RESTRICTED_WEIGHTED), + s_etHitMapsBits); + packerNeutral(pin, 0, s_paddingBits); + // G-Link parity errors + for (int p = 0; p <= pin; ++p) packerNeutralParity(p); + } + return true; +} + +// Pack uncompressed data + +bool CmxEnergySubBlock::packUncompressed() +{ + std::vector<uint32_t>::const_iterator pos; + for (pos = m_sumsData.begin(); pos != m_sumsData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CmxEnergySubBlock::unpackNeutral() +{ + resize(); + int bunchCrossing = 0; // BunchCrossing number + int overflow = 0; // FIFO overflow + int parity = 0; // GLink parity + unsigned int en[MAX_ENERGY_TYPE]; // Energies standard + unsigned int rn[MAX_ENERGY_TYPE]; // Energies restricted/weighted + int er[MAX_ENERGY_TYPE]; // Errors standard (bit 0 overflow, bit 1 parity) + int rr[MAX_ENERGY_TYPE]; // Errors restricted/weighted + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_maxJems; ++pin) { + // JEM energy sums (jem == pin); parity errors + for (int eType = 0; eType < MAX_ENERGY_TYPE; ++eType) { + en[eType] = unpackerNeutral(pin, s_jemSumBits); + unpackerNeutral(pin, s_jemPaddingBits); + er[eType] = unpackerNeutral(pin, 1) << 1; + } + unpackerNeutral(pin, s_jemSumBits); + unpackerNeutral(pin, s_jemPaddingBits); + unpackerNeutral(pin, 1); + setSubsums(slice, pin, en[ENERGY_EX], en[ENERGY_EY], en[ENERGY_ET], + er[ENERGY_EX], er[ENERGY_EY], er[ENERGY_ET]); + } + // Remote Ex, Ey, Et, parity, overflow + int pin = s_maxJems; + en[ENERGY_EX] = unpackerNeutral(pin, s_sumBitsExEy); + er[ENERGY_EX] = unpackerNeutral(pin, 1) << 1; + er[ENERGY_ET] = er[ENERGY_EX]; + rn[ENERGY_EX] = unpackerNeutral(pin, s_sumBitsExEy); + rr[ENERGY_EX] = unpackerNeutral(pin, 1) << 1; + rr[ENERGY_ET] = rr[ENERGY_EX]; + er[ENERGY_EX] |= unpackerNeutral(pin, 1); // Or is it both? + en[ENERGY_EY] = unpackerNeutral(pin, s_sumBitsExEy); + er[ENERGY_EY] = unpackerNeutral(pin, 1) << 1; + er[ENERGY_ET] |= er[ENERGY_EY]; + rn[ENERGY_EY] = unpackerNeutral(pin, s_sumBitsExEy); + rr[ENERGY_EY] = unpackerNeutral(pin, 1) << 1; + rr[ENERGY_ET] |= rr[ENERGY_EY]; + er[ENERGY_EY] |= unpackerNeutral(pin, 1); + en[ENERGY_ET] = unpackerNeutral(pin, s_sumBitsEtCrate); + unpackerNeutral(pin, 1); + rn[ENERGY_ET] = unpackerNeutral(pin, s_sumBitsEtCrate); + er[ENERGY_ET] |= unpackerNeutral(pin, 1); + setSubsums(slice, REMOTE, STANDARD, + en[ENERGY_EX], en[ENERGY_EY], en[ENERGY_ET], + er[ENERGY_EX], er[ENERGY_EY], er[ENERGY_ET]); + setSubsums(slice, REMOTE, RESTRICTED_WEIGHTED, + rn[ENERGY_EX], rn[ENERGY_EY], rn[ENERGY_ET], + rr[ENERGY_EX], rr[ENERGY_EY], rr[ENERGY_ET]); + // Local Ex, Ey, Et, overflow + ++pin; + en[ENERGY_EX] = unpackerNeutral(pin, s_sumBitsExEy); + unpackerNeutral(pin, 1); + rn[ENERGY_EX] = unpackerNeutral(pin, s_sumBitsExEy); + unpackerNeutral(pin, 1); + er[ENERGY_EX] = unpackerNeutral(pin, 1); // Or is it both? + rr[ENERGY_EX] = 0; + en[ENERGY_EY] = unpackerNeutral(pin, s_sumBitsExEy); + unpackerNeutral(pin, 1); + rn[ENERGY_EY] = unpackerNeutral(pin, s_sumBitsExEy); + unpackerNeutral(pin, 1); + er[ENERGY_EY] = unpackerNeutral(pin, 1); + rr[ENERGY_EY] = 0; + en[ENERGY_ET] = unpackerNeutral(pin, s_sumBitsEtCrate); + unpackerNeutral(pin, 1); + rn[ENERGY_ET] = unpackerNeutral(pin, s_sumBitsEtCrate); + er[ENERGY_ET] = unpackerNeutral(pin, 1); + rr[ENERGY_ET] = 0; + setSubsums(slice, LOCAL, STANDARD, + en[ENERGY_EX], en[ENERGY_EY], en[ENERGY_ET], + er[ENERGY_EX], er[ENERGY_EY], er[ENERGY_ET]); + setSubsums(slice, LOCAL, RESTRICTED_WEIGHTED, + rn[ENERGY_EX], rn[ENERGY_EY], rn[ENERGY_ET], + rr[ENERGY_EX], rr[ENERGY_EY], rr[ENERGY_ET]); + // Total Ex, Ey, Et, overflow + ++pin; + en[ENERGY_EX] = unpackerNeutral(pin, s_sumBitsExEy); + unpackerNeutral(pin, 1); + rn[ENERGY_EX] = unpackerNeutral(pin, s_sumBitsExEy); + unpackerNeutral(pin, 1); + er[ENERGY_EX] = unpackerNeutral(pin, 1); // Or is it both? + rr[ENERGY_EX] = 0; + en[ENERGY_EY] = unpackerNeutral(pin, s_sumBitsExEy); + unpackerNeutral(pin, 1); + rn[ENERGY_EY] = unpackerNeutral(pin, s_sumBitsExEy); + er[ENERGY_ET] = unpackerNeutral(pin, 1); + rr[ENERGY_ET] = 0; + er[ENERGY_EY] = unpackerNeutral(pin, 1); + rr[ENERGY_EY] = 0; + en[ENERGY_ET] = unpackerNeutral(pin, s_sumBitsEtSys); + rn[ENERGY_ET] = unpackerNeutral(pin, s_sumBitsEtSys); + setSubsums(slice, TOTAL, STANDARD, + en[ENERGY_EX], en[ENERGY_EY], en[ENERGY_ET], + er[ENERGY_EX], er[ENERGY_EY], er[ENERGY_ET]); + setSubsums(slice, TOTAL, RESTRICTED_WEIGHTED, + rn[ENERGY_EX], rn[ENERGY_EY], rn[ENERGY_ET], + rr[ENERGY_EX], rr[ENERGY_EY], rr[ENERGY_ET]); + // Bunchcrossing number, Fifo overflow + ++pin; + bunchCrossing = unpackerNeutral(pin, s_bunchCrossingBits); + overflow = unpackerNeutral(pin, 1); + // Et hit maps + setEtHits(slice, SUM_ET, STANDARD, + unpackerNeutral(pin, s_etHitMapsBits)); + setEtHits(slice, MISSING_ET, STANDARD, + unpackerNeutral(pin, s_etHitMapsBits)); + setEtHits(slice, MISSING_ET_SIG, STANDARD, + unpackerNeutral(pin, s_etHitMapsBits)); + setEtHits(slice, SUM_ET, RESTRICTED_WEIGHTED, + unpackerNeutral(pin, s_etHitMapsBits)); + setEtHits(slice, MISSING_ET, RESTRICTED_WEIGHTED, + unpackerNeutral(pin, s_etHitMapsBits)); + unpackerNeutral(pin, s_paddingBits); + // G-Link parity errors + for (int p = 0; p <= pin; ++p) parity |= unpackerNeutralParityError(p); + } + setBunchCrossing(bunchCrossing); + setDaqOverflow(overflow); + setGlinkParity(parity); + + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CmxEnergySubBlock::unpackUncompressed() +{ + resize(); + unpackerInit(); + bool error = false; + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + if (word) { + const int wordId = (word >> s_wordIdBit) & s_wordIdMask; + if (wordId == MODULE_ID) { + const int jem = (word >> s_jemBit) & s_jemMask; + const int eType = (word >> s_energyTypeJemBit) & s_energyTypeMask; + const int pos = 3*jem + eType; + if (eType < MAX_ENERGY_TYPE && m_sumsData[pos] == 0) { + m_sumsData[pos] = word; + } else error = true; + } else if (wordId == CRATE_SYSTEM_ID) { + const int source = (word >> s_sourceBit) & s_sourceMask; + const int sType = (word >> s_sumTypeBit) & s_sumTypeMask; + const int eType = (word >> s_energyTypeBit) & s_energyTypeMask; + const int pos = 3*(s_maxJems + 2*source + sType) + eType; + if (source < MAX_SOURCE_TYPE && eType < MAX_ENERGY_TYPE + && m_sumsData[pos] == 0) { + m_sumsData[pos] = word; + } else error = true; + } else error = true; + if (error) { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxEnergySubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxEnergySubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..7766d869d6067a67912a375947764460a48a4431 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxEnergySubBlock.h @@ -0,0 +1,121 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMXENERGYSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMXENERGYSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "CmxSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMX-Energy data post LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx //<<== CHECK + * + * @author Peter Faulkner + */ + +class CmxEnergySubBlock : public CmxSubBlock { + + public: + enum WordIdType { MODULE_ID, CRATE_SYSTEM_ID }; + enum EnergyType { ENERGY_EX, ENERGY_EY, ENERGY_ET, MAX_ENERGY_TYPE }; + enum HitsType { MISSING_ET_SIG, MISSING_ET, SUM_ET, MAX_HITS_TYPE }; + enum SourceType { REMOTE, LOCAL, TOTAL, MAX_SOURCE_TYPE }; + enum SumType { STANDARD, RESTRICTED_WEIGHTED, MAX_SUM_TYPE }; + + CmxEnergySubBlock(); + ~CmxEnergySubBlock(); + + /// Clear all data + void clear(); + + /// Return energy subsum for given JEM and energy type + unsigned int energy(int slice, int jem, EnergyType eType) const; + /// Return energy subsum error for given JEM and energy type + int error(int slice, int jem, EnergyType eType) const; + /// Return energy subsum for given source, sum type and energy type + unsigned int energy(int slice, SourceType source, SumType sType, + EnergyType eType) const; + /// Return energy subsum error for given source, sum type and energy type + int error(int slice, SourceType source, SumType sType, + EnergyType eType) const; + /// Return hits map for given hits type and sum type + unsigned int hits(int slice, HitsType hType, SumType sType) const; + + /// Store energy subsums and errors for given JEM + void setSubsums(int slice, int jem, + unsigned int ex, unsigned int ey, unsigned int et, + int exError, int eyError, int etError); + /// Store energy subsums and errors for given source and sum type + void setSubsums(int slice, SourceType source, SumType sType, + unsigned int ex, unsigned int ey, unsigned int et, + int exError, int eyError, int etError); + /// Store hits map for given hits type and sum type + void setEtHits(int slice, HitsType hType, SumType sType, unsigned int map); + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Data word length + static const int s_wordLength = 32; + // Energy subsums bit positions and masks + static const int s_overflowBit = 15; + static const int s_errorBit = 16; + static const int s_etHitsBit = 16; + static const int s_energyTypeJemBit = 23; + static const int s_jemBit = 25; + static const int s_energyTypeBit = 24; + static const int s_sumTypeBit = 26; + static const int s_sourceBit = 27; + static const int s_wordIdBit = 29; + static const int s_maxJems = 16; + static const int s_maxSums = 66; + static const uint32_t s_energyJemMask = 0x3fff; + static const uint32_t s_energySumMask = 0x7fff; + static const uint32_t s_errorMask = 0x1; + static const uint32_t s_overflowMask = 0x1; + static const uint32_t s_etHitsMask = 0xff; + static const uint32_t s_jemMask = 0xf; + static const uint32_t s_energyTypeMask = 0x3; + static const uint32_t s_sumTypeMask = 0x1; + static const uint32_t s_sourceMask = 0x3; + static const uint32_t s_wordIdMask = 0x7; + // Neutral format + static const int s_jemSumBits = 14; + static const int s_jemPaddingBits = 9; + static const int s_sumBitsEtCrate = 14; + static const int s_sumBitsEtSys = 15; + static const int s_sumBitsExEy = 15; + static const int s_bunchCrossingBits = 12; + static const int s_etHitMapsBits = 8; + static const int s_paddingBits = 43; + + int index(int slice, int pos) const; + void resize(); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Energy subsums data + std::vector<uint32_t> m_sumsData; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxJetSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxJetSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..d80afa8e1e932e2213070355b95dc819c419bc2c --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxJetSubBlock.cxx @@ -0,0 +1,630 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CmxJetSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CmxJetSubBlock::s_wordLength; + +const int CmxJetSubBlock::s_tobEnergyLgBit; +const int CmxJetSubBlock::s_tobEnergySmBit; +const int CmxJetSubBlock::s_tobErrorBit; +const int CmxJetSubBlock::s_tobCoordBit; +const int CmxJetSubBlock::s_tobFrameBit; +const int CmxJetSubBlock::s_tobJemBit; +const int CmxJetSubBlock::s_tobWordId; +const uint32_t CmxJetSubBlock::s_tobEnergyLgMask; +const uint32_t CmxJetSubBlock::s_tobEnergySmMask; +const uint32_t CmxJetSubBlock::s_tobErrorMask; +const uint32_t CmxJetSubBlock::s_tobCoordMask; +const uint32_t CmxJetSubBlock::s_tobFrameMask; +const uint32_t CmxJetSubBlock::s_tobJemMask; + +const int CmxJetSubBlock::s_threshBit; +const int CmxJetSubBlock::s_threshErrorBit; +const int CmxJetSubBlock::s_hlFlagBit; +const int CmxJetSubBlock::s_sourceIdBit; +const int CmxJetSubBlock::s_dataWordIdBit; +const int CmxJetSubBlock::s_threshWordId; +const uint32_t CmxJetSubBlock::s_threshMainMask; +const uint32_t CmxJetSubBlock::s_threshFwdLMask; +const uint32_t CmxJetSubBlock::s_threshFwdHMask; +const uint32_t CmxJetSubBlock::s_errorMask; +const uint32_t CmxJetSubBlock::s_topoCheckMask; +const uint32_t CmxJetSubBlock::s_topoMapMask; +const uint32_t CmxJetSubBlock::s_topoCountsMask; +const uint32_t CmxJetSubBlock::s_hlFlagMask; +const uint32_t CmxJetSubBlock::s_sourceIdMask; +const uint32_t CmxJetSubBlock::s_dataWordIdMask; + +const int CmxJetSubBlock::s_presenceBits; +const int CmxJetSubBlock::s_coordBits; +const int CmxJetSubBlock::s_energyLgBits; +//const int CmxJetSubBlock::s_energySmBits[8]; +const int CmxJetSubBlock::s_energySmBits[8] = {3,6,5,4,7,2,9,0}; +const int CmxJetSubBlock::s_threshMainBits; +const int CmxJetSubBlock::s_threshFwdLBits; +const int CmxJetSubBlock::s_threshFwdHBits; +const int CmxJetSubBlock::s_parityErrorBits; +const int CmxJetSubBlock::s_roiOverflowBits; +const int CmxJetSubBlock::s_paddingBits; +const int CmxJetSubBlock::s_bunchCrossingBits; +const int CmxJetSubBlock::s_fifoOverflowBits; +const int CmxJetSubBlock::s_topoChecksumBits; +const int CmxJetSubBlock::s_topoMapBits; +const int CmxJetSubBlock::s_topoCountsBits; +const int CmxJetSubBlock::s_topoPaddingBits; +const int CmxJetSubBlock::s_glinkPins; +const int CmxJetSubBlock::s_modules; +const int CmxJetSubBlock::s_tobsPerModule; +const int CmxJetSubBlock::s_muxPhases; + + +CmxJetSubBlock::CmxJetSubBlock() +{ +} + +CmxJetSubBlock::~CmxJetSubBlock() +{ +} + +// Clear all data + +void CmxJetSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_tobData.clear(); + m_hitsData.clear(); + m_presenceMaps.clear(); + m_parityBits.clear(); +} + +// Return presence map for given JEM + +unsigned int CmxJetSubBlock::presenceMap(const int slice, + const int jem) const +{ + unsigned int map = 0; + const unsigned int ix = mapIndex(slice, jem); + if (ix < m_presenceMaps.size()) map = m_presenceMaps[ix]; + return map; +} + +// Return frame for given jem and tob + +int CmxJetSubBlock::frame(const int slice, const int jem, const int tob) const +{ + int fr = 0; + const unsigned int ix = tobIndex(slice, jem, tob); + if (ix < m_tobData.size()) { + fr = (m_tobData[ix] >> s_tobFrameBit) & s_tobFrameMask; + } + return fr; +} + +// Return Local coordinate for given jem and tob + +int CmxJetSubBlock::localCoord(const int slice, const int jem, const int tob) const +{ + int coord = 0; + const unsigned int ix = tobIndex(slice, jem, tob); + if (ix < m_tobData.size()) { + coord = (m_tobData[ix] >> s_tobCoordBit) & s_tobCoordMask; + } + return coord; +} + +// Return energy large window size for given jem and tob + +int CmxJetSubBlock::energyLarge(const int slice, const int jem, const int tob) const +{ + int et = 0; + const unsigned int ix = tobIndex(slice, jem, tob); + if (ix < m_tobData.size()) { + et = (m_tobData[ix] >> s_tobEnergyLgBit) & s_tobEnergyLgMask; + } + return et; +} + +// Return energy small window size for given jem and tob + +int CmxJetSubBlock::energySmall(const int slice, const int jem, const int tob) const +{ + int et = 0; + const unsigned int ix = tobIndex(slice, jem, tob); + if (ix < m_tobData.size()) { + et = (m_tobData[ix] >> s_tobEnergySmBit) & s_tobEnergySmMask; + } + return et; +} + +// Return error bits for given jem and tob + +int CmxJetSubBlock::tobError(int slice, int jem, int tob) const +{ + int error = 0; + const unsigned int ix = tobIndex(slice, jem, tob); + if (ix < m_tobData.size()) { + error = (m_tobData[ix] >> s_tobErrorBit) & s_tobErrorMask; + } + return error; +} + +// Return parity bits for given JEM + +int CmxJetSubBlock::parityBits(const int slice, const int jem) const +{ + int parity = 0; + const unsigned int ix = parIndex(slice, jem); + if (ix < m_parityBits.size()) parity = m_parityBits[ix]; + return parity; +} + +// Return hit/topo counts for given source ID and HL flag + +unsigned int CmxJetSubBlock::hits(const int slice, const int source, + const int flag) const +{ + unsigned int hits = 0; + const unsigned int ix = hitIndex(slice, source, flag); + if (ix < m_hitsData.size()) { + uint32_t mask = s_threshMainMask; + if (source == REMOTE_FORWARD || source == LOCAL_FORWARD + || source == TOTAL_FORWARD) { + mask = (flag) ? s_threshFwdHMask : s_threshFwdLMask; + } + else if (source == TOPO_CHECKSUM) mask = s_topoCheckMask; + else if (source == TOPO_OCCUPANCY_MAP) mask = s_topoMapMask; + else if (source == TOPO_OCCUPANCY_COUNTS) mask = s_topoCountsMask; + hits = (m_hitsData[ix] >> s_threshBit) & mask; + } + return hits; +} + +// Return hit error for given source ID and HL flag + +int CmxJetSubBlock::hitsError(const int slice, const int source, + const int flag) const +{ + int error = 0; + if (source == REMOTE_MAIN || source == LOCAL_MAIN || source == TOTAL_MAIN || + source == REMOTE_FORWARD || source == LOCAL_FORWARD || + source == TOTAL_FORWARD) { + const unsigned int ix = hitIndex(slice, source, flag); + if (ix < m_hitsData.size()) { + error = (m_hitsData[ix] >> s_threshErrorBit) & s_errorMask; + } + } + return error; +} + +// Store presence map + +void CmxJetSubBlock::setPresenceMap(const int slice, const int jem, + const unsigned int map) +{ + resize(); + if (map) { + const unsigned int ix = mapIndex(slice, jem); + if (ix < m_presenceMaps.size()) m_presenceMaps[ix] = map; + } +} + +// Store TOB (RoI) data for given JEM, frame, local coord + +void CmxJetSubBlock::setTob(const int slice, const int jem, const int frame, + const int loc, const int energyLarge, + const int energySmall, const int error) +{ + resize(); + if (energyLarge || energySmall || error) { + uint32_t word = 0; + word |= (energyLarge & s_tobEnergyLgMask) << s_tobEnergyLgBit; + word |= (energySmall & s_tobEnergySmMask) << s_tobEnergySmBit; + word |= (error & s_tobErrorMask) << s_tobErrorBit; + word |= (loc & s_tobCoordMask) << s_tobCoordBit; + word |= (frame & s_tobFrameMask) << s_tobFrameBit; + word |= (jem & s_tobJemMask) << s_tobJemBit; + word |= (s_tobWordId) << s_dataWordIdBit; + // Order by frame == presence bit // <<== CHECK + for (int tob = 0; tob < s_tobsPerModule; ++tob) { + const unsigned int ix = tobIndex(slice, jem, tob); + if (m_tobData[ix] == 0) { + m_tobData[ix] = word; + break; + } else { + const int frameOld = (m_tobData[ix]>>s_tobFrameBit)&s_tobFrameMask; + if (frame < frameOld) { + for (int i = s_tobsPerModule-tob-1; i > 0; --i) { + m_tobData[ix + i] = m_tobData[ix + i - 1]; + } + m_tobData[ix] = word; + break; + } + } + } + } +} + +// Store parity bits for neutral format + +void CmxJetSubBlock::setParityBits(const int slice, const int jem, + const int parity) +{ + resize(); + if (parity) { + const unsigned int ix = parIndex(slice, jem); + if (ix < m_parityBits.size()) m_parityBits[ix] = parity; + } +} + +// Store hit counts for given source ID and HL flag + +void CmxJetSubBlock::setHits(const int slice, const int source, const int flag, + const unsigned int hits, const int error) +{ + resize(); + const unsigned int ix = hitIndex(slice, source, flag); + if (ix < m_hitsData.size() && (hits || error)) { + uint32_t word = m_hitsData[ix]; + uint32_t mask = s_threshMainMask; + if (source == REMOTE_FORWARD || source == LOCAL_FORWARD || + source == TOTAL_FORWARD) { + mask = (flag) ? s_threshFwdHMask : s_threshFwdLMask; + } + else if (source == TOPO_CHECKSUM) mask = s_topoCheckMask; + else if (source == TOPO_OCCUPANCY_MAP) mask = s_topoMapMask; + else if (source == TOPO_OCCUPANCY_COUNTS) mask = s_topoCountsMask; + word |= (hits & mask) << s_threshBit; + word |= (error & s_errorMask) << s_threshErrorBit; + word |= (flag & s_hlFlagMask) << s_hlFlagBit; + word |= (source & s_sourceIdMask) << s_sourceIdBit; + word |= (s_threshWordId) << s_dataWordIdBit; + m_hitsData[ix] = word; + } +} + +// Packing/Unpacking routines + +bool CmxJetSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CmxJetSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return presence map index appropriate to format + +unsigned int CmxJetSubBlock::mapIndex(const int slice, + const int jem) const +{ + unsigned int ix = jem; + if (format() == NEUTRAL) ix += slice * s_modules; + return ix; +} + +// Return parity bits index appropriate to format + +unsigned int CmxJetSubBlock::parIndex(const int slice, + const int jem) const +{ + unsigned int ix = jem; + if (format() == NEUTRAL) ix += slice * s_modules; + return ix; +} + +// Return tob data index appropriate to format + +unsigned int CmxJetSubBlock::tobIndex(const int slice, const int jem, + const int tob) const +{ + unsigned int ix = jem * s_tobsPerModule + tob; + if (format() == NEUTRAL) ix += slice * s_modules * s_tobsPerModule; + return ix; +} + +// Return hits data index appropriate to format + +unsigned int CmxJetSubBlock::hitIndex(const int slice, const int source, + const int flag) const +{ + unsigned int ix = (source<<1)|flag; + if (format() == NEUTRAL) ix += slice * 2 * MAX_SOURCE_ID; + return ix; +} + +// Resize the data vectors according to format + +void CmxJetSubBlock::resize() +{ + if (m_tobData.empty()) { + int size1 = s_modules * s_tobsPerModule; + int size2 = 2 * MAX_SOURCE_ID; + int size3 = s_modules; + int size4 = s_modules; + if (format() == NEUTRAL) { + size1 *= timeslices(); + size2 *= timeslices(); + size3 *= timeslices(); + size4 *= timeslices(); + } + m_tobData.resize(size1); + m_hitsData.resize(size2); + m_presenceMaps.resize(size3); + m_parityBits.resize(size4); + } +} + +// Pack neutral data + +bool CmxJetSubBlock::packNeutral() +{ + resize(); + std::vector<int> locVec(s_tobsPerModule); + std::vector<int> energyLgVec(s_tobsPerModule); + std::vector<int> energySmVec(s_tobsPerModule); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (pin < s_modules) { // TOB data + const int jem = pin; + // Presence map + packerNeutral(pin, presenceMap(slice, jem), s_presenceBits); + // Get tob data for this jem + locVec.clear(); + energyLgVec.clear(); + energySmVec.clear(); + for (int tob = 0; tob < s_tobsPerModule; ++tob) { + locVec.push_back(localCoord(slice, jem, tob)); + energyLgVec.push_back(energyLarge(slice, jem, tob)); + energySmVec.push_back(energySmall(slice, jem, tob)); + } + const int parity = parityBits(slice, jem); + // And pack + for (int tob = 0; tob < s_tobsPerModule; ++tob) { + // Energy small window LSB + const int nbitsL = s_energySmBits[2*tob]; + packerNeutral(pin, energySmVec[tob], nbitsL); + // Local coordinates + packerNeutral(pin, locVec[tob], s_coordBits); + // Energy large window + packerNeutral(pin, energyLgVec[tob], s_energyLgBits); + // Backplane parity error + packerNeutral(pin, (parity>>tob), s_parityErrorBits); + // Energy small window HSB + const int nbitsH = s_energySmBits[2*tob+1]; + if (nbitsH > 0) { + packerNeutral(pin, (energySmVec[tob]>>nbitsL), nbitsH); + } + } + } else { // Hits and Topo data + if (pin < s_glinkPins-1) { + // Remote, local and total hits; parity error + const int source1 = pin - s_modules + REMOTE_MAIN; + const int source2 = pin - s_modules + REMOTE_FORWARD; + packerNeutral(pin, hits(slice, source1, 0), s_threshMainBits); + packerNeutral(pin, hitsError(slice, source1, 0), s_parityErrorBits); + packerNeutral(pin, hits(slice, source1, 1), s_threshMainBits); + packerNeutral(pin, (hitsError(slice, source1, 1)>>1), s_parityErrorBits); + packerNeutral(pin, hits(slice, source2, 0), s_threshFwdLBits); + packerNeutral(pin, hitsError(slice, source2, 0), s_parityErrorBits); + packerNeutral(pin, hits(slice, source2, 1), s_threshFwdHBits); + packerNeutral(pin, (hitsError(slice, source2, 1)>>1), s_parityErrorBits); + packerNeutral(pin, (hitsError(slice, source1, 0)>>2), s_roiOverflowBits); + packerNeutral(pin, 0, s_paddingBits); + } else { + // Bunch crossing number, Fifo overflow and Topo data + packerNeutral(pin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(pin, daqOverflow(), s_fifoOverflowBits); + packerNeutral(pin, hits(slice, TOPO_CHECKSUM, 0), s_topoChecksumBits); + packerNeutral(pin, hits(slice, TOPO_OCCUPANCY_MAP, 0), s_topoMapBits); + packerNeutral(pin, hits(slice, TOPO_OCCUPANCY_COUNTS, 0), s_topoCountsBits); + packerNeutral(pin, hits(slice, TOPO_OCCUPANCY_COUNTS, 1), s_topoCountsBits); + packerNeutral(pin, 0, s_topoPaddingBits); + } + } + // G-Link parity + packerNeutralParity(pin); + } + } + return true; +} + +// Pack uncompressed data + +bool CmxJetSubBlock::packUncompressed() +{ + std::vector<uint32_t>::const_iterator pos; + for (pos = m_tobData.begin(); pos != m_tobData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + for (pos = m_hitsData.begin(); pos != m_hitsData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CmxJetSubBlock::unpackNeutral() +{ + resize(); + int bunchCrossing = 0; + int fifoOverflow = 0; + int glinkParity = 0; + std::vector<int> locVec(s_tobsPerModule); + std::vector<int> energyLgVec(s_tobsPerModule); + std::vector<int> energySmVec(s_tobsPerModule); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (pin < s_modules) { // TOB data + // Presence map + const unsigned int map = unpackerNeutral(pin, s_presenceBits); + locVec.assign(s_tobsPerModule, 0); + energyLgVec.assign(s_tobsPerModule, 0); + energySmVec.assign(s_tobsPerModule, 0); + int parity = 0; + for (int tob = 0; tob < s_tobsPerModule; ++tob) { + // Energy small window LSB + const int nbitsL = s_energySmBits[2*tob]; + energySmVec[tob] = unpackerNeutral(pin, nbitsL); + // Local coordinates + locVec[tob] = unpackerNeutral(pin, s_coordBits); + // Energy large window + energyLgVec[tob] = unpackerNeutral(pin, s_energyLgBits); + // Backplane parity error + parity |= (unpackerNeutral(pin, s_parityErrorBits) << tob); + // Energy small window HSB + const int nbitsH = s_energySmBits[2*tob+1]; + if (nbitsH > 0) { + energySmVec[tob] += (unpackerNeutral(pin, nbitsH) << nbitsL); + } + } + const int error = (parity) ? 1 : 0; + int tob = 0; + const int jem = pin; + for (int frame = 0; frame < s_presenceBits && tob < s_tobsPerModule; ++frame) { // <<== CHECK - assuming bit==frame + if ((map>>frame)&1) { + setTob(slice, jem, frame, locVec[tob], energyLgVec[tob], + energySmVec[tob], error); + ++tob; + } + } + setPresenceMap(slice, jem, map); + setParityBits(slice, jem, parity); + } else { // Hits and Topo data + if (pin < s_glinkPins-1) { + // Remote, local and total hits; parity error, RoI overflow + const int source1 = pin - s_modules + REMOTE_MAIN; + const int source2 = pin - s_modules + REMOTE_FORWARD; + const unsigned int main0 = unpackerNeutral(pin, s_threshMainBits); + int errorMain = unpackerNeutral(pin, s_parityErrorBits); + const unsigned int main1 = unpackerNeutral(pin, s_threshMainBits); + errorMain |= (unpackerNeutral(pin, s_parityErrorBits)<<1); + const unsigned int fwd0 = unpackerNeutral(pin, s_threshFwdLBits); + int errorFwd = unpackerNeutral(pin, s_parityErrorBits); + const unsigned int fwd1 = unpackerNeutral(pin, s_threshFwdHBits); + errorFwd |= (unpackerNeutral(pin, s_parityErrorBits)<<1); + const int overflow = (unpackerNeutral(pin, s_roiOverflowBits)<<2); + errorMain |= overflow; + errorFwd |= overflow; + setHits(slice, source1, 0, main0, errorMain); + setHits(slice, source1, 1, main1, errorMain); + setHits(slice, source2, 0, fwd0, errorFwd); + setHits(slice, source2, 1, fwd1, errorFwd); + unpackerNeutral(pin, s_paddingBits); + } else { + // Bunch crossing number, Fifo overflow and Topo data + bunchCrossing = unpackerNeutral(pin, s_bunchCrossingBits); + fifoOverflow |= unpackerNeutral(pin, s_fifoOverflowBits); + unsigned int hits = unpackerNeutral(pin, s_topoChecksumBits); + int error = 0; + setHits(slice, TOPO_CHECKSUM, 0, hits, error); + hits = unpackerNeutral(pin, s_topoMapBits); + setHits(slice, TOPO_OCCUPANCY_MAP, 0, hits, error); + hits = unpackerNeutral(pin, s_topoCountsBits); + setHits(slice, TOPO_OCCUPANCY_COUNTS, 0, hits, error); + hits = unpackerNeutral(pin, s_topoCountsBits); + setHits(slice, TOPO_OCCUPANCY_COUNTS, 1, hits, error); + unpackerNeutral(pin, s_topoPaddingBits); + } + } + // G-Link parity errors + glinkParity |= unpackerNeutralParityError(pin); + } + } + setBunchCrossing(bunchCrossing); + setDaqOverflow(fifoOverflow); + setGlinkParity(glinkParity); + + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CmxJetSubBlock::unpackUncompressed() +{ + resize(); + const int maxHits = m_hitsData.size(); + m_jemTobCount.assign(s_modules, 0); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataWordId(word); + if (id == s_tobWordId) { // TOB data + const int index = jem(word); + const int count = m_jemTobCount[index]; + const int index2 = index*s_tobsPerModule + count; + if (count < s_tobsPerModule) { + m_tobData[index2] = word; + ++m_jemTobCount[index]; + } else { + setUnpackErrorCode(UNPACK_EXCESS_TOBS); // New code. Check consequences + return false; + } + } else if (id == s_threshWordId) { // Hits and Topo data + const int index = (sourceId(word)<<1) | hlFlag(word); + if (index < maxHits && m_hitsData[index] == 0) { + m_hitsData[index] = word; + } else { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + } else { + setUnpackErrorCode(UNPACK_DATA_ID); // New code + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxJetSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxJetSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..0dbfe58d9668cadbe61e99514e0dde824d2ab96f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxJetSubBlock.h @@ -0,0 +1,182 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMXJETSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMXJETSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "CmxSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMX-Jet data post LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx //<<== CHECK + * + * @author Peter Faulkner + */ + +class CmxJetSubBlock : public CmxSubBlock { + + public: + enum SourceId { REMOTE_MAIN, LOCAL_MAIN, TOTAL_MAIN, + REMOTE_FORWARD, LOCAL_FORWARD, TOTAL_FORWARD, + TOPO_CHECKSUM, TOPO_OCCUPANCY_MAP, TOPO_OCCUPANCY_COUNTS, + MAX_SOURCE_ID }; + + CmxJetSubBlock(); + ~CmxJetSubBlock(); + + /// Clear all data + void clear(); + + /// Return presence map for given JEM + unsigned int presenceMap(int slice, int jem) const; + /// Return frame for given jem and tob + int frame(int slice, int jem, int tob) const; + /// Return Local coordinate for given jem and tob + int localCoord(int slice, int jem, int tob) const; + /// Return energy large window size for given jem and tob + int energyLarge(int slice, int jem, int tob) const; + /// Return energy small window size for given jem and tob + int energySmall(int slice, int jem, int tob) const; + /// Return error bit for given jem and tob + int tobError(int slice, int jem, int tob) const; + /// Return parity bits for given JEM + int parityBits(int slice, int jem) const; + /// Return hit/topo counts for given source ID and HL flag + unsigned int hits(int slice, int source, int flag) const; + /// Return hit error for given source ID and HL flag + int hitsError(int slice, int source, int flag) const; + + /// Store presence map + void setPresenceMap(int slice, int jem, unsigned int map); + /// Store TOB (RoI) data for given JEM, frame, local coord + void setTob(int slice, int jem, int frame, int loc, + int energyLarge, int energySmall, int error); + /// Store parity bits for neutral format + void setParityBits(int slice, int jem, int parity); + /// Store hit counts for given source ID and HL flag + void setHits(int slice, int source, int flag, unsigned int hits, int error); + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Data word length + static const int s_wordLength = 32; + // TOB bit positions and masks + static const int s_tobEnergyLgBit = 0; + static const int s_tobEnergySmBit = 10; + static const int s_tobErrorBit = 19; + static const int s_tobCoordBit = 20; + static const int s_tobFrameBit = 22; + static const int s_tobJemBit = 25; + static const int s_tobWordId = 0; + static const uint32_t s_tobEnergyLgMask = 0x3ff; + static const uint32_t s_tobEnergySmMask = 0x1ff; + static const uint32_t s_tobErrorMask = 0x1; + static const uint32_t s_tobCoordMask = 0x3; + static const uint32_t s_tobFrameMask = 0x7; + static const uint32_t s_tobJemMask = 0xf; + // Jet hit and topo counts bit positions and masks + static const int s_threshBit = 0; + static const int s_threshErrorBit = 16; + static const int s_hlFlagBit = 24; + static const int s_sourceIdBit = 25; + static const int s_dataWordIdBit = 29; + static const int s_threshWordId = 1; + static const uint32_t s_threshMainMask = 0x7fff; + static const uint32_t s_threshFwdLMask = 0xffff; + static const uint32_t s_threshFwdHMask = 0x3fff; + static const uint32_t s_errorMask = 0x7; // Includes RoI overflow + static const uint32_t s_topoCheckMask = 0xffff; + static const uint32_t s_topoMapMask = 0xffff; + static const uint32_t s_topoCountsMask = 0xffffff; + static const uint32_t s_hlFlagMask = 0x1; + static const uint32_t s_sourceIdMask = 0xf; + static const uint32_t s_dataWordIdMask = 0x7; + // Neutral format + static const int s_presenceBits = 8; + static const int s_coordBits = 2; + static const int s_energyLgBits = 10; + //static const int s_energySmBits[8] = {3,6,5,4,7,2,9,0}; + static const int s_energySmBits[8]; + static const int s_threshMainBits = 15; + static const int s_threshFwdLBits = 16; + static const int s_threshFwdHBits = 14; + static const int s_parityErrorBits = 1; + static const int s_roiOverflowBits = 1; + static const int s_paddingBits = 31; + static const int s_bunchCrossingBits = 12; + static const int s_fifoOverflowBits = 1; + static const int s_topoChecksumBits = 16; + static const int s_topoMapBits = 16; + static const int s_topoCountsBits = 24; + static const int s_topoPaddingBits = 3; + static const int s_glinkPins = 20; + static const int s_modules = 16; + static const int s_tobsPerModule = 4; + static const int s_muxPhases = 4; + + int dataWordId(uint32_t word) const; + int sourceId(uint32_t word) const; + int jem(uint32_t word) const; + int hlFlag(uint32_t word) const; + unsigned int mapIndex(int slice, int jem) const; + unsigned int parIndex(int slice, int jem) const; + unsigned int tobIndex(int slice, int jem, int tob) const; + unsigned int hitIndex(int slice, int source, int flag) const; + void resize(); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// TOB data + std::vector<uint32_t> m_tobData; + /// Hits and topo data + std::vector<uint32_t> m_hitsData; + /// Presence maps + std::vector<unsigned int> m_presenceMaps; + /// Parity data for neutral format + std::vector<int> m_parityBits; + /// JEM TOB count vector for unpacking + std::vector<int> m_jemTobCount; + +}; + +inline int CmxJetSubBlock::dataWordId(const uint32_t word) const +{ + return (word >> s_dataWordIdBit) & s_dataWordIdMask; +} + +inline int CmxJetSubBlock::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +inline int CmxJetSubBlock::jem(const uint32_t word) const +{ + return (word >> s_tobJemBit) & s_tobJemMask; +} + +inline int CmxJetSubBlock::hlFlag(const uint32_t word) const +{ + return (word >> s_hlFlagBit) & s_hlFlagMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..77a380ae3d1fbc62015f9c5a63aa80d7fd97a24b --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxSubBlock.cxx @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CmxSubBlock.h" + +namespace LVL1BS { + +// Static constant definitions + +const int CmxSubBlock::s_wordIdVal; + +const int CmxSubBlock::s_cmxSummingBit; +const int CmxSubBlock::s_cmxFirmwareBit; +const int CmxSubBlock::s_cmxPositionBit; +const uint32_t CmxSubBlock::s_cmxSummingMask; +const uint32_t CmxSubBlock::s_cmxFirmwareMask; +const uint32_t CmxSubBlock::s_cmxPositionMask; + +const int CmxSubBlock::s_glinkBitsPerSlice; + +CmxSubBlock::CmxSubBlock() +{ +} + +CmxSubBlock::~CmxSubBlock() +{ +} + +// Store CMX header + +void CmxSubBlock::setCmxHeader(const int version, const int format, + const int slice, const int crate, + const int summing, const int firmware, + const int position, const int timeslices) +{ + int module = 0; + module |= (summing & s_cmxSummingMask) << s_cmxSummingBit; + module |= (firmware & s_cmxFirmwareMask) << s_cmxFirmwareBit; + module |= (position & s_cmxPositionMask) << s_cmxPositionBit; + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, + timeslices); +} + +// Return number of timeslices + +int CmxSubBlock::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Static function to determine CMX type + +CmxSubBlock::CmxFirmwareCode CmxSubBlock::cmxType(const uint32_t word) +{ + CmxFirmwareCode type; + const int module = L1CaloSubBlock::module(word); + const int code = (module >> s_cmxFirmwareBit) & s_cmxFirmwareMask; + switch (code) { + case CMX_CP: + type = CMX_CP; + break; + case CMX_JET: + type = CMX_JET; + break; + case CMX_ENERGY: + type = CMX_ENERGY; + break; + default: + type = CMX_UNKNOWN; + break; + } + return type; +} + +// Static function to determine if header word corresponds to CMX block + +bool CmxSubBlock::cmxBlock(const uint32_t word) +{ + return L1CaloSubBlock::wordId(word) == s_wordIdVal; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..7a5924177d2e7b0915748a6e2f9b20d26047cd55 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CmxSubBlock.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CMXSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CMXSUBBLOCK_H + +#include <stdint.h> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CMX data post LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx <<== CHECK + * + * @author Peter Faulkner + */ + +class CmxSubBlock : public L1CaloSubBlock { + + public: + enum CmxFirmwareCode { CMX_CP = 0, CMX_JET = 1, CMX_ENERGY = 2, // <<== CHECK + CMX_UNKNOWN = 3 }; + enum CmxSummingCode { CRATE = 0, SYSTEM = 1 }; + enum CmxPositions { LEFT = 0, RIGHT = 1 }; + + CmxSubBlock(); + ~CmxSubBlock(); + + /// Store CMX header + void setCmxHeader(int version, int format, int slice, int crate, + int summing, int firmware, int position, int timeslices); + + // Return CMX specific header data + int cmxSumming() const; + int cmxFirmware() const; + int cmxPosition() const; + int timeslices() const; + + /// CMX differentiation (CMX_CP, CMX_JET, or CMX_ENERGY) + static CmxFirmwareCode cmxType(uint32_t word); + /// Determine if header word corresponds to CMX + static bool cmxBlock(uint32_t word); + + private: + /// CMX header word ID + static const int s_wordIdVal = 0xe; + // CMX fields packed in module field + static const int s_cmxSummingBit = 3; + static const int s_cmxFirmwareBit = 1; + static const int s_cmxPositionBit = 0; + static const uint32_t s_cmxSummingMask = 0x1; + static const uint32_t s_cmxFirmwareMask = 0x3; + static const uint32_t s_cmxPositionMask = 0x1; + /// Needed for neutral format + static const int s_glinkBitsPerSlice = 97; + +}; + +inline int CmxSubBlock::cmxSumming() const +{ + return (module() >> s_cmxSummingBit) & s_cmxSummingMask; +} + +inline int CmxSubBlock::cmxFirmware() const +{ + return (module() >> s_cmxFirmwareBit) & s_cmxFirmwareMask; +} + +inline int CmxSubBlock::cmxPosition() const +{ + return (module() >> s_cmxPositionBit) & s_cmxPositionMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamCnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..cbf15e1a2ebfc810d0fc5520f8da1b3c01d3625d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamCnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/CPBSCollection.h" + +#include "CpByteStreamCnv.h" +#include "CpByteStreamTool.h" + +namespace LVL1BS { + +CpByteStreamCnv::CpByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpByteStreamCnv"), + m_tool("LVL1BS::CpByteStreamTool/CpByteStreamTool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +CpByteStreamCnv::~CpByteStreamCnv() +{ +} + +// CLID + +const CLID& CpByteStreamCnv::classID() +{ + return ClassID_traits<LVL1::CPBSCollection>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpByteStreamCnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode CpByteStreamCnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::CPBSCollection* cp = 0; + if( !SG::fromStorable( pObj, cp ) ) { + m_log << MSG::ERROR << " Cannot cast to CPBSCollection" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( cp, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..361ded10ce81f4b1354783200b88cb74b770fec4 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamCnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_CPBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpByteStreamTool; + +/** ByteStream converter for CP container + * + * @author Peter Faulkner + */ + +class CpByteStreamCnv: public Converter { + + friend class CnvFactory<CpByteStreamCnv>; + +protected: + + CpByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~CpByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from Cp Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpByteStreamTool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamTool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..a91f60534a3a92b7633ccde83108bd69011fe98c --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamTool.cxx @@ -0,0 +1,1158 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMMCPHits.h" +#include "TrigT1CaloEvent/CPMHits.h" +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/CPBSCollection.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "CmmCpSubBlock.h" +#include "CmmSubBlock.h" +#include "CpmSubBlock.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "ModifySlices.h" + +#include "CpByteStreamTool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_ICpByteStreamTool("CpByteStreamTool", 1, 1); + +const InterfaceID& CpByteStreamTool::interfaceID() +{ + return IID_ICpByteStreamTool; +} + +// Constructor + +CpByteStreamTool::CpByteStreamTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_cpmMaps("LVL1::CpmMappingTool/CpmMappingTool"), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_channels(80), m_crates(4), m_modules(14), + m_coreOverlap(0), m_subDetector(eformat::TDAQ_CALO_CLUSTER_PROC_DAQ), + m_srcIdMap(0), m_towerKey(0), m_cpmSubBlock(0), m_cmmCpSubBlock(0), + m_rodStatus(0), m_fea(0) +{ + declareInterface<CpByteStreamTool>(this); + + declareProperty("CpmMappingTool", m_cpmMaps, + "Crate/Module/Channel to Eta/Phi/Layer mapping tool"); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 8, + "Offset of CP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of CP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 2, + "The number of S-Links per crate"); + declareProperty("SimulSlices", m_dfltSlices = 1, + "The number of slices in the simulation"); + declareProperty("ForceSlices", m_forceSlices = 0, + "If >0, the number of slices in bytestream"); + +} + +// Destructor + +CpByteStreamTool::~CpByteStreamTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpByteStreamTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_cpmMaps.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_cpmMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_cpmMaps << endreq; + + sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_towerKey = new LVL1::TriggerTowerKey(); + m_cpmSubBlock = new CpmSubBlock(); + m_cmmCpSubBlock = new CmmCpSubBlock(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpByteStreamTool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_cmmCpSubBlock; + delete m_cpmSubBlock; + delete m_towerKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to CPM towers + +StatusCode CpByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTower>* const ttCollection) +{ + m_ttCollection = ttCollection; + m_ttMap.clear(); + return convertBs(robFrags, CPM_TOWERS); +} + +// Conversion bytestream to CPM hits + +StatusCode CpByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMHits>* const hitCollection) +{ + m_hitCollection = hitCollection; + m_hitsMap.clear(); + return convertBs(robFrags, CPM_HITS); +} + +// Conversion bytestream to CMM-CP hits + +StatusCode CpByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMCPHits>* const hitCollection) +{ + m_cmmHitCollection = hitCollection; + m_cmmHitsMap.clear(); + return convertBs(robFrags, CMM_CP_HITS); +} + +// Conversion of CP container to bytestream + +StatusCode CpByteStreamTool::convert(const LVL1::CPBSCollection* const cp, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + setupCpmTowerMap(cp->towers()); + setupCpmHitsMap(cp->hits()); + setupCmmCpHitsMap(cp->cmmHits()); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + int timeslices = 1; + int trigCpm = 0; + int timeslicesNew = 1; + int trigCpmNew = 0; + for (int crate=0; crate < m_crates; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + // CPM modules are numbered 1 to m_modules + for (int module=1; module <= m_modules; ++module) { + const int mod = module - 1; + + // Pack required number of modules per slink + + if (mod%modulesPerSlink == 0) { + const int daqOrRoi = 0; + const int slink = (m_slinks == 2) ? 2*(mod/modulesPerSlink) + : mod/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq; + } + // Get number of CPM slices and triggered slice offset + // for this slink + if ( ! slinkSlices(crate, module, modulesPerSlink, + timeslices, trigCpm)) { + msg(MSG::ERROR) << "Inconsistent number of slices or " + << "triggered slice offsets in data for crate " + << hwCrate << " slink " << slink << endreq; + return StatusCode::FAILURE; + } + timeslicesNew = (m_forceSlices) ? m_forceSlices : timeslices; + trigCpmNew = ModifySlices::peak(trigCpm, timeslices, timeslicesNew); + if (debug) { + msg() << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq + << "Slices/offset: " << timeslices << " " << trigCpm; + if (timeslices != timeslicesNew) { + msg() << " modified to " << timeslicesNew << " " << trigCpmNew; + } + msg() << endreq; + } + L1CaloUserHeader userHeader; + userHeader.setCpm(trigCpmNew); + const uint32_t rodIdCpm = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdCpm); + theROD->push_back(userHeader.header()); + m_rodStatusMap.insert(make_pair(rodIdCpm, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block for each slice (except Neutral format) + + m_cpmBlocks.clear(); + for (int slice = 0; slice < timeslicesNew; ++slice) { + CpmSubBlock* const subBlock = new CpmSubBlock(); + subBlock->setCpmHeader(m_version, m_dataFormat, slice, + hwCrate, module, timeslicesNew); + m_cpmBlocks.push_back(subBlock); + if (neutralFormat) break; + } + + // Find CPM towers corresponding to each eta/phi pair and fill + // sub-blocks + + for (int chan=0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_cpmMaps->mapping(crate, module, chan, eta, phi, layer)) { + const unsigned int key = m_towerKey->ttKey(phi, eta); + const LVL1::CPMTower* const tt = findCpmTower(key); + if (tt ) { + std::vector<int> emData; + std::vector<int> hadData; + std::vector<int> emError; + std::vector<int> hadError; + ModifySlices::data(tt->emEnergyVec(), emData, timeslicesNew); + ModifySlices::data(tt->hadEnergyVec(), hadData, timeslicesNew); + ModifySlices::data(tt->emErrorVec(), emError, timeslicesNew); + ModifySlices::data(tt->hadErrorVec(), hadError, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError emErrBits(emError[slice]); + const LVL1::DataError hadErrBits(hadError[slice]); + const int emErr = + (emErrBits.get(LVL1::DataError::LinkDown) << 1) | + emErrBits.get(LVL1::DataError::Parity); + const int hadErr = + (hadErrBits.get(LVL1::DataError::LinkDown) << 1) | + hadErrBits.get(LVL1::DataError::Parity); + const int index = ( neutralFormat ) ? 0 : slice; + CpmSubBlock* const subBlock = m_cpmBlocks[index]; + subBlock->fillTowerData(slice, chan, emData[slice], + hadData[slice], emErr, hadErr); + } + } + } + } + + // Add CPM hits + + const LVL1::CPMHits* const hits = findCpmHits(crate, module); + if (hits) { + std::vector<unsigned int> vec0; + std::vector<unsigned int> vec1; + ModifySlices::data(hits->HitsVec0(), vec0, timeslicesNew); + ModifySlices::data(hits->HitsVec1(), vec1, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const int index = ( neutralFormat ) ? 0 : slice; + CpmSubBlock* const subBlock = m_cpmBlocks[index]; + subBlock->setHits(slice, vec0[slice], vec1[slice]); + } + } + + // Pack and write the sub-blocks + + DataVector<CpmSubBlock>::const_iterator pos; + for (pos = m_cpmBlocks.begin(); pos != m_cpmBlocks.end(); ++pos) { + CpmSubBlock* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CPM sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CPM sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Append CMMs to last S-Link of the crate + + // Create a sub-block for each slice (except Neutral format) + + m_cmmHit0Blocks.clear(); + m_cmmHit1Blocks.clear(); + const int summing = (crate == m_crates - 1) ? CmmSubBlock::SYSTEM + : CmmSubBlock::CRATE; + for (int slice = 0; slice < timeslicesNew; ++slice) { + CmmCpSubBlock* const h0Block = new CmmCpSubBlock(); + h0Block->setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_CP, + CmmSubBlock::RIGHT, timeslicesNew); + m_cmmHit0Blocks.push_back(h0Block); + CmmCpSubBlock* const h1Block = new CmmCpSubBlock(); + h1Block->setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_CP, + CmmSubBlock::LEFT, timeslicesNew); + m_cmmHit1Blocks.push_back(h1Block); + if (neutralFormat) break; + } + + // CMM-CP + + const int maxDataID = LVL1::CMMCPHits::MAXID; + for (int dataID = 1; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID > m_modules) { + if (summing == CmmSubBlock::CRATE && + dataID != LVL1::CMMCPHits::LOCAL) continue; + switch (dataID) { + case LVL1::CMMCPHits::LOCAL: + source = CmmCpSubBlock::LOCAL; + break; + case LVL1::CMMCPHits::REMOTE_0: + source = CmmCpSubBlock::REMOTE_0; + break; + case LVL1::CMMCPHits::REMOTE_1: + source = CmmCpSubBlock::REMOTE_1; + break; + case LVL1::CMMCPHits::REMOTE_2: + source = CmmCpSubBlock::REMOTE_2; + break; + case LVL1::CMMCPHits::TOTAL: + source = CmmCpSubBlock::TOTAL; + break; + default: + continue; + } + } + const LVL1::CMMCPHits* const ch = findCmmCpHits(crate, dataID); + if ( ch ) { + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + std::vector<int> err0; + std::vector<int> err1; + ModifySlices::data(ch->HitsVec0(), hits0, timeslicesNew); + ModifySlices::data(ch->HitsVec1(), hits1, timeslicesNew); + ModifySlices::data(ch->ErrorVec0(), err0, timeslicesNew); + ModifySlices::data(ch->ErrorVec1(), err1, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError err0Bits(err0[slice]); + const LVL1::DataError err1Bits(err1[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + CmmCpSubBlock* subBlock = m_cmmHit0Blocks[index]; + subBlock->setHits(slice, source, hits0[slice], + err0Bits.get(LVL1::DataError::Parity)); + subBlock = m_cmmHit1Blocks[index]; + subBlock->setHits(slice, source, hits1[slice], + err1Bits.get(LVL1::DataError::Parity)); + } + } + } + DataVector<CmmCpSubBlock>::const_iterator cos = m_cmmHit0Blocks.begin(); + for (; cos != m_cmmHit0Blocks.end(); ++cos) { + CmmCpSubBlock* const subBlock = *cos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Cp sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Cp sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + cos = m_cmmHit1Blocks.begin(); + for (; cos != m_cmmHit1Blocks.end(); ++cos) { + CmmCpSubBlock* const subBlock = *cos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Cp sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Cp sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& CpByteStreamTool::sourceIDs( + const std::string& sgKey) +{ + // Check if overlap tower channels wanted + const std::string flag("Overlap"); + const std::string::size_type pos = sgKey.find(flag); + m_coreOverlap = + (pos == std::string::npos || pos != sgKey.length() - flag.length()) ? 0 : 1; + + if (m_sourceIDs.empty()) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 0; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + m_sourceIDs.push_back(robId); + } + } + } + return m_sourceIDs; +} + +// Convert bytestream to given container type + +StatusCode CpByteStreamTool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: ROD " + << MSG::hex << sourceID << " ROB " << robid + << MSG::dec << endreq; + } + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word should be User Header + if ( !L1CaloUserHeader::isValid(*payload) ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Invalid or missing user header" << endreq; + continue; + } + L1CaloUserHeader userHeader(*payload); + const int minorVersion = (*rob)->rod_version() & 0xffff; + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + // triggered slice offsets + int trigCpm = userHeader.cpm(); + int trigCmm = userHeader.cpCmm(); + if (debug) { + msg() << "Minor format version number: " << MSG::hex + << minorVersion << MSG::dec << endreq + << "CPM triggered slice offset: " << trigCpm << endreq + << "CMM triggered slice offset: " << trigCmm << endreq; + } + if (trigCpm != trigCmm) { + const int newTrig = (trigCpm > trigCmm) ? trigCpm : trigCmm; + trigCpm = newTrig; + trigCmm = newTrig; + if (debug) msg() << "Changed both offsets to " << newTrig << endreq; + } + + // Loop over sub-blocks + + m_rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER) { + if (debug) msg() << "Unexpected data sequence" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MISSING_HEADER; + break; + } + if (CmmSubBlock::cmmBlock(*payload)) { + // CMM + if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_CP) { + m_cmmCpSubBlock->clear(); + payload = m_cmmCpSubBlock->read(payload, payloadEnd); + if (m_cmmCpSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMM_CP_HITS) { + decodeCmmCp(m_cmmCpSubBlock, trigCmm); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmmCp failed" << endreq; + break; + } + } + } else { + if (debug) msg() << "Invalid CMM type in module field" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + } else { + // CPM + CpmSubBlock subBlock; + m_cpmSubBlock->clear(); + payload = m_cpmSubBlock->read(payload, payloadEnd); + if (m_cpmSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CPM_TOWERS || collection == CPM_HITS) { + decodeCpm(m_cpmSubBlock, trigCpm, collection); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCpm failed" << endreq; + break; + } + } + } + } + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, m_rodErr); + } + + return StatusCode::SUCCESS; +} + +// Unpack CMM-CP sub-block + +void CpByteStreamTool::decodeCmmCp(CmmCpSubBlock* subBlock, int trigCmm) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmmPosition(); + const int firmware = subBlock->cmmFirmware(); + const int summing = subBlock->cmmSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMM-CP: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigCmm) { + if (debug) msg() << "Triggered CMM slice from header " + << "inconsistent with number of slices: " + << trigCmm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMM-CP sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const uint32_t subStatus = subBlock->subStatus(); + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSid = CmmCpSubBlock::MAX_SOURCE_ID; + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Jet hit counts + + for (int source = 1; source < maxSid; ++source) { + int dataID = source; + if (source > m_modules) { + if (summing == CmmSubBlock::CRATE && + source != CmmCpSubBlock::LOCAL) continue; + switch (source) { + case CmmCpSubBlock::LOCAL: + dataID = LVL1::CMMCPHits::LOCAL; + break; + case CmmCpSubBlock::REMOTE_0: + dataID = LVL1::CMMCPHits::REMOTE_0; + break; + case CmmCpSubBlock::REMOTE_1: + dataID = LVL1::CMMCPHits::REMOTE_1; + break; + case CmmCpSubBlock::REMOTE_2: + dataID = LVL1::CMMCPHits::REMOTE_2; + break; + case CmmCpSubBlock::TOTAL: + dataID = LVL1::CMMCPHits::TOTAL; + break; + default: + continue; + } + } + const unsigned int hits = subBlock->hits(slice, source); + int err = subBlock->hitsError(slice, source); + LVL1::DataError errorBits; + errorBits.set(LVL1::DataError::Parity, err & 0x1); + errorBits.set(LVL1::DataError::SubStatusWord, subStatus); + err = errorBits.error(); + if (hits || err) { + LVL1::CMMCPHits* ch = findCmmCpHits(crate, dataID); + if ( ! ch ) { // create new CMM hits + m_hitsVec0.assign(timeslices, 0); + m_hitsVec1.assign(timeslices, 0); + m_errVec0.assign(timeslices, 0); + m_errVec1.assign(timeslices, 0); + if (module == CmmSubBlock::RIGHT) { + m_hitsVec0[slice] = hits; + m_errVec0[slice] = err; + } else { + m_hitsVec1[slice] = hits; + m_errVec1[slice] = err; + } + ch = new LVL1::CMMCPHits(swCrate, dataID, m_hitsVec0, m_hitsVec1, + m_errVec0, m_errVec1, trigCmm); + const int key = crate*100 + dataID; + m_cmmHitsMap.insert(std::make_pair(key, ch)); + m_cmmHitCollection->push_back(ch); + } else { + m_hitsVec0 = ch->HitsVec0(); + m_hitsVec1 = ch->HitsVec1(); + m_errVec0 = ch->ErrorVec0(); + m_errVec1 = ch->ErrorVec1(); + const int nsl = m_hitsVec0.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if ((module == CmmSubBlock::RIGHT && (m_hitsVec0[slice] != 0 || + m_errVec0[slice] != 0)) || (module == CmmSubBlock::LEFT && + (m_hitsVec1[slice] != 0 || m_errVec1[slice] != 0))) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + if (module == CmmSubBlock::RIGHT) { + m_hitsVec0[slice] = hits; + m_errVec0[slice] = err; + } else { + m_hitsVec1[slice] = hits; + m_errVec1[slice] = err; + } + ch->addHits(m_hitsVec0, m_hitsVec1, m_errVec0, m_errVec1); + } + } + } + } + + return; +} + +// Unpack CPM sub-block + +void CpByteStreamTool::decodeCpm(CpmSubBlock* subBlock, + int trigCpm, const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + const bool verbose = msgLvl(MSG::VERBOSE); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->module(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CPM: Crate " << hwCrate + << " Module " << module + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (module < 1 || module > m_modules) { + if (debug) msg() << "Unexpected module number: " << module << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + return; + } + if (timeslices <= trigCpm) { + if (debug) msg() << "Triggered CPM slice from header " + << "inconsistent with number of slices: " + << trigCpm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CPM sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + LVL1::DataError dErr; + dErr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = dErr.error(); + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + if (collection == CPM_TOWERS) { + + // Loop over tower channels and fill CPM towers + + for (int chan = 0; chan < m_channels; ++chan) { + if (!ssError && !subBlock->anyTowerData(chan)) continue; + const int em = subBlock->emData(slice, chan); + const int had = subBlock->hadData(slice, chan); + const int emErr = subBlock->emError(slice, chan); + const int hadErr = subBlock->hadError(slice, chan); + int emErr1 = ssError; + if (emErr) { + LVL1::DataError emErrBits(emErr1); + emErrBits.set(LVL1::DataError::Parity, emErr & 0x1); + emErrBits.set(LVL1::DataError::LinkDown, (emErr >> 1) & 0x1); + emErr1 = emErrBits.error(); + } + int hadErr1 = ssError; + if (hadErr) { + LVL1::DataError hadErrBits(hadErr1); + hadErrBits.set(LVL1::DataError::Parity, hadErr & 0x1); + hadErrBits.set(LVL1::DataError::LinkDown, (hadErr >> 1) & 0x1); + hadErr1 = hadErrBits.error(); + } + if (em || had || emErr1 || hadErr1) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_cpmMaps->mapping(crate, module, chan, eta, phi, layer)) { + if (layer == m_coreOverlap) { + const unsigned int key = m_towerKey->ttKey(phi, eta); + LVL1::CPMTower* tt = findCpmTower(key); + if ( ! tt ) { // create new CPM tower + m_emVec.assign(timeslices, 0); + m_hadVec.assign(timeslices, 0); + m_emErrVec.assign(timeslices, 0); + m_hadErrVec.assign(timeslices, 0); + m_emVec[slice] = em; + m_hadVec[slice] = had; + m_emErrVec[slice] = emErr1; + m_hadErrVec[slice] = hadErr1; + tt = new LVL1::CPMTower(phi, eta, m_emVec, m_emErrVec, + m_hadVec, m_hadErrVec, trigCpm); + m_ttMap.insert(std::make_pair(key, tt)); + m_ttCollection->push_back(tt); + } else { + m_emVec = tt->emEnergyVec(); + m_hadVec = tt->hadEnergyVec(); + m_emErrVec = tt->emErrorVec(); + m_hadErrVec = tt->hadErrorVec(); + const int nsl = m_emVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_emVec[slice] != 0 || m_hadVec[slice] != 0 || + m_emErrVec[slice] != 0 || m_hadErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_emVec[slice] = em; + m_hadVec[slice] = had; + m_emErrVec[slice] = emErr1; + m_hadErrVec[slice] = hadErr1; + tt->fill(m_emVec, m_emErrVec, m_hadVec, m_hadErrVec, trigCpm); + } + } + } else if (verbose && (em || had || emErr || hadErr)) { + msg(MSG::VERBOSE) << "Non-zero data but no channel mapping for channel " + << chan << endreq; + msg(MSG::DEBUG); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No CPM tower data for channel " + << chan << " slice " << slice << endreq; + msg(MSG::DEBUG); + } + } + } else if (collection == CPM_HITS) { + + // Get CPM hits + + const unsigned int hits0 = subBlock->hits0(slice); + const unsigned int hits1 = subBlock->hits1(slice); + if (hits0 || hits1) { + LVL1::CPMHits* ch = findCpmHits(crate, module); + if ( ! ch ) { // create new CPM hits + m_hitsVec0.assign(timeslices, 0); + m_hitsVec1.assign(timeslices, 0); + m_hitsVec0[slice] = hits0; + m_hitsVec1[slice] = hits1; + ch = new LVL1::CPMHits(swCrate, module, m_hitsVec0, m_hitsVec1, trigCpm); + m_hitsMap.insert(std::make_pair(crate*m_modules+module-1, ch)); + m_hitCollection->push_back(ch); + } else { + m_hitsVec0 = ch->HitsVec0(); + m_hitsVec1 = ch->HitsVec1(); + const int nsl = m_hitsVec0.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec0[slice] != 0 || m_hitsVec1[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec0[slice] = hits0; + m_hitsVec1[slice] = hits1; + ch->addHits(m_hitsVec0, m_hitsVec1); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No CPM hits data for crate/module/slice " + << hwCrate << "/" << module << "/" << slice + << endreq; + msg(MSG::DEBUG); + } + } + } + return; +} + +// Find a CPM tower for given key + +LVL1::CPMTower* CpByteStreamTool::findCpmTower(const unsigned int key) +{ + LVL1::CPMTower* tt = 0; + CpmTowerMap::const_iterator mapIter; + mapIter = m_ttMap.find(key); + if (mapIter != m_ttMap.end()) tt = mapIter->second; + return tt; +} + +// Find CPM hits for given crate, module + +LVL1::CPMHits* CpByteStreamTool::findCpmHits(const int crate, const int module) +{ + LVL1::CPMHits* hits = 0; + CpmHitsMap::const_iterator mapIter; + mapIter = m_hitsMap.find(crate*m_modules + module - 1); + if (mapIter != m_hitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find CMM-CP hits for given crate, dataID + +LVL1::CMMCPHits* CpByteStreamTool::findCmmCpHits(const int crate, + const int dataID) +{ + LVL1::CMMCPHits* hits = 0; + CmmCpHitsMap::const_iterator mapIter; + mapIter = m_cmmHitsMap.find(crate*100 + dataID); + if (mapIter != m_cmmHitsMap.end()) hits = mapIter->second; + return hits; +} + +// Set up CPM tower map + +void CpByteStreamTool::setupCpmTowerMap(const CpmTowerCollection* + const ttCollection) +{ + m_ttMap.clear(); + if (ttCollection) { + CpmTowerCollection::const_iterator pos = ttCollection->begin(); + CpmTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CPMTower* const tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + m_ttMap.insert(std::make_pair(key, tt)); + } + } +} + +// Set up CPM hits map + +void CpByteStreamTool::setupCpmHitsMap(const CpmHitsCollection* + const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + CpmHitsCollection::const_iterator pos = hitCollection->begin(); + CpmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CPMHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = m_modules * crate + hits->module() - 1; + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM-CP hits map + +void CpByteStreamTool::setupCmmCpHitsMap(const CmmCpHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmCpHitsCollection::const_iterator pos = hitCollection->begin(); + CmmCpHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMMCPHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = crate*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Get number of slices and triggered slice offset for next slink + +bool CpByteStreamTool::slinkSlices(const int crate, const int module, + const int modulesPerSlink, int& timeslices, int& trigCpm) +{ + int slices = -1; + int trigC = m_dfltSlices/2; + for (int mod = module; mod < module + modulesPerSlink; ++mod) { + for (int chan = 0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if ( !m_cpmMaps->mapping(crate, mod, chan, eta, phi, layer)) continue; + const unsigned int key = m_towerKey->ttKey(phi, eta); + const LVL1::CPMTower* const tt = findCpmTower(key); + if ( !tt ) continue; + const int numdat = 4; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((tt->emEnergyVec()).begin(), + (tt->emEnergyVec()).end(), 0); + sums[1] = std::accumulate((tt->hadEnergyVec()).begin(), + (tt->hadEnergyVec()).end(), 0); + sums[2] = std::accumulate((tt->emErrorVec()).begin(), + (tt->emErrorVec()).end(), 0); + sums[3] = std::accumulate((tt->hadErrorVec()).begin(), + (tt->hadErrorVec()).end(), 0); + sizes[0] = (tt->emEnergyVec()).size(); + sizes[1] = (tt->hadEnergyVec()).size(); + sizes[2] = (tt->emErrorVec()).size(); + sizes[3] = (tt->hadErrorVec()).size(); + const int peak = tt->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + const LVL1::CPMHits* const hits = findCpmHits(crate, mod); + if (hits) { + const int numdat = 2; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((hits->HitsVec0()).begin(), + (hits->HitsVec0()).end(), 0); + sums[1] = std::accumulate((hits->HitsVec1()).begin(), + (hits->HitsVec1()).end(), 0); + sizes[0] = (hits->HitsVec0()).size(); + sizes[1] = (hits->HitsVec1()).size(); + const int peak = hits->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + } + // CMM last slink of crate + if (module/modulesPerSlink == m_slinks - 1) { + const int maxDataID = LVL1::CMMCPHits::MAXID; + for (int dataID = 0; dataID < maxDataID; ++dataID) { + const int numdat = 4; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + const LVL1::CMMCPHits* const hits = findCmmCpHits(crate, dataID); + if (hits) { + sums[0] = std::accumulate((hits->HitsVec0()).begin(), + (hits->HitsVec0()).end(), 0); + sums[1] = std::accumulate((hits->HitsVec1()).begin(), + (hits->HitsVec1()).end(), 0); + sums[2] = std::accumulate((hits->ErrorVec0()).begin(), + (hits->ErrorVec0()).end(), 0); + sums[3] = std::accumulate((hits->ErrorVec1()).begin(), + (hits->ErrorVec1()).end(), 0); + sizes[0] = (hits->HitsVec0()).size(); + sizes[1] = (hits->HitsVec1()).size(); + sizes[2] = (hits->ErrorVec0()).size(); + sizes[3] = (hits->ErrorVec1()).size(); + const int peak = hits->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + } + } + if (slices < 0) slices = m_dfltSlices; + timeslices = slices; + trigCpm = trigC; + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamTool.h new file mode 100755 index 0000000000000000000000000000000000000000..11ce0ad1b9d4e94b181f7ff0d2767b0463990e51 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamTool.h @@ -0,0 +1,206 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPBYTESTREAMTOOL_H +#define TRIGT1CALOBYTESTREAM_CPBYTESTREAMTOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <typename> class FullEventAssembler; + +namespace LVL1 { + class CMMCPHits; + class CPMHits; + class CPMTower; + class CPBSCollection; + class IL1CaloMappingTool; + class TriggerTowerKey; +} + +namespace LVL1BS { + +class CmmCpSubBlock; +class CpmSubBlock; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to CPM towers, CPM hits and CMM-CP hits, + * and CP container to raw data conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class CpByteStreamTool : public AthAlgTool { + + public: + CpByteStreamTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~CpByteStreamTool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to CPM towers + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTower>* ttCollection); + /// Convert ROB fragments to CPM hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMHits>* hitCollection); + /// Convert ROB fragments to CMM-CP hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMCPHits>* hitCollection); + + /// Convert CP Container to bytestream + StatusCode convert(const LVL1::CPBSCollection* cp, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + + enum CollectionType { CPM_TOWERS, CPM_HITS, CMM_CP_HITS }; + + typedef DataVector<LVL1::CPMTower> CpmTowerCollection; + typedef DataVector<LVL1::CPMHits> CpmHitsCollection; + typedef DataVector<LVL1::CMMCPHits> CmmCpHitsCollection; + typedef std::map<unsigned int, LVL1::CPMTower*> CpmTowerMap; + typedef std::map<int, LVL1::CPMHits*> CpmHitsMap; + typedef std::map<int, LVL1::CMMCPHits*> CmmCpHitsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + /// Unpack CMM-CP sub-block + void decodeCmmCp(CmmCpSubBlock* subBlock, int trigCmm); + /// Unpack CPM sub-block + void decodeCpm(CpmSubBlock* subBlock, int trigCpm, CollectionType collection); + + /// Find a CPM tower for given key + LVL1::CPMTower* findCpmTower(unsigned int key); + /// Find CPM hits for given crate, module + LVL1::CPMHits* findCpmHits(int crate, int module); + /// Find CMM-CP hits for given crate, data ID + LVL1::CMMCPHits* findCmmCpHits(int crate, int dataID); + + /// Set up CPM tower map + void setupCpmTowerMap(const CpmTowerCollection* ttCollection); + /// Set up CPM hits map + void setupCpmHitsMap(const CpmHitsCollection* hitCollection); + /// Set up CMM-CP hits map + void setupCmmCpHitsMap(const CmmCpHitsCollection* hitCollection); + + /// Get number of slices and triggered slice offset for next slink + bool slinkSlices(int crate, int module, int modulesPerSlink, + int& timeslices, int& trigJem); + + /// Channel mapping tool + ToolHandle<LVL1::IL1CaloMappingTool> m_cpmMaps; + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of channels per module + int m_channels; + /// Number of crates + int m_crates; + /// Number of CPM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Default number of slices in simulation + int m_dfltSlices; + /// Force number of slices in bytestream + int m_forceSlices; + /// Tower channels to accept (1=Core, 2=Overlap) + int m_coreOverlap; + /// Unpacking error code + unsigned int m_rodErr; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Trigger tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// CPM sub-block for unpacking + CpmSubBlock* m_cpmSubBlock; + /// CMM-CP sub-block for unpacking + CmmCpSubBlock* m_cmmCpSubBlock; + /// Hits0 vector for unpacking + std::vector<unsigned int> m_hitsVec0; + /// Hits1 vector for unpacking + std::vector<unsigned int> m_hitsVec1; + /// Error0 vector for unpacking + std::vector<int> m_errVec0; + /// Error1 vector for unpacking + std::vector<int> m_errVec1; + /// EM data vector for unpacking + std::vector<int> m_emVec; + /// Had data vector for unpacking + std::vector<int> m_hadVec; + /// EM error data vector for unpacking + std::vector<int> m_emErrVec; + /// Had error data vector for unpacking + std::vector<int> m_hadErrVec; + /// Vector for current CPM sub-blocks + DataVector<CpmSubBlock> m_cpmBlocks; + /// Vector for current CMM-CP hit0 sub-blocks + DataVector<CmmCpSubBlock> m_cmmHit0Blocks; + /// Vector for current CMM-CP hit1 sub-blocks + DataVector<CmmCpSubBlock> m_cmmHit1Blocks; + /// Current CPM tower collection + CpmTowerCollection* m_ttCollection; + /// Current CPM hits collection + CpmHitsCollection* m_hitCollection; + /// Current CMM-CP hits collection + CmmCpHitsCollection* m_cmmHitCollection; + /// CPM tower map + CpmTowerMap m_ttMap; + /// CPM hits map + CpmHitsMap m_hitsMap; + /// CMM-CP hits map + CmmCpHitsMap m_cmmHitsMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..256aacf7a6d53a3d871a231953a9191c0f97b94f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Cnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/CPBSCollectionV1.h" + +#include "CpByteStreamV1Cnv.h" +#include "CpByteStreamV1Tool.h" + +namespace LVL1BS { + +CpByteStreamV1Cnv::CpByteStreamV1Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpByteStreamV1Cnv"), + m_tool("LVL1BS::CpByteStreamV1Tool/CpByteStreamV1Tool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +CpByteStreamV1Cnv::~CpByteStreamV1Cnv() +{ +} + +// CLID + +const CLID& CpByteStreamV1Cnv::classID() +{ + return ClassID_traits<LVL1::CPBSCollectionV1>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpByteStreamV1Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode CpByteStreamV1Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::CPBSCollectionV1* cp = 0; + if( !SG::fromStorable( pObj, cp ) ) { + m_log << MSG::ERROR << " Cannot cast to CPBSCollectionV1" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( cp, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..48dcce6ca189479c7a58cbad7339db071c0ef237 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Cnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPBYTESTREAMV1CNV_H +#define TRIGT1CALOBYTESTREAM_CPBYTESTREAMV1CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpByteStreamV1Tool; + +/** ByteStream converter for CP container + * + * @author Peter Faulkner + */ + +class CpByteStreamV1Cnv: public Converter { + + friend class CnvFactory<CpByteStreamV1Cnv>; + +protected: + + CpByteStreamV1Cnv(ISvcLocator* svcloc); + +public: + + ~CpByteStreamV1Cnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from Cp Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpByteStreamV1Tool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..39df3097db4387cfb101f2878765afadd37c6f08 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Tool.cxx @@ -0,0 +1,1173 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMMCPHits.h" +#include "TrigT1CaloEvent/CPMHits.h" +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/CPBSCollectionV1.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "CmmCpSubBlock.h" +#include "CmmSubBlock.h" +#include "CpmSubBlockV1.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "ModifySlices.h" + +#include "CpByteStreamV1Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_ICpByteStreamV1Tool("CpByteStreamV1Tool", 1, 1); + +const InterfaceID& CpByteStreamV1Tool::interfaceID() +{ + return IID_ICpByteStreamV1Tool; +} + +// Constructor + +CpByteStreamV1Tool::CpByteStreamV1Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_cpmMaps("LVL1::CpmMappingTool/CpmMappingTool"), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_channels(80), m_crates(4), m_modules(14), + m_coreOverlap(0), m_subDetector(eformat::TDAQ_CALO_CLUSTER_PROC_DAQ), + m_srcIdMap(0), m_towerKey(0), m_cpmSubBlock(0), m_cmmCpSubBlock(0), + m_rodStatus(0), m_fea(0) +{ + declareInterface<CpByteStreamV1Tool>(this); + + declareProperty("CpmMappingTool", m_cpmMaps, + "Crate/Module/Channel to Eta/Phi/Layer mapping tool"); + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 8, + "Offset of CP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of CP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 2, + "The number of S-Links per crate"); + declareProperty("SimulSlices", m_dfltSlices = 1, + "The number of slices in the simulation"); + declareProperty("ForceSlices", m_forceSlices = 0, + "If >0, the number of slices in bytestream"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +CpByteStreamV1Tool::~CpByteStreamV1Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpByteStreamV1Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_cpmMaps.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_cpmMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_cpmMaps << endreq; + + sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_towerKey = new LVL1::TriggerTowerKey(); + m_cpmSubBlock = new CpmSubBlockV1(); + m_cmmCpSubBlock = new CmmCpSubBlock(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpByteStreamV1Tool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_cmmCpSubBlock; + delete m_cpmSubBlock; + delete m_towerKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to CPM towers + +StatusCode CpByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTower>* const ttCollection) +{ + m_ttCollection = ttCollection; + m_ttMap.clear(); + return convertBs(robFrags, CPM_TOWERS); +} + +// Conversion bytestream to CPM hits + +StatusCode CpByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMHits>* const hitCollection) +{ + m_hitCollection = hitCollection; + m_hitsMap.clear(); + return convertBs(robFrags, CPM_HITS); +} + +// Conversion bytestream to CMM-CP hits + +StatusCode CpByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMCPHits>* const hitCollection) +{ + m_cmmHitCollection = hitCollection; + m_cmmHitsMap.clear(); + return convertBs(robFrags, CMM_CP_HITS); +} + +// Conversion of CP container to bytestream + +StatusCode CpByteStreamV1Tool::convert(const LVL1::CPBSCollectionV1* const cp, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersionPreLS1(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + setupCpmTowerMap(cp->towers()); + setupCpmHitsMap(cp->hits()); + setupCmmCpHitsMap(cp->cmmHits()); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + int timeslices = 1; + int trigCpm = 0; + int timeslicesNew = 1; + int trigCpmNew = 0; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + // CPM modules are numbered 1 to m_modules + for (int module=1; module <= m_modules; ++module) { + const int mod = module - 1; + + // Pack required number of modules per slink + + if (mod%modulesPerSlink == 0) { + const int daqOrRoi = 0; + const int slink = (m_slinks == 2) ? 2*(mod/modulesPerSlink) + : mod/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq; + } + // Get number of CPM slices and triggered slice offset + // for this slink + if ( ! slinkSlices(crate, module, modulesPerSlink, + timeslices, trigCpm)) { + msg(MSG::ERROR) << "Inconsistent number of slices or " + << "triggered slice offsets in data for crate " + << hwCrate << " slink " << slink << endreq; + return StatusCode::FAILURE; + } + timeslicesNew = (m_forceSlices) ? m_forceSlices : timeslices; + trigCpmNew = ModifySlices::peak(trigCpm, timeslices, timeslicesNew); + if (debug) { + msg() << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq + << "Slices/offset: " << timeslices << " " << trigCpm; + if (timeslices != timeslicesNew) { + msg() << " modified to " << timeslicesNew << " " << trigCpmNew; + } + msg() << endreq; + } + L1CaloUserHeader userHeader; + userHeader.setCpm(trigCpmNew); + const uint32_t rodIdCpm = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdCpm); + theROD->push_back(userHeader.header()); + m_rodStatusMap.insert(make_pair(rodIdCpm, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block for each slice (except Neutral format) + + m_cpmBlocks.clear(); + for (int slice = 0; slice < timeslicesNew; ++slice) { + CpmSubBlockV1* const subBlock = new CpmSubBlockV1(); + subBlock->setCpmHeader(m_version, m_dataFormat, slice, + hwCrate, module, timeslicesNew); + m_cpmBlocks.push_back(subBlock); + if (neutralFormat) break; + } + + // Find CPM towers corresponding to each eta/phi pair and fill + // sub-blocks + + for (int chan=0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_cpmMaps->mapping(crate, module, chan, eta, phi, layer)) { + const unsigned int key = m_towerKey->ttKey(phi, eta); + const LVL1::CPMTower* const tt = findCpmTower(key); + if (tt ) { + std::vector<int> emData; + std::vector<int> hadData; + std::vector<int> emError; + std::vector<int> hadError; + ModifySlices::data(tt->emEnergyVec(), emData, timeslicesNew); + ModifySlices::data(tt->hadEnergyVec(), hadData, timeslicesNew); + ModifySlices::data(tt->emErrorVec(), emError, timeslicesNew); + ModifySlices::data(tt->hadErrorVec(), hadError, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError emErrBits(emError[slice]); + const LVL1::DataError hadErrBits(hadError[slice]); + const int emErr = + (emErrBits.get(LVL1::DataError::LinkDown) << 1) | + emErrBits.get(LVL1::DataError::Parity); + const int hadErr = + (hadErrBits.get(LVL1::DataError::LinkDown) << 1) | + hadErrBits.get(LVL1::DataError::Parity); + const int index = ( neutralFormat ) ? 0 : slice; + CpmSubBlockV1* const subBlock = m_cpmBlocks[index]; + subBlock->fillTowerData(slice, chan, emData[slice], + hadData[slice], emErr, hadErr); + } + } + } + } + + // Add CPM hits + + const LVL1::CPMHits* const hits = findCpmHits(crate, module); + if (hits) { + std::vector<unsigned int> vec0; + std::vector<unsigned int> vec1; + ModifySlices::data(hits->HitsVec0(), vec0, timeslicesNew); + ModifySlices::data(hits->HitsVec1(), vec1, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const int index = ( neutralFormat ) ? 0 : slice; + CpmSubBlockV1* const subBlock = m_cpmBlocks[index]; + subBlock->setHits(slice, vec0[slice], vec1[slice]); + } + } + + // Pack and write the sub-blocks + + DataVector<CpmSubBlockV1>::const_iterator pos; + for (pos = m_cpmBlocks.begin(); pos != m_cpmBlocks.end(); ++pos) { + CpmSubBlockV1* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CPM sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CPM sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Append CMMs to last S-Link of the crate + + // Create a sub-block for each slice (except Neutral format) + + m_cmmHit0Blocks.clear(); + m_cmmHit1Blocks.clear(); + const int summing = (crate == m_crates - 1) ? CmmSubBlock::SYSTEM + : CmmSubBlock::CRATE; + for (int slice = 0; slice < timeslicesNew; ++slice) { + CmmCpSubBlock* const h0Block = new CmmCpSubBlock(); + h0Block->setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_CP, + CmmSubBlock::RIGHT, timeslicesNew); + m_cmmHit0Blocks.push_back(h0Block); + CmmCpSubBlock* const h1Block = new CmmCpSubBlock(); + h1Block->setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_CP, + CmmSubBlock::LEFT, timeslicesNew); + m_cmmHit1Blocks.push_back(h1Block); + if (neutralFormat) break; + } + + // CMM-CP + + const int maxDataID = LVL1::CMMCPHits::MAXID; + for (int dataID = 1; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID > m_modules) { + if (summing == CmmSubBlock::CRATE && + dataID != LVL1::CMMCPHits::LOCAL) continue; + switch (dataID) { + case LVL1::CMMCPHits::LOCAL: + source = CmmCpSubBlock::LOCAL; + break; + case LVL1::CMMCPHits::REMOTE_0: + source = CmmCpSubBlock::REMOTE_0; + break; + case LVL1::CMMCPHits::REMOTE_1: + source = CmmCpSubBlock::REMOTE_1; + break; + case LVL1::CMMCPHits::REMOTE_2: + source = CmmCpSubBlock::REMOTE_2; + break; + case LVL1::CMMCPHits::TOTAL: + source = CmmCpSubBlock::TOTAL; + break; + default: + continue; + } + } + const LVL1::CMMCPHits* const ch = findCmmCpHits(crate, dataID); + if ( ch ) { + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + std::vector<int> err0; + std::vector<int> err1; + ModifySlices::data(ch->HitsVec0(), hits0, timeslicesNew); + ModifySlices::data(ch->HitsVec1(), hits1, timeslicesNew); + ModifySlices::data(ch->ErrorVec0(), err0, timeslicesNew); + ModifySlices::data(ch->ErrorVec1(), err1, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError err0Bits(err0[slice]); + const LVL1::DataError err1Bits(err1[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + CmmCpSubBlock* subBlock = m_cmmHit0Blocks[index]; + subBlock->setHits(slice, source, hits0[slice], + err0Bits.get(LVL1::DataError::Parity)); + subBlock = m_cmmHit1Blocks[index]; + subBlock->setHits(slice, source, hits1[slice], + err1Bits.get(LVL1::DataError::Parity)); + } + } + } + DataVector<CmmCpSubBlock>::const_iterator cos = m_cmmHit0Blocks.begin(); + for (; cos != m_cmmHit0Blocks.end(); ++cos) { + CmmCpSubBlock* const subBlock = *cos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Cp sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Cp sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + cos = m_cmmHit1Blocks.begin(); + for (; cos != m_cmmHit1Blocks.end(); ++cos) { + CmmCpSubBlock* const subBlock = *cos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Cp sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Cp sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& CpByteStreamV1Tool::sourceIDs( + const std::string& sgKey) +{ + // Check if overlap tower channels wanted + const std::string flag("Overlap"); + const std::string::size_type pos = sgKey.find(flag); + m_coreOverlap = + (pos == std::string::npos || pos != sgKey.length() - flag.length()) ? 0 : 1; + + if (m_sourceIDs.empty()) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 0; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + m_sourceIDs.push_back(robId); + } + } + } + return m_sourceIDs; +} + +// Convert bytestream to given container type + +StatusCode CpByteStreamV1Tool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: ROD " + << MSG::hex << sourceID << " ROB " << robid + << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion > m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping post-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word should be User Header + if ( !L1CaloUserHeader::isValid(*payload) ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Invalid or missing user header" << endreq; + continue; + } + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + // triggered slice offsets + int trigCpm = userHeader.cpm(); + int trigCmm = userHeader.cpCmm(); + if (debug) { + msg() << "Minor format version number: " << MSG::hex + << minorVersion << MSG::dec << endreq + << "CPM triggered slice offset: " << trigCpm << endreq + << "CMM triggered slice offset: " << trigCmm << endreq; + } + if (trigCpm != trigCmm) { + const int newTrig = (trigCpm > trigCmm) ? trigCpm : trigCmm; + trigCpm = newTrig; + trigCmm = newTrig; + if (debug) msg() << "Changed both offsets to " << newTrig << endreq; + } + + // Loop over sub-blocks + + m_rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER) { + if (debug) msg() << "Unexpected data sequence" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MISSING_HEADER; + break; + } + if (L1CaloSubBlock::version(*payload) != 1) { // <<== CHECK + if (debug) msg() << "Skipping post-LS1 data" << endreq; + break; + } + if (CmmSubBlock::cmmBlock(*payload)) { + // CMM + if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_CP) { + m_cmmCpSubBlock->clear(); + payload = m_cmmCpSubBlock->read(payload, payloadEnd); + if (m_cmmCpSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMM_CP_HITS) { + decodeCmmCp(m_cmmCpSubBlock, trigCmm); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmmCp failed" << endreq; + break; + } + } + } else { + if (debug) msg() << "Invalid CMM type in module field" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + } else { + // CPM + m_cpmSubBlock->clear(); + payload = m_cpmSubBlock->read(payload, payloadEnd); + if (m_cpmSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CPM_TOWERS || collection == CPM_HITS) { + decodeCpm(m_cpmSubBlock, trigCpm, collection); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCpm failed" << endreq; + break; + } + } + } + } + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, m_rodErr); + } + + return StatusCode::SUCCESS; +} + +// Unpack CMM-CP sub-block + +void CpByteStreamV1Tool::decodeCmmCp(CmmCpSubBlock* subBlock, int trigCmm) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmmPosition(); + const int firmware = subBlock->cmmFirmware(); + const int summing = subBlock->cmmSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMM-CP: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigCmm) { + if (debug) msg() << "Triggered CMM slice from header " + << "inconsistent with number of slices: " + << trigCmm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMM-CP sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const uint32_t subStatus = subBlock->subStatus(); + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSid = CmmCpSubBlock::MAX_SOURCE_ID; + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Jet hit counts + + for (int source = 1; source < maxSid; ++source) { + int dataID = source; + if (source > m_modules) { + if (summing == CmmSubBlock::CRATE && + source != CmmCpSubBlock::LOCAL) continue; + switch (source) { + case CmmCpSubBlock::LOCAL: + dataID = LVL1::CMMCPHits::LOCAL; + break; + case CmmCpSubBlock::REMOTE_0: + dataID = LVL1::CMMCPHits::REMOTE_0; + break; + case CmmCpSubBlock::REMOTE_1: + dataID = LVL1::CMMCPHits::REMOTE_1; + break; + case CmmCpSubBlock::REMOTE_2: + dataID = LVL1::CMMCPHits::REMOTE_2; + break; + case CmmCpSubBlock::TOTAL: + dataID = LVL1::CMMCPHits::TOTAL; + break; + default: + continue; + } + } + const unsigned int hits = subBlock->hits(slice, source); + int err = subBlock->hitsError(slice, source); + LVL1::DataError errorBits; + errorBits.set(LVL1::DataError::Parity, err & 0x1); + errorBits.set(LVL1::DataError::SubStatusWord, subStatus); + err = errorBits.error(); + if (hits || err) { + LVL1::CMMCPHits* ch = findCmmCpHits(crate, dataID); + if ( ! ch ) { // create new CMM hits + m_hitsVec0.assign(timeslices, 0); + m_hitsVec1.assign(timeslices, 0); + m_errVec0.assign(timeslices, 0); + m_errVec1.assign(timeslices, 0); + if (module == CmmSubBlock::RIGHT) { + m_hitsVec0[slice] = hits; + m_errVec0[slice] = err; + } else { + m_hitsVec1[slice] = hits; + m_errVec1[slice] = err; + } + ch = new LVL1::CMMCPHits(swCrate, dataID, m_hitsVec0, m_hitsVec1, + m_errVec0, m_errVec1, trigCmm); + const int key = crate*100 + dataID; + m_cmmHitsMap.insert(std::make_pair(key, ch)); + m_cmmHitCollection->push_back(ch); + } else { + m_hitsVec0 = ch->HitsVec0(); + m_hitsVec1 = ch->HitsVec1(); + m_errVec0 = ch->ErrorVec0(); + m_errVec1 = ch->ErrorVec1(); + const int nsl = m_hitsVec0.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if ((module == CmmSubBlock::RIGHT && (m_hitsVec0[slice] != 0 || + m_errVec0[slice] != 0)) || (module == CmmSubBlock::LEFT && + (m_hitsVec1[slice] != 0 || m_errVec1[slice] != 0))) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + if (module == CmmSubBlock::RIGHT) { + m_hitsVec0[slice] = hits; + m_errVec0[slice] = err; + } else { + m_hitsVec1[slice] = hits; + m_errVec1[slice] = err; + } + ch->addHits(m_hitsVec0, m_hitsVec1, m_errVec0, m_errVec1); + } + } + } + } + + return; +} + +// Unpack CPM sub-block + +void CpByteStreamV1Tool::decodeCpm(CpmSubBlockV1* subBlock, + int trigCpm, const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + const bool verbose = msgLvl(MSG::VERBOSE); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->module(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CPM: Crate " << hwCrate + << " Module " << module + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (module < 1 || module > m_modules) { + if (debug) msg() << "Unexpected module number: " << module << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + return; + } + if (timeslices <= trigCpm) { + if (debug) msg() << "Triggered CPM slice from header " + << "inconsistent with number of slices: " + << trigCpm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CPM sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + LVL1::DataError dErr; + dErr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = dErr.error(); + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + if (collection == CPM_TOWERS) { + + // Loop over tower channels and fill CPM towers + + for (int chan = 0; chan < m_channels; ++chan) { + if (!ssError && !subBlock->anyTowerData(chan)) continue; + const int em = subBlock->emData(slice, chan); + const int had = subBlock->hadData(slice, chan); + const int emErr = subBlock->emError(slice, chan); + const int hadErr = subBlock->hadError(slice, chan); + int emErr1 = ssError; + if (emErr) { + LVL1::DataError emErrBits(emErr1); + emErrBits.set(LVL1::DataError::Parity, emErr & 0x1); + emErrBits.set(LVL1::DataError::LinkDown, (emErr >> 1) & 0x1); + emErr1 = emErrBits.error(); + } + int hadErr1 = ssError; + if (hadErr) { + LVL1::DataError hadErrBits(hadErr1); + hadErrBits.set(LVL1::DataError::Parity, hadErr & 0x1); + hadErrBits.set(LVL1::DataError::LinkDown, (hadErr >> 1) & 0x1); + hadErr1 = hadErrBits.error(); + } + if (em || had || emErr1 || hadErr1) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_cpmMaps->mapping(crate, module, chan, eta, phi, layer)) { + if (layer == m_coreOverlap) { + const unsigned int key = m_towerKey->ttKey(phi, eta); + LVL1::CPMTower* tt = findCpmTower(key); + if ( ! tt ) { // create new CPM tower + m_emVec.assign(timeslices, 0); + m_hadVec.assign(timeslices, 0); + m_emErrVec.assign(timeslices, 0); + m_hadErrVec.assign(timeslices, 0); + m_emVec[slice] = em; + m_hadVec[slice] = had; + m_emErrVec[slice] = emErr1; + m_hadErrVec[slice] = hadErr1; + tt = new LVL1::CPMTower(phi, eta, m_emVec, m_emErrVec, + m_hadVec, m_hadErrVec, trigCpm); + m_ttMap.insert(std::make_pair(key, tt)); + m_ttCollection->push_back(tt); + } else { + m_emVec = tt->emEnergyVec(); + m_hadVec = tt->hadEnergyVec(); + m_emErrVec = tt->emErrorVec(); + m_hadErrVec = tt->hadErrorVec(); + const int nsl = m_emVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_emVec[slice] != 0 || m_hadVec[slice] != 0 || + m_emErrVec[slice] != 0 || m_hadErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_emVec[slice] = em; + m_hadVec[slice] = had; + m_emErrVec[slice] = emErr1; + m_hadErrVec[slice] = hadErr1; + tt->fill(m_emVec, m_emErrVec, m_hadVec, m_hadErrVec, trigCpm); + } + } + } else if (verbose && (em || had || emErr || hadErr)) { + msg(MSG::VERBOSE) << "Non-zero data but no channel mapping for channel " + << chan << endreq; + msg(MSG::DEBUG); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No CPM tower data for channel " + << chan << " slice " << slice << endreq; + msg(MSG::DEBUG); + } + } + } else if (collection == CPM_HITS) { + + // Get CPM hits + + const unsigned int hits0 = subBlock->hits0(slice); + const unsigned int hits1 = subBlock->hits1(slice); + if (hits0 || hits1) { + LVL1::CPMHits* ch = findCpmHits(crate, module); + if ( ! ch ) { // create new CPM hits + m_hitsVec0.assign(timeslices, 0); + m_hitsVec1.assign(timeslices, 0); + m_hitsVec0[slice] = hits0; + m_hitsVec1[slice] = hits1; + ch = new LVL1::CPMHits(swCrate, module, m_hitsVec0, m_hitsVec1, trigCpm); + m_hitsMap.insert(std::make_pair(crate*m_modules+module-1, ch)); + m_hitCollection->push_back(ch); + } else { + m_hitsVec0 = ch->HitsVec0(); + m_hitsVec1 = ch->HitsVec1(); + const int nsl = m_hitsVec0.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec0[slice] != 0 || m_hitsVec1[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec0[slice] = hits0; + m_hitsVec1[slice] = hits1; + ch->addHits(m_hitsVec0, m_hitsVec1); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No CPM hits data for crate/module/slice " + << hwCrate << "/" << module << "/" << slice + << endreq; + msg(MSG::DEBUG); + } + } + } + return; +} + +// Find a CPM tower for given key + +LVL1::CPMTower* CpByteStreamV1Tool::findCpmTower(const unsigned int key) +{ + LVL1::CPMTower* tt = 0; + CpmTowerMap::const_iterator mapIter; + mapIter = m_ttMap.find(key); + if (mapIter != m_ttMap.end()) tt = mapIter->second; + return tt; +} + +// Find CPM hits for given crate, module + +LVL1::CPMHits* CpByteStreamV1Tool::findCpmHits(const int crate, const int module) +{ + LVL1::CPMHits* hits = 0; + CpmHitsMap::const_iterator mapIter; + mapIter = m_hitsMap.find(crate*m_modules + module - 1); + if (mapIter != m_hitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find CMM-CP hits for given crate, dataID + +LVL1::CMMCPHits* CpByteStreamV1Tool::findCmmCpHits(const int crate, + const int dataID) +{ + LVL1::CMMCPHits* hits = 0; + CmmCpHitsMap::const_iterator mapIter; + mapIter = m_cmmHitsMap.find(crate*100 + dataID); + if (mapIter != m_cmmHitsMap.end()) hits = mapIter->second; + return hits; +} + +// Set up CPM tower map + +void CpByteStreamV1Tool::setupCpmTowerMap(const CpmTowerCollection* + const ttCollection) +{ + m_ttMap.clear(); + if (ttCollection) { + CpmTowerCollection::const_iterator pos = ttCollection->begin(); + CpmTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CPMTower* const tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + m_ttMap.insert(std::make_pair(key, tt)); + } + } +} + +// Set up CPM hits map + +void CpByteStreamV1Tool::setupCpmHitsMap(const CpmHitsCollection* + const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + CpmHitsCollection::const_iterator pos = hitCollection->begin(); + CpmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CPMHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = m_modules * crate + hits->module() - 1; + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM-CP hits map + +void CpByteStreamV1Tool::setupCmmCpHitsMap(const CmmCpHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmCpHitsCollection::const_iterator pos = hitCollection->begin(); + CmmCpHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMMCPHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = crate*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Get number of slices and triggered slice offset for next slink + +bool CpByteStreamV1Tool::slinkSlices(const int crate, const int module, + const int modulesPerSlink, int& timeslices, int& trigCpm) +{ + int slices = -1; + int trigC = m_dfltSlices/2; + for (int mod = module; mod < module + modulesPerSlink; ++mod) { + for (int chan = 0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if ( !m_cpmMaps->mapping(crate, mod, chan, eta, phi, layer)) continue; + const unsigned int key = m_towerKey->ttKey(phi, eta); + const LVL1::CPMTower* const tt = findCpmTower(key); + if ( !tt ) continue; + const int numdat = 4; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((tt->emEnergyVec()).begin(), + (tt->emEnergyVec()).end(), 0); + sums[1] = std::accumulate((tt->hadEnergyVec()).begin(), + (tt->hadEnergyVec()).end(), 0); + sums[2] = std::accumulate((tt->emErrorVec()).begin(), + (tt->emErrorVec()).end(), 0); + sums[3] = std::accumulate((tt->hadErrorVec()).begin(), + (tt->hadErrorVec()).end(), 0); + sizes[0] = (tt->emEnergyVec()).size(); + sizes[1] = (tt->hadEnergyVec()).size(); + sizes[2] = (tt->emErrorVec()).size(); + sizes[3] = (tt->hadErrorVec()).size(); + const int peak = tt->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + const LVL1::CPMHits* const hits = findCpmHits(crate, mod); + if (hits) { + const int numdat = 2; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((hits->HitsVec0()).begin(), + (hits->HitsVec0()).end(), 0); + sums[1] = std::accumulate((hits->HitsVec1()).begin(), + (hits->HitsVec1()).end(), 0); + sizes[0] = (hits->HitsVec0()).size(); + sizes[1] = (hits->HitsVec1()).size(); + const int peak = hits->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + } + // CMM last slink of crate + if (module/modulesPerSlink == m_slinks - 1) { + const int maxDataID = LVL1::CMMCPHits::MAXID; + for (int dataID = 0; dataID < maxDataID; ++dataID) { + const int numdat = 4; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + const LVL1::CMMCPHits* const hits = findCmmCpHits(crate, dataID); + if (hits) { + sums[0] = std::accumulate((hits->HitsVec0()).begin(), + (hits->HitsVec0()).end(), 0); + sums[1] = std::accumulate((hits->HitsVec1()).begin(), + (hits->HitsVec1()).end(), 0); + sums[2] = std::accumulate((hits->ErrorVec0()).begin(), + (hits->ErrorVec0()).end(), 0); + sums[3] = std::accumulate((hits->ErrorVec1()).begin(), + (hits->ErrorVec1()).end(), 0); + sizes[0] = (hits->HitsVec0()).size(); + sizes[1] = (hits->HitsVec1()).size(); + sizes[2] = (hits->ErrorVec0()).size(); + sizes[3] = (hits->ErrorVec1()).size(); + const int peak = hits->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + } + } + if (slices < 0) slices = m_dfltSlices; + timeslices = slices; + trigCpm = trigC; + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..f1653634171e9808c66f199dcccfb2ce552232b6 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV1Tool.h @@ -0,0 +1,210 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPBYTESTREAMV1TOOL_H +#define TRIGT1CALOBYTESTREAM_CPBYTESTREAMV1TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <typename> class FullEventAssembler; + +namespace LVL1 { + class CMMCPHits; + class CPMHits; + class CPMTower; + class CPBSCollectionV1; + class IL1CaloMappingTool; + class TriggerTowerKey; +} + +namespace LVL1BS { + +class CmmCpSubBlock; +class CpmSubBlockV1; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to CPM towers, CPM hits and CMM-CP hits, + * and CP container to raw data conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class CpByteStreamV1Tool : public AthAlgTool { + + public: + CpByteStreamV1Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~CpByteStreamV1Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to CPM towers + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTower>* ttCollection); + /// Convert ROB fragments to CPM hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMHits>* hitCollection); + /// Convert ROB fragments to CMM-CP hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMCPHits>* hitCollection); + + /// Convert CP Container to bytestream + StatusCode convert(const LVL1::CPBSCollectionV1* cp, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + + enum CollectionType { CPM_TOWERS, CPM_HITS, CMM_CP_HITS }; + + typedef DataVector<LVL1::CPMTower> CpmTowerCollection; + typedef DataVector<LVL1::CPMHits> CpmHitsCollection; + typedef DataVector<LVL1::CMMCPHits> CmmCpHitsCollection; + typedef std::map<unsigned int, LVL1::CPMTower*> CpmTowerMap; + typedef std::map<int, LVL1::CPMHits*> CpmHitsMap; + typedef std::map<int, LVL1::CMMCPHits*> CmmCpHitsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + /// Unpack CMM-CP sub-block + void decodeCmmCp(CmmCpSubBlock* subBlock, int trigCmm); + /// Unpack CPM sub-block + void decodeCpm(CpmSubBlockV1* subBlock, int trigCpm, CollectionType collection); + + /// Find a CPM tower for given key + LVL1::CPMTower* findCpmTower(unsigned int key); + /// Find CPM hits for given crate, module + LVL1::CPMHits* findCpmHits(int crate, int module); + /// Find CMM-CP hits for given crate, data ID + LVL1::CMMCPHits* findCmmCpHits(int crate, int dataID); + + /// Set up CPM tower map + void setupCpmTowerMap(const CpmTowerCollection* ttCollection); + /// Set up CPM hits map + void setupCpmHitsMap(const CpmHitsCollection* hitCollection); + /// Set up CMM-CP hits map + void setupCmmCpHitsMap(const CmmCpHitsCollection* hitCollection); + + /// Get number of slices and triggered slice offset for next slink + bool slinkSlices(int crate, int module, int modulesPerSlink, + int& timeslices, int& trigJem); + + /// Channel mapping tool + ToolHandle<LVL1::IL1CaloMappingTool> m_cpmMaps; + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of channels per module + int m_channels; + /// Number of crates + int m_crates; + /// Number of CPM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Default number of slices in simulation + int m_dfltSlices; + /// Force number of slices in bytestream + int m_forceSlices; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// Tower channels to accept (1=Core, 2=Overlap) + int m_coreOverlap; + /// Unpacking error code + unsigned int m_rodErr; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Trigger tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// CPM sub-block for unpacking + CpmSubBlockV1* m_cpmSubBlock; + /// CMM-CP sub-block for unpacking + CmmCpSubBlock* m_cmmCpSubBlock; + /// Hits0 vector for unpacking + std::vector<unsigned int> m_hitsVec0; + /// Hits1 vector for unpacking + std::vector<unsigned int> m_hitsVec1; + /// Error0 vector for unpacking + std::vector<int> m_errVec0; + /// Error1 vector for unpacking + std::vector<int> m_errVec1; + /// EM data vector for unpacking + std::vector<int> m_emVec; + /// Had data vector for unpacking + std::vector<int> m_hadVec; + /// EM error data vector for unpacking + std::vector<int> m_emErrVec; + /// Had error data vector for unpacking + std::vector<int> m_hadErrVec; + /// Vector for current CPM sub-blocks + DataVector<CpmSubBlockV1> m_cpmBlocks; + /// Vector for current CMM-CP hit0 sub-blocks + DataVector<CmmCpSubBlock> m_cmmHit0Blocks; + /// Vector for current CMM-CP hit1 sub-blocks + DataVector<CmmCpSubBlock> m_cmmHit1Blocks; + /// Current CPM tower collection + CpmTowerCollection* m_ttCollection; + /// Current CPM hits collection + CpmHitsCollection* m_hitCollection; + /// Current CMM-CP hits collection + CmmCpHitsCollection* m_cmmHitCollection; + /// CPM tower map + CpmTowerMap m_ttMap; + /// CPM hits map + CpmHitsMap m_hitsMap; + /// CMM-CP hits map + CmmCpHitsMap m_cmmHitsMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..d648bf2d3b5b44056fb97dcef9fbc19e6187c8cc --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Cnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/CPBSCollectionV2.h" + +#include "CpByteStreamV2Cnv.h" +#include "CpByteStreamV2Tool.h" + +namespace LVL1BS { + +CpByteStreamV2Cnv::CpByteStreamV2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpByteStreamV2Cnv"), + m_tool("LVL1BS::CpByteStreamV2Tool/CpByteStreamV2Tool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +CpByteStreamV2Cnv::~CpByteStreamV2Cnv() +{ +} + +// CLID + +const CLID& CpByteStreamV2Cnv::classID() +{ + return ClassID_traits<LVL1::CPBSCollectionV2>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpByteStreamV2Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode CpByteStreamV2Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::CPBSCollectionV2* cp = 0; + if( !SG::fromStorable( pObj, cp ) ) { + m_log << MSG::ERROR << " Cannot cast to CPBSCollectionV2" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( cp, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..f7fc65683ff973980b9174dc14a29e9a76e2a028 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Cnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPBYTESTREAMV2CNV_H +#define TRIGT1CALOBYTESTREAM_CPBYTESTREAMV2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpByteStreamV2Tool; + +/** ByteStream converter for CP container post LS1 + * + * @author Peter Faulkner + */ + +class CpByteStreamV2Cnv: public Converter { + + friend class CnvFactory<CpByteStreamV2Cnv>; + +protected: + + CpByteStreamV2Cnv(ISvcLocator* svcloc); + +public: + + ~CpByteStreamV2Cnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from Cp Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpByteStreamV2Tool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..54f6a7f72dde59bf88583b3bce7a97200096443d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Tool.cxx @@ -0,0 +1,1204 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMXCPHits.h" +#include "TrigT1CaloEvent/CMXCPTob.h" +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/CPBSCollectionV2.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "CmxCpSubBlock.h" +#include "CmxSubBlock.h" +#include "CpmSubBlockV2.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "ModifySlices.h" + +#include "CpByteStreamV2Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_ICpByteStreamV2Tool("CpByteStreamV2Tool", 1, 1); + +const InterfaceID& CpByteStreamV2Tool::interfaceID() +{ + return IID_ICpByteStreamV2Tool; +} + +// Constructor + +CpByteStreamV2Tool::CpByteStreamV2Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_cpmMaps("LVL1::CpmMappingTool/CpmMappingTool"), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_channels(80), m_crates(4), m_modules(14), m_cmxs(2), m_maxTobs(5), + m_chips(16), m_locs(4), + m_coreOverlap(0), m_subDetector(eformat::TDAQ_CALO_CLUSTER_PROC_DAQ), + m_srcIdMap(0), m_towerKey(0), m_cpmSubBlock(0), m_cmxCpSubBlock(0), + m_rodStatus(0), m_fea(0) +{ + declareInterface<CpByteStreamV2Tool>(this); + + declareProperty("CpmMappingTool", m_cpmMaps, + "Crate/Module/Channel to Eta/Phi/Layer mapping tool"); + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 8, + "Offset of CP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of CP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 2, // <<== CHECK + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 2, + "The number of S-Links per crate"); + declareProperty("SimulSlices", m_dfltSlices = 1, + "The number of slices in the simulation"); + declareProperty("ForceSlices", m_forceSlices = 0, + "If >0, the number of slices in bytestream"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +CpByteStreamV2Tool::~CpByteStreamV2Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpByteStreamV2Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_cpmMaps.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_cpmMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_cpmMaps << endreq; + + sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_towerKey = new LVL1::TriggerTowerKey(); + m_cpmSubBlock = new CpmSubBlockV2(); + m_cmxCpSubBlock = new CmxCpSubBlock(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpByteStreamV2Tool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_cmxCpSubBlock; + delete m_cpmSubBlock; + delete m_towerKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to CPM towers + +StatusCode CpByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTower>* const ttCollection) +{ + m_ttCollection = ttCollection; + m_ttMap.clear(); + return convertBs(robFrags, CPM_TOWERS); +} + +// Conversion bytestream to CMX-CP TOBs + +StatusCode CpByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXCPTob>* const tobCollection) +{ + m_tobCollection = tobCollection; + m_tobMap.clear(); + return convertBs(robFrags, CMX_CP_TOBS); +} + +// Conversion bytestream to CMX-CP hits + +StatusCode CpByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXCPHits>* const hitCollection) +{ + m_hitCollection = hitCollection; + m_hitsMap.clear(); + return convertBs(robFrags, CMX_CP_HITS); +} + +// Conversion of CP container to bytestream + +StatusCode CpByteStreamV2Tool::convert(const LVL1::CPBSCollectionV2* const cp, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + setupCpmTowerMap(cp->towers()); + setupCmxCpTobMap(cp->tobs()); + setupCmxCpHitsMap(cp->hits()); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + int timeslices = 1; + int trigCpm = 0; + int timeslicesNew = 1; + int trigCpmNew = 0; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + // CPM modules are numbered 1 to m_modules + for (int module=1; module <= m_modules; ++module) { + const int mod = module - 1; + + // Pack required number of modules per slink + + if (mod%modulesPerSlink == 0) { + const int daqOrRoi = 0; + const int slink = (m_slinks == 2) ? 2*(mod/modulesPerSlink) + : mod/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq; + } + // Get number of CPM slices and triggered slice offset + // for this slink + if ( ! slinkSlices(crate, module, modulesPerSlink, + timeslices, trigCpm)) { + msg(MSG::ERROR) << "Inconsistent number of slices or " + << "triggered slice offsets in data for crate " + << hwCrate << " slink " << slink << endreq; + return StatusCode::FAILURE; + } + timeslicesNew = (m_forceSlices) ? m_forceSlices : timeslices; + trigCpmNew = ModifySlices::peak(trigCpm, timeslices, timeslicesNew); + if (debug) { + msg() << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq + << "Slices/offset: " << timeslices << " " << trigCpm; + if (timeslices != timeslicesNew) { + msg() << " modified to " << timeslicesNew << " " << trigCpmNew; + } + msg() << endreq; + } + L1CaloUserHeader userHeader; + userHeader.setCpm(trigCpmNew); + const uint32_t rodIdCpm = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdCpm); + theROD->push_back(userHeader.header()); + m_rodStatusMap.insert(make_pair(rodIdCpm, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block for each slice (except Neutral format) + + m_cpmBlocks.clear(); + for (int slice = 0; slice < timeslicesNew; ++slice) { + CpmSubBlockV2* const subBlock = new CpmSubBlockV2(); + subBlock->setCpmHeader(m_version, m_dataFormat, slice, + hwCrate, module, timeslicesNew); + m_cpmBlocks.push_back(subBlock); + if (neutralFormat) break; + } + + // Find CPM towers corresponding to each eta/phi pair and fill + // sub-blocks + + for (int chan=0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_cpmMaps->mapping(crate, module, chan, eta, phi, layer)) { + const unsigned int key = m_towerKey->ttKey(phi, eta); + const LVL1::CPMTower* const tt = findCpmTower(key); + if (tt ) { + std::vector<int> emData; + std::vector<int> hadData; + std::vector<int> emError; + std::vector<int> hadError; + ModifySlices::data(tt->emEnergyVec(), emData, timeslicesNew); + ModifySlices::data(tt->hadEnergyVec(), hadData, timeslicesNew); + ModifySlices::data(tt->emErrorVec(), emError, timeslicesNew); + ModifySlices::data(tt->hadErrorVec(), hadError, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError emErrBits(emError[slice]); + const LVL1::DataError hadErrBits(hadError[slice]); + const int emErr = + (emErrBits.get(LVL1::DataError::LinkDown) << 1) | + emErrBits.get(LVL1::DataError::Parity); + const int hadErr = + (hadErrBits.get(LVL1::DataError::LinkDown) << 1) | + hadErrBits.get(LVL1::DataError::Parity); + const int index = ( neutralFormat ) ? 0 : slice; + CpmSubBlockV2* const subBlock = m_cpmBlocks[index]; + subBlock->fillTowerData(slice, chan, emData[slice], + hadData[slice], emErr, hadErr); + if ((emErrBits.error() >> LVL1::DataError::GLinkParity)) { + int gLinkParity = emErrBits.get(LVL1::DataError::GLinkParity); + int gLinkProtocol = emErrBits.get(LVL1::DataError::GLinkProtocol); + int bCNMismatch = emErrBits.get(LVL1::DataError::BCNMismatch); + int fIFOOverflow = emErrBits.get(LVL1::DataError::FIFOOverflow); + int moduleError = emErrBits.get(LVL1::DataError::ModuleError); + int gLinkDown = emErrBits.get(LVL1::DataError::GLinkDown); + int gLinkTimeout = emErrBits.get(LVL1::DataError::GLinkTimeout); + uint32_t failingBCN = emErrBits.get(LVL1::DataError::FailingBCN); + subBlock->setStatus(failingBCN, gLinkTimeout, gLinkDown, + moduleError, fIFOOverflow, bCNMismatch, + gLinkProtocol, gLinkParity); + } + } + } + } + } + + // Pack and write the sub-blocks + + DataVector<CpmSubBlockV2>::const_iterator pos; + for (pos = m_cpmBlocks.begin(); pos != m_cpmBlocks.end(); ++pos) { + CpmSubBlockV2* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CPM sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CPM sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Append CMXs to last S-Link of the crate + + for (int cmx = 0; cmx < m_cmxs; ++cmx) { + + // Create a sub-block for each slice (except Neutral format) + + m_cmxBlocks.clear(); + const int summing = (crate == m_crates - 1) ? CmxSubBlock::SYSTEM + : CmxSubBlock::CRATE; + for (int slice = 0; slice < timeslicesNew; ++slice) { + CmxCpSubBlock* const block = new CmxCpSubBlock(); + block->setCmxHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmxSubBlock::CMX_CP, cmx, timeslicesNew); + m_cmxBlocks.push_back(block); + if (neutralFormat) break; + } + + // CMX-CP Tobs + + for (int cpm = 1; cpm <= m_modules; ++cpm) { + for (int chip = 0; chip < m_chips; ++chip) { + for (int loc = 0; loc < m_locs; ++loc) { + const int key = tobKey(crate, cmx, cpm, chip, loc); + const LVL1::CMXCPTob* const ct = findCmxCpTob(key); + if ( ct ) { + std::vector<int> energy; + std::vector<int> isolation; + std::vector<int> error; + std::vector<unsigned int> presence; + ModifySlices::data(ct->energyVec(), energy, timeslicesNew); + ModifySlices::data(ct->isolationVec(), isolation, timeslicesNew); + ModifySlices::data(ct->errorVec(), error, timeslicesNew); + ModifySlices::data(ct->presenceMapVec(), presence, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError errBits(error[slice]); + int err = errBits.get(LVL1::DataError::ParityMerge); + err |= (errBits.get(LVL1::DataError::ParityPhase0))<<1; + err |= (errBits.get(LVL1::DataError::ParityPhase1))<<2; + err |= (errBits.get(LVL1::DataError::ParityPhase2))<<3; + err |= (errBits.get(LVL1::DataError::ParityPhase3))<<4; + err |= (errBits.get(LVL1::DataError::Overflow))<<5; + const int index = ( neutralFormat ) ? 0 : slice; + CmxCpSubBlock* const subBlock = m_cmxBlocks[index]; + subBlock->setTob(slice, cpm, chip, loc, energy[slice], + isolation[slice], err); + subBlock->setPresenceMap(slice, cpm, presence[slice]); + } + } + } + } + } + + // CMX-CP Hits + + for (int source = 0; source < LVL1::CMXCPHits::MAXSOURCE; ++source) { + const int key = hitsKey(crate, cmx, source); + const LVL1::CMXCPHits* const ch = findCmxCpHits(key); + if ( ch ) { + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + std::vector<int> err0; + std::vector<int> err1; + ModifySlices::data(ch->hitsVec0(), hits0, timeslicesNew); + ModifySlices::data(ch->hitsVec1(), hits1, timeslicesNew); + ModifySlices::data(ch->errorVec0(), err0, timeslicesNew); + ModifySlices::data(ch->errorVec1(), err1, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError err0Bits(err0[slice]); + const LVL1::DataError err1Bits(err1[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + CmxCpSubBlock* const subBlock = m_cmxBlocks[index]; + subBlock->setHits(slice, source, 0, hits0[slice], // Assuming CMXCPHits::source == CmxCpSubBlock::source + err0Bits.get(LVL1::DataError::Parity)); + subBlock->setHits(slice, source, 1, hits1[slice], + err1Bits.get(LVL1::DataError::Parity)); + if (neutralFormat) { // Neutral format wants RoI overflow bit + subBlock->setRoiOverflow(slice, source, + err0Bits.get(LVL1::DataError::Overflow)); + } + } + } + } + DataVector<CmxCpSubBlock>::const_iterator cos = m_cmxBlocks.begin(); + for (; cos != m_cmxBlocks.end(); ++cos) { + CmxCpSubBlock* const subBlock = *cos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMX-Cp sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMX-Cp sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& CpByteStreamV2Tool::sourceIDs( + const std::string& sgKey) +{ + // Check if overlap tower channels wanted + const std::string flag("Overlap"); + const std::string::size_type pos = sgKey.find(flag); + m_coreOverlap = + (pos == std::string::npos || pos != sgKey.length() - flag.length()) ? 0 : 1; + + if (m_sourceIDs.empty()) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 0; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + m_sourceIDs.push_back(robId); + } + } + } + return m_sourceIDs; +} + +// Convert bytestream to given container type + +StatusCode CpByteStreamV2Tool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + const uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: ROD " + << MSG::hex << sourceID << " ROB " << robid + << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion <= m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping pre-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word should be User Header + if ( !L1CaloUserHeader::isValid(*payload) ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Invalid or missing user header" << endreq; + continue; + } + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + // triggered slice offset + const int trigCpm = userHeader.cpm(); + if (debug) { + msg() << "Minor format version number: " << MSG::hex + << minorVersion << MSG::dec << endreq + << "Triggered slice offset: " << trigCpm << endreq; + } + + // Loop over sub-blocks + + m_rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER) { + if (debug) msg() << "Unexpected data sequence" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MISSING_HEADER; + break; + } + if (L1CaloSubBlock::version(*payload) == 1) { // <<== CHECK + if (debug) msg() << "Skipping pre-LS1 data" << endreq; // Why again - also done above ? + break; + } + if (CmxSubBlock::cmxBlock(*payload)) { + // CMX + if (CmxSubBlock::cmxType(*payload) == CmxSubBlock::CMX_CP) { + m_cmxCpSubBlock->clear(); + payload = m_cmxCpSubBlock->read(payload, payloadEnd); + if (m_cmxCpSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMX_CP_TOBS || collection == CMX_CP_HITS) { + decodeCmxCp(m_cmxCpSubBlock, trigCpm, collection); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmxCp failed" << endreq; + break; + } + } + } else { + if (debug) msg() << "Invalid CMX type in module field" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + } else { + // CPM + m_cpmSubBlock->clear(); + payload = m_cpmSubBlock->read(payload, payloadEnd); + if (m_cpmSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CPM_TOWERS) { + decodeCpm(m_cpmSubBlock, trigCpm); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCpm failed" << endreq; + break; + } + } + } + } + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, m_rodErr); + } + + return StatusCode::SUCCESS; +} + +// Unpack CMX-CP sub-block + +void CpByteStreamV2Tool::decodeCmxCp(CmxCpSubBlock* subBlock, int trigCpm, + CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int cmx = subBlock->cmxPosition(); + const int firmware = subBlock->cmxFirmware(); + const int summing = subBlock->cmxSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMX-CP: Crate " << hwCrate + << " Position " << cmx + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum + << endreq; + } + if (timeslices <= trigCpm) { + if (debug) msg() << "Triggered slice from header " + << "inconsistent with number of slices: " + << trigCpm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMX-CP sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + LVL1::DataError dErr; + dErr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int subStatus = dErr.error(); + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSid = CmxCpSubBlock::MAX_SOURCE_ID; + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + if (collection == CMX_CP_TOBS) { + + // TOBs + + for (int cpm = 1; cpm <= m_modules; ++cpm) { + const unsigned int presenceMap = subBlock->presenceMap(slice, cpm); + for (int tob = 0; tob < m_maxTobs; ++tob) { + const int energy = subBlock->energy(slice, cpm, tob); + const int isolation = subBlock->isolation(slice, cpm, tob); + int error = subBlock->tobError(slice, cpm, tob); + if (energy == 0 && isolation == 0 && error == 0) break; + const int loc = subBlock->localCoord(slice, cpm, tob); + const int chip = subBlock->chip(slice, cpm, tob); + LVL1::DataError errBits(subStatus); + if (error) { + errBits.set(LVL1::DataError::Parity, (error&0x1f) ? 1 : 0); + errBits.set(LVL1::DataError::ParityMerge, error); + errBits.set(LVL1::DataError::ParityPhase0, (error>>1)); + errBits.set(LVL1::DataError::ParityPhase1, (error>>2)); + errBits.set(LVL1::DataError::ParityPhase2, (error>>3)); + errBits.set(LVL1::DataError::ParityPhase3, (error>>4)); + errBits.set(LVL1::DataError::Overflow, (error>>5)); + } + error = errBits.error(); + const int key = tobKey(crate, cmx, cpm, chip, loc); + LVL1::CMXCPTob* tb = findCmxCpTob(key); + if ( ! tb ) { // create new CMX TOB + m_energyVec.assign(timeslices, 0); + m_isolVec.assign(timeslices, 0); + m_errorVec.assign(timeslices, 0); + m_presenceMapVec.assign(timeslices, 0); + m_energyVec[slice] = energy; + m_isolVec[slice] = isolation; + m_errorVec[slice] = error; + m_presenceMapVec[slice] = presenceMap; + tb = new LVL1::CMXCPTob(swCrate, cmx, cpm, chip, loc, + m_energyVec, m_isolVec, m_errorVec, + m_presenceMapVec, trigCpm); + m_tobMap.insert(std::make_pair(key, tb)); + m_tobCollection->push_back(tb); + } else { + m_energyVec = tb->energyVec(); + m_isolVec = tb->isolationVec(); + m_errorVec = tb->errorVec(); + m_presenceMapVec = tb->presenceMapVec(); + const int nsl = m_energyVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_energyVec[slice] != 0 || m_isolVec[slice] != 0 || + m_errorVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_energyVec[slice] = energy; + m_isolVec[slice] = isolation; + m_errorVec[slice] = error; + m_presenceMapVec[slice] = presenceMap; + tb->addTob(m_energyVec, m_isolVec, m_errorVec, m_presenceMapVec); + } + } + } + + } else if (collection == CMX_CP_HITS) { + + // Hit/Topo counts + + for (int source = 0; source < maxSid; ++source) { + if (summing == CmxSubBlock::CRATE && + (source == CmxCpSubBlock::REMOTE_0 || + source == CmxCpSubBlock::REMOTE_1 || + source == CmxCpSubBlock::REMOTE_2 || + source == CmxCpSubBlock::TOTAL)) continue; + const unsigned int hits0 = subBlock->hits(slice, source, 0); //low + const unsigned int hits1 = subBlock->hits(slice, source, 1); //high + int err0 = subBlock->hitsError(slice, source, 0); + int err1 = subBlock->hitsError(slice, source, 1); + int overflow = subBlock->roiOverflow(slice, source); + LVL1::DataError err0Bits(subStatus); + err0Bits.set(LVL1::DataError::Parity, err0); + err0Bits.set(LVL1::DataError::Overflow, overflow); + err0 = err0Bits.error(); + LVL1::DataError err1Bits(subStatus); + err1Bits.set(LVL1::DataError::Parity, err1); + err1Bits.set(LVL1::DataError::Overflow, overflow); + err1 = err1Bits.error(); + if (hits0 || hits1 || err0 || err1) { + const int key = hitsKey(crate, cmx, source); + LVL1::CMXCPHits* ch = findCmxCpHits(key); + if ( ! ch ) { // create new CMX hits + m_hitsVec0.assign(timeslices, 0); + m_hitsVec1.assign(timeslices, 0); + m_errVec0.assign(timeslices, 0); + m_errVec1.assign(timeslices, 0); + m_hitsVec0[slice] = hits0; + m_hitsVec1[slice] = hits1; + m_errVec0[slice] = err0; + m_errVec1[slice] = err1; + ch = new LVL1::CMXCPHits(swCrate, cmx, source, + m_hitsVec0, m_hitsVec1, + m_errVec0, m_errVec1, trigCpm); + m_hitsMap.insert(std::make_pair(key, ch)); + m_hitCollection->push_back(ch); + } else { + m_hitsVec0 = ch->hitsVec0(); + m_hitsVec1 = ch->hitsVec1(); + m_errVec0 = ch->errorVec0(); + m_errVec1 = ch->errorVec1(); + const int nsl = m_hitsVec0.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec0[slice] != 0 || m_hitsVec1[slice] != 0 || + m_errVec0[slice] != 0 || m_errVec1[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec0[slice] = hits0; + m_hitsVec1[slice] = hits1; + m_errVec0[slice] = err0; + m_errVec1[slice] = err1; + ch->addHits(m_hitsVec0, m_hitsVec1, m_errVec0, m_errVec1); + } + } + } + } + } + + return; +} + +// Unpack CPM sub-block + +void CpByteStreamV2Tool::decodeCpm(CpmSubBlockV2* subBlock, int trigCpm) +{ + const bool debug = msgLvl(MSG::DEBUG); + const bool verbose = msgLvl(MSG::VERBOSE); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->module(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CPM: Crate " << hwCrate + << " Module " << module + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (module < 1 || module > m_modules) { + if (debug) msg() << "Unexpected module number: " << module << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + return; + } + if (timeslices <= trigCpm) { + if (debug) msg() << "Triggered slice from header " + << "inconsistent with number of slices: " + << trigCpm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CPM sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + LVL1::DataError dErr; + dErr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int subStatus = dErr.error(); + const int crate = hwCrate - m_crateOffsetHw; + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Loop over tower channels and fill CPM towers + + for (int chan = 0; chan < m_channels; ++chan) { + if (!subStatus && !subBlock->anyTowerData(chan)) continue; + const int em = subBlock->emData(slice, chan); + const int had = subBlock->hadData(slice, chan); + const int emErr = subBlock->emError(slice, chan); + const int hadErr = subBlock->hadError(slice, chan); + int emErr1 = subStatus; + if (emErr) { + LVL1::DataError emErrBits(emErr1); + emErrBits.set(LVL1::DataError::Parity, emErr & 0x1); + emErrBits.set(LVL1::DataError::LinkDown, (emErr >> 1) & 0x1); + emErr1 = emErrBits.error(); + } + int hadErr1 = subStatus; + if (hadErr) { + LVL1::DataError hadErrBits(hadErr1); + hadErrBits.set(LVL1::DataError::Parity, hadErr & 0x1); + hadErrBits.set(LVL1::DataError::LinkDown, (hadErr >> 1) & 0x1); + hadErr1 = hadErrBits.error(); + } + if (em || had || emErr1 || hadErr1) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_cpmMaps->mapping(crate, module, chan, eta, phi, layer)) { + if (layer == m_coreOverlap) { + const unsigned int key = m_towerKey->ttKey(phi, eta); + LVL1::CPMTower* tt = findCpmTower(key); + if ( ! tt ) { // create new CPM tower + m_emVec.assign(timeslices, 0); + m_hadVec.assign(timeslices, 0); + m_emErrVec.assign(timeslices, 0); + m_hadErrVec.assign(timeslices, 0); + m_emVec[slice] = em; + m_hadVec[slice] = had; + m_emErrVec[slice] = emErr1; + m_hadErrVec[slice] = hadErr1; + tt = new LVL1::CPMTower(phi, eta, m_emVec, m_emErrVec, + m_hadVec, m_hadErrVec, trigCpm); + m_ttMap.insert(std::make_pair(key, tt)); + m_ttCollection->push_back(tt); + } else { + m_emVec = tt->emEnergyVec(); + m_hadVec = tt->hadEnergyVec(); + m_emErrVec = tt->emErrorVec(); + m_hadErrVec = tt->hadErrorVec(); + const int nsl = m_emVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_emVec[slice] != 0 || m_hadVec[slice] != 0 || + m_emErrVec[slice] != 0 || m_hadErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_emVec[slice] = em; + m_hadVec[slice] = had; + m_emErrVec[slice] = emErr1; + m_hadErrVec[slice] = hadErr1; + tt->fill(m_emVec, m_emErrVec, m_hadVec, m_hadErrVec, trigCpm); + } + } + } else if (verbose && (em || had || emErr || hadErr)) { + msg(MSG::VERBOSE) << "Non-zero data but no channel mapping for channel " + << chan << endreq; + msg(MSG::DEBUG); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No CPM tower data for channel " + << chan << " slice " << slice << endreq; + msg(MSG::DEBUG); + } + } + } + return; +} + +// Find a CPM tower for given key + +LVL1::CPMTower* CpByteStreamV2Tool::findCpmTower(const unsigned int key) +{ + LVL1::CPMTower* tt = 0; + CpmTowerMap::const_iterator mapIter; + mapIter = m_ttMap.find(key); + if (mapIter != m_ttMap.end()) tt = mapIter->second; + return tt; +} + +// Find CMX-CP TOB for given key + +LVL1::CMXCPTob* CpByteStreamV2Tool::findCmxCpTob(const int key) +{ + LVL1::CMXCPTob* tob = 0; + CmxCpTobMap::const_iterator mapIter; + mapIter = m_tobMap.find(key); + if (mapIter != m_tobMap.end()) tob = mapIter->second; + return tob; +} + +// Find CMX-CP hits for given key + +LVL1::CMXCPHits* CpByteStreamV2Tool::findCmxCpHits(const int key) +{ + LVL1::CMXCPHits* hits = 0; + CmxCpHitsMap::const_iterator mapIter; + mapIter = m_hitsMap.find(key); + if (mapIter != m_hitsMap.end()) hits = mapIter->second; + return hits; +} + +// Set up CPM tower map + +void CpByteStreamV2Tool::setupCpmTowerMap(const CpmTowerCollection* + const ttCollection) +{ + m_ttMap.clear(); + if (ttCollection) { + CpmTowerCollection::const_iterator pos = ttCollection->begin(); + CpmTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CPMTower* const tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + m_ttMap.insert(std::make_pair(key, tt)); + } + } +} + +// Set up CMX-CP TOB map + +void CpByteStreamV2Tool::setupCmxCpTobMap(const CmxCpTobCollection* + const tobCollection) +{ + m_tobMap.clear(); + if (tobCollection) { + CmxCpTobCollection::const_iterator pos = tobCollection->begin(); + CmxCpTobCollection::const_iterator pose = tobCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMXCPTob* const tob = *pos; + const int crate = tob->crate() - m_crateOffsetSw; + const int cmx = tob->cmx(); + const int cpm = tob->cpm(); + const int chip = tob->chip(); + const int loc = tob->location(); + const int key = tobKey(crate, cmx, cpm, chip, loc); + m_tobMap.insert(std::make_pair(key, tob)); + } + } +} + +// Set up CMX-CP hits map + +void CpByteStreamV2Tool::setupCmxCpHitsMap(const CmxCpHitsCollection* + const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + CmxCpHitsCollection::const_iterator pos = hitCollection->begin(); + CmxCpHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMXCPHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int cmx = hits->cmx(); + const int source = hits->source(); + const int key = hitsKey(crate, cmx, source); + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Key for TOBs + +int CpByteStreamV2Tool::tobKey(const int crate, const int cmx, const int cpm, + const int chip, const int loc) const +{ + return (((((((crate<<1)|cmx)<<4)|cpm)<<4)|chip)<<2)|loc; +} + +// Key for Hits + +int CpByteStreamV2Tool::hitsKey(const int crate, const int cmx, + const int source) const +{ + return (((crate<<1)|cmx)<<3)|source; +} + +// Get number of slices and triggered slice offset for next slink + +bool CpByteStreamV2Tool::slinkSlices(const int crate, const int module, + const int modulesPerSlink, int& timeslices, int& trigCpm) +{ + int slices = -1; + int trigC = m_dfltSlices/2; + for (int mod = module; mod < module + modulesPerSlink; ++mod) { + for (int chan = 0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if ( !m_cpmMaps->mapping(crate, mod, chan, eta, phi, layer)) continue; + const unsigned int key = m_towerKey->ttKey(phi, eta); + const LVL1::CPMTower* const tt = findCpmTower(key); + if ( !tt ) continue; + const int numdat = 4; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((tt->emEnergyVec()).begin(), + (tt->emEnergyVec()).end(), 0); + sums[1] = std::accumulate((tt->hadEnergyVec()).begin(), + (tt->hadEnergyVec()).end(), 0); + sums[2] = std::accumulate((tt->emErrorVec()).begin(), + (tt->emErrorVec()).end(), 0); + sums[3] = std::accumulate((tt->hadErrorVec()).begin(), + (tt->hadErrorVec()).end(), 0); + sizes[0] = (tt->emEnergyVec()).size(); + sizes[1] = (tt->hadEnergyVec()).size(); + sizes[2] = (tt->emErrorVec()).size(); + sizes[3] = (tt->hadErrorVec()).size(); + const int peak = tt->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + } + // CMXs last slink of crate + if (module/modulesPerSlink == m_slinks - 1) { + for (int cmx = 0; cmx < m_cmxs; ++cmx) { + for (int cpm = 1; cpm <= m_modules; ++ cpm) { + for (int chip = 0; chip < m_chips; ++chip) { + for (int loc = 0; loc < m_locs; ++loc) { + const int key = tobKey(crate, cmx, cpm, chip, loc); + const LVL1::CMXCPTob* const tob = findCmxCpTob(key); + if (tob) { + const int numdat = 3; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((tob->energyVec()).begin(), + (tob->energyVec()).end(), 0); + sums[1] = std::accumulate((tob->isolationVec()).begin(), + (tob->isolationVec()).end(), 0); + sums[2] = std::accumulate((tob->errorVec()).begin(), + (tob->errorVec()).end(), 0); + sizes[0] = (tob->energyVec()).size(); + sizes[1] = (tob->isolationVec()).size(); + sizes[2] = (tob->errorVec()).size(); + const int peak = tob->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + } + } + } + for (int source = 0; source < LVL1::CMXCPHits::MAXSOURCE; ++source) { + const int key = hitsKey(crate, cmx, source); + const LVL1::CMXCPHits* const hits = findCmxCpHits(key); + if (hits) { + const int numdat = 4; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((hits->hitsVec0()).begin(), + (hits->hitsVec0()).end(), 0); + sums[1] = std::accumulate((hits->hitsVec1()).begin(), + (hits->hitsVec1()).end(), 0); + sums[2] = std::accumulate((hits->errorVec0()).begin(), + (hits->errorVec0()).end(), 0); + sums[3] = std::accumulate((hits->errorVec1()).begin(), + (hits->errorVec1()).end(), 0); + sizes[0] = (hits->hitsVec0()).size(); + sizes[1] = (hits->hitsVec1()).size(); + sizes[2] = (hits->errorVec0()).size(); + sizes[3] = (hits->errorVec1()).size(); + const int peak = hits->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigC = peak; + } else if (slices != sizes[i] || trigC != peak) return false; + } + } + } + } + } + if (slices < 0) slices = m_dfltSlices; + timeslices = slices; + trigCpm = trigC; + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..4ec2bb568c5b1f0de67ce79bbe74825d13d4eadd --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpByteStreamV2Tool.h @@ -0,0 +1,230 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPBYTESTREAMV2TOOL_H +#define TRIGT1CALOBYTESTREAM_CPBYTESTREAMV2TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <typename> class FullEventAssembler; + +namespace LVL1 { + class CMXCPHits; + class CMXCPTob; + class CPMTower; + class CPBSCollectionV2; + class IL1CaloMappingTool; + class TriggerTowerKey; +} + +namespace LVL1BS { + +class CmxCpSubBlock; +class CpmSubBlockV2; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to CPM towers, CMX-CP TOBs and CMX-CP hits, + * and CP container to raw data conversions. + * + * Based on ROD document version X_xxx. + * + * @author Peter Faulkner + */ + +class CpByteStreamV2Tool : public AthAlgTool { + + public: + CpByteStreamV2Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~CpByteStreamV2Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to CPM towers + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTower>* ttCollection); + /// Convert ROB fragments to CMX-CP TOBs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXCPTob>* tobCollection); + /// Convert ROB fragments to CMX-CP hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXCPHits>* hitCollection); + + /// Convert CP Container to bytestream + StatusCode convert(const LVL1::CPBSCollectionV2* cp, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + + enum CollectionType { CPM_TOWERS, CMX_CP_TOBS, CMX_CP_HITS }; + + typedef DataVector<LVL1::CPMTower> CpmTowerCollection; + typedef DataVector<LVL1::CMXCPTob> CmxCpTobCollection; + typedef DataVector<LVL1::CMXCPHits> CmxCpHitsCollection; + typedef std::map<unsigned int, LVL1::CPMTower*> CpmTowerMap; + typedef std::map<int, LVL1::CMXCPTob*> CmxCpTobMap; + typedef std::map<int, LVL1::CMXCPHits*> CmxCpHitsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + /// Unpack CMX-CP sub-block + void decodeCmxCp(CmxCpSubBlock* subBlock, int trigCpm, + CollectionType collection); + /// Unpack CPM sub-block + void decodeCpm(CpmSubBlockV2* subBlock, int trigCpm); + + /// Find a CPM tower for given key + LVL1::CPMTower* findCpmTower(unsigned int key); + /// Find CMX-CP TOB for given key + LVL1::CMXCPTob* findCmxCpTob(int key); + /// Find CMX-CP hits for given key + LVL1::CMXCPHits* findCmxCpHits(int key); + + /// Set up CPM tower map + void setupCpmTowerMap(const CpmTowerCollection* ttCollection); + /// Set up CMX-CP TOB map + void setupCmxCpTobMap(const CmxCpTobCollection* tobCollection); + /// Set up CMX-CP hits map + void setupCmxCpHitsMap(const CmxCpHitsCollection* hitCollection); + + /// Key for TOBs + int tobKey(int crate, int cmx, int cpm, int chip, int loc) const; + /// Key for Hits + int hitsKey(int crate, int cmx, int source) const; + + /// Get number of slices and triggered slice offset for next slink + bool slinkSlices(int crate, int module, int modulesPerSlink, + int& timeslices, int& trigJem); + + /// Channel mapping tool + ToolHandle<LVL1::IL1CaloMappingTool> m_cpmMaps; + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of channels per module + int m_channels; + /// Number of crates + int m_crates; + /// Number of CPM modules per crate + int m_modules; + /// Number of CMXs per crate + int m_cmxs; + /// Maximum number of TOBS per module + int m_maxTobs; + /// Number of chips + int m_chips; + /// Number of Local coordinates + int m_locs; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Default number of slices in simulation + int m_dfltSlices; + /// Force number of slices in bytestream + int m_forceSlices; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// Tower channels to accept (1=Core, 2=Overlap) + int m_coreOverlap; + /// Unpacking error code + unsigned int m_rodErr; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Trigger tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// CPM sub-block for unpacking + CpmSubBlockV2* m_cpmSubBlock; + /// CMX-CP sub-block for unpacking + CmxCpSubBlock* m_cmxCpSubBlock; + /// Energy vector for unpacking + std::vector<int> m_energyVec; + /// Isolation vector for unpacking + std::vector<int> m_isolVec; + /// TOB error vector for unpacking + std::vector<int> m_errorVec; + /// Presence map vector for unpacking + std::vector<unsigned int> m_presenceMapVec; + /// Hits0 vector for unpacking + std::vector<unsigned int> m_hitsVec0; + /// Hits1 vector for unpacking + std::vector<unsigned int> m_hitsVec1; + /// Error0 vector for unpacking + std::vector<int> m_errVec0; + /// Error1 vector for unpacking + std::vector<int> m_errVec1; + /// EM data vector for unpacking + std::vector<int> m_emVec; + /// Had data vector for unpacking + std::vector<int> m_hadVec; + /// EM error data vector for unpacking + std::vector<int> m_emErrVec; + /// Had error data vector for unpacking + std::vector<int> m_hadErrVec; + /// Vector for current CPM sub-blocks + DataVector<CpmSubBlockV2> m_cpmBlocks; + /// Vector for current CMX-CP sub-blocks + DataVector<CmxCpSubBlock> m_cmxBlocks; + /// Current CPM tower collection + CpmTowerCollection* m_ttCollection; + /// Current CMX-CP TOB collection + CmxCpTobCollection* m_tobCollection; + /// Current CMX-CP hits collection + CmxCpHitsCollection* m_hitCollection; + /// CPM tower map + CpmTowerMap m_ttMap; + /// CMX-CP TOB map + CmxCpTobMap m_tobMap; + /// CMX-CP hits map + CmxCpHitsMap m_hitsMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..b5968927e5a47e4b03f7afa4e809483fcb6e6d70 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamCnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpByteStreamTool; + +/** ByteStream converter for CP component containers. + * + * @author Peter Faulkner + */ + +template <typename Container> +class CpReadByteStreamCnv: public Converter { + + friend class CnvFactory<CpReadByteStreamCnv<Container> >; + +protected: + + CpReadByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~CpReadByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpByteStreamTool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "CpReadByteStreamCnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamCnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamCnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..bda64c7c709588abd6430f647ae2f7e08f364d48 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamCnv.icc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "CpByteStreamTool.h" + +namespace LVL1BS { + +template <typename Container> +CpReadByteStreamCnv<Container>::CpReadByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpReadByteStreamCnv"), + m_tool("LVL1BS::CpByteStreamTool/CpByteStreamTool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +CpReadByteStreamCnv<Container>::~CpReadByteStreamCnv() +{ +} + +// CLID + +template <typename Container> +const CLID& CpReadByteStreamCnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode CpReadByteStreamCnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode CpReadByteStreamCnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..1c80738fca8bf82411eeafffee7311cb8002b467 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1Cnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMV1CNV_H +#define TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMV1CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpByteStreamV1Tool; + +/** ByteStream converter for CP component containers. + * + * @author Peter Faulkner + */ + +template <typename Container> +class CpReadByteStreamV1Cnv: public Converter { + + friend class CnvFactory<CpReadByteStreamV1Cnv<Container> >; + +protected: + + CpReadByteStreamV1Cnv(ISvcLocator* svcloc); + +public: + + ~CpReadByteStreamV1Cnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpByteStreamV1Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "CpReadByteStreamV1Cnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1Cnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1Cnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..77e3e86da6f54e88e8ee662ac58cca4e45dde8b3 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1Cnv.icc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "CpByteStreamV1Tool.h" + +namespace LVL1BS { + +template <typename Container> +CpReadByteStreamV1Cnv<Container>::CpReadByteStreamV1Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpReadByteStreamV1Cnv"), + m_tool("LVL1BS::CpByteStreamV1Tool/CpByteStreamV1Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +CpReadByteStreamV1Cnv<Container>::~CpReadByteStreamV1Cnv() +{ +} + +// CLID + +template <typename Container> +const CLID& CpReadByteStreamV1Cnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode CpReadByteStreamV1Cnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode CpReadByteStreamV1Cnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1V2Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1V2Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..2491d3848509220388aabacc3f274a41ffc10066 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1V2Cnv.cxx @@ -0,0 +1,162 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/CPMTower.h" + +#include "CpReadByteStreamV1V2Cnv.h" +#include "CpByteStreamV1Tool.h" +#include "CpByteStreamV2Tool.h" + +namespace LVL1BS { + +CpReadByteStreamV1V2Cnv::CpReadByteStreamV1V2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpReadByteStreamV1V2Cnv"), + m_tool1("LVL1BS::CpByteStreamV1Tool/CpByteStreamV1Tool"), + m_tool2("LVL1BS::CpByteStreamV2Tool/CpByteStreamV2Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +CpReadByteStreamV1V2Cnv::~CpReadByteStreamV1V2Cnv() +{ +} + +// CLID + +const CLID& CpReadByteStreamV1V2Cnv::classID() +{ + return ClassID_traits<DataVector<LVL1::CPMTower> >::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpReadByteStreamV1V2Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tools + sc = m_tool1.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool1 << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool1 << endreq; + sc = m_tool2.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool2 << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool2 << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::WARNING << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +StatusCode CpReadByteStreamV1V2Cnv::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID1(m_tool1->sourceIDs(nm)); + const std::vector<uint32_t>& vID2(m_tool2->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags1; + m_robDataProvider->getROBData( vID1, robFrags1 ); + IROBDataProviderSvc::VROBFRAG robFrags2; + m_robDataProvider->getROBData( vID2, robFrags2 ); + + // size check + DataVector<LVL1::CPMTower>* const towerCollection = new DataVector<LVL1::CPMTower>; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags1.size() + << ", " << robFrags2.size() << endreq; + } + if (robFrags1.size() == 0 && robFrags2.size() == 0) { + pObj = SG::asStorable(towerCollection) ; + return StatusCode::SUCCESS; + } + + // Pre-LS1 data + if (robFrags1.size() > 0) { + StatusCode sc = m_tool1->convert(robFrags1, towerCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete towerCollection; + return sc; + } + } + // Post-LS1 data + if (robFrags2.size() > 0) { + StatusCode sc = m_tool2->convert(robFrags2, towerCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete towerCollection; + return sc; + } + } + + pObj = SG::asStorable(towerCollection); + + return StatusCode::SUCCESS; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1V2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1V2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..b55dc3b28de44ac56cde156b1013f11ea776db77 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV1V2Cnv.h @@ -0,0 +1,82 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMV1V2CNV_H +#define TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMV1V2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpByteStreamV1Tool; +class CpByteStreamV2Tool; + +/** ByteStream converter for Cluster Processor Module Towers + * allowing for data containing pre-LS1 or post-LS1 format sub-blocks. + * For reading only. + * + * @author Peter Faulkner + */ + +class CpReadByteStreamV1V2Cnv: public Converter { + + friend class CnvFactory<CpReadByteStreamV1V2Cnv>; + +protected: + + CpReadByteStreamV1V2Cnv(ISvcLocator* svcloc); + +public: + + ~CpReadByteStreamV1V2Cnv(); + + virtual StatusCode initialize(); + /// Create CPM Towers from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work pre-LS1 + ToolHandle<LVL1BS::CpByteStreamV1Tool> m_tool1; + /// Tool that does the actual work post-LS1 + ToolHandle<LVL1BS::CpByteStreamV2Tool> m_tool2; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..c68f220336600372f847b91693719ff138236daa --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV2Cnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMV2CNV_H +#define TRIGT1CALOBYTESTREAM_CPREADBYTESTREAMV2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpByteStreamV2Tool; + +/** ByteStream converter for CP component containers post LS1. + * + * @author Peter Faulkner + */ + +template <typename Container> +class CpReadByteStreamV2Cnv: public Converter { + + friend class CnvFactory<CpReadByteStreamV2Cnv<Container> >; + +protected: + + CpReadByteStreamV2Cnv(ISvcLocator* svcloc); + +public: + + ~CpReadByteStreamV2Cnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpByteStreamV2Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "CpReadByteStreamV2Cnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV2Cnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV2Cnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..26bff4683e7900b4395cbabdae19222c6cc54413 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpReadByteStreamV2Cnv.icc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "CpByteStreamV2Tool.h" + +namespace LVL1BS { + +template <typename Container> +CpReadByteStreamV2Cnv<Container>::CpReadByteStreamV2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpReadByteStreamV2Cnv"), + m_tool("LVL1BS::CpByteStreamV2Tool/CpByteStreamV2Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +CpReadByteStreamV2Cnv<Container>::~CpReadByteStreamV2Cnv() +{ +} + +// CLID + +template <typename Container> +const CLID& CpReadByteStreamV2Cnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode CpReadByteStreamV2Cnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode CpReadByteStreamV2Cnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamCnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..1140456502851439804b89b20b58f7407139fdcb --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamCnv.cxx @@ -0,0 +1,178 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/CPMRoI.h" + +#include "CpmRoiByteStreamCnv.h" +#include "CpmRoiByteStreamTool.h" + +namespace LVL1BS { + +CpmRoiByteStreamCnv::CpmRoiByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpmRoiByteStreamCnv"), + m_tool("LVL1BS::CpmRoiByteStreamTool/CpmRoiByteStreamTool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +CpmRoiByteStreamCnv::~CpmRoiByteStreamCnv() +{ +} + +// CLID + +const CLID& CpmRoiByteStreamCnv::classID() +{ + return ClassID_traits<DataVector<LVL1::CPMRoI> >::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmRoiByteStreamCnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::WARNING << "Failed to retrieve service " + << m_robDataProvider << endreq; + // return is disabled for Write BS which does not require ROBDataProviderSvc + // return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +StatusCode CpmRoiByteStreamCnv::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + DataVector<LVL1::CPMRoI>* const roiCollection = new DataVector<LVL1::CPMRoI>; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(roiCollection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, roiCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete roiCollection; + return sc; + } + + pObj = SG::asStorable(roiCollection); + + return sc; +} + +// createRep should create the bytestream from RDOs. + +StatusCode CpmRoiByteStreamCnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + DataVector<LVL1::CPMRoI>* roiCollection = 0; + if( !SG::fromStorable( pObj, roiCollection ) ) { + m_log << MSG::ERROR << " Cannot cast to DataVector<CPMRoI>" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( roiCollection, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..0626179e1dd3d8e0b6ce698bfd9b96f168aa97eb --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamCnv.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpmRoiByteStreamTool; + +/** ByteStream converter for Cluster Processor Module RoIs. + * + * @author Peter Faulkner + */ + +class CpmRoiByteStreamCnv: public Converter { + + friend class CnvFactory<CpmRoiByteStreamCnv>; + +protected: + + CpmRoiByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~CpmRoiByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create CPM RoIs from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + /// Create ByteStream from CPM RoIs + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpmRoiByteStreamTool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamTool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..5b3e8a77e7cdb1d61a5c376088497abdee8c8de7 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamTool.cxx @@ -0,0 +1,432 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "TrigT1CaloEvent/CPMRoI.h" + +#include "CpmRoiSubBlock.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloUserHeader.h" + +#include "CpmRoiByteStreamTool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_ICpmRoiByteStreamTool("CpmRoiByteStreamTool", + 1, 1); + +const InterfaceID& CpmRoiByteStreamTool::interfaceID() +{ + return IID_ICpmRoiByteStreamTool; +} + +// Constructor + +CpmRoiByteStreamTool::CpmRoiByteStreamTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_crates(4), m_modules(14), m_srcIdMap(0), m_subBlock(0), m_rodStatus(0), + m_fea(0) +{ + declareInterface<CpmRoiByteStreamTool>(this); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 8, + "Offset of CP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of CP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + declareProperty("ROBSourceIDsRoIB", m_sourceIDsRoIB, + "ROB fragment source identifiers for RoIBs"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 1, + "The number of S-Links per crate"); + +} + +// Destructor + +CpmRoiByteStreamTool::~CpmRoiByteStreamTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmRoiByteStreamTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_subDetector = eformat::TDAQ_CALO_CLUSTER_PROC_ROI; + m_srcIdMap = new L1CaloSrcIdMap(); + m_rodStatus = new std::vector<uint32_t>(2); + m_subBlock = new CpmRoiSubBlock(); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpmRoiByteStreamTool::finalize() +{ + delete m_fea; + delete m_subBlock; + delete m_rodStatus; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Convert ROB fragments to CPM RoIs + +StatusCode CpmRoiByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMRoI>* const roiCollection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + std::set<uint32_t> dupRoiCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 1 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: " + << MSG::hex << sourceID << MSG::dec << endreq; + } + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word may be User Header + if (L1CaloUserHeader::isValid(*payload)) { + L1CaloUserHeader userHeader(*payload); + const int minorVersion = (*rob)->rod_version() & 0xffff; + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1 ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + } + + // Loop over sub-blocks if there are any + + unsigned int rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER) { + m_subBlock->clear(); + payload = m_subBlock->read(payload, payloadEnd); + if (debug) { + msg() << "CPM RoI sub-block: Crate " << m_subBlock->crate() + << " Module " << m_subBlock->module() << endreq; + } + // Unpack sub-block + if (m_subBlock->dataWords() && !m_subBlock->unpack()) { + if (debug) { + std::string errMsg(m_subBlock->unpackErrorMsg()); + msg() << "CPM RoI sub-block unpacking failed: " << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const int numChips = 8; + const int numLocs = 2; + for (int chip = 0; chip < numChips; ++chip) { + for (int loc = 0; loc < numLocs; ++loc) { + const LVL1::CPMRoI roi = m_subBlock->roi(chip, loc); + if (roi.hits() || roi.error()) { + roiCollection->push_back(new LVL1::CPMRoI(roi)); + } + } + } + } else { + // Just RoI word + LVL1::CPMRoI roi; + if (roi.setRoiWord(*payload)) { + if (roi.crate() != rodCrate - m_crateOffsetHw) { + if (debug) msg() << "Inconsistent RoI crate number: " + << roi.crate() << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (roi.cpm() == 0 || roi.cpm() > m_modules) { + if (debug) msg() << "Invalid CPM number: " + << roi.cpm() << endreq; + rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + const uint32_t location = (*payload) & 0xfffc0000; + if (dupRoiCheck.insert(location).second) { + if (roi.hits() || roi.error()) { + roiCollection->push_back(new LVL1::CPMRoI(*payload)); + } + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } else { + if (debug) msg() << "Invalid RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_ROI_TYPE; + break; + } + ++payload; + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, rodErr); + } + + return StatusCode::SUCCESS; +} + +// Convert CPM RoI to bytestream + +StatusCode CpmRoiByteStreamTool::convert( + const DataVector<LVL1::CPMRoI>* const roiCollection, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container map + + setupCpmRoiMap(roiCollection); + CpmRoiMap::const_iterator mapIter = m_roiMap.begin(); + CpmRoiMap::const_iterator mapIterEnd = m_roiMap.end(); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + for (int crate=0; crate < m_crates; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + // CPM modules are numbered 1 to m_modules + for (int module=1; module <= m_modules; ++module) { + const int mod = module - 1; + + // Pack required number of modules per slink + + if (mod%modulesPerSlink == 0) { + const int daqOrRoi = 1; + const int slink = (m_slinks == 2) ? 2*(mod/modulesPerSlink) + : mod/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq + << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq; + } + const uint32_t rodIdCpm = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdCpm); + if (neutralFormat) { + const L1CaloUserHeader userHeader; + theROD->push_back(userHeader.header()); + } + m_rodStatusMap.insert(make_pair(rodIdCpm, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block (Neutral format only) + + if (neutralFormat) { + m_subBlock->clear(); + m_subBlock->setRoiHeader(m_version, hwCrate, module); + } + + // Find CPM RoIs for this module + + for (; mapIter != mapIterEnd; ++mapIter) { + const LVL1::CPMRoI* const roi = mapIter->second; + if (roi->crate() < crate) continue; + if (roi->crate() > crate) break; + if (roi->cpm() < module) continue; + if (roi->cpm() > module) break; + if (roi->hits() || roi->error()) { + if (neutralFormat) m_subBlock->fillRoi(*roi); + else theROD->push_back(roi->roiWord()); + } + } + + // Pack and write the sub-block + + if (neutralFormat) { + if ( !m_subBlock->pack()) { + msg(MSG::ERROR) << "CPMRoI sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CPMRoI sub-block data words: " + << m_subBlock->dataWords() << endreq; + } + m_subBlock->write(theROD); + } + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& CpmRoiByteStreamTool::sourceIDs( + const std::string& sgKey) +{ + const std::string flag("RoIB"); + const std::string::size_type pos = sgKey.find(flag); + const bool roiDaq = + (pos == std::string::npos || pos != sgKey.length() - flag.length()); + const bool empty = (roiDaq) ? m_sourceIDs.empty() : m_sourceIDsRoIB.empty(); + if (empty) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 1; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + if (roiDaq) { + if (slink < 2) m_sourceIDs.push_back(robId); + } else if (slink >= 2) m_sourceIDsRoIB.push_back(robId); + } + } + } + return (roiDaq) ? m_sourceIDs : m_sourceIDsRoIB; +} + +// Set up CPM RoI map + +void CpmRoiByteStreamTool::setupCpmRoiMap(const CpmRoiCollection* + const roiCollection) +{ + m_roiMap.clear(); + if (roiCollection) { + CpmRoiCollection::const_iterator pos = roiCollection->begin(); + CpmRoiCollection::const_iterator pose = roiCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamTool.h new file mode 100755 index 0000000000000000000000000000000000000000..50dff2a413b055788812af4b396e2380fffa75a4 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamTool.h @@ -0,0 +1,120 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMTOOL_H +#define TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMTOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <typename> class FullEventAssembler; + +namespace LVL1 { + class CPMRoI; +} + +namespace LVL1BS { + +class CpmRoiSubBlock; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to CPM RoI and CPM RoI to raw data + * conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class CpmRoiByteStreamTool : public AthAlgTool { + + public: + CpmRoiByteStreamTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~CpmRoiByteStreamTool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to CPM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMRoI>* roiCollection); + + /// Convert CPM RoI to bytestream + StatusCode convert(const DataVector<LVL1::CPMRoI>* roiCollection, + RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + + typedef DataVector<LVL1::CPMRoI> CpmRoiCollection; + typedef std::map<uint32_t, const LVL1::CPMRoI*> CpmRoiMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Set up CPM RoI map + void setupCpmRoiMap(const CpmRoiCollection* roiCollection); + + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of crates + int m_crates; + /// Number of CPM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// ROB source IDs for RoIB + std::vector<uint32_t> m_sourceIDsRoIB; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Sub-block for neutral format + CpmRoiSubBlock* m_subBlock; + /// CPM RoI map + CpmRoiMap m_roiMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..840c9e913ffebbebb674a82e8533c4f1127ad887 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Cnv.cxx @@ -0,0 +1,178 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/CPMRoI.h" + +#include "CpmRoiByteStreamV1Cnv.h" +#include "CpmRoiByteStreamV1Tool.h" + +namespace LVL1BS { + +CpmRoiByteStreamV1Cnv::CpmRoiByteStreamV1Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpmRoiByteStreamV1Cnv"), + m_tool("LVL1BS::CpmRoiByteStreamV1Tool/CpmRoiByteStreamV1Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +CpmRoiByteStreamV1Cnv::~CpmRoiByteStreamV1Cnv() +{ +} + +// CLID + +const CLID& CpmRoiByteStreamV1Cnv::classID() +{ + return ClassID_traits<DataVector<LVL1::CPMRoI> >::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmRoiByteStreamV1Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::WARNING << "Failed to retrieve service " + << m_robDataProvider << endreq; + // return is disabled for Write BS which does not require ROBDataProviderSvc + // return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +StatusCode CpmRoiByteStreamV1Cnv::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + DataVector<LVL1::CPMRoI>* const roiCollection = new DataVector<LVL1::CPMRoI>; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(roiCollection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, roiCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete roiCollection; + return sc; + } + + pObj = SG::asStorable(roiCollection); + + return sc; +} + +// createRep should create the bytestream from RDOs. + +StatusCode CpmRoiByteStreamV1Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + DataVector<LVL1::CPMRoI>* roiCollection = 0; + if( !SG::fromStorable( pObj, roiCollection ) ) { + m_log << MSG::ERROR << " Cannot cast to DataVector<CPMRoI>" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( roiCollection, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..60a6c0ff31026ae1ec785b8275cd47c40db50d48 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Cnv.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV1CNV_H +#define TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV1CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpmRoiByteStreamV1Tool; + +/** ByteStream converter for Cluster Processor Module RoIs. + * + * @author Peter Faulkner + */ + +class CpmRoiByteStreamV1Cnv: public Converter { + + friend class CnvFactory<CpmRoiByteStreamV1Cnv>; + +protected: + + CpmRoiByteStreamV1Cnv(ISvcLocator* svcloc); + +public: + + ~CpmRoiByteStreamV1Cnv(); + + virtual StatusCode initialize(); + /// Create CPM RoIs from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + /// Create ByteStream from CPM RoIs + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpmRoiByteStreamV1Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..3f6d4851491a7fc27f4205c78e7f7c9dcb2cea46 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Tool.cxx @@ -0,0 +1,444 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "TrigT1CaloEvent/CPMRoI.h" + +#include "CpmRoiSubBlockV1.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloUserHeader.h" + +#include "CpmRoiByteStreamV1Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_ICpmRoiByteStreamV1Tool("CpmRoiByteStreamV1Tool", + 1, 1); + +const InterfaceID& CpmRoiByteStreamV1Tool::interfaceID() +{ + return IID_ICpmRoiByteStreamV1Tool; +} + +// Constructor + +CpmRoiByteStreamV1Tool::CpmRoiByteStreamV1Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_crates(4), m_modules(14), m_srcIdMap(0), m_subBlock(0), m_rodStatus(0), + m_fea(0) +{ + declareInterface<CpmRoiByteStreamV1Tool>(this); + + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + declareProperty("CrateOffsetHw", m_crateOffsetHw = 8, + "Offset of CP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of CP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + declareProperty("ROBSourceIDsRoIB", m_sourceIDsRoIB, + "ROB fragment source identifiers for RoIBs"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 1, + "The number of S-Links per crate"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +CpmRoiByteStreamV1Tool::~CpmRoiByteStreamV1Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmRoiByteStreamV1Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_subDetector = eformat::TDAQ_CALO_CLUSTER_PROC_ROI; + m_srcIdMap = new L1CaloSrcIdMap(); + m_rodStatus = new std::vector<uint32_t>(2); + m_subBlock = new CpmRoiSubBlockV1(); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpmRoiByteStreamV1Tool::finalize() +{ + delete m_fea; + delete m_subBlock; + delete m_rodStatus; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Convert ROB fragments to CPM RoIs + +StatusCode CpmRoiByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMRoI>* const roiCollection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + std::set<uint32_t> dupRoiCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 1 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: " + << MSG::hex << sourceID << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion > m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping post-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word may be User Header + if (L1CaloUserHeader::isValid(*payload)) { + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1 ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + } + + // Loop over sub-blocks if there are any + + unsigned int rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER) { + m_subBlock->clear(); + payload = m_subBlock->read(payload, payloadEnd); + if (debug) { + msg() << "CPM RoI sub-block: Crate " << m_subBlock->crate() + << " Module " << m_subBlock->module() << endreq; + } + // Unpack sub-block + if (m_subBlock->dataWords() && !m_subBlock->unpack()) { + if (debug) { + std::string errMsg(m_subBlock->unpackErrorMsg()); + msg() << "CPM RoI sub-block unpacking failed: " << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const int numChips = 8; + const int numLocs = 2; + for (int chip = 0; chip < numChips; ++chip) { + for (int loc = 0; loc < numLocs; ++loc) { + const LVL1::CPMRoI roi = m_subBlock->roi(chip, loc); + if (roi.hits() || roi.error()) { + roiCollection->push_back(new LVL1::CPMRoI(roi)); + } + } + } + } else { + // Just RoI word + LVL1::CPMRoI roi; + if (roi.setRoiWord(*payload)) { + if (roi.crate() != rodCrate - m_crateOffsetHw) { + if (debug) msg() << "Inconsistent RoI crate number: " + << roi.crate() << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (roi.cpm() == 0 || roi.cpm() > m_modules) { + if (debug) msg() << "Invalid CPM number: " + << roi.cpm() << endreq; + rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + const uint32_t location = (*payload) & 0xfffc0000; + if (dupRoiCheck.insert(location).second) { + if (roi.hits() || roi.error()) { + roiCollection->push_back(new LVL1::CPMRoI(*payload)); + } + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } else { + if (debug) msg() << "Invalid RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_ROI_TYPE; + break; + } + ++payload; + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, rodErr); + } + + return StatusCode::SUCCESS; +} + +// Convert CPM RoI to bytestream + +StatusCode CpmRoiByteStreamV1Tool::convert( + const DataVector<LVL1::CPMRoI>* const roiCollection, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + uint16_t minorVersion = m_srcIdMap->minorVersionPreLS1(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container map + + setupCpmRoiMap(roiCollection); + CpmRoiMap::const_iterator mapIter = m_roiMap.begin(); + CpmRoiMap::const_iterator mapIterEnd = m_roiMap.end(); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + // CPM modules are numbered 1 to m_modules + for (int module=1; module <= m_modules; ++module) { + const int mod = module - 1; + + // Pack required number of modules per slink + + if (mod%modulesPerSlink == 0) { + const int daqOrRoi = 1; + const int slink = (m_slinks == 2) ? 2*(mod/modulesPerSlink) + : mod/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq + << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq; + } + const uint32_t rodIdCpm = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdCpm); + if (neutralFormat) { + const L1CaloUserHeader userHeader; + theROD->push_back(userHeader.header()); + } + m_rodStatusMap.insert(make_pair(rodIdCpm, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block (Neutral format only) + + if (neutralFormat) { + m_subBlock->clear(); + m_subBlock->setRoiHeader(m_version, hwCrate, module); + } + + // Find CPM RoIs for this module + + for (; mapIter != mapIterEnd; ++mapIter) { + const LVL1::CPMRoI* const roi = mapIter->second; + if (roi->crate() < crate) continue; + if (roi->crate() > crate) break; + if (roi->cpm() < module) continue; + if (roi->cpm() > module) break; + if (roi->hits() || roi->error()) { + if (neutralFormat) m_subBlock->fillRoi(*roi); + else theROD->push_back(roi->roiWord()); + } + } + + // Pack and write the sub-block + + if (neutralFormat) { + if ( !m_subBlock->pack()) { + msg(MSG::ERROR) << "CPMRoI sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CPMRoI sub-block data words: " + << m_subBlock->dataWords() << endreq; + } + m_subBlock->write(theROD); + } + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& CpmRoiByteStreamV1Tool::sourceIDs( + const std::string& sgKey) +{ + const std::string flag("RoIB"); + const std::string::size_type pos = sgKey.find(flag); + const bool roiDaq = + (pos == std::string::npos || pos != sgKey.length() - flag.length()); + const bool empty = (roiDaq) ? m_sourceIDs.empty() : m_sourceIDsRoIB.empty(); + if (empty) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 1; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + if (roiDaq) { + if (slink < 2) m_sourceIDs.push_back(robId); + } else if (slink >= 2) m_sourceIDsRoIB.push_back(robId); + } + } + } + return (roiDaq) ? m_sourceIDs : m_sourceIDsRoIB; +} + +// Set up CPM RoI map + +void CpmRoiByteStreamV1Tool::setupCpmRoiMap(const CpmRoiCollection* + const roiCollection) +{ + m_roiMap.clear(); + if (roiCollection) { + CpmRoiCollection::const_iterator pos = roiCollection->begin(); + CpmRoiCollection::const_iterator pose = roiCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..42420950da954778cc109421db658ca324e9cf9a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV1Tool.h @@ -0,0 +1,124 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV1TOOL_H +#define TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV1TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <typename> class FullEventAssembler; + +namespace LVL1 { + class CPMRoI; +} + +namespace LVL1BS { + +class CpmRoiSubBlockV1; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to CPM RoI and CPM RoI to raw data + * conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class CpmRoiByteStreamV1Tool : public AthAlgTool { + + public: + CpmRoiByteStreamV1Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~CpmRoiByteStreamV1Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to CPM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMRoI>* roiCollection); + + /// Convert CPM RoI to bytestream + StatusCode convert(const DataVector<LVL1::CPMRoI>* roiCollection, + RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + + typedef DataVector<LVL1::CPMRoI> CpmRoiCollection; + typedef std::map<uint32_t, const LVL1::CPMRoI*> CpmRoiMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Set up CPM RoI map + void setupCpmRoiMap(const CpmRoiCollection* roiCollection); + + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of crates + int m_crates; + /// Number of CPM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// ROB source IDs for RoIB + std::vector<uint32_t> m_sourceIDsRoIB; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Sub-block for neutral format + CpmRoiSubBlockV1* m_subBlock; + /// CPM RoI map + CpmRoiMap m_roiMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..1488112b394b1213625d5d4fd9aeee994ec2f714 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Cnv.cxx @@ -0,0 +1,178 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/CPMTobRoI.h" + +#include "CpmRoiByteStreamV2Cnv.h" +#include "CpmRoiByteStreamV2Tool.h" + +namespace LVL1BS { + +CpmRoiByteStreamV2Cnv::CpmRoiByteStreamV2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("CpmRoiByteStreamV2Cnv"), + m_tool("LVL1BS::CpmRoiByteStreamV2Tool/CpmRoiByteStreamV2Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +CpmRoiByteStreamV2Cnv::~CpmRoiByteStreamV2Cnv() +{ +} + +// CLID + +const CLID& CpmRoiByteStreamV2Cnv::classID() +{ + return ClassID_traits<DataVector<LVL1::CPMTobRoI> >::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmRoiByteStreamV2Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::WARNING << "Failed to retrieve service " + << m_robDataProvider << endreq; + // return is disabled for Write BS which does not require ROBDataProviderSvc + // return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +StatusCode CpmRoiByteStreamV2Cnv::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + DataVector<LVL1::CPMTobRoI>* const roiCollection = new DataVector<LVL1::CPMTobRoI>; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(roiCollection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, roiCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete roiCollection; + return sc; + } + + pObj = SG::asStorable(roiCollection); + + return sc; +} + +// createRep should create the bytestream from RDOs. + +StatusCode CpmRoiByteStreamV2Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + DataVector<LVL1::CPMTobRoI>* roiCollection = 0; + if( !SG::fromStorable( pObj, roiCollection ) ) { + m_log << MSG::ERROR << " Cannot cast to DataVector<CPMTobRoI>" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( roiCollection, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..741f6db5e3b39ebbb700ba3a4cda207f04c8496d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Cnv.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV2CNV_H +#define TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class CpmRoiByteStreamV2Tool; + +/** ByteStream converter for Cluster Processor Module RoIs post LS1. + * + * @author Peter Faulkner + */ + +class CpmRoiByteStreamV2Cnv: public Converter { + + friend class CnvFactory<CpmRoiByteStreamV2Cnv>; + +protected: + + CpmRoiByteStreamV2Cnv(ISvcLocator* svcloc); + +public: + + ~CpmRoiByteStreamV2Cnv(); + + virtual StatusCode initialize(); + /// Create CPM RoIs from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + /// Create ByteStream from CPM RoIs + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::CpmRoiByteStreamV2Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..9d2f51b22a48b94ade85d6e04c7bb08a01acfb14 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Tool.cxx @@ -0,0 +1,466 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "TrigT1CaloEvent/CPMTobRoI.h" + +#include "CpmRoiSubBlockV2.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloUserHeader.h" + +#include "CpmRoiByteStreamV2Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_ICpmRoiByteStreamV2Tool("CpmRoiByteStreamV2Tool", + 1, 1); + +const InterfaceID& CpmRoiByteStreamV2Tool::interfaceID() +{ + return IID_ICpmRoiByteStreamV2Tool; +} + +// Constructor + +CpmRoiByteStreamV2Tool::CpmRoiByteStreamV2Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_crates(4), m_modules(14), m_srcIdMap(0), m_subBlock(0), m_rodStatus(0), + m_fea(0) +{ + declareInterface<CpmRoiByteStreamV2Tool>(this); + + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + declareProperty("CrateOffsetHw", m_crateOffsetHw = 8, + "Offset of CP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of CP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + declareProperty("ROBSourceIDsRoIB", m_sourceIDsRoIB, + "ROB fragment source identifiers for RoIBs"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 2, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 1, + "The number of S-Links per crate"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +CpmRoiByteStreamV2Tool::~CpmRoiByteStreamV2Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmRoiByteStreamV2Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_subDetector = eformat::TDAQ_CALO_CLUSTER_PROC_ROI; + m_srcIdMap = new L1CaloSrcIdMap(); + m_rodStatus = new std::vector<uint32_t>(2); + m_subBlock = new CpmRoiSubBlockV2(); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpmRoiByteStreamV2Tool::finalize() +{ + delete m_fea; + delete m_subBlock; + delete m_rodStatus; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Convert ROB fragments to CPM RoIs + +StatusCode CpmRoiByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTobRoI>* const roiCollection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + std::set<uint32_t> dupRoiCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 1 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: " + << MSG::hex << sourceID << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion <= m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping pre-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word may be User Header + if (L1CaloUserHeader::isValid(*payload)) { + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1 ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + } + + // Loop over sub-blocks if there are any + + unsigned int rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER) { + m_subBlock->clear(); + payload = m_subBlock->read(payload, payloadEnd); + if (debug) { + msg() << "CPM RoI sub-block: Crate " << m_subBlock->crate() + << " Module " << m_subBlock->module() << endreq; + } + // Unpack sub-block + if (m_subBlock->dataWords() && !m_subBlock->unpack()) { + if (debug) { + std::string errMsg(m_subBlock->unpackErrorMsg()); + msg() << "CPM RoI sub-block unpacking failed: " << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const int numChips = 8; + const int numLocs = 2; + const int numTypes = 2; + for (int chip = 0; chip < numChips; ++chip) { + for (int loc = 0; loc < numLocs; ++loc) { + for (int type = 0; type < numTypes; ++type) { + const LVL1::CPMTobRoI roi = m_subBlock->roi(chip, loc, type); + if (roi.energy() || roi.isolation()) { + roiCollection->push_back(new LVL1::CPMTobRoI(roi)); + } + } + } + } + } else { + // Just RoI word + LVL1::CPMTobRoI roi; + if (roi.setRoiWord(*payload)) { + if (roi.crate() != rodCrate - m_crateOffsetHw) { + if (debug) msg() << "Inconsistent RoI crate number: " + << roi.crate() << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (roi.cpm() == 0 || roi.cpm() > m_modules) { + if (debug) msg() << "Invalid CPM number: " + << roi.cpm() << endreq; + rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + const uint32_t location = (*payload) & 0xffff0000; + if (dupRoiCheck.insert(location).second) { + if (roi.energy() || roi.isolation()) { + roiCollection->push_back(new LVL1::CPMTobRoI(*payload)); + } + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } else { + if (debug) msg() << "Invalid RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_ROI_TYPE; + break; + } + ++payload; + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, rodErr); + } + if (debug) { + msg() << "Number of RoIs read = " << roiCollection->size() << endreq; + } + + return StatusCode::SUCCESS; +} + +// Convert CPM RoI to bytestream + +StatusCode CpmRoiByteStreamV2Tool::convert( + const DataVector<LVL1::CPMTobRoI>* const roiCollection, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container map + + setupCpmRoiMap(roiCollection); + if (debug) { + msg() << "Number of RoIs to be written = " << roiCollection->size() + << " (collection), " << m_roiMap.size() << " (map)" + << endreq; + } + int count = 0; + CpmRoiMap::const_iterator mapIter = m_roiMap.begin(); + CpmRoiMap::const_iterator mapIterEnd = m_roiMap.end(); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + // CPM modules are numbered 1 to m_modules + for (int module=1; module <= m_modules; ++module) { + const int mod = module - 1; + + // Pack required number of modules per slink + + if (mod%modulesPerSlink == 0) { + const int daqOrRoi = 1; + const int slink = (m_slinks == 2) ? 2*(mod/modulesPerSlink) + : mod/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq + << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq; + } + const uint32_t rodIdCpm = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdCpm); + if (neutralFormat) { + const L1CaloUserHeader userHeader; + theROD->push_back(userHeader.header()); + } + m_rodStatusMap.insert(make_pair(rodIdCpm, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block (Neutral format only) + + if (neutralFormat) { + m_subBlock->clear(); + m_subBlock->setRoiHeader(m_version, hwCrate, module); + } + + // Find CPM RoIs for this module + + for (; mapIter != mapIterEnd; ++mapIter) { + const LVL1::CPMTobRoI* const roi = mapIter->second; + if (roi->crate() < crate) continue; + if (roi->crate() > crate) break; + if (roi->cpm() < module) continue; + if (roi->cpm() > module) break; + if (roi->energy() || roi->isolation()) { + if (neutralFormat) m_subBlock->fillRoi(*roi); + else theROD->push_back(roi->roiWord()); + ++count; + } + } + + // Pack and write the sub-block + + if (neutralFormat) { + if ( !m_subBlock->pack()) { + msg(MSG::ERROR) << "CPMTobRoI sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CPMTobRoI sub-block data words: " + << m_subBlock->dataWords() << endreq; + } + m_subBlock->write(theROD); + } + } + } + if (debug) { + msg() << "Number of RoIs written = " << count << endreq; + } + + // Fill the raw event + + m_fea->fill(re, msg()); + if (debug) msg() << MSG::dec; // fill seems to leave it in hex + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& CpmRoiByteStreamV2Tool::sourceIDs( + const std::string& sgKey) +{ + const std::string flag("RoIB"); + const std::string::size_type pos = sgKey.find(flag); + const bool roiDaq = + (pos == std::string::npos || pos != sgKey.length() - flag.length()); + const bool empty = (roiDaq) ? m_sourceIDs.empty() : m_sourceIDsRoIB.empty(); + if (empty) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 1; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + if (roiDaq) { + if (slink < 2) m_sourceIDs.push_back(robId); + } else if (slink >= 2) m_sourceIDsRoIB.push_back(robId); + } + } + } + return (roiDaq) ? m_sourceIDs : m_sourceIDsRoIB; +} + +// Set up CPM RoI map + +void CpmRoiByteStreamV2Tool::setupCpmRoiMap(const CpmRoiCollection* + const roiCollection) +{ + m_roiMap.clear(); + if (roiCollection) { + CpmRoiCollection::const_iterator pos = roiCollection->begin(); + CpmRoiCollection::const_iterator pose = roiCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMTobRoI* const roi = *pos; + const int type = roi->type(); + const int crate = roi->crate(); + const int cpm = roi->cpm(); + const int chip = roi->chip(); + const int loc = roi->location()>>2; + const uint32_t key = (((((((crate<<4)|cpm)<<3)|chip)<<1)|loc)<<1)|type; + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..874a4f4c90fcdd3fabc323f7ee39ffddcf5b8e1e --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiByteStreamV2Tool.h @@ -0,0 +1,124 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV2TOOL_H +#define TRIGT1CALOBYTESTREAM_CPMROIBYTESTREAMV2TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <typename> class FullEventAssembler; + +namespace LVL1 { + class CPMTobRoI; +} + +namespace LVL1BS { + +class CpmRoiSubBlockV2; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to CPM TOB RoI and CPM TOB RoI to raw data + * conversions. + * + * Based on ROD document version X_xxx. <<== CHECK + * + * @author Peter Faulkner + */ + +class CpmRoiByteStreamV2Tool : public AthAlgTool { + + public: + CpmRoiByteStreamV2Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~CpmRoiByteStreamV2Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to CPM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CPMTobRoI>* roiCollection); + + /// Convert CPM RoI to bytestream + StatusCode convert(const DataVector<LVL1::CPMTobRoI>* roiCollection, + RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + + typedef DataVector<LVL1::CPMTobRoI> CpmRoiCollection; + typedef std::map<uint32_t, const LVL1::CPMTobRoI*> CpmRoiMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Set up CPM RoI map + void setupCpmRoiMap(const CpmRoiCollection* roiCollection); + + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of crates + int m_crates; + /// Number of CPM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// ROB source IDs for RoIB + std::vector<uint32_t> m_sourceIDsRoIB; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Sub-block for neutral format + CpmRoiSubBlockV2* m_subBlock; + /// CPM RoI map + CpmRoiMap m_roiMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..07ef5f5f95059080f2919f5509599bdec87390eb --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlock.cxx @@ -0,0 +1,159 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TrigT1CaloEvent/CPMRoI.h" + +#include "CpmRoiSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CpmRoiSubBlock::s_wordIdVal; + +const int CpmRoiSubBlock::s_glinkPins; +const int CpmRoiSubBlock::s_hitsLen; +const int CpmRoiSubBlock::s_errorLen; +const int CpmRoiSubBlock::s_locationLen; +const int CpmRoiSubBlock::s_bunchCrossingBits; + + +CpmRoiSubBlock::CpmRoiSubBlock() +{ +} + +CpmRoiSubBlock::~CpmRoiSubBlock() +{ +} + +// Clear all data + +void CpmRoiSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_roiData.clear(); +} + +// Store header + +void CpmRoiSubBlock::setRoiHeader(const int version, const int crate, + const int module) +{ + setHeader(s_wordIdVal, version, NEUTRAL, 0, crate, module, 0, 1); +} + +// Store RoI + +void CpmRoiSubBlock::fillRoi(const LVL1::CPMRoI roi) +{ + const LVL1::CPMRoI roiTemp(crate(), module(), 0, 0, 0, 0); + if (roi.crate() == roiTemp.crate() && roi.cpm() == roiTemp.cpm()) { + m_roiData.resize(s_glinkPins); + const int pin = (roi.chip() << 1) | + ((roi.location() >> s_locationLen) & 0x1); + m_roiData[pin] = roi; + } +} + +// Return RoI for given chip and location (left/right) + +LVL1::CPMRoI CpmRoiSubBlock::roi(const int chip, const int loc) const +{ + const int pin = (chip << 1) | (loc & 0x1); + if (pin < s_glinkPins && !m_roiData.empty()) return m_roiData[pin]; + else return LVL1::CPMRoI(0); +} + +// Packing/Unpacking routines + +bool CpmRoiSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CpmRoiSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Pack neutral data + +bool CpmRoiSubBlock::packNeutral() +{ + m_roiData.resize(s_glinkPins); + for (int pin = 0; pin < s_glinkPins; ++pin) { + // RoI data + const LVL1::CPMRoI& roi(m_roiData[pin]); + packerNeutral(pin, roi.hits(), s_hitsLen); + packerNeutral(pin, roi.error(), s_errorLen); + packerNeutral(pin, roi.location(), s_locationLen); + // Bunch Crossing number + if (pin < s_bunchCrossingBits) { + packerNeutral(pin, bunchCrossing() >> pin, 1); + } else packerNeutral(pin, 0, 1); + // G-Link parity + packerNeutralParity(pin); + } + return true; +} + +// Unpack neutral data + +bool CpmRoiSubBlock::unpackNeutral() +{ + m_roiData.resize(s_glinkPins); + int bunchCrossing = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + // RoI data + const int hits = unpackerNeutral(pin, s_hitsLen); + const int error = unpackerNeutral(pin, s_errorLen); + const int loc = unpackerNeutral(pin, s_locationLen) | + ((pin & 0x1) << s_locationLen); + const int chip = pin >> 1; + m_roiData[pin] = LVL1::CPMRoI(crate(), module(), chip, loc, hits, error); + // Bunch Crossing number + if (pin < s_bunchCrossingBits) { + bunchCrossing |= unpackerNeutral(pin, 1) << pin; + } else unpackerNeutral(pin, 1); + // G-Link parity error + unpackerNeutralParityError(pin); + } + setBunchCrossing(bunchCrossing); + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..48b027a228ea41352c444cdb07a4b05ea3e872dc --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlock.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROISUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CPMROISUBBLOCK_H + +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1 { + class CPMRoI; +} + +namespace LVL1BS { + +/** Sub-Block class for CPM RoI data (neutral format). + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.09h + * + * @author Peter Faulkner + */ + +class CpmRoiSubBlock : public L1CaloSubBlock { + + public: + CpmRoiSubBlock(); + ~CpmRoiSubBlock(); + + /// Clear all data + void clear(); + + /// Store header + void setRoiHeader(int version, int crate, int module); + /// Store RoI + void fillRoi(LVL1::CPMRoI roi); + + /// Return RoI for given chip and location (left/right) + LVL1::CPMRoI roi(int chip, int loc) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Header word ID + static const int s_wordIdVal = 0xc; + // G-Link/Neutral format + static const int s_glinkPins = 16; + static const int s_hitsLen = 16; + static const int s_errorLen = 2; + static const int s_locationLen = 2; + static const int s_bunchCrossingBits = 12; + + /// Pack neutral data + bool packNeutral(); + /// Unpack neutral data + bool unpackNeutral(); + + /// RoI words + std::vector<LVL1::CPMRoI> m_roiData; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV1.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV1.cxx new file mode 100755 index 0000000000000000000000000000000000000000..23ac7bca1ccac8168d735d8e1f85b9e9c4f388d9 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV1.cxx @@ -0,0 +1,159 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TrigT1CaloEvent/CPMRoI.h" + +#include "CpmRoiSubBlockV1.h" + +namespace LVL1BS { + +// Constant definitions + +const int CpmRoiSubBlockV1::s_wordIdVal; + +const int CpmRoiSubBlockV1::s_glinkPins; +const int CpmRoiSubBlockV1::s_hitsLen; +const int CpmRoiSubBlockV1::s_errorLen; +const int CpmRoiSubBlockV1::s_locationLen; +const int CpmRoiSubBlockV1::s_bunchCrossingBits; + + +CpmRoiSubBlockV1::CpmRoiSubBlockV1() +{ +} + +CpmRoiSubBlockV1::~CpmRoiSubBlockV1() +{ +} + +// Clear all data + +void CpmRoiSubBlockV1::clear() +{ + L1CaloSubBlock::clear(); + m_roiData.clear(); +} + +// Store header + +void CpmRoiSubBlockV1::setRoiHeader(const int version, const int crate, + const int module) +{ + setHeader(s_wordIdVal, version, NEUTRAL, 0, crate, module, 0, 1); +} + +// Store RoI + +void CpmRoiSubBlockV1::fillRoi(const LVL1::CPMRoI roi) +{ + const LVL1::CPMRoI roiTemp(crate(), module(), 0, 0, 0, 0); + if (roi.crate() == roiTemp.crate() && roi.cpm() == roiTemp.cpm()) { + m_roiData.resize(s_glinkPins); + const int pin = (roi.chip() << 1) | + ((roi.location() >> s_locationLen) & 0x1); + m_roiData[pin] = roi; + } +} + +// Return RoI for given chip and location (left/right) + +LVL1::CPMRoI CpmRoiSubBlockV1::roi(const int chip, const int loc) const +{ + const int pin = (chip << 1) | (loc & 0x1); + if (pin < s_glinkPins && !m_roiData.empty()) return m_roiData[pin]; + else return LVL1::CPMRoI(0); +} + +// Packing/Unpacking routines + +bool CpmRoiSubBlockV1::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CpmRoiSubBlockV1::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Pack neutral data + +bool CpmRoiSubBlockV1::packNeutral() +{ + m_roiData.resize(s_glinkPins); + for (int pin = 0; pin < s_glinkPins; ++pin) { + // RoI data + const LVL1::CPMRoI& roi(m_roiData[pin]); + packerNeutral(pin, roi.hits(), s_hitsLen); + packerNeutral(pin, roi.error(), s_errorLen); + packerNeutral(pin, roi.location(), s_locationLen); + // Bunch Crossing number + if (pin < s_bunchCrossingBits) { + packerNeutral(pin, bunchCrossing() >> pin, 1); + } else packerNeutral(pin, 0, 1); + // G-Link parity + packerNeutralParity(pin); + } + return true; +} + +// Unpack neutral data + +bool CpmRoiSubBlockV1::unpackNeutral() +{ + m_roiData.resize(s_glinkPins); + int bunchCrossing = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + // RoI data + const int hits = unpackerNeutral(pin, s_hitsLen); + const int error = unpackerNeutral(pin, s_errorLen); + const int loc = unpackerNeutral(pin, s_locationLen) | + ((pin & 0x1) << s_locationLen); + const int chip = pin >> 1; + m_roiData[pin] = LVL1::CPMRoI(crate(), module(), chip, loc, hits, error); + // Bunch Crossing number + if (pin < s_bunchCrossingBits) { + bunchCrossing |= unpackerNeutral(pin, 1) << pin; + } else unpackerNeutral(pin, 1); + // G-Link parity error + unpackerNeutralParityError(pin); + } + setBunchCrossing(bunchCrossing); + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV1.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV1.h new file mode 100755 index 0000000000000000000000000000000000000000..4ea8945f1c002a92b762fba9ae9f8680b509ca25 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV1.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROISUBBLOCKV1_H +#define TRIGT1CALOBYTESTREAM_CPMROISUBBLOCKV1_H + +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1 { + class CPMRoI; +} + +namespace LVL1BS { + +/** Sub-Block class for CPM RoI data (neutral format). + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.09h + * + * @author Peter Faulkner + */ + +class CpmRoiSubBlockV1 : public L1CaloSubBlock { + + public: + CpmRoiSubBlockV1(); + ~CpmRoiSubBlockV1(); + + /// Clear all data + void clear(); + + /// Store header + void setRoiHeader(int version, int crate, int module); + /// Store RoI + void fillRoi(LVL1::CPMRoI roi); + + /// Return RoI for given chip and location (left/right) + LVL1::CPMRoI roi(int chip, int loc) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Header word ID + static const int s_wordIdVal = 0xc; + // G-Link/Neutral format + static const int s_glinkPins = 16; + static const int s_hitsLen = 16; + static const int s_errorLen = 2; + static const int s_locationLen = 2; + static const int s_bunchCrossingBits = 12; + + /// Pack neutral data + bool packNeutral(); + /// Unpack neutral data + bool unpackNeutral(); + + /// RoI words + std::vector<LVL1::CPMRoI> m_roiData; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV2.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV2.cxx new file mode 100755 index 0000000000000000000000000000000000000000..6cd53dfacc0809d60c8269f502a77573229e5ed2 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV2.cxx @@ -0,0 +1,177 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TrigT1CaloEvent/CPMTobRoI.h" + +#include "CpmRoiSubBlockV2.h" + +namespace LVL1BS { + +// Constant definitions + +const int CpmRoiSubBlockV2::s_wordIdVal; + +const int CpmRoiSubBlockV2::s_glinkPins; +const int CpmRoiSubBlockV2::s_energyLen; +const int CpmRoiSubBlockV2::s_isolLen; +const int CpmRoiSubBlockV2::s_locationLen; +const int CpmRoiSubBlockV2::s_bunchCrossingBits; + + +CpmRoiSubBlockV2::CpmRoiSubBlockV2() +{ +} + +CpmRoiSubBlockV2::~CpmRoiSubBlockV2() +{ +} + +// Clear all data + +void CpmRoiSubBlockV2::clear() +{ + L1CaloSubBlock::clear(); + m_roiData.clear(); +} + +// Store header + +void CpmRoiSubBlockV2::setRoiHeader(const int version, const int crate, + const int module) +{ + setHeader(s_wordIdVal, version, NEUTRAL, 0, crate, module, 0, 1); +} + +// Store RoI + +void CpmRoiSubBlockV2::fillRoi(const LVL1::CPMTobRoI roi) +{ + const LVL1::CPMTobRoI roiTemp(crate(), module(), 0, 0, 0, 0, 0); + if (roi.crate() == roiTemp.crate() && roi.cpm() == roiTemp.cpm()) { + m_roiData.resize(2*s_glinkPins); + const int pin = (roi.chip() << 1) | + ((roi.location() >> s_locationLen) & 0x1); + const int type = roi.type(); // em or tau (0/1) + m_roiData[2*pin+type] = roi; + } +} + +// Return RoI for given chip and location (left/right) and type (em/tau) + +LVL1::CPMTobRoI CpmRoiSubBlockV2::roi(const int chip, const int loc, + const int type) const +{ + const int pin = (chip << 1) | (loc & 0x1); + if (pin < s_glinkPins && !m_roiData.empty()) return m_roiData[2*pin+type]; + else return LVL1::CPMTobRoI(0); +} + +// Packing/Unpacking routines + +bool CpmRoiSubBlockV2::pack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CpmRoiSubBlockV2::unpack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Pack neutral data + +bool CpmRoiSubBlockV2::packNeutral() +{ + m_roiData.resize(2*s_glinkPins); + for (int pin = 0; pin < s_glinkPins; ++pin) { + // RoI data + const int idx = 2*pin; + const LVL1::CPMTobRoI& roiEm(m_roiData[idx]); + const LVL1::CPMTobRoI& roiTau(m_roiData[idx+1]); + packerNeutral(pin, roiEm.energy(), s_energyLen); + packerNeutral(pin, roiEm.isolation(), s_isolLen); + packerNeutral(pin, 0, 1); //parity + packerNeutral(pin, roiTau.energy(), s_energyLen); + packerNeutral(pin, roiTau.isolation(), s_isolLen); + packerNeutral(pin, 0, 1); //parity + packerNeutral(pin, 0, 1); //error + packerNeutral(pin, (roiEm.location()|roiTau.location()), s_locationLen); + // Bunch Crossing number + if (pin < s_bunchCrossingBits) { + packerNeutral(pin, bunchCrossing() >> pin, 1); + } else packerNeutral(pin, 0, 1); + // G-Link parity + packerNeutralParity(pin); + } + return true; +} + +// Unpack neutral data + +bool CpmRoiSubBlockV2::unpackNeutral() +{ + m_roiData.resize(2*s_glinkPins); + int bunchCrossing = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + // RoI data + const int energyEm = unpackerNeutral(pin, s_energyLen); + const int isolEm = unpackerNeutral(pin, s_isolLen); + unpackerNeutral(pin, 1); //parity + const int energyTau = unpackerNeutral(pin, s_energyLen); + const int isolTau = unpackerNeutral(pin, s_isolLen); + unpackerNeutral(pin, 1); //parity + unpackerNeutral(pin, 1); //error + const int loc = unpackerNeutral(pin, s_locationLen) | + ((pin & 0x1) << s_locationLen); + const int chip = pin >> 1; + const int idx = 2*pin; + m_roiData[idx] = LVL1::CPMTobRoI(crate(), module(), chip, loc, 0, + energyEm, isolEm); + m_roiData[idx+1] = LVL1::CPMTobRoI(crate(), module(), chip, loc, 1, + energyTau, isolTau); + // Bunch Crossing number + if (pin < s_bunchCrossingBits) { + bunchCrossing |= unpackerNeutral(pin, 1) << pin; + } else unpackerNeutral(pin, 1); + // G-Link parity error + unpackerNeutralParityError(pin); + } + setBunchCrossing(bunchCrossing); + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV2.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV2.h new file mode 100755 index 0000000000000000000000000000000000000000..c058e8645d718723e6a8f8f1e40b78bfa3631346 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmRoiSubBlockV2.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMROISUBBLOCKV2_H +#define TRIGT1CALOBYTESTREAM_CPMROISUBBLOCKV2_H + +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1 { + class CPMTobRoI; +} + +namespace LVL1BS { + +/** Sub-Block class for CPM RoI data (neutral format) post LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx <<== CHECK + * + * @author Peter Faulkner + */ + +class CpmRoiSubBlockV2 : public L1CaloSubBlock { + + public: + CpmRoiSubBlockV2(); + ~CpmRoiSubBlockV2(); + + /// Clear all data + void clear(); + + /// Store header + void setRoiHeader(int version, int crate, int module); + /// Store RoI + void fillRoi(LVL1::CPMTobRoI roi); + + /// Return RoI for given chip and location (left/right) and type (em/tau) + LVL1::CPMTobRoI roi(int chip, int loc, int type) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Header word ID + static const int s_wordIdVal = 0xc; + // G-Link/Neutral format + static const int s_glinkPins = 16; + static const int s_energyLen = 8; + static const int s_isolLen = 5; + static const int s_locationLen = 2; + static const int s_bunchCrossingBits = 12; + + /// Pack neutral data + bool packNeutral(); + /// Unpack neutral data + bool unpackNeutral(); + + /// RoI words + std::vector<LVL1::CPMTobRoI> m_roiData; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..7fb764a2c89ae68661aec4a245c0be8ec7ffcb3f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlock.cxx @@ -0,0 +1,455 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CpmSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int CpmSubBlock::s_wordIdVal; + +const int CpmSubBlock::s_wordLength; + +const int CpmSubBlock::s_ttDataABit; +const int CpmSubBlock::s_ttDataBBit; +const int CpmSubBlock::s_parityABit; +const int CpmSubBlock::s_parityBBit; +const int CpmSubBlock::s_linkDownABit; +const int CpmSubBlock::s_linkDownBBit; +const int CpmSubBlock::s_pairBit; +const int CpmSubBlock::s_fpgaBit; +const int CpmSubBlock::s_dataIdBit; +const int CpmSubBlock::s_ttWordId; +const uint32_t CpmSubBlock::s_ttDataMask; +const uint32_t CpmSubBlock::s_pairPinMask; +const uint32_t CpmSubBlock::s_dataIdMask; + +const int CpmSubBlock::s_indicatorBit; +const int CpmSubBlock::s_threshWordId; +const uint32_t CpmSubBlock::s_threshMask; + +const int CpmSubBlock::s_pairsPerPin; +const int CpmSubBlock::s_wordsPerPin; +const int CpmSubBlock::s_ttBits; +const int CpmSubBlock::s_errBits; +const int CpmSubBlock::s_hitBits; +const int CpmSubBlock::s_hitWords; +const int CpmSubBlock::s_glinkPins; +const int CpmSubBlock::s_glinkBitsPerSlice; + + +CpmSubBlock::CpmSubBlock() : m_channels(80) +{ + m_chanPresent.assign(m_channels, 0); +} + +CpmSubBlock::~CpmSubBlock() +{ +} + +// Clear all data + +void CpmSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_ttData.clear(); + m_hitData.clear(); + m_chanPresent.assign(m_channels, 0); +} + +// Store CPM header + +void CpmSubBlock::setCpmHeader(const int version, const int format, + const int slice, const int crate, + const int module, const int timeslices) +{ + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, timeslices); +} + +// Store trigger tower data + +void CpmSubBlock::fillTowerData(const int slice, const int channel, + const int em, const int had, + const int emErr, const int hadErr) +{ + if (channel < m_channels && (em || emErr || had || hadErr)) { + resize(m_ttData, m_channels); + int dat = em; + int err = emErr; + for (int pinOffset = 0; pinOffset < 2; ++pinOffset) { + if (dat || err) { + const int pin = 2 * (channel/s_wordsPerPin) + pinOffset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + word |= (dat & s_ttDataMask) << s_ttDataABit; + word |= (err & 0x1) << s_parityABit; + word |= ((err >> 1) & 0x1) << s_linkDownABit; + } else { + word |= (dat & s_ttDataMask) << s_ttDataBBit; + word |= (err & 0x1) << s_parityBBit; + word |= ((err >> 1) & 0x1) << s_linkDownBBit; + } + word |= pair << s_pairBit; + word |= pin << s_fpgaBit; + word |= s_ttWordId << s_dataIdBit; + m_ttData[ix] = word; + } + dat = had; + err = hadErr; + } + m_chanPresent[channel] = 1; + } +} + +// Store hit counts + +void CpmSubBlock::setHits(const int slice, const unsigned int hit0, + const unsigned int hit1) +{ + if (hit0 || hit1) { + resize(m_hitData, 2); + const int ix = index(slice)*2; + unsigned int hits = hit0; + for (int indicator = 0; indicator < 2; ++indicator) { + if (hits) { + uint32_t word = (hits & s_threshMask); + word |= indicator << s_indicatorBit; + word |= s_threshWordId << s_dataIdBit; + m_hitData[ix + indicator] = word; + } + hits = hit1; + } + } +} + +// Return Em data for given channel + +int CpmSubBlock::emData(const int slice, const int channel) const +{ + return data(slice, channel, 0); +} + +// Return Had data for given channel + +int CpmSubBlock::hadData(const int slice, const int channel) const +{ + return data(slice, channel, 1); +} + +// Return Em error for given channel + +int CpmSubBlock::emError(const int slice, const int channel) const +{ + return error(slice, channel, 0); +} + +// Return Had error for given channel + +int CpmSubBlock::hadError(const int slice, const int channel) const +{ + return error(slice, channel, 1); +} + +// Return first hit counts word + +unsigned int CpmSubBlock::hits0(const int slice) const +{ + return hits(slice, 0); +} + +// Return second hit counts word + +unsigned int CpmSubBlock::hits1(const int slice) const +{ + return hits(slice, 1); +} + +// Return number of timeslices + +int CpmSubBlock::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Packing/Unpacking routines + +bool CpmSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CpmSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data for given channel and pin offset + +int CpmSubBlock::data(const int slice, const int channel, + const int offset) const +{ + int dat = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_ttData.empty()) { + const int pin = 2 * (channel/s_wordsPerPin) + offset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + const uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + dat = (word >> s_ttDataABit) & s_ttDataMask; + } else dat = (word >> s_ttDataBBit) & s_ttDataMask; + } + return dat; +} + +// Return error for given channel and pin offset + +int CpmSubBlock::error(const int slice, const int channel, + const int offset) const +{ + int err = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_ttData.empty()) { + const int pin = 2 * (channel/s_wordsPerPin) + offset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + const uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + err = (word >> s_parityABit) & 0x1; + err |= ((word >> s_linkDownABit) & 0x1) << 1; + } else { + err = (word >> s_parityBBit) & 0x1; + err |= ((word >> s_linkDownBBit) & 0x1) << 1; + } + } + return err; +} + +// Return hit counts with given offset + +unsigned int CpmSubBlock::hits(const int slice, const int offset) const +{ + unsigned int hit = 0; + if (slice >= 0 && slice < timeslices() && !m_hitData.empty()) { + hit = m_hitData[index(slice)*2 + offset] & s_threshMask; + } + return hit; +} + +// Return data index appropriate to format + +int CpmSubBlock::index(const int slice) const +{ + return (format() == NEUTRAL) ? slice : 0; +} + +// Resize a data vector according to format + +void CpmSubBlock::resize(std::vector<uint32_t>& vec, int channels) +{ + if (vec.empty()) { + int size = channels; + if (format() == NEUTRAL) size *= timeslices(); + vec.resize(size); + } +} + +// Pack neutral data + +bool CpmSubBlock::packNeutral() +{ + resize(m_ttData, m_channels); + resize(m_hitData, 2); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + const unsigned int hit0 = hits0(slice); + const unsigned int hit1 = hits1(slice); + for (int pin = 0; pin < s_glinkPins; ++pin) { + // Trigger tower data + for (int pair = 0; pair < s_pairsPerPin; ++pair) { + for (int i = 0; i < 2; ++i) { + const int channel = s_wordsPerPin*(pin/2) + 2*pair + i; + if ((pin & 0x1)) { // Odd pins Had, even Em + packerNeutral(pin, hadData(slice, channel), s_ttBits); + packerNeutral(pin, hadError(slice, channel), s_errBits); + } else { + packerNeutral(pin, emData(slice, channel), s_ttBits); + packerNeutral(pin, emError(slice, channel), s_errBits); + } + } + } + // Hits and Bunch Crossing number + if (pin < s_hitWords) { + packerNeutral(pin, hit0 >> pin*s_hitBits, s_hitBits); + } else if (pin < 2*s_hitWords) { + packerNeutral(pin, hit1 >> (pin - s_hitWords)*s_hitBits, s_hitBits); + } else { + packerNeutral(pin, bunchCrossing() >> (pin - 2*s_hitWords)*s_hitBits, + s_hitBits); + } + // G-Link parity + packerNeutralParity(pin); + } + } + return true; +} + +// Pack uncompressed data + +bool CpmSubBlock::packUncompressed() +{ + // Trigger tower data + std::vector<uint32_t>::const_iterator pos; + for (pos = m_ttData.begin(); pos != m_ttData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + + // Hits data + for (pos = m_hitData.begin(); pos != m_hitData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CpmSubBlock::unpackNeutral() +{ + resize(m_ttData, m_channels); + resize(m_hitData, 2); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + unsigned int hit0 = 0; + unsigned int hit1 = 0; + int bunchCrossing = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + // Trigger tower data + for (int pair = 0; pair < s_pairsPerPin; ++pair) { + for (int i = 0; i < 2; ++i) { + const int channel = s_wordsPerPin*(pin/2) + 2*pair + i; + int em = 0; + int had = 0; + int emErr = 0; + int hadErr = 0; + if ((pin & 0x1)) { // Odd pins Had, even Em + em = emData(slice, channel); + had = unpackerNeutral(pin, s_ttBits); + emErr = emError(slice, channel); + hadErr = unpackerNeutral(pin, s_errBits); + } else { + em = unpackerNeutral(pin, s_ttBits); + had = hadData(slice, channel); + emErr = unpackerNeutral(pin, s_errBits); + hadErr = hadError(slice, channel); + } + fillTowerData(slice, channel, em, had, emErr, hadErr); + } + } + // Hits and Bunch Crossing number + if (pin < s_hitWords) { + hit0 |= unpackerNeutral(pin, s_hitBits) << pin*s_hitBits; + } else if (pin < 2*s_hitWords) { + hit1 |= unpackerNeutral(pin, s_hitBits) << (pin - s_hitWords)*s_hitBits; + } else { + bunchCrossing |= unpackerNeutral(pin, s_hitBits) + << (pin - 2*s_hitWords)*s_hitBits; + } + // G-Link parity error + unpackerNeutralParityError(pin); + } + setHits(slice, hit0, hit1); + setBunchCrossing(bunchCrossing); + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CpmSubBlock::unpackUncompressed() +{ + resize(m_ttData, m_channels); + resize(m_hitData, 2); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataId(word); + bool err = false; + // Trigger tower data + if (id == s_ttWordId) { + const int ix = (word >> s_pairBit) & s_pairPinMask; + if (ix < m_channels && m_ttData[ix] == 0) { + m_ttData[ix] = word; + const int pin = ix/4; + const int pair = ix%4; + const int channel = s_wordsPerPin*(pin/2) + 2*pair; + m_chanPresent[channel] = 1; + m_chanPresent[channel+1] = 1; + } else err = true; + // Hits + } else { + const int indicator = (word >> s_indicatorBit) & 0x1; + if (m_hitData[indicator] == 0) m_hitData[indicator] = word; + else err = true; + } + if (err) { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..e8b3778e943df781a84c08f0f846e4e7b8150fef --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlock.h @@ -0,0 +1,141 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_CPMSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CPM data. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class CpmSubBlock : public L1CaloSubBlock { + + public: + CpmSubBlock(); + ~CpmSubBlock(); + + /// Clear all data + void clear(); + + /// Store CPM header + void setCpmHeader(int version, int format, int slice, int crate, + int module, int timeslices); + /// Store trigger tower data + void fillTowerData(int slice, int channel, int em, int had, + int emErr, int hadErr); + /// Store hit counts + void setHits(int slice, unsigned int hit0, unsigned int hit1); + + /// Return Em data for given channel + int emData(int slice, int channel) const; + /// Return Had data for given channel + int hadData(int slice, int channel) const; + /// Return Em error for given channel + int emError(int slice, int channel) const; + /// Return Had error for given channel + int hadError(int slice, int channel) const; + /// Return e/gamma hit counts + unsigned int hits0(int slice) const; + /// Return tau hit counts + unsigned int hits1(int slice) const; + /// Return number of timeslices + int timeslices() const; + /// Return true if there is tower data for given channel + bool anyTowerData(int channel) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// CPM header word ID + static const int s_wordIdVal = 0xc; + /// Data word length + static const int s_wordLength = 32; + // Trigger tower data word bit positions and masks + static const int s_ttDataABit = 0; + static const int s_ttDataBBit = 9; + static const int s_parityABit = 8; + static const int s_parityBBit = 17; + static const int s_linkDownABit = 19; + static const int s_linkDownBBit = 20; + static const int s_pairBit = 21; + static const int s_fpgaBit = 23; + static const int s_dataIdBit = 30; + static const int s_ttWordId = 0x1; + static const uint32_t s_ttDataMask = 0xff; + static const uint32_t s_pairPinMask = 0x7f; + static const uint32_t s_dataIdMask = 0x3; + // Hit counts bit positions and masks + static const int s_indicatorBit = 24; + static const int s_threshWordId = 0x2; + static const uint32_t s_threshMask = 0xffffff; + // G-Link/Neutral format + static const int s_pairsPerPin = 4; + static const int s_wordsPerPin = 8; + static const int s_ttBits = 8; + static const int s_errBits = 2; + static const int s_hitBits = 3; + static const int s_hitWords = 8; + static const int s_glinkPins = 20; + static const int s_glinkBitsPerSlice = 84; + + /// Return data WordID + int dataId(uint32_t word) const; + /// Return data for given channel and pin offset + int data(int slice, int channel, int offset) const; + /// Return error for given channel and pin offset + int error(int slice, int channel, int offset) const; + /// Return hit counts with given offset + unsigned int hits(int slice, int offset) const; + /// Return data index appropriate to format + int index(int slice) const; + /// Resize a data vector according to format + void resize(std::vector<uint32_t>& vec, int channels); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Trigger tower data + std::vector<uint32_t> m_ttData; + /// Hit counts + std::vector<uint32_t> m_hitData; + /// Channel present flags vector + std::vector<int> m_chanPresent; + /// Number of Trigger tower channels per module + int m_channels; + +}; + +inline int CpmSubBlock::dataId(const uint32_t word) const +{ + return (word >> s_dataIdBit) & s_dataIdMask; +} + +inline bool CpmSubBlock::anyTowerData(const int channel) const +{ + return m_chanPresent[channel]; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV1.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV1.cxx new file mode 100755 index 0000000000000000000000000000000000000000..797c7f08407c56329d83eea080bc9befa019e0b2 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV1.cxx @@ -0,0 +1,455 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CpmSubBlockV1.h" + +namespace LVL1BS { + +// Constant definitions + +const int CpmSubBlockV1::s_wordIdVal; + +const int CpmSubBlockV1::s_wordLength; + +const int CpmSubBlockV1::s_ttDataABit; +const int CpmSubBlockV1::s_ttDataBBit; +const int CpmSubBlockV1::s_parityABit; +const int CpmSubBlockV1::s_parityBBit; +const int CpmSubBlockV1::s_linkDownABit; +const int CpmSubBlockV1::s_linkDownBBit; +const int CpmSubBlockV1::s_pairBit; +const int CpmSubBlockV1::s_fpgaBit; +const int CpmSubBlockV1::s_dataIdBit; +const int CpmSubBlockV1::s_ttWordId; +const uint32_t CpmSubBlockV1::s_ttDataMask; +const uint32_t CpmSubBlockV1::s_pairPinMask; +const uint32_t CpmSubBlockV1::s_dataIdMask; + +const int CpmSubBlockV1::s_indicatorBit; +const int CpmSubBlockV1::s_threshWordId; +const uint32_t CpmSubBlockV1::s_threshMask; + +const int CpmSubBlockV1::s_pairsPerPin; +const int CpmSubBlockV1::s_wordsPerPin; +const int CpmSubBlockV1::s_ttBits; +const int CpmSubBlockV1::s_errBits; +const int CpmSubBlockV1::s_hitBits; +const int CpmSubBlockV1::s_hitWords; +const int CpmSubBlockV1::s_glinkPins; +const int CpmSubBlockV1::s_glinkBitsPerSlice; + + +CpmSubBlockV1::CpmSubBlockV1() : m_channels(80) +{ + m_chanPresent.assign(m_channels, 0); +} + +CpmSubBlockV1::~CpmSubBlockV1() +{ +} + +// Clear all data + +void CpmSubBlockV1::clear() +{ + L1CaloSubBlock::clear(); + m_ttData.clear(); + m_hitData.clear(); + m_chanPresent.assign(m_channels, 0); +} + +// Store CPM header + +void CpmSubBlockV1::setCpmHeader(const int version, const int format, + const int slice, const int crate, + const int module, const int timeslices) +{ + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, timeslices); +} + +// Store trigger tower data + +void CpmSubBlockV1::fillTowerData(const int slice, const int channel, + const int em, const int had, + const int emErr, const int hadErr) +{ + if (channel < m_channels && (em || emErr || had || hadErr)) { + resize(m_ttData, m_channels); + int dat = em; + int err = emErr; + for (int pinOffset = 0; pinOffset < 2; ++pinOffset) { + if (dat || err) { + const int pin = 2 * (channel/s_wordsPerPin) + pinOffset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + word |= (dat & s_ttDataMask) << s_ttDataABit; + word |= (err & 0x1) << s_parityABit; + word |= ((err >> 1) & 0x1) << s_linkDownABit; + } else { + word |= (dat & s_ttDataMask) << s_ttDataBBit; + word |= (err & 0x1) << s_parityBBit; + word |= ((err >> 1) & 0x1) << s_linkDownBBit; + } + word |= pair << s_pairBit; + word |= pin << s_fpgaBit; + word |= s_ttWordId << s_dataIdBit; + m_ttData[ix] = word; + } + dat = had; + err = hadErr; + } + m_chanPresent[channel] = 1; + } +} + +// Store hit counts + +void CpmSubBlockV1::setHits(const int slice, const unsigned int hit0, + const unsigned int hit1) +{ + if (hit0 || hit1) { + resize(m_hitData, 2); + const int ix = index(slice)*2; + unsigned int hits = hit0; + for (int indicator = 0; indicator < 2; ++indicator) { + if (hits) { + uint32_t word = (hits & s_threshMask); + word |= indicator << s_indicatorBit; + word |= s_threshWordId << s_dataIdBit; + m_hitData[ix + indicator] = word; + } + hits = hit1; + } + } +} + +// Return Em data for given channel + +int CpmSubBlockV1::emData(const int slice, const int channel) const +{ + return data(slice, channel, 0); +} + +// Return Had data for given channel + +int CpmSubBlockV1::hadData(const int slice, const int channel) const +{ + return data(slice, channel, 1); +} + +// Return Em error for given channel + +int CpmSubBlockV1::emError(const int slice, const int channel) const +{ + return error(slice, channel, 0); +} + +// Return Had error for given channel + +int CpmSubBlockV1::hadError(const int slice, const int channel) const +{ + return error(slice, channel, 1); +} + +// Return first hit counts word + +unsigned int CpmSubBlockV1::hits0(const int slice) const +{ + return hits(slice, 0); +} + +// Return second hit counts word + +unsigned int CpmSubBlockV1::hits1(const int slice) const +{ + return hits(slice, 1); +} + +// Return number of timeslices + +int CpmSubBlockV1::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Packing/Unpacking routines + +bool CpmSubBlockV1::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CpmSubBlockV1::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data for given channel and pin offset + +int CpmSubBlockV1::data(const int slice, const int channel, + const int offset) const +{ + int dat = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_ttData.empty()) { + const int pin = 2 * (channel/s_wordsPerPin) + offset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + const uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + dat = (word >> s_ttDataABit) & s_ttDataMask; + } else dat = (word >> s_ttDataBBit) & s_ttDataMask; + } + return dat; +} + +// Return error for given channel and pin offset + +int CpmSubBlockV1::error(const int slice, const int channel, + const int offset) const +{ + int err = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_ttData.empty()) { + const int pin = 2 * (channel/s_wordsPerPin) + offset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + const uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + err = (word >> s_parityABit) & 0x1; + err |= ((word >> s_linkDownABit) & 0x1) << 1; + } else { + err = (word >> s_parityBBit) & 0x1; + err |= ((word >> s_linkDownBBit) & 0x1) << 1; + } + } + return err; +} + +// Return hit counts with given offset + +unsigned int CpmSubBlockV1::hits(const int slice, const int offset) const +{ + unsigned int hit = 0; + if (slice >= 0 && slice < timeslices() && !m_hitData.empty()) { + hit = m_hitData[index(slice)*2 + offset] & s_threshMask; + } + return hit; +} + +// Return data index appropriate to format + +int CpmSubBlockV1::index(const int slice) const +{ + return (format() == NEUTRAL) ? slice : 0; +} + +// Resize a data vector according to format + +void CpmSubBlockV1::resize(std::vector<uint32_t>& vec, int channels) +{ + if (vec.empty()) { + int size = channels; + if (format() == NEUTRAL) size *= timeslices(); + vec.resize(size); + } +} + +// Pack neutral data + +bool CpmSubBlockV1::packNeutral() +{ + resize(m_ttData, m_channels); + resize(m_hitData, 2); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + const unsigned int hit0 = hits0(slice); + const unsigned int hit1 = hits1(slice); + for (int pin = 0; pin < s_glinkPins; ++pin) { + // Trigger tower data + for (int pair = 0; pair < s_pairsPerPin; ++pair) { + for (int i = 0; i < 2; ++i) { + const int channel = s_wordsPerPin*(pin/2) + 2*pair + i; + if ((pin & 0x1)) { // Odd pins Had, even Em + packerNeutral(pin, hadData(slice, channel), s_ttBits); + packerNeutral(pin, hadError(slice, channel), s_errBits); + } else { + packerNeutral(pin, emData(slice, channel), s_ttBits); + packerNeutral(pin, emError(slice, channel), s_errBits); + } + } + } + // Hits and Bunch Crossing number + if (pin < s_hitWords) { + packerNeutral(pin, hit0 >> pin*s_hitBits, s_hitBits); + } else if (pin < 2*s_hitWords) { + packerNeutral(pin, hit1 >> (pin - s_hitWords)*s_hitBits, s_hitBits); + } else { + packerNeutral(pin, bunchCrossing() >> (pin - 2*s_hitWords)*s_hitBits, + s_hitBits); + } + // G-Link parity + packerNeutralParity(pin); + } + } + return true; +} + +// Pack uncompressed data + +bool CpmSubBlockV1::packUncompressed() +{ + // Trigger tower data + std::vector<uint32_t>::const_iterator pos; + for (pos = m_ttData.begin(); pos != m_ttData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + + // Hits data + for (pos = m_hitData.begin(); pos != m_hitData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CpmSubBlockV1::unpackNeutral() +{ + resize(m_ttData, m_channels); + resize(m_hitData, 2); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + unsigned int hit0 = 0; + unsigned int hit1 = 0; + int bunchCrossing = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + // Trigger tower data + for (int pair = 0; pair < s_pairsPerPin; ++pair) { + for (int i = 0; i < 2; ++i) { + const int channel = s_wordsPerPin*(pin/2) + 2*pair + i; + int em = 0; + int had = 0; + int emErr = 0; + int hadErr = 0; + if ((pin & 0x1)) { // Odd pins Had, even Em + em = emData(slice, channel); + had = unpackerNeutral(pin, s_ttBits); + emErr = emError(slice, channel); + hadErr = unpackerNeutral(pin, s_errBits); + } else { + em = unpackerNeutral(pin, s_ttBits); + had = hadData(slice, channel); + emErr = unpackerNeutral(pin, s_errBits); + hadErr = hadError(slice, channel); + } + fillTowerData(slice, channel, em, had, emErr, hadErr); + } + } + // Hits and Bunch Crossing number + if (pin < s_hitWords) { + hit0 |= unpackerNeutral(pin, s_hitBits) << pin*s_hitBits; + } else if (pin < 2*s_hitWords) { + hit1 |= unpackerNeutral(pin, s_hitBits) << (pin - s_hitWords)*s_hitBits; + } else { + bunchCrossing |= unpackerNeutral(pin, s_hitBits) + << (pin - 2*s_hitWords)*s_hitBits; + } + // G-Link parity error + unpackerNeutralParityError(pin); + } + setHits(slice, hit0, hit1); + setBunchCrossing(bunchCrossing); + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CpmSubBlockV1::unpackUncompressed() +{ + resize(m_ttData, m_channels); + resize(m_hitData, 2); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataId(word); + bool err = false; + // Trigger tower data + if (id == s_ttWordId) { + const int ix = (word >> s_pairBit) & s_pairPinMask; + if (ix < m_channels && m_ttData[ix] == 0) { + m_ttData[ix] = word; + const int pin = ix/4; + const int pair = ix%4; + const int channel = s_wordsPerPin*(pin/2) + 2*pair; + m_chanPresent[channel] = 1; + m_chanPresent[channel+1] = 1; + } else err = true; + // Hits + } else { + const int indicator = (word >> s_indicatorBit) & 0x1; + if (m_hitData[indicator] == 0) m_hitData[indicator] = word; + else err = true; + } + if (err) { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV1.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV1.h new file mode 100755 index 0000000000000000000000000000000000000000..d866d240abe80c951fb504d8cefee9a82e19967a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV1.h @@ -0,0 +1,141 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMSUBBLOCKV1_H +#define TRIGT1CALOBYTESTREAM_CPMSUBBLOCKV1_H + +#include <stdint.h> +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CPM data. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class CpmSubBlockV1 : public L1CaloSubBlock { + + public: + CpmSubBlockV1(); + ~CpmSubBlockV1(); + + /// Clear all data + void clear(); + + /// Store CPM header + void setCpmHeader(int version, int format, int slice, int crate, + int module, int timeslices); + /// Store trigger tower data + void fillTowerData(int slice, int channel, int em, int had, + int emErr, int hadErr); + /// Store hit counts + void setHits(int slice, unsigned int hit0, unsigned int hit1); + + /// Return Em data for given channel + int emData(int slice, int channel) const; + /// Return Had data for given channel + int hadData(int slice, int channel) const; + /// Return Em error for given channel + int emError(int slice, int channel) const; + /// Return Had error for given channel + int hadError(int slice, int channel) const; + /// Return e/gamma hit counts + unsigned int hits0(int slice) const; + /// Return tau hit counts + unsigned int hits1(int slice) const; + /// Return number of timeslices + int timeslices() const; + /// Return true if there is tower data for given channel + bool anyTowerData(int channel) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// CPM header word ID + static const int s_wordIdVal = 0xc; + /// Data word length + static const int s_wordLength = 32; + // Trigger tower data word bit positions and masks + static const int s_ttDataABit = 0; + static const int s_ttDataBBit = 9; + static const int s_parityABit = 8; + static const int s_parityBBit = 17; + static const int s_linkDownABit = 19; + static const int s_linkDownBBit = 20; + static const int s_pairBit = 21; + static const int s_fpgaBit = 23; + static const int s_dataIdBit = 30; + static const int s_ttWordId = 0x1; + static const uint32_t s_ttDataMask = 0xff; + static const uint32_t s_pairPinMask = 0x7f; + static const uint32_t s_dataIdMask = 0x3; + // Hit counts bit positions and masks + static const int s_indicatorBit = 24; + static const int s_threshWordId = 0x2; + static const uint32_t s_threshMask = 0xffffff; + // G-Link/Neutral format + static const int s_pairsPerPin = 4; + static const int s_wordsPerPin = 8; + static const int s_ttBits = 8; + static const int s_errBits = 2; + static const int s_hitBits = 3; + static const int s_hitWords = 8; + static const int s_glinkPins = 20; + static const int s_glinkBitsPerSlice = 84; + + /// Return data WordID + int dataId(uint32_t word) const; + /// Return data for given channel and pin offset + int data(int slice, int channel, int offset) const; + /// Return error for given channel and pin offset + int error(int slice, int channel, int offset) const; + /// Return hit counts with given offset + unsigned int hits(int slice, int offset) const; + /// Return data index appropriate to format + int index(int slice) const; + /// Resize a data vector according to format + void resize(std::vector<uint32_t>& vec, int channels); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Trigger tower data + std::vector<uint32_t> m_ttData; + /// Hit counts + std::vector<uint32_t> m_hitData; + /// Channel present flags vector + std::vector<int> m_chanPresent; + /// Number of Trigger tower channels per module + int m_channels; + +}; + +inline int CpmSubBlockV1::dataId(const uint32_t word) const +{ + return (word >> s_dataIdBit) & s_dataIdMask; +} + +inline bool CpmSubBlockV1::anyTowerData(const int channel) const +{ + return m_chanPresent[channel]; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV2.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV2.cxx new file mode 100755 index 0000000000000000000000000000000000000000..44612bbf9ce0b70f3e6a0ec0953d3a663f237c29 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV2.cxx @@ -0,0 +1,382 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "CpmSubBlockV2.h" + +namespace LVL1BS { + +// Constant definitions + +const int CpmSubBlockV2::s_wordIdVal; + +const int CpmSubBlockV2::s_wordLength; + +const int CpmSubBlockV2::s_ttDataABit; +const int CpmSubBlockV2::s_ttDataBBit; +const int CpmSubBlockV2::s_parityABit; +const int CpmSubBlockV2::s_parityBBit; +const int CpmSubBlockV2::s_linkDownABit; +const int CpmSubBlockV2::s_linkDownBBit; +const int CpmSubBlockV2::s_pairBit; +const int CpmSubBlockV2::s_fpgaBit; +const int CpmSubBlockV2::s_dataIdBit; +const int CpmSubBlockV2::s_ttWordId; +const uint32_t CpmSubBlockV2::s_ttDataMask; +const uint32_t CpmSubBlockV2::s_pairPinMask; +const uint32_t CpmSubBlockV2::s_dataIdMask; + +const int CpmSubBlockV2::s_pairsPerPin; +const int CpmSubBlockV2::s_wordsPerPin; +const int CpmSubBlockV2::s_ttBits; +const int CpmSubBlockV2::s_errBits; +const int CpmSubBlockV2::s_bcnBits; +const int CpmSubBlockV2::s_bcnPin; +const int CpmSubBlockV2::s_glinkPins; +const int CpmSubBlockV2::s_glinkBitsPerSlice; + + +CpmSubBlockV2::CpmSubBlockV2() : m_channels(80) +{ + m_chanPresent.assign(m_channels, 0); +} + +CpmSubBlockV2::~CpmSubBlockV2() +{ +} + +// Clear all data + +void CpmSubBlockV2::clear() +{ + L1CaloSubBlock::clear(); + m_ttData.clear(); + m_chanPresent.assign(m_channels, 0); +} + +// Store CPM header + +void CpmSubBlockV2::setCpmHeader(const int version, const int format, + const int slice, const int crate, + const int module, const int timeslices) +{ + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, timeslices); +} + +// Store trigger tower data + +void CpmSubBlockV2::fillTowerData(const int slice, const int channel, + const int em, const int had, + const int emErr, const int hadErr) +{ + if (channel < m_channels && (em || emErr || had || hadErr)) { + resize(m_ttData, m_channels); + int dat = em; + int err = emErr; + for (int pinOffset = 0; pinOffset < 2; ++pinOffset) { + if (dat || err) { + const int pin = 2 * (channel/s_wordsPerPin) + pinOffset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + word |= (dat & s_ttDataMask) << s_ttDataABit; + word |= (err & 0x1) << s_parityABit; + word |= ((err >> 1) & 0x1) << s_linkDownABit; + } else { + word |= (dat & s_ttDataMask) << s_ttDataBBit; + word |= (err & 0x1) << s_parityBBit; + word |= ((err >> 1) & 0x1) << s_linkDownBBit; + } + word |= pair << s_pairBit; + word |= pin << s_fpgaBit; + word |= s_ttWordId << s_dataIdBit; + m_ttData[ix] = word; + } + dat = had; + err = hadErr; + } + m_chanPresent[channel] = 1; + } +} + +// Return Em data for given channel + +int CpmSubBlockV2::emData(const int slice, const int channel) const +{ + return data(slice, channel, 0); +} + +// Return Had data for given channel + +int CpmSubBlockV2::hadData(const int slice, const int channel) const +{ + return data(slice, channel, 1); +} + +// Return Em error for given channel + +int CpmSubBlockV2::emError(const int slice, const int channel) const +{ + return error(slice, channel, 0); +} + +// Return Had error for given channel + +int CpmSubBlockV2::hadError(const int slice, const int channel) const +{ + return error(slice, channel, 1); +} + +// Return number of timeslices + +int CpmSubBlockV2::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Packing/Unpacking routines + +bool CpmSubBlockV2::pack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool CpmSubBlockV2::unpack() +{ + bool rc = false; + switch (version()) { + case 2: // <<== CHECK + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data for given channel and pin offset + +int CpmSubBlockV2::data(const int slice, const int channel, + const int offset) const +{ + int dat = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_ttData.empty()) { + const int pin = 2 * (channel/s_wordsPerPin) + offset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + const uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + dat = (word >> s_ttDataABit) & s_ttDataMask; + } else dat = (word >> s_ttDataBBit) & s_ttDataMask; + } + return dat; +} + +// Return error for given channel and pin offset + +int CpmSubBlockV2::error(const int slice, const int channel, + const int offset) const +{ + int err = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_ttData.empty()) { + const int pin = 2 * (channel/s_wordsPerPin) + offset; + const int pair = (channel % s_wordsPerPin) / 2; + const int pos = pin * s_pairsPerPin + pair; + const int ix = index(slice) * m_channels + pos; + const uint32_t word = m_ttData[ix]; + if (channel % 2 == 0) { + err = (word >> s_parityABit) & 0x1; + err |= ((word >> s_linkDownABit) & 0x1) << 1; + } else { + err = (word >> s_parityBBit) & 0x1; + err |= ((word >> s_linkDownBBit) & 0x1) << 1; + } + } + return err; +} + +// Return data index appropriate to format + +int CpmSubBlockV2::index(const int slice) const +{ + return (format() == NEUTRAL) ? slice : 0; +} + +// Resize a data vector according to format + +void CpmSubBlockV2::resize(std::vector<uint32_t>& vec, int channels) +{ + if (vec.empty()) { + int size = channels; + if (format() == NEUTRAL) size *= timeslices(); + vec.resize(size); + } +} + +// Pack neutral data + +bool CpmSubBlockV2::packNeutral() +{ + resize(m_ttData, m_channels); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + // Trigger tower data + for (int pair = 0; pair < s_pairsPerPin; ++pair) { + for (int i = 0; i < 2; ++i) { + const int channel = s_wordsPerPin*(pin/2) + 2*pair + i; + if ((pin & 0x1)) { // Odd pins Had, even Em + packerNeutral(pin, hadData(slice, channel), s_ttBits); + packerNeutral(pin, hadError(slice, channel), s_errBits); + } else { + packerNeutral(pin, emData(slice, channel), s_ttBits); + packerNeutral(pin, emError(slice, channel), s_errBits); + } + } + } + // Padding and Bunch Crossing number + if (pin < s_bcnPin) { + packerNeutral(pin, 0, s_bcnBits); + } else { + packerNeutral(pin, bunchCrossing() >> (pin - s_bcnPin)*s_bcnBits, + s_bcnBits); + } + // G-Link parity + packerNeutralParity(pin); + } + } + return true; +} + +// Pack uncompressed data + +bool CpmSubBlockV2::packUncompressed() +{ + // Trigger tower data + std::vector<uint32_t>::const_iterator pos; + for (pos = m_ttData.begin(); pos != m_ttData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool CpmSubBlockV2::unpackNeutral() +{ + resize(m_ttData, m_channels); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + int bunchCrossing = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + // Trigger tower data + for (int pair = 0; pair < s_pairsPerPin; ++pair) { + for (int i = 0; i < 2; ++i) { + const int channel = s_wordsPerPin*(pin/2) + 2*pair + i; + int em = 0; + int had = 0; + int emErr = 0; + int hadErr = 0; + if ((pin & 0x1)) { // Odd pins Had, even Em + em = emData(slice, channel); + had = unpackerNeutral(pin, s_ttBits); + emErr = emError(slice, channel); + hadErr = unpackerNeutral(pin, s_errBits); + } else { + em = unpackerNeutral(pin, s_ttBits); + had = hadData(slice, channel); + emErr = unpackerNeutral(pin, s_errBits); + hadErr = hadError(slice, channel); + } + fillTowerData(slice, channel, em, had, emErr, hadErr); + } + } + // Padding and Bunch Crossing number + if (pin < s_bcnPin) { + unpackerNeutral(pin, s_bcnBits); + } else { + bunchCrossing |= unpackerNeutral(pin, s_bcnBits) + << (pin - s_bcnPin)*s_bcnBits; + } + // G-Link parity error + unpackerNeutralParityError(pin); + } + setBunchCrossing(bunchCrossing); + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool CpmSubBlockV2::unpackUncompressed() +{ + resize(m_ttData, m_channels); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataId(word); + bool err = false; + // Trigger tower data + if (id == s_ttWordId) { + const int ix = (word >> s_pairBit) & s_pairPinMask; + if (ix < m_channels && m_ttData[ix] == 0) { + m_ttData[ix] = word; + const int pin = ix/4; + const int pair = ix%4; + const int channel = s_wordsPerPin*(pin/2) + 2*pair; + m_chanPresent[channel] = 1; + m_chanPresent[channel+1] = 1; + } else err = true; + } else err = true; + if (err) { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV2.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV2.h new file mode 100755 index 0000000000000000000000000000000000000000..c899117724ec32e49666d6c4d259df6ede854edb --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/CpmSubBlockV2.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMSUBBLOCKV2_H +#define TRIGT1CALOBYTESTREAM_CPMSUBBLOCKV2_H + +#include <stdint.h> +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for CPM data post LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx <<== CHECK + * + * @author Peter Faulkner + */ + +class CpmSubBlockV2 : public L1CaloSubBlock { + + public: + CpmSubBlockV2(); + ~CpmSubBlockV2(); + + /// Clear all data + void clear(); + + /// Store CPM header + void setCpmHeader(int version, int format, int slice, int crate, + int module, int timeslices); + /// Store trigger tower data + void fillTowerData(int slice, int channel, int em, int had, + int emErr, int hadErr); + + /// Return Em data for given channel + int emData(int slice, int channel) const; + /// Return Had data for given channel + int hadData(int slice, int channel) const; + /// Return Em error for given channel + int emError(int slice, int channel) const; + /// Return Had error for given channel + int hadError(int slice, int channel) const; + /// Return number of timeslices + int timeslices() const; + /// Return true if there is tower data for given channel + bool anyTowerData(int channel) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// CPM header word ID + static const int s_wordIdVal = 0xc; + /// Data word length + static const int s_wordLength = 32; + // Trigger tower data word bit positions and masks + static const int s_ttDataABit = 0; + static const int s_ttDataBBit = 9; + static const int s_parityABit = 8; + static const int s_parityBBit = 17; + static const int s_linkDownABit = 19; + static const int s_linkDownBBit = 20; + static const int s_pairBit = 21; + static const int s_fpgaBit = 23; + static const int s_dataIdBit = 30; + static const int s_ttWordId = 0x1; + static const uint32_t s_ttDataMask = 0xff; + static const uint32_t s_pairPinMask = 0x7f; + static const uint32_t s_dataIdMask = 0x3; + // G-Link/Neutral format + static const int s_pairsPerPin = 4; + static const int s_wordsPerPin = 8; + static const int s_ttBits = 8; + static const int s_errBits = 2; + static const int s_bcnBits = 3; + static const int s_bcnPin = 16; + static const int s_glinkPins = 20; + static const int s_glinkBitsPerSlice = 84; + + /// Return data WordID + int dataId(uint32_t word) const; + /// Return data for given channel and pin offset + int data(int slice, int channel, int offset) const; + /// Return error for given channel and pin offset + int error(int slice, int channel, int offset) const; + /// Return data index appropriate to format + int index(int slice) const; + /// Resize a data vector according to format + void resize(std::vector<uint32_t>& vec, int channels); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Trigger tower data + std::vector<uint32_t> m_ttData; + /// Channel present flags vector + std::vector<int> m_chanPresent; + /// Number of Trigger tower channels per module + int m_channels; + +}; + +inline int CpmSubBlockV2::dataId(const uint32_t word) const +{ + return (word >> s_dataIdBit) & s_dataIdMask; +} + +inline bool CpmSubBlockV2::anyTowerData(const int channel) const +{ + return m_chanPresent[channel]; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/IPpmByteStreamSubsetTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/IPpmByteStreamSubsetTool.h new file mode 100644 index 0000000000000000000000000000000000000000..595e10f43db522148c2f08c1a0591406a473c42e --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/IPpmByteStreamSubsetTool.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_IPPMBYTESTREAMSUBSETTOOL_H +#define TRIGT1CALOBYTESTREAM_IPPMBYTESTREAMSUBSETTOOL_H + +#include <vector> + +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/IInterface.h" + +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "DataModel/DataVector.h" + +namespace LVL1 { + class TriggerTower; +} + +namespace LVL1BS { + +static const InterfaceID IID_IPpmByteStreamSubsetTool("LVL1BS::IPpmByteStreamSubsetTool", 1, 0); + +class IPpmByteStreamSubsetTool : virtual public IAlgTool { + + public: + static const InterfaceID& interfaceID(); + + virtual StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::TriggerTower>* ttCollection, + const std::vector<unsigned int>& chanIds) = 0; + virtual void eventNumber(const unsigned int eN ) = 0; + +}; + +inline const InterfaceID& IPpmByteStreamSubsetTool::interfaceID() +{ + return IID_IPpmByteStreamSubsetTool; +} + +} // end of namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/ITriggerTowerSelectionTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/ITriggerTowerSelectionTool.h new file mode 100644 index 0000000000000000000000000000000000000000..aae45e46d687b5048eeb60d97e5d2283bee78e29 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/ITriggerTowerSelectionTool.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_ITRIGGERTOWERSELECTIONTOOL_H +#define TRIGT1CALOBYTESTREAM_ITRIGGERTOWERSELECTIONTOOL_H + +#include <vector> + +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/IInterface.h" + + +namespace LVL1BS { + +static const InterfaceID IID_ITriggerTowerSelectionTool("LVL1BS::ITriggerTowerSelectionTool", 1, 0); + +class ITriggerTowerSelectionTool : virtual public IAlgTool { + + public: + static const InterfaceID& interfaceID(); + + virtual void channelIDs(double etaMin, double etaMax, + double phiMin, double phiMax, + std::vector<unsigned int>& chanIds) = 0; + virtual void robIDs(const std::vector<unsigned int>& chanIds, + std::vector<unsigned int>& robs) = 0; + +}; + +inline const InterfaceID& ITriggerTowerSelectionTool::interfaceID() +{ + return IID_ITriggerTowerSelectionTool; +} + +} // end of namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemJetElement.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemJetElement.cxx new file mode 100755 index 0000000000000000000000000000000000000000..d110fbeb6b84c5f8eb6f0cb7fa6e5ce1952cfb97 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemJetElement.cxx @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JemJetElement.h" + +namespace LVL1BS { + +// Constant definitions + +const int JemJetElement::s_emDataBit; +const int JemJetElement::s_emParityBit; +const int JemJetElement::s_hadDataBit; +const int JemJetElement::s_hadParityBit; +const int JemJetElement::s_linkErrorBit; +const int JemJetElement::s_pairBit; +const int JemJetElement::s_pinBit; +const int JemJetElement::s_wordIdBit; +const int JemJetElement::s_jeWordId; +const int JemJetElement::s_pairsPerPin; +const int JemJetElement::s_pairOffset; +const uint32_t JemJetElement::s_emDataMask; +const uint32_t JemJetElement::s_emParityMask; +const uint32_t JemJetElement::s_hadDataMask; +const uint32_t JemJetElement::s_hadParityMask; +const uint32_t JemJetElement::s_linkErrorMask; +const uint32_t JemJetElement::s_pairMask; +const uint32_t JemJetElement::s_pinMask; +const uint32_t JemJetElement::s_wordIdMask; + +JemJetElement::JemJetElement(uint32_t word) : m_data(word) +{ +} + +JemJetElement::JemJetElement(const int chan, const int emDat, const int hadDat, + const int emParErr, const int hadParErr, + const int linkErr) +{ + uint32_t word = 0; + word |= (emDat & s_emDataMask) << s_emDataBit; + word |= (emParErr & s_emParityMask) << s_emParityBit; + word |= (hadDat & s_hadDataMask) << s_hadDataBit; + word |= (hadParErr & s_hadParityMask) << s_hadParityBit; + word |= (linkErr & s_linkErrorMask) << s_linkErrorBit; + if (word) { + word |= ((chan % s_pairsPerPin + s_pairOffset) & s_pairMask) << s_pairBit; + word |= ((chan / s_pairsPerPin) & s_pinMask) << s_pinBit; + word |= (s_jeWordId & s_wordIdMask) << s_wordIdBit; + } + m_data = word; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemJetElement.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemJetElement.h new file mode 100755 index 0000000000000000000000000000000000000000..a36385406e222f5ca5a31c0b2420c781d5d6e555 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemJetElement.h @@ -0,0 +1,118 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMJETELEMENT_H +#define TRIGT1CALOBYTESTREAM_JEMJETELEMENT_H + +#include <stdint.h> + +namespace LVL1BS { + +/** JEM jet element dataword class. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class JemJetElement { + + public: + JemJetElement(uint32_t word); + JemJetElement(int chan, int emDat, int hadDat, + int emParErr, int hadParErr, int linkErr); + + // Return jet element data + int channel() const; + int emData() const; + int hadData() const; + int emParity() const; + int hadParity() const; + int linkError() const; + int pair() const; + int pin() const; + int wordId() const; + uint32_t data() const; + + private: + // Jet Element data word bit positions and masks + static const int s_emDataBit = 0; + static const int s_emParityBit = 9; + static const int s_hadDataBit = 10; + static const int s_hadParityBit = 19; + static const int s_linkErrorBit = 20; + static const int s_pairBit = 23; + static const int s_pinBit = 25; + static const int s_wordIdBit = 30; + static const int s_jeWordId = 0x1; + static const int s_pairsPerPin = 3; + static const int s_pairOffset = 1; + static const uint32_t s_emDataMask = 0x1ff; + static const uint32_t s_emParityMask = 0x1; + static const uint32_t s_hadDataMask = 0x1ff; + static const uint32_t s_hadParityMask = 0x1; + static const uint32_t s_linkErrorMask = 0x3; + static const uint32_t s_pairMask = 0x3; + static const uint32_t s_pinMask = 0x1f; + static const uint32_t s_wordIdMask = 0x3; + + /// Jet element data + uint32_t m_data; + +}; + +inline int JemJetElement::channel() const +{ + return s_pairsPerPin * pin() + pair() - s_pairOffset; +} + +inline int JemJetElement::emData() const +{ + return (m_data >> s_emDataBit) & s_emDataMask; +} + +inline int JemJetElement::hadData() const +{ + return (m_data >> s_hadDataBit) & s_hadDataMask; +} + +inline int JemJetElement::emParity() const +{ + return (m_data >> s_emParityBit) & s_emParityMask; +} + +inline int JemJetElement::hadParity() const +{ + return (m_data >> s_hadParityBit) & s_hadParityMask; +} + +inline int JemJetElement::linkError() const +{ + return (m_data >> s_linkErrorBit) & s_linkErrorMask; +} + +inline int JemJetElement::pair() const +{ + return (m_data >> s_pairBit) & s_pairMask; +} + +inline int JemJetElement::pin() const +{ + return (m_data >> s_pinBit) & s_pinMask; +} + +inline int JemJetElement::wordId() const +{ + return (m_data >> s_wordIdBit) & s_wordIdMask; +} + +inline uint32_t JemJetElement::data() const +{ + return m_data; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..a26be0c6d712930fa578a79b2473d138f68cb7da --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlock.cxx @@ -0,0 +1,187 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TrigT1CaloEvent/JEMRoI.h" + +#include "JemRoiSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int JemRoiSubBlock::s_wordIdVal; + +const int JemRoiSubBlock::s_frames; +const int JemRoiSubBlock::s_framesPerPin; +const int JemRoiSubBlock::s_bunchCrossingPin; +const int JemRoiSubBlock::s_hitsBits; +const int JemRoiSubBlock::s_locationBits; +const int JemRoiSubBlock::s_saturationBits; +const int JemRoiSubBlock::s_bunchCrossingBits; +const int JemRoiSubBlock::s_paddingBits; + + +JemRoiSubBlock::JemRoiSubBlock() +{ +} + +JemRoiSubBlock::~JemRoiSubBlock() +{ +} + +// Clear all data + +void JemRoiSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_roiData.clear(); +} + +// Store header + +void JemRoiSubBlock::setRoiHeader(const int version, const int crate, + const int module) +{ + setHeader(s_wordIdVal, version, NEUTRAL, 0, crate, module, 0, 1); +} + +// Store RoI + +void JemRoiSubBlock::fillRoi(const LVL1::JEMRoI roi) +{ + const LVL1::JEMRoI roiTemp(crate(), module(), 0, 0, 0, 0, 0); + if (roi.crate() == roiTemp.crate() && roi.jem() == roiTemp.jem()) { + m_roiData.resize(2*s_frames); + const int pos = roi.frame() + roi.forward()*s_frames; + m_roiData[pos] = roi; + } +} + +// Return RoI for given frame and forward + +LVL1::JEMRoI JemRoiSubBlock::roi(const int frame, const int forward) const +{ + const int pos = frame + forward*s_frames; + if (pos >= 0 && pos < 2*s_frames && !m_roiData.empty()) { + return m_roiData[pos]; + } else return LVL1::JEMRoI(0); +} + +// Packing/Unpacking routines + +bool JemRoiSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool JemRoiSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Pack neutral data + +bool JemRoiSubBlock::packNeutral() +{ + m_roiData.resize(2*s_frames); + int maxPin = 0; + // RoI data + for (int pos = 0; pos < 2*s_frames; ++pos) { + const LVL1::JEMRoI& roi(m_roiData[pos]); + int pin = pos/s_framesPerPin; + if (pin >= s_bunchCrossingPin) ++pin; // forward rois + packerNeutral(pin, roi.hits(), s_hitsBits); + packerNeutral(pin, roi.error(), s_saturationBits); + packerNeutral(pin, roi.location(), s_locationBits); + maxPin = pin; + } + // Bunch Crossing number + packerNeutral(s_bunchCrossingPin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(s_bunchCrossingPin, 0, s_paddingBits); + // G-Link parity + for (int pin = 0; pin <= maxPin; ++pin) packerNeutralParity(pin); + + return true; +} + +// Unpack neutral data + +bool JemRoiSubBlock::unpackNeutral() +{ + m_roiData.resize(2*s_frames); + int maxPin = 0; + int forward = 0; + int parity = 0; + // RoI data + for (int pos = 0; pos < 2*s_frames; ++pos) { + int pin = pos/s_framesPerPin; + if (pin >= s_bunchCrossingPin) { + ++pin; + forward = 1; + } + const int hits = unpackerNeutral(pin, s_hitsBits); + const int sat = unpackerNeutral(pin, s_saturationBits); + const int loc = unpackerNeutral(pin, s_locationBits); + const int err = (parity << 1) | sat; + m_roiData[pos] = LVL1::JEMRoI(crate(), module(), pos%s_frames, loc, + forward, hits, err); + maxPin = pin; + } + // Bunch Crossing number + setBunchCrossing(unpackerNeutral(s_bunchCrossingPin, s_bunchCrossingBits)); + unpackerNeutral(s_bunchCrossingPin, s_paddingBits); + // G-Link parity + parity = 1; + for (int pin = 0; pin <= maxPin; ++pin) { + const bool error = unpackerNeutralParityError(pin); + if (pin == s_bunchCrossingPin) continue; + if (error) { + for (int frame = 0; frame < s_framesPerPin; ++frame) { + int pos = pin * s_framesPerPin + frame; + if (pin > s_bunchCrossingPin) pos -= s_framesPerPin; + const LVL1::JEMRoI roi = m_roiData[pos]; + const int err = (parity << 1) | roi.error(); + m_roiData[pos] = LVL1::JEMRoI(roi.crate(), roi.jem(), roi.frame(), + roi.location(), roi.forward(), + roi.hits(), err); + } + } + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..aa85ae733e99e0f9c4d3555070a1d9b09b205cd4 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlock.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMROISUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_JEMROISUBBLOCK_H + +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1 { + class JEMRoI; +} + +namespace LVL1BS { + +/** Sub-Block class for JEM RoI data (neutral format). + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.09h + * + * @author Peter Faulkner + */ + +class JemRoiSubBlock : public L1CaloSubBlock { + + public: + JemRoiSubBlock(); + ~JemRoiSubBlock(); + + /// Clear all data + void clear(); + + /// Store header + void setRoiHeader(int version, int crate, int module); + /// Store RoI + void fillRoi(LVL1::JEMRoI roi); + + /// Return RoI for given frame and forward + LVL1::JEMRoI roi(int frame, int forward) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Header word ID + static const int s_wordIdVal = 0xc; + // G-Link/Neutral format + static const int s_frames = 8; + static const int s_framesPerPin = 4; + static const int s_bunchCrossingPin = 2; + static const int s_hitsBits = 8; + static const int s_locationBits = 2; + static const int s_saturationBits = 1; + static const int s_bunchCrossingBits = 12; + static const int s_paddingBits = 32; + + /// Pack neutral data + bool packNeutral(); + /// Unpack neutral data + bool unpackNeutral(); + + /// RoIs + std::vector<LVL1::JEMRoI> m_roiData; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV1.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV1.cxx new file mode 100755 index 0000000000000000000000000000000000000000..1e79947681f8625a4efc7bba734aeb10dc84f4fb --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV1.cxx @@ -0,0 +1,187 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TrigT1CaloEvent/JEMRoI.h" + +#include "JemRoiSubBlockV1.h" + +namespace LVL1BS { + +// Constant definitions + +const int JemRoiSubBlockV1::s_wordIdVal; + +const int JemRoiSubBlockV1::s_frames; +const int JemRoiSubBlockV1::s_framesPerPin; +const int JemRoiSubBlockV1::s_bunchCrossingPin; +const int JemRoiSubBlockV1::s_hitsBits; +const int JemRoiSubBlockV1::s_locationBits; +const int JemRoiSubBlockV1::s_saturationBits; +const int JemRoiSubBlockV1::s_bunchCrossingBits; +const int JemRoiSubBlockV1::s_paddingBits; + + +JemRoiSubBlockV1::JemRoiSubBlockV1() +{ +} + +JemRoiSubBlockV1::~JemRoiSubBlockV1() +{ +} + +// Clear all data + +void JemRoiSubBlockV1::clear() +{ + L1CaloSubBlock::clear(); + m_roiData.clear(); +} + +// Store header + +void JemRoiSubBlockV1::setRoiHeader(const int version, const int crate, + const int module) +{ + setHeader(s_wordIdVal, version, NEUTRAL, 0, crate, module, 0, 1); +} + +// Store RoI + +void JemRoiSubBlockV1::fillRoi(const LVL1::JEMRoI roi) +{ + const LVL1::JEMRoI roiTemp(crate(), module(), 0, 0, 0, 0, 0); + if (roi.crate() == roiTemp.crate() && roi.jem() == roiTemp.jem()) { + m_roiData.resize(2*s_frames); + const int pos = roi.frame() + roi.forward()*s_frames; + m_roiData[pos] = roi; + } +} + +// Return RoI for given frame and forward + +LVL1::JEMRoI JemRoiSubBlockV1::roi(const int frame, const int forward) const +{ + const int pos = frame + forward*s_frames; + if (pos >= 0 && pos < 2*s_frames && !m_roiData.empty()) { + return m_roiData[pos]; + } else return LVL1::JEMRoI(0); +} + +// Packing/Unpacking routines + +bool JemRoiSubBlockV1::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool JemRoiSubBlockV1::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Pack neutral data + +bool JemRoiSubBlockV1::packNeutral() +{ + m_roiData.resize(2*s_frames); + int maxPin = 0; + // RoI data + for (int pos = 0; pos < 2*s_frames; ++pos) { + const LVL1::JEMRoI& roi(m_roiData[pos]); + int pin = pos/s_framesPerPin; + if (pin >= s_bunchCrossingPin) ++pin; // forward rois + packerNeutral(pin, roi.hits(), s_hitsBits); + packerNeutral(pin, roi.error(), s_saturationBits); + packerNeutral(pin, roi.location(), s_locationBits); + maxPin = pin; + } + // Bunch Crossing number + packerNeutral(s_bunchCrossingPin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(s_bunchCrossingPin, 0, s_paddingBits); + // G-Link parity + for (int pin = 0; pin <= maxPin; ++pin) packerNeutralParity(pin); + + return true; +} + +// Unpack neutral data + +bool JemRoiSubBlockV1::unpackNeutral() +{ + m_roiData.resize(2*s_frames); + int maxPin = 0; + int forward = 0; + int parity = 0; + // RoI data + for (int pos = 0; pos < 2*s_frames; ++pos) { + int pin = pos/s_framesPerPin; + if (pin >= s_bunchCrossingPin) { + ++pin; + forward = 1; + } + const int hits = unpackerNeutral(pin, s_hitsBits); + const int sat = unpackerNeutral(pin, s_saturationBits); + const int loc = unpackerNeutral(pin, s_locationBits); + const int err = (parity << 1) | sat; + m_roiData[pos] = LVL1::JEMRoI(crate(), module(), pos%s_frames, loc, + forward, hits, err); + maxPin = pin; + } + // Bunch Crossing number + setBunchCrossing(unpackerNeutral(s_bunchCrossingPin, s_bunchCrossingBits)); + unpackerNeutral(s_bunchCrossingPin, s_paddingBits); + // G-Link parity + parity = 1; + for (int pin = 0; pin <= maxPin; ++pin) { + const bool error = unpackerNeutralParityError(pin); + if (pin == s_bunchCrossingPin) continue; + if (error) { + for (int frame = 0; frame < s_framesPerPin; ++frame) { + int pos = pin * s_framesPerPin + frame; + if (pin > s_bunchCrossingPin) pos -= s_framesPerPin; + const LVL1::JEMRoI roi = m_roiData[pos]; + const int err = (parity << 1) | roi.error(); + m_roiData[pos] = LVL1::JEMRoI(roi.crate(), roi.jem(), roi.frame(), + roi.location(), roi.forward(), + roi.hits(), err); + } + } + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV1.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV1.h new file mode 100755 index 0000000000000000000000000000000000000000..c57701d1b31c90ff94fa3f9fb015c773389a0641 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV1.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMROISUBBLOCKV1_H +#define TRIGT1CALOBYTESTREAM_JEMROISUBBLOCKV1_H + +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1 { + class JEMRoI; +} + +namespace LVL1BS { + +/** Sub-Block class for JEM RoI data (neutral format) pre-LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.09h + * + * @author Peter Faulkner + */ + +class JemRoiSubBlockV1 : public L1CaloSubBlock { + + public: + JemRoiSubBlockV1(); + ~JemRoiSubBlockV1(); + + /// Clear all data + void clear(); + + /// Store header + void setRoiHeader(int version, int crate, int module); + /// Store RoI + void fillRoi(LVL1::JEMRoI roi); + + /// Return RoI for given frame and forward + LVL1::JEMRoI roi(int frame, int forward) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Header word ID + static const int s_wordIdVal = 0xc; + // G-Link/Neutral format + static const int s_frames = 8; + static const int s_framesPerPin = 4; + static const int s_bunchCrossingPin = 2; + static const int s_hitsBits = 8; + static const int s_locationBits = 2; + static const int s_saturationBits = 1; + static const int s_bunchCrossingBits = 12; + static const int s_paddingBits = 32; + + /// Pack neutral data + bool packNeutral(); + /// Unpack neutral data + bool unpackNeutral(); + + /// RoIs + std::vector<LVL1::JEMRoI> m_roiData; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV2.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV2.cxx new file mode 100755 index 0000000000000000000000000000000000000000..6dcca955eb03dd9b625def1809001b17927c3122 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV2.cxx @@ -0,0 +1,167 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TrigT1CaloEvent/JEMTobRoI.h" + +#include "JemRoiSubBlockV2.h" + +namespace LVL1BS { + +// Constant definitions + +const int JemRoiSubBlockV2::s_wordIdVal; + +const int JemRoiSubBlockV2::s_frames; +const int JemRoiSubBlockV2::s_framesPerPin; +const int JemRoiSubBlockV2::s_bunchCrossingPin; +const int JemRoiSubBlockV2::s_energySmallBits; +const int JemRoiSubBlockV2::s_energyLargeBits; +const int JemRoiSubBlockV2::s_locationBits; +const int JemRoiSubBlockV2::s_bunchCrossingBits; +const int JemRoiSubBlockV2::s_paddingBits; + + +JemRoiSubBlockV2::JemRoiSubBlockV2() +{ +} + +JemRoiSubBlockV2::~JemRoiSubBlockV2() +{ +} + +// Clear all data + +void JemRoiSubBlockV2::clear() +{ + L1CaloSubBlock::clear(); + m_roiData.clear(); +} + +// Store header + +void JemRoiSubBlockV2::setRoiHeader(const int version, const int crate, + const int module) +{ + setHeader(s_wordIdVal, version, NEUTRAL, 0, crate, module, 0, 1); +} + +// Store RoI + +void JemRoiSubBlockV2::fillRoi(const LVL1::JEMTobRoI roi) +{ + const LVL1::JEMTobRoI roiTemp(crate(), module(), 0, 0, 0, 0); + if (roi.crate() == roiTemp.crate() && roi.jem() == roiTemp.jem()) { + m_roiData.resize(s_frames); + const int pos = roi.frame(); + m_roiData[pos] = roi; + } +} + +// Return RoI for given frame + +LVL1::JEMTobRoI JemRoiSubBlockV2::roi(const int frame) const +{ + if (frame >= 0 && frame < s_frames && !m_roiData.empty()) { + return m_roiData[frame]; + } else return LVL1::JEMTobRoI(0); +} + +// Packing/Unpacking routines + +bool JemRoiSubBlockV2::pack() +{ + bool rc = false; + switch (version()) { + case 2: //<< CHECK + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool JemRoiSubBlockV2::unpack() +{ + bool rc = false; + switch (version()) { + case 2: //<< CHECK + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Pack neutral data + +bool JemRoiSubBlockV2::packNeutral() +{ + m_roiData.resize(s_frames); + int maxPin = 0; + // RoI data + for (int frame = 0; frame < s_frames; ++frame) { + const LVL1::JEMTobRoI& roi(m_roiData[frame]); + const int pin1 = frame/s_framesPerPin; + const int pin2 = s_bunchCrossingPin + pin1 + 1; + packerNeutral(pin1, roi.energyLarge(), s_energyLargeBits); + packerNeutral(pin1, 0, 1); + packerNeutral(pin2, roi.energySmall(), s_energySmallBits); + packerNeutral(pin2, roi.location(), s_locationBits); + maxPin = pin2; + } + // Bunch Crossing number + packerNeutral(s_bunchCrossingPin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(s_bunchCrossingPin, 0, s_paddingBits); + // G-Link parity + for (int pin = 0; pin <= maxPin; ++pin) packerNeutralParity(pin); + + return true; +} + +// Unpack neutral data + +bool JemRoiSubBlockV2::unpackNeutral() +{ + m_roiData.resize(s_frames); + int maxPin = 0; + // RoI data + for (int frame = 0; frame < s_frames; ++frame) { + const int pin1 = frame/s_framesPerPin; + const int pin2 = s_bunchCrossingPin + pin1 + 1; + const int enLarge = unpackerNeutral(pin1, s_energyLargeBits); + unpackerNeutral(pin1, 1); + const int enSmall = unpackerNeutral(pin2, s_energySmallBits); + const int loc = unpackerNeutral(pin2, s_locationBits); + m_roiData[frame] = LVL1::JEMTobRoI(crate(), module(), + frame, loc, enLarge, enSmall); + maxPin = pin2; + } + // Bunch Crossing number + setBunchCrossing(unpackerNeutral(s_bunchCrossingPin, s_bunchCrossingBits)); + unpackerNeutral(s_bunchCrossingPin, s_paddingBits); + // G-Link parity + for (int pin = 0; pin <= maxPin; ++pin) unpackerNeutralParityError(pin); + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV2.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV2.h new file mode 100755 index 0000000000000000000000000000000000000000..16aabd0afcd4f8bd1c036a44fc1fa37f55044fe3 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemRoiSubBlockV2.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMROISUBBLOCKV2_H +#define TRIGT1CALOBYTESTREAM_JEMROISUBBLOCKV2_H + +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1 { + class JEMTobRoI; +} + +namespace LVL1BS { + +/** Sub-Block class for JEM RoI data (neutral format) post-LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx //<< CHECK + * + * @author Peter Faulkner + */ + +class JemRoiSubBlockV2 : public L1CaloSubBlock { + + public: + JemRoiSubBlockV2(); + ~JemRoiSubBlockV2(); + + /// Clear all data + void clear(); + + /// Store header + void setRoiHeader(int version, int crate, int module); + /// Store RoI + void fillRoi(LVL1::JEMTobRoI roi); + + /// Return RoI for given frame + LVL1::JEMTobRoI roi(int frame) const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// Header word ID + static const int s_wordIdVal = 0xc; + // G-Link/Neutral format + static const int s_frames = 8; + static const int s_framesPerPin = 4; + static const int s_bunchCrossingPin = 2; + static const int s_energySmallBits = 9; + static const int s_energyLargeBits = 10; + static const int s_locationBits = 2; + static const int s_bunchCrossingBits = 12; + static const int s_paddingBits = 32; + + /// Pack neutral data + bool packNeutral(); + /// Unpack neutral data + bool unpackNeutral(); + + /// RoIs + std::vector<LVL1::JEMTobRoI> m_roiData; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..40f5b945778998d48939667fdd3d156ff0a48b2a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlock.cxx @@ -0,0 +1,417 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JemJetElement.h" +#include "JemSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const int JemSubBlock::s_wordIdVal; + +const int JemSubBlock::s_wordLength; + +const int JemSubBlock::s_dataIdBit; +const int JemSubBlock::s_jeWordId; +const uint32_t JemSubBlock::s_dataIdMask; + +const int JemSubBlock::s_threshBit; +const int JemSubBlock::s_sourceIdBit; +const int JemSubBlock::s_jetIndicatorBit; +const int JemSubBlock::s_jetIndicator; +const int JemSubBlock::s_mainThreshId; +const int JemSubBlock::s_mainFwdThreshId; +const int JemSubBlock::s_threshWordId; +const uint32_t JemSubBlock::s_threshMask; +const uint32_t JemSubBlock::s_sourceIdMask; + +const int JemSubBlock::s_exBit; +const int JemSubBlock::s_eyBit; +const int JemSubBlock::s_etBit; +const int JemSubBlock::s_sumIndicatorBit; +const int JemSubBlock::s_sumIndicator; +const int JemSubBlock::s_subsumId; +const uint32_t JemSubBlock::s_exMask; +const uint32_t JemSubBlock::s_eyMask; +const uint32_t JemSubBlock::s_etMask; + +const int JemSubBlock::s_pairsPerPin; +const int JemSubBlock::s_jetElementBits; +const int JemSubBlock::s_jePaddingBits; +const int JemSubBlock::s_jetHitsBits; +const int JemSubBlock::s_energyBits; +const int JemSubBlock::s_bunchCrossingBits; +const int JemSubBlock::s_hitPaddingBits; +const int JemSubBlock::s_glinkBitsPerSlice; + + +JemSubBlock::JemSubBlock() : m_channels(44) +{ +} + +JemSubBlock::~JemSubBlock() +{ +} + +// Clear all data + +void JemSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_jeData.clear(); + m_jetHits.clear(); + m_energySubsums.clear(); +} + +// Store JEM header + +void JemSubBlock::setJemHeader(const int version, const int format, + const int slice, const int crate, + const int module, const int timeslices) +{ + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, timeslices); +} + +// Store jet element data + +void JemSubBlock::fillJetElement(const int slice, const JemJetElement& jetEle) +{ + if (jetEle.data()) { + const int channel = jetEle.channel(); + if (channel < m_channels) { + resize(m_jeData, m_channels); + m_jeData[index(slice)*m_channels + channel] = jetEle.data(); + } + } +} + +// Store jet hit counts + +void JemSubBlock::setJetHits(const int slice, const unsigned int hits) +{ + if (hits) { + const int jem = module(); + const int sourceId = (jem == 0 || jem == 7 || jem == 8 || jem == 15) + ? s_mainFwdThreshId : s_mainThreshId; + uint32_t word = 0; + word |= (hits & s_threshMask) << s_threshBit; + word |= s_jetIndicator << s_jetIndicatorBit; + word |= (sourceId & s_sourceIdMask) << s_sourceIdBit; + word |= s_threshWordId << s_dataIdBit; + resize(m_jetHits); + m_jetHits[index(slice)] = word; + } +} + +// Store energy subsum data + +void JemSubBlock::setEnergySubsums(const int slice, const unsigned int ex, + const unsigned int ey, const unsigned int et) +{ + uint32_t word = 0; + word |= (ex & s_exMask) << s_exBit; + word |= (ey & s_eyMask) << s_eyBit; + word |= (et & s_etMask) << s_etBit; + if (word) { + word |= s_sumIndicator << s_sumIndicatorBit; + word |= s_subsumId << s_sourceIdBit; + word |= s_threshWordId << s_dataIdBit; + resize(m_energySubsums); + m_energySubsums[index(slice)] = word; + } +} + +// Return jet element for given channel + +JemJetElement JemSubBlock::jetElement(const int slice, const int channel) const +{ + uint32_t je = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_jeData.empty()) { + je = m_jeData[index(slice)*m_channels + channel]; + } + return JemJetElement(je); +} + +// Return jet hit counts + +unsigned int JemSubBlock::jetHits(const int slice) const +{ + unsigned int hits = 0; + if (slice >= 0 && slice < timeslices() && !m_jetHits.empty()) { + hits = (m_jetHits[index(slice)] >> s_threshBit) & s_threshMask; + } + return hits; +} + +// Return energy subsum Ex + +unsigned int JemSubBlock::ex(const int slice) const +{ + unsigned int ex = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + ex = (m_energySubsums[index(slice)] >> s_exBit) & s_exMask; + } + return ex; +} + +// Return energy subsum Ey + +unsigned int JemSubBlock::ey(const int slice) const +{ + unsigned int ey = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + ey = (m_energySubsums[index(slice)] >> s_eyBit) & s_eyMask; + } + return ey; +} + +// Return energy subsum Et + +unsigned int JemSubBlock::et(const int slice) const +{ + unsigned int et = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + et = (m_energySubsums[index(slice)] >> s_etBit) & s_etMask; + } + return et; +} + +// Return number of timeslices + +int JemSubBlock::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Packing/Unpacking routines + +bool JemSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool JemSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data index appropriate to format + +int JemSubBlock::index(const int slice) const +{ + return (format() == NEUTRAL) ? slice : 0; +} + +// Resize a data vector according to format + +void JemSubBlock::resize(std::vector<uint32_t>& vec, const int channels) +{ + if (vec.empty()) { + int size = channels; + if (format() == NEUTRAL) size *= timeslices(); + vec.resize(size); + } +} + +// Pack neutral data + +bool JemSubBlock::packNeutral() +{ + resize(m_jeData, m_channels); + resize(m_jetHits); + resize(m_energySubsums); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + // Jet element data + for (int channel = 0; channel < m_channels; ++channel) { + const int pin = channel / s_pairsPerPin; + const JemJetElement je = jetElement(slice, channel); + packerNeutral(pin, je.emData(), s_jetElementBits); + packerNeutral(pin, je.emParity(), 1); + packerNeutral(pin, je.linkError(), 1); + packerNeutral(pin, je.hadData(), s_jetElementBits); + packerNeutral(pin, je.hadParity(), 1); + packerNeutral(pin, (je.linkError() >> 1), 1); + } + // Pad out last jet element pin + int lastpin = (m_channels - 1) / s_pairsPerPin; + packerNeutral(lastpin, 0, s_jePaddingBits); + // Jet Hits and Energy Sums with parity bits + ++lastpin; + packerNeutral(lastpin, jetHits(slice), s_jetHitsBits); + packerNeutral(lastpin, parityBit(1, jetHits(slice), s_jetHitsBits), 1); + packerNeutral(lastpin, ex(slice), s_energyBits); + packerNeutral(lastpin, ey(slice), s_energyBits); + packerNeutral(lastpin, et(slice), s_energyBits); + int parity = parityBit(1, ex(slice), s_energyBits); + parity = parityBit(parity, ey(slice), s_energyBits); + parity = parityBit(parity, et(slice), s_energyBits); + packerNeutral(lastpin, parity, 1); + // Bunch Crossing number and padding + packerNeutral(lastpin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(lastpin, 0, s_hitPaddingBits); + // G-Link parity + for (int pin = 0; pin <= lastpin; ++pin) packerNeutralParity(pin); + } + return true; +} + +// Pack uncompressed data + +bool JemSubBlock::packUncompressed() +{ + // Jet element data + std::vector<uint32_t>::const_iterator pos; + for (pos = m_jeData.begin(); pos != m_jeData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + + // Hits and Subsum data + if ( !m_jetHits.empty() && m_jetHits[0]) packer(m_jetHits[0], s_wordLength); + if ( !m_energySubsums.empty() && m_energySubsums[0]) { + packer(m_energySubsums[0], s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool JemSubBlock::unpackNeutral() +{ + resize(m_jeData, m_channels); + resize(m_jetHits); + resize(m_energySubsums); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + // Jet element data + for (int channel = 0; channel < m_channels; ++channel) { + const int pin = channel / s_pairsPerPin; + const int emData = unpackerNeutral(pin, s_jetElementBits); + const int emParity = unpackerNeutral(pin, 1); + int linkError = unpackerNeutral(pin, 1); + const int hadData = unpackerNeutral(pin, s_jetElementBits); + const int hadParity = unpackerNeutral(pin, 1); + linkError |= unpackerNeutral(pin, 1) << 1; + const JemJetElement je(channel, emData, hadData, emParity, + hadParity, linkError); + fillJetElement(slice, je); + } + // Padding from last jet element pin + int lastpin = (m_channels - 1) / s_pairsPerPin; + unpackerNeutral(lastpin, s_jePaddingBits); + // Jet Hits and Energy Sums + ++lastpin; + setJetHits(slice, unpackerNeutral(lastpin, s_jetHitsBits)); + unpackerNeutral(lastpin, 1); // parity bit + const unsigned int ex = unpackerNeutral(lastpin, s_energyBits); + const unsigned int ey = unpackerNeutral(lastpin, s_energyBits); + const unsigned int et = unpackerNeutral(lastpin, s_energyBits); + setEnergySubsums(slice, ex, ey, et); + unpackerNeutral(lastpin, 1); // parity bit + // Bunch Crossing number and padding + setBunchCrossing(unpackerNeutral(lastpin, s_bunchCrossingBits)); + unpackerNeutral(lastpin, s_hitPaddingBits); + // G-Link parity errors + for (int pin = 0; pin <= lastpin; ++pin) unpackerNeutralParityError(pin); + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool JemSubBlock::unpackUncompressed() +{ + resize(m_jeData, m_channels); + resize(m_jetHits); + resize(m_energySubsums); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataId(word); + bool err = false; + // Jet element data + if (id == s_jeWordId) { + const JemJetElement jetEle(word); + const int channel = jetEle.channel(); + if (channel < m_channels && m_jeData[channel] == 0) { + m_jeData[channel] = word; + } else err = true; + // Other data + } else { + switch (sourceId(word)) { + // Jet hit counts/thresholds + case s_mainThreshId: + case s_mainFwdThreshId: { + if (m_jetHits[0] == 0) m_jetHits[0] = word; + else err = true; + break; + } + // Energy subsums + case s_subsumId: { + if (m_energySubsums[0] == 0) m_energySubsums[0] = word; + else err = true; + break; + } + default: + err = true; + break; + } + } + if (err) { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..b70fa822d8897e15067bd0191d9a54fe61dbdd80 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlock.h @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_JEMSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +class JemJetElement; + +/** Sub-Block class for JEM data. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class JemSubBlock : public L1CaloSubBlock { + + public: + JemSubBlock(); + ~JemSubBlock(); + + /// Clear all data + void clear(); + + /// Store JEM header + void setJemHeader(int version, int format, int slice, int crate, + int module, int timeslices); + /// Store jet element data + void fillJetElement(int slice, const JemJetElement& jetEle); + /// Store jet hit counts + void setJetHits(int slice, unsigned int hits); + /// Store energy subsum data + void setEnergySubsums(int slice, unsigned int ex, + unsigned int ey, unsigned int et); + + /// Return jet element for given channel + JemJetElement jetElement(int slice, int channel) const; + /// Return jet hit counts + unsigned int jetHits(int slice) const; + /// Return energy subsum Ex + unsigned int ex(int slice) const; + /// Return energy subsum Ey + unsigned int ey(int slice) const; + /// Return energy subsum Et + unsigned int et(int slice) const; + /// Return number of timeslices + int timeslices() const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// JEM header word ID + static const int s_wordIdVal = 0xc; + /// Data word length + static const int s_wordLength = 32; + // Jet Element data word bit positions and masks + static const int s_dataIdBit = 30; + static const int s_jeWordId = 0x1; + static const uint32_t s_dataIdMask = 0x3; + // Jet hit counts bit positions and masks + static const int s_threshBit = 0; + static const int s_sourceIdBit = 25; + static const int s_jetIndicatorBit = 24; + static const int s_jetIndicator = 0x0; + static const int s_mainThreshId = 20; + static const int s_mainFwdThreshId = 21; + static const int s_threshWordId = 0x2; + static const uint32_t s_threshMask = 0xffffff; + static const uint32_t s_sourceIdMask = 0x1f; + // Energy subsum data bit positions and masks + static const int s_exBit = 0; + static const int s_eyBit = 8; + static const int s_etBit = 16; + static const int s_sumIndicatorBit = 24; + static const int s_sumIndicator = 0x1; + static const int s_subsumId = 22; + static const uint32_t s_exMask = 0xff; + static const uint32_t s_eyMask = 0xff; + static const uint32_t s_etMask = 0xff; + // Neutral format data lengths + static const int s_pairsPerPin = 3; + static const int s_jetElementBits = 9; + static const int s_jePaddingBits = 22; + static const int s_jetHitsBits = 24; + static const int s_energyBits = 8; + static const int s_bunchCrossingBits = 12; + static const int s_hitPaddingBits = 4; + static const int s_glinkBitsPerSlice = 67; + + int sourceId(uint32_t word) const; + int dataId(uint32_t word) const; + int index(int slice) const; + void resize(std::vector<uint32_t>& vec, int channels = 1); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Jet element data + std::vector<uint32_t> m_jeData; + /// Jet hit counts + std::vector<uint32_t> m_jetHits; + /// Energy subsum data + std::vector<uint32_t> m_energySubsums; + /// Number of jet element channels + int m_channels; + +}; + +inline int JemSubBlock::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +inline int JemSubBlock::dataId(const uint32_t word) const +{ + return (word >> s_dataIdBit) & s_dataIdMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV1.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV1.cxx new file mode 100755 index 0000000000000000000000000000000000000000..cec0c05c5b361d22c05af508dae0a2d9615c515f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV1.cxx @@ -0,0 +1,417 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JemJetElement.h" +#include "JemSubBlockV1.h" + +namespace LVL1BS { + +// Constant definitions + +const int JemSubBlockV1::s_wordIdVal; + +const int JemSubBlockV1::s_wordLength; + +const int JemSubBlockV1::s_dataIdBit; +const int JemSubBlockV1::s_jeWordId; +const uint32_t JemSubBlockV1::s_dataIdMask; + +const int JemSubBlockV1::s_threshBit; +const int JemSubBlockV1::s_sourceIdBit; +const int JemSubBlockV1::s_jetIndicatorBit; +const int JemSubBlockV1::s_jetIndicator; +const int JemSubBlockV1::s_mainThreshId; +const int JemSubBlockV1::s_mainFwdThreshId; +const int JemSubBlockV1::s_threshWordId; +const uint32_t JemSubBlockV1::s_threshMask; +const uint32_t JemSubBlockV1::s_sourceIdMask; + +const int JemSubBlockV1::s_exBit; +const int JemSubBlockV1::s_eyBit; +const int JemSubBlockV1::s_etBit; +const int JemSubBlockV1::s_sumIndicatorBit; +const int JemSubBlockV1::s_sumIndicator; +const int JemSubBlockV1::s_subsumId; +const uint32_t JemSubBlockV1::s_exMask; +const uint32_t JemSubBlockV1::s_eyMask; +const uint32_t JemSubBlockV1::s_etMask; + +const int JemSubBlockV1::s_pairsPerPin; +const int JemSubBlockV1::s_jetElementBits; +const int JemSubBlockV1::s_jePaddingBits; +const int JemSubBlockV1::s_jetHitsBits; +const int JemSubBlockV1::s_energyBits; +const int JemSubBlockV1::s_bunchCrossingBits; +const int JemSubBlockV1::s_hitPaddingBits; +const int JemSubBlockV1::s_glinkBitsPerSlice; + + +JemSubBlockV1::JemSubBlockV1() : m_channels(44) +{ +} + +JemSubBlockV1::~JemSubBlockV1() +{ +} + +// Clear all data + +void JemSubBlockV1::clear() +{ + L1CaloSubBlock::clear(); + m_jeData.clear(); + m_jetHits.clear(); + m_energySubsums.clear(); +} + +// Store JEM header + +void JemSubBlockV1::setJemHeader(const int version, const int format, + const int slice, const int crate, + const int module, const int timeslices) +{ + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, timeslices); +} + +// Store jet element data + +void JemSubBlockV1::fillJetElement(const int slice, const JemJetElement& jetEle) +{ + if (jetEle.data()) { + const int channel = jetEle.channel(); + if (channel < m_channels) { + resize(m_jeData, m_channels); + m_jeData[index(slice)*m_channels + channel] = jetEle.data(); + } + } +} + +// Store jet hit counts + +void JemSubBlockV1::setJetHits(const int slice, const unsigned int hits) +{ + if (hits) { + const int jem = module(); + const int sourceId = (jem == 0 || jem == 7 || jem == 8 || jem == 15) + ? s_mainFwdThreshId : s_mainThreshId; + uint32_t word = 0; + word |= (hits & s_threshMask) << s_threshBit; + word |= s_jetIndicator << s_jetIndicatorBit; + word |= (sourceId & s_sourceIdMask) << s_sourceIdBit; + word |= s_threshWordId << s_dataIdBit; + resize(m_jetHits); + m_jetHits[index(slice)] = word; + } +} + +// Store energy subsum data + +void JemSubBlockV1::setEnergySubsums(const int slice, const unsigned int ex, + const unsigned int ey, const unsigned int et) +{ + uint32_t word = 0; + word |= (ex & s_exMask) << s_exBit; + word |= (ey & s_eyMask) << s_eyBit; + word |= (et & s_etMask) << s_etBit; + if (word) { + word |= s_sumIndicator << s_sumIndicatorBit; + word |= s_subsumId << s_sourceIdBit; + word |= s_threshWordId << s_dataIdBit; + resize(m_energySubsums); + m_energySubsums[index(slice)] = word; + } +} + +// Return jet element for given channel + +JemJetElement JemSubBlockV1::jetElement(const int slice, const int channel) const +{ + uint32_t je = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_jeData.empty()) { + je = m_jeData[index(slice)*m_channels + channel]; + } + return JemJetElement(je); +} + +// Return jet hit counts + +unsigned int JemSubBlockV1::jetHits(const int slice) const +{ + unsigned int hits = 0; + if (slice >= 0 && slice < timeslices() && !m_jetHits.empty()) { + hits = (m_jetHits[index(slice)] >> s_threshBit) & s_threshMask; + } + return hits; +} + +// Return energy subsum Ex + +unsigned int JemSubBlockV1::ex(const int slice) const +{ + unsigned int ex = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + ex = (m_energySubsums[index(slice)] >> s_exBit) & s_exMask; + } + return ex; +} + +// Return energy subsum Ey + +unsigned int JemSubBlockV1::ey(const int slice) const +{ + unsigned int ey = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + ey = (m_energySubsums[index(slice)] >> s_eyBit) & s_eyMask; + } + return ey; +} + +// Return energy subsum Et + +unsigned int JemSubBlockV1::et(const int slice) const +{ + unsigned int et = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + et = (m_energySubsums[index(slice)] >> s_etBit) & s_etMask; + } + return et; +} + +// Return number of timeslices + +int JemSubBlockV1::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Packing/Unpacking routines + +bool JemSubBlockV1::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool JemSubBlockV1::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data index appropriate to format + +int JemSubBlockV1::index(const int slice) const +{ + return (format() == NEUTRAL) ? slice : 0; +} + +// Resize a data vector according to format + +void JemSubBlockV1::resize(std::vector<uint32_t>& vec, const int channels) +{ + if (vec.empty()) { + int size = channels; + if (format() == NEUTRAL) size *= timeslices(); + vec.resize(size); + } +} + +// Pack neutral data + +bool JemSubBlockV1::packNeutral() +{ + resize(m_jeData, m_channels); + resize(m_jetHits); + resize(m_energySubsums); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + // Jet element data + for (int channel = 0; channel < m_channels; ++channel) { + const int pin = channel / s_pairsPerPin; + const JemJetElement je = jetElement(slice, channel); + packerNeutral(pin, je.emData(), s_jetElementBits); + packerNeutral(pin, je.emParity(), 1); + packerNeutral(pin, je.linkError(), 1); + packerNeutral(pin, je.hadData(), s_jetElementBits); + packerNeutral(pin, je.hadParity(), 1); + packerNeutral(pin, (je.linkError() >> 1), 1); + } + // Pad out last jet element pin + int lastpin = (m_channels - 1) / s_pairsPerPin; + packerNeutral(lastpin, 0, s_jePaddingBits); + // Jet Hits and Energy Sums with parity bits + ++lastpin; + packerNeutral(lastpin, jetHits(slice), s_jetHitsBits); + packerNeutral(lastpin, parityBit(1, jetHits(slice), s_jetHitsBits), 1); + packerNeutral(lastpin, ex(slice), s_energyBits); + packerNeutral(lastpin, ey(slice), s_energyBits); + packerNeutral(lastpin, et(slice), s_energyBits); + int parity = parityBit(1, ex(slice), s_energyBits); + parity = parityBit(parity, ey(slice), s_energyBits); + parity = parityBit(parity, et(slice), s_energyBits); + packerNeutral(lastpin, parity, 1); + // Bunch Crossing number and padding + packerNeutral(lastpin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(lastpin, 0, s_hitPaddingBits); + // G-Link parity + for (int pin = 0; pin <= lastpin; ++pin) packerNeutralParity(pin); + } + return true; +} + +// Pack uncompressed data + +bool JemSubBlockV1::packUncompressed() +{ + // Jet element data + std::vector<uint32_t>::const_iterator pos; + for (pos = m_jeData.begin(); pos != m_jeData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + + // Hits and Subsum data + if ( !m_jetHits.empty() && m_jetHits[0]) packer(m_jetHits[0], s_wordLength); + if ( !m_energySubsums.empty() && m_energySubsums[0]) { + packer(m_energySubsums[0], s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool JemSubBlockV1::unpackNeutral() +{ + resize(m_jeData, m_channels); + resize(m_jetHits); + resize(m_energySubsums); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + // Jet element data + for (int channel = 0; channel < m_channels; ++channel) { + const int pin = channel / s_pairsPerPin; + const int emData = unpackerNeutral(pin, s_jetElementBits); + const int emParity = unpackerNeutral(pin, 1); + int linkError = unpackerNeutral(pin, 1); + const int hadData = unpackerNeutral(pin, s_jetElementBits); + const int hadParity = unpackerNeutral(pin, 1); + linkError |= unpackerNeutral(pin, 1) << 1; + const JemJetElement je(channel, emData, hadData, emParity, + hadParity, linkError); + fillJetElement(slice, je); + } + // Padding from last jet element pin + int lastpin = (m_channels - 1) / s_pairsPerPin; + unpackerNeutral(lastpin, s_jePaddingBits); + // Jet Hits and Energy Sums + ++lastpin; + setJetHits(slice, unpackerNeutral(lastpin, s_jetHitsBits)); + unpackerNeutral(lastpin, 1); // parity bit + const unsigned int ex = unpackerNeutral(lastpin, s_energyBits); + const unsigned int ey = unpackerNeutral(lastpin, s_energyBits); + const unsigned int et = unpackerNeutral(lastpin, s_energyBits); + setEnergySubsums(slice, ex, ey, et); + unpackerNeutral(lastpin, 1); // parity bit + // Bunch Crossing number and padding + setBunchCrossing(unpackerNeutral(lastpin, s_bunchCrossingBits)); + unpackerNeutral(lastpin, s_hitPaddingBits); + // G-Link parity errors + for (int pin = 0; pin <= lastpin; ++pin) unpackerNeutralParityError(pin); + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool JemSubBlockV1::unpackUncompressed() +{ + resize(m_jeData, m_channels); + resize(m_jetHits); + resize(m_energySubsums); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataId(word); + bool err = false; + // Jet element data + if (id == s_jeWordId) { + const JemJetElement jetEle(word); + const int channel = jetEle.channel(); + if (channel < m_channels && m_jeData[channel] == 0) { + m_jeData[channel] = word; + } else err = true; + // Other data + } else { + switch (sourceId(word)) { + // Jet hit counts/thresholds + case s_mainThreshId: + case s_mainFwdThreshId: { + if (m_jetHits[0] == 0) m_jetHits[0] = word; + else err = true; + break; + } + // Energy subsums + case s_subsumId: { + if (m_energySubsums[0] == 0) m_energySubsums[0] = word; + else err = true; + break; + } + default: + err = true; + break; + } + } + if (err) { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV1.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV1.h new file mode 100755 index 0000000000000000000000000000000000000000..22c8f2341c4d89e2457116a7b95090cedda33d4d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV1.h @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMSUBBLOCKV1_H +#define TRIGT1CALOBYTESTREAM_JEMSUBBLOCKV1_H + +#include <stdint.h> +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +class JemJetElement; + +/** Sub-Block class for JEM data pre-LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version 1.06d + * + * @author Peter Faulkner + */ + +class JemSubBlockV1 : public L1CaloSubBlock { + + public: + JemSubBlockV1(); + ~JemSubBlockV1(); + + /// Clear all data + void clear(); + + /// Store JEM header + void setJemHeader(int version, int format, int slice, int crate, + int module, int timeslices); + /// Store jet element data + void fillJetElement(int slice, const JemJetElement& jetEle); + /// Store jet hit counts + void setJetHits(int slice, unsigned int hits); + /// Store energy subsum data + void setEnergySubsums(int slice, unsigned int ex, + unsigned int ey, unsigned int et); + + /// Return jet element for given channel + JemJetElement jetElement(int slice, int channel) const; + /// Return jet hit counts + unsigned int jetHits(int slice) const; + /// Return energy subsum Ex + unsigned int ex(int slice) const; + /// Return energy subsum Ey + unsigned int ey(int slice) const; + /// Return energy subsum Et + unsigned int et(int slice) const; + /// Return number of timeslices + int timeslices() const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// JEM header word ID + static const int s_wordIdVal = 0xc; + /// Data word length + static const int s_wordLength = 32; + // Jet Element data word bit positions and masks + static const int s_dataIdBit = 30; + static const int s_jeWordId = 0x1; + static const uint32_t s_dataIdMask = 0x3; + // Jet hit counts bit positions and masks + static const int s_threshBit = 0; + static const int s_sourceIdBit = 25; + static const int s_jetIndicatorBit = 24; + static const int s_jetIndicator = 0x0; + static const int s_mainThreshId = 20; + static const int s_mainFwdThreshId = 21; + static const int s_threshWordId = 0x2; + static const uint32_t s_threshMask = 0xffffff; + static const uint32_t s_sourceIdMask = 0x1f; + // Energy subsum data bit positions and masks + static const int s_exBit = 0; + static const int s_eyBit = 8; + static const int s_etBit = 16; + static const int s_sumIndicatorBit = 24; + static const int s_sumIndicator = 0x1; + static const int s_subsumId = 22; + static const uint32_t s_exMask = 0xff; + static const uint32_t s_eyMask = 0xff; + static const uint32_t s_etMask = 0xff; + // Neutral format data lengths + static const int s_pairsPerPin = 3; + static const int s_jetElementBits = 9; + static const int s_jePaddingBits = 22; + static const int s_jetHitsBits = 24; + static const int s_energyBits = 8; + static const int s_bunchCrossingBits = 12; + static const int s_hitPaddingBits = 4; + static const int s_glinkBitsPerSlice = 67; + + int sourceId(uint32_t word) const; + int dataId(uint32_t word) const; + int index(int slice) const; + void resize(std::vector<uint32_t>& vec, int channels = 1); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Jet element data + std::vector<uint32_t> m_jeData; + /// Jet hit counts + std::vector<uint32_t> m_jetHits; + /// Energy subsum data + std::vector<uint32_t> m_energySubsums; + /// Number of jet element channels + int m_channels; + +}; + +inline int JemSubBlockV1::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +inline int JemSubBlockV1::dataId(const uint32_t word) const +{ + return (word >> s_dataIdBit) & s_dataIdMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV2.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV2.cxx new file mode 100755 index 0000000000000000000000000000000000000000..5531730266a22e1daa74970f04dcd5eadf4b0844 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV2.cxx @@ -0,0 +1,371 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JemJetElement.h" +#include "JemSubBlockV2.h" + +namespace LVL1BS { + +// Constant definitions + +const int JemSubBlockV2::s_wordIdVal; + +const int JemSubBlockV2::s_wordLength; + +const int JemSubBlockV2::s_dataIdBit; +const int JemSubBlockV2::s_jeWordId; +const uint32_t JemSubBlockV2::s_dataIdMask; + +const int JemSubBlockV2::s_energyWordId; +const int JemSubBlockV2::s_sourceIdBit; +const uint32_t JemSubBlockV2::s_sourceIdMask; +const int JemSubBlockV2::s_etId; +const int JemSubBlockV2::s_exEyId; +const int JemSubBlockV2::s_exBit; +const int JemSubBlockV2::s_eyBit; +const int JemSubBlockV2::s_etBit; +const uint32_t JemSubBlockV2::s_exMask; +const uint32_t JemSubBlockV2::s_eyMask; +const uint32_t JemSubBlockV2::s_etMask; + +const int JemSubBlockV2::s_pairsPerPin; +const int JemSubBlockV2::s_jetElementBits; +const int JemSubBlockV2::s_jePaddingBits; +const int JemSubBlockV2::s_energyBits; +const int JemSubBlockV2::s_bunchCrossingBits; +const int JemSubBlockV2::s_energyPaddingBits; +const int JemSubBlockV2::s_glinkBitsPerSlice; + + +JemSubBlockV2::JemSubBlockV2() : m_channels(44), m_energyWords(2) +{ +} + +JemSubBlockV2::~JemSubBlockV2() +{ +} + +// Clear all data + +void JemSubBlockV2::clear() +{ + L1CaloSubBlock::clear(); + m_jeData.clear(); + m_energySubsums.clear(); +} + +// Store JEM header + +void JemSubBlockV2::setJemHeader(const int version, const int format, + const int slice, const int crate, + const int module, const int timeslices) +{ + setHeader(s_wordIdVal, version, format, slice, crate, module, 0, timeslices); +} + +// Store jet element data + +void JemSubBlockV2::fillJetElement(const int slice, const JemJetElement& jetEle) +{ + if (jetEle.data()) { + const int channel = jetEle.channel(); + if (channel < m_channels) { + resize(m_jeData, m_channels); + m_jeData[index(slice, m_channels) + channel] = jetEle.data(); + } + } +} + +// Store energy subsum data + +void JemSubBlockV2::setEnergySubsums(const int slice, const unsigned int ex, + const unsigned int ey, const unsigned int et) +{ + uint32_t word1 = 0; + uint32_t word2 = 0; + word1 |= (et & s_etMask) << s_etBit; + word2 |= (ex & s_exMask) << s_exBit; + word2 |= (ey & s_eyMask) << s_eyBit; + if (word1 || word2) { + resize(m_energySubsums, m_energyWords); + const int ix = index(slice, m_energyWords); + if (word1) { + word1 |= s_etId << s_sourceIdBit; + word1 |= s_energyWordId << s_dataIdBit; + m_energySubsums[ix] = word1; + } + if (word2) { + word2 |= s_exEyId << s_sourceIdBit; + word2 |= s_energyWordId << s_dataIdBit; + m_energySubsums[ix+1] = word2; + } + } +} + +// Return jet element for given channel + +JemJetElement JemSubBlockV2::jetElement(const int slice, const int channel) const +{ + uint32_t je = 0; + if (slice >= 0 && slice < timeslices() && + channel >= 0 && channel < m_channels && !m_jeData.empty()) { + je = m_jeData[index(slice, m_channels) + channel]; + } + return JemJetElement(je); +} + +// Return energy subsum Ex + +unsigned int JemSubBlockV2::ex(const int slice) const +{ + unsigned int ex = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + ex = (m_energySubsums[index(slice, m_energyWords)+1] >> s_exBit) & s_exMask; + } + return ex; +} + +// Return energy subsum Ey + +unsigned int JemSubBlockV2::ey(const int slice) const +{ + unsigned int ey = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + ey = (m_energySubsums[index(slice, m_energyWords)+1] >> s_eyBit) & s_eyMask; + } + return ey; +} + +// Return energy subsum Et + +unsigned int JemSubBlockV2::et(const int slice) const +{ + unsigned int et = 0; + if (slice >= 0 && slice < timeslices() && !m_energySubsums.empty()) { + et = (m_energySubsums[index(slice, m_energyWords)] >> s_etBit) & s_etMask; + } + return et; +} + +// Return number of timeslices + +int JemSubBlockV2::timeslices() const +{ + int slices = slices1(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords() / s_glinkBitsPerSlice; + } + if (slices == 0) slices = 1; + return slices; +} + +// Packing/Unpacking routines + +bool JemSubBlockV2::pack() +{ + bool rc = false; + switch (version()) { + case 2: //<< CHECK + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + rc = packUncompressed(); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool JemSubBlockV2::unpack() +{ + bool rc = false; + switch (version()) { + case 2: //<< CHECK + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + rc = unpackUncompressed(); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Return data index appropriate to format + +int JemSubBlockV2::index(const int slice, const int channels) const +{ + return (format() == NEUTRAL) ? slice*channels : 0; +} + +// Resize a data vector according to format + +void JemSubBlockV2::resize(std::vector<uint32_t>& vec, const int channels) +{ + if (vec.empty()) { + int size = channels; + if (format() == NEUTRAL) size *= timeslices(); + vec.resize(size); + } +} + +// Pack neutral data + +bool JemSubBlockV2::packNeutral() +{ + resize(m_jeData, m_channels); + resize(m_energySubsums, m_energyWords); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + // Jet element data + for (int channel = 0; channel < m_channels; ++channel) { + const int pin = channel / s_pairsPerPin; + const JemJetElement je = jetElement(slice, channel); + packerNeutral(pin, je.emData(), s_jetElementBits); + packerNeutral(pin, je.emParity(), 1); + packerNeutral(pin, je.linkError(), 1); + packerNeutral(pin, je.hadData(), s_jetElementBits); + packerNeutral(pin, je.hadParity(), 1); + packerNeutral(pin, (je.linkError() >> 1), 1); + } + // Pad out last jet element pin + int lastpin = (m_channels - 1) / s_pairsPerPin; + packerNeutral(lastpin, 0, s_jePaddingBits); + // Energy Sums + ++lastpin; + packerNeutral(lastpin, ex(slice), s_energyBits); + packerNeutral(lastpin, ey(slice), s_energyBits); + packerNeutral(lastpin, et(slice), s_energyBits); + // Bunch Crossing number and padding + packerNeutral(lastpin, bunchCrossing(), s_bunchCrossingBits); + packerNeutral(lastpin, 0, s_energyPaddingBits); + // G-Link parity + for (int pin = 0; pin <= lastpin; ++pin) packerNeutralParity(pin); + } + return true; +} + +// Pack uncompressed data + +bool JemSubBlockV2::packUncompressed() +{ + // Jet element data + std::vector<uint32_t>::const_iterator pos; + for (pos = m_jeData.begin(); pos != m_jeData.end(); ++pos) { + if (*pos) packer(*pos, s_wordLength); + } + + // Subsum data + if ( !m_energySubsums.empty() ) { + if (m_energySubsums[0]) packer(m_energySubsums[0], s_wordLength); + if (m_energySubsums[1]) packer(m_energySubsums[1], s_wordLength); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool JemSubBlockV2::unpackNeutral() +{ + resize(m_jeData, m_channels); + resize(m_energySubsums, m_energyWords); + const int slices = timeslices(); + for (int slice = 0; slice < slices; ++slice) { + // Jet element data + for (int channel = 0; channel < m_channels; ++channel) { + const int pin = channel / s_pairsPerPin; + const int emData = unpackerNeutral(pin, s_jetElementBits); + const int emParity = unpackerNeutral(pin, 1); + int linkError = unpackerNeutral(pin, 1); + const int hadData = unpackerNeutral(pin, s_jetElementBits); + const int hadParity = unpackerNeutral(pin, 1); + linkError |= unpackerNeutral(pin, 1) << 1; + const JemJetElement je(channel, emData, hadData, emParity, + hadParity, linkError); + fillJetElement(slice, je); + } + // Padding from last jet element pin + int lastpin = (m_channels - 1) / s_pairsPerPin; + unpackerNeutral(lastpin, s_jePaddingBits); + // Energy Sums + ++lastpin; + const unsigned int ex = unpackerNeutral(lastpin, s_energyBits); + const unsigned int ey = unpackerNeutral(lastpin, s_energyBits); + const unsigned int et = unpackerNeutral(lastpin, s_energyBits); + setEnergySubsums(slice, ex, ey, et); + // Bunch Crossing number and padding + setBunchCrossing(unpackerNeutral(lastpin, s_bunchCrossingBits)); + unpackerNeutral(lastpin, s_energyPaddingBits); + // G-Link parity errors + for (int pin = 0; pin <= lastpin; ++pin) unpackerNeutralParityError(pin); + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack uncompressed data + +bool JemSubBlockV2::unpackUncompressed() +{ + resize(m_jeData, m_channels); + resize(m_energySubsums, m_energyWords); + unpackerInit(); + uint32_t word = unpacker(s_wordLength); + while (unpackerSuccess()) { + const int id = dataId(word); + bool err = false; + // Jet element data + if (id == s_jeWordId) { + const JemJetElement jetEle(word); + const int channel = jetEle.channel(); + if (channel < m_channels && m_jeData[channel] == 0) { + m_jeData[channel] = word; + } else err = true; + // Energy subsums + } else if (id == s_energyWordId) { + switch (sourceId(word)) { + case s_etId: { + if (m_energySubsums[0] == 0) m_energySubsums[0] = word; + else err = true; + break; + } + case s_exEyId: { + if (m_energySubsums[1] == 0) m_energySubsums[1] = word; + else err = true; + break; + } + default: + err = true; + break; + } + } else err = true; + if (err) { + setUnpackErrorCode(UNPACK_SOURCE_ID); + return false; + } + word = unpacker(s_wordLength); + } + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV2.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV2.h new file mode 100755 index 0000000000000000000000000000000000000000..845e2f70897d8f25e2c3544744976180a74649c9 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JemSubBlockV2.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMSUBBLOCKV2_H +#define TRIGT1CALOBYTESTREAM_JEMSUBBLOCKV2_H + +#include <stdint.h> +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +class JemJetElement; + +/** Sub-Block class for JEM data post LS1. + * + * Based on "ATLAS Level-1 Calorimeter Trigger Read-out Driver" + * Version X.xxx //<<== CHECK + * + * @author Peter Faulkner + */ + +class JemSubBlockV2 : public L1CaloSubBlock { + + public: + JemSubBlockV2(); + ~JemSubBlockV2(); + + /// Clear all data + void clear(); + + /// Store JEM header + void setJemHeader(int version, int format, int slice, int crate, + int module, int timeslices); + /// Store jet element data + void fillJetElement(int slice, const JemJetElement& jetEle); + /// Store energy subsum data + void setEnergySubsums(int slice, unsigned int ex, + unsigned int ey, unsigned int et); + + /// Return jet element for given channel + JemJetElement jetElement(int slice, int channel) const; + /// Return energy subsum Ex + unsigned int ex(int slice) const; + /// Return energy subsum Ey + unsigned int ey(int slice) const; + /// Return energy subsum Et + unsigned int et(int slice) const; + /// Return number of timeslices + int timeslices() const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + private: + /// JEM header word ID + static const int s_wordIdVal = 0xc; + /// Data word length + static const int s_wordLength = 32; + // Jet Element data word bit positions and masks + static const int s_dataIdBit = 30; + static const int s_jeWordId = 0x1; + static const uint32_t s_dataIdMask = 0x3; + // Energy subsum data bit positions and masks + static const int s_energyWordId = 0x2; + static const int s_sourceIdBit = 28; + static const uint32_t s_sourceIdMask = 0x3; + static const int s_etId = 2; + static const int s_exEyId = 3; + static const int s_exBit = 0; + static const int s_eyBit = 14; + static const int s_etBit = 14; + static const uint32_t s_exMask = 0x3fff; + static const uint32_t s_eyMask = 0x3fff; + static const uint32_t s_etMask = 0x3fff; + // Neutral format data lengths + static const int s_pairsPerPin = 3; + static const int s_jetElementBits = 9; + static const int s_jePaddingBits = 22; + static const int s_energyBits = 14; + static const int s_bunchCrossingBits = 12; + static const int s_energyPaddingBits = 12; + static const int s_glinkBitsPerSlice = 67; + + int sourceId(uint32_t word) const; + int dataId(uint32_t word) const; + int index(int slice, int channels) const; + void resize(std::vector<uint32_t>& vec, int channels); + + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressed(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressed(); + + /// Jet element data + std::vector<uint32_t> m_jeData; + /// Energy subsum data + std::vector<uint32_t> m_energySubsums; + /// Number of jet element channels + int m_channels; + /// Number of energy data words + int m_energyWords; + +}; + +inline int JemSubBlockV2::sourceId(const uint32_t word) const +{ + return (word >> s_sourceIdBit) & s_sourceIdMask; +} + +inline int JemSubBlockV2::dataId(const uint32_t word) const +{ + return (word >> s_dataIdBit) & s_dataIdMask; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamCnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..90cf6a9b2ac1843478d30b69de091fe7b56b1939 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamCnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/JEPBSCollection.h" + +#include "JepByteStreamCnv.h" +#include "JepByteStreamTool.h" + +namespace LVL1BS { + +JepByteStreamCnv::JepByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepByteStreamCnv"), + m_tool("LVL1BS::JepByteStreamTool/JepByteStreamTool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +JepByteStreamCnv::~JepByteStreamCnv() +{ +} + +// CLID + +const CLID& JepByteStreamCnv::classID() +{ + return ClassID_traits<LVL1::JEPBSCollection>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepByteStreamCnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode JepByteStreamCnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::JEPBSCollection* jep = 0; + if( !SG::fromStorable( pObj, jep ) ) { + m_log << MSG::ERROR << " Cannot cast to JEPBSCollection" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( jep, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..36b4009d76208f548082464572acffd50868009d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamCnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_JEPBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepByteStreamTool; + +/** ByteStream converter for JEP container + * + * @author Peter Faulkner + */ + +class JepByteStreamCnv: public Converter { + + friend class CnvFactory<JepByteStreamCnv>; + +protected: + + JepByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~JepByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from JEP Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepByteStreamTool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamTool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..d25542f6b8bbbae0965a085d01e9a10e73cb759a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamTool.cxx @@ -0,0 +1,1729 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/JEMHits.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JEPBSCollection.h" +#include "TrigT1CaloEvent/JetElement.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/JetElementKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "CmmEnergySubBlock.h" +#include "CmmJetSubBlock.h" +#include "CmmSubBlock.h" +#include "JemJetElement.h" +#include "JemSubBlock.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "ModifySlices.h" + +#include "JepByteStreamTool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IJepByteStreamTool("JepByteStreamTool", 1, 1); + +const InterfaceID& JepByteStreamTool::interfaceID() +{ + return IID_IJepByteStreamTool; +} + +// Constructor + +JepByteStreamTool::JepByteStreamTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_jemMaps("LVL1::JemMappingTool/JemMappingTool"), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_channels(44), m_crates(2), m_modules(16), m_coreOverlap(0), + m_subDetector(eformat::TDAQ_CALO_JET_PROC_DAQ), + m_srcIdMap(0), m_elementKey(0), + m_jemSubBlock(0), m_cmmEnergySubBlock(0), m_cmmJetSubBlock(0), + m_rodStatus(0), m_fea(0) +{ + declareInterface<JepByteStreamTool>(this); + + declareProperty("JemMappingTool", m_jemMaps, + "Crate/Module/Channel to Eta/Phi/Layer mapping tool"); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 12, + "Offset of JEP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of JEP crate numbers in RDOs"); + declareProperty("SlinksPerCrate", m_slinks = 4, + "The number of S-Links per crate"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SimulSlices", m_dfltSlices = 1, + "The number of slices in the simulation"); + declareProperty("ForceSlices", m_forceSlices = 0, + "If >0, the number of slices in bytestream"); + +} + +// Destructor + +JepByteStreamTool::~JepByteStreamTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepByteStreamTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_jemMaps.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_jemMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_jemMaps << endreq; + + sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_elementKey = new LVL1::JetElementKey(); + m_jemSubBlock = new JemSubBlock(); + m_cmmEnergySubBlock = new CmmEnergySubBlock(); + m_cmmJetSubBlock = new CmmJetSubBlock(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JepByteStreamTool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_cmmJetSubBlock; + delete m_cmmEnergySubBlock; + delete m_jemSubBlock; + delete m_elementKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to jet elements + +StatusCode JepByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JetElement>* const jeCollection) +{ + m_jeCollection = jeCollection; + m_jeMap.clear(); + return convertBs(robFrags, JET_ELEMENTS); +} + +// Conversion bytestream to jet hits + +StatusCode JepByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMHits>* const hitCollection) +{ + m_hitCollection = hitCollection; + m_hitsMap.clear(); + return convertBs(robFrags, JET_HITS); +} + +// Conversion bytestream to energy sums + +StatusCode JepByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMEtSums>* const etCollection) +{ + m_etCollection = etCollection; + m_etMap.clear(); + return convertBs(robFrags, ENERGY_SUMS); +} + +// Conversion bytestream to CMM hits + +StatusCode JepByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMJetHits>* const hitCollection) +{ + m_cmmHitCollection = hitCollection; + m_cmmHitsMap.clear(); + return convertBs(robFrags, CMM_HITS); +} + +// Conversion bytestream to CMM energy sums + +StatusCode JepByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMEtSums>* const etCollection) +{ + m_cmmEtCollection = etCollection; + m_cmmEtMap.clear(); + return convertBs(robFrags, CMM_SUMS); +} + +// Conversion of JEP container to bytestream + +StatusCode JepByteStreamTool::convert(const LVL1::JEPBSCollection* const jep, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + setupJeMap(jep->JetElements()); + setupHitsMap(jep->JetHits()); + setupEtMap(jep->EnergySums()); + setupCmmHitsMap(jep->CmmHits()); + setupCmmEtMap(jep->CmmSums()); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + int timeslices = 1; + int trigJem = 0; + int timeslicesNew = 1; + int trigJemNew = 0; + for (int crate=0; crate < m_crates; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + for (int module=0; module < m_modules; ++module) { + + // Pack required number of modules per slink + + if (module%modulesPerSlink == 0) { + const int daqOrRoi = 0; + const int slink = module/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq; + } + // Get number of JEM slices and triggered slice offset + // for this slink + if ( ! slinkSlices(crate, module, modulesPerSlink, + timeslices, trigJem)) { + msg(MSG::ERROR) << "Inconsistent number of slices or " + << "triggered slice offsets in data for crate " + << hwCrate << " slink " << slink << endreq; + return StatusCode::FAILURE; + } + timeslicesNew = (m_forceSlices) ? m_forceSlices : timeslices; + trigJemNew = ModifySlices::peak(trigJem, timeslices, timeslicesNew); + if (debug) { + msg() << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq + << "Slices/offset: " << timeslices << " " << trigJem; + if (timeslices != timeslicesNew) { + msg() << " modified to " << timeslicesNew << " " << trigJemNew; + } + msg() << endreq; + } + L1CaloUserHeader userHeader; + userHeader.setJem(trigJemNew); + const uint32_t rodIdJem = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdJem); + theROD->push_back(userHeader.header()); + m_rodStatusMap.insert(make_pair(rodIdJem, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block for each slice (except Neutral format) + + m_jemBlocks.clear(); + for (int slice = 0; slice < timeslicesNew; ++slice) { + JemSubBlock* const subBlock = new JemSubBlock(); + subBlock->setJemHeader(m_version, m_dataFormat, slice, + hwCrate, module, timeslicesNew); + m_jemBlocks.push_back(subBlock); + if (neutralFormat) break; + } + + // Find jet elements corresponding to each eta/phi pair and fill + // sub-blocks + + for (int chan=0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_jemMaps->mapping(crate, module, chan, eta, phi, layer)) { + const LVL1::JetElement* const je = findJetElement(eta, phi); + if (je ) { + std::vector<int> emData; + std::vector<int> hadData; + std::vector<int> emErrors; + std::vector<int> hadErrors; + ModifySlices::data(je->emEnergyVec(), emData, timeslicesNew); + ModifySlices::data(je->hadEnergyVec(), hadData, timeslicesNew); + ModifySlices::data(je->emErrorVec(), emErrors, timeslicesNew); + ModifySlices::data(je->hadErrorVec(), hadErrors, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError emErrBits(emErrors[slice]); + const LVL1::DataError hadErrBits(hadErrors[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlock* const subBlock = m_jemBlocks[index]; + const JemJetElement jetEle(chan, emData[slice], hadData[slice], + emErrBits.get(LVL1::DataError::Parity), + hadErrBits.get(LVL1::DataError::Parity), + emErrBits.get(LVL1::DataError::LinkDown) + + (hadErrBits.get(LVL1::DataError::LinkDown) << 1)); + subBlock->fillJetElement(slice, jetEle); + } + } + } + } + + // Add jet hits and energy subsums + + const LVL1::JEMHits* const hits = findJetHits(crate, module); + if (hits) { + std::vector<unsigned int> vec; + ModifySlices::data(hits->JetHitsVec(), vec, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlock* const subBlock = m_jemBlocks[index]; + subBlock->setJetHits(slice, vec[slice]); + } + } + const LVL1::JEMEtSums* const et = findEnergySums(crate, module); + if (et) { + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + ModifySlices::data(et->ExVec(), exVec, timeslicesNew); + ModifySlices::data(et->EyVec(), eyVec, timeslicesNew); + ModifySlices::data(et->EtVec(), etVec, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlock* const subBlock = m_jemBlocks[index]; + subBlock->setEnergySubsums(slice, exVec[slice], eyVec[slice], + etVec[slice]); + } + } + + // Pack and write the sub-blocks + + DataVector<JemSubBlock>::const_iterator pos; + for (pos = m_jemBlocks.begin(); pos != m_jemBlocks.end(); ++pos) { + JemSubBlock* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "JEM sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "JEM sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Append CMMs to last S-Link of the crate + + // Create a sub-block for each slice (except Neutral format) + + m_cmmEnergyBlocks.clear(); + m_cmmJetBlocks.clear(); + const int summing = (crate == m_crates - 1) ? CmmSubBlock::SYSTEM + : CmmSubBlock::CRATE; + for (int slice = 0; slice < timeslicesNew; ++slice) { + CmmEnergySubBlock* const enBlock = new CmmEnergySubBlock(); + const int cmmEnergyVersion = 2; // with Missing-ET-Sig + enBlock->setCmmHeader(cmmEnergyVersion, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_ENERGY, + CmmSubBlock::LEFT, timeslicesNew); + m_cmmEnergyBlocks.push_back(enBlock); + CmmJetSubBlock* const jetBlock = new CmmJetSubBlock(); + jetBlock->setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_JET, + CmmSubBlock::RIGHT, timeslicesNew); + m_cmmJetBlocks.push_back(jetBlock); + if (neutralFormat) break; + } + + // CMM-Energy + + int maxDataID = static_cast<int>(LVL1::CMMEtSums::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + if (summing == CmmSubBlock::CRATE && + dataID != LVL1::CMMEtSums::LOCAL) continue; + switch (dataID) { + case LVL1::CMMEtSums::LOCAL: + source = CmmEnergySubBlock::LOCAL; + break; + case LVL1::CMMEtSums::REMOTE: + source = CmmEnergySubBlock::REMOTE; + break; + case LVL1::CMMEtSums::TOTAL: + source = CmmEnergySubBlock::TOTAL; + break; + case LVL1::CMMEtSums::MISSING_ET_MAP: + case LVL1::CMMEtSums::SUM_ET_MAP: + case LVL1::CMMEtSums::MISSING_ET_SIG_MAP: + break; + default: + continue; + } + } + const LVL1::CMMEtSums* const sums = findCmmSums(crate, dataID); + if ( sums ) { + std::vector<unsigned int> ex; + std::vector<unsigned int> ey; + std::vector<unsigned int> et; + std::vector<int> exErr; + std::vector<int> eyErr; + std::vector<int> etErr; + ModifySlices::data(sums->ExVec(), ex, timeslicesNew); + ModifySlices::data(sums->EyVec(), ey, timeslicesNew); + ModifySlices::data(sums->EtVec(), et, timeslicesNew); + ModifySlices::data(sums->ExErrorVec(), exErr, timeslicesNew); + ModifySlices::data(sums->EyErrorVec(), eyErr, timeslicesNew); + ModifySlices::data(sums->EtErrorVec(), etErr, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError exErrBits(exErr[slice]); + const LVL1::DataError eyErrBits(eyErr[slice]); + const LVL1::DataError etErrBits(etErr[slice]); + int exError = exErrBits.get(LVL1::DataError::Parity); + int eyError = eyErrBits.get(LVL1::DataError::Parity); + int etError = etErrBits.get(LVL1::DataError::Parity); + if (dataID == LVL1::CMMEtSums::LOCAL || + dataID == LVL1::CMMEtSums::REMOTE || + dataID == LVL1::CMMEtSums::TOTAL) { + exError = (exError << 1) + exErrBits.get(LVL1::DataError::Overflow); + eyError = (eyError << 1) + eyErrBits.get(LVL1::DataError::Overflow); + etError = (etError << 1) + etErrBits.get(LVL1::DataError::Overflow); + } + const int index = ( neutralFormat ) ? 0 : slice; + CmmEnergySubBlock* const subBlock = m_cmmEnergyBlocks[index]; + if (dataID == LVL1::CMMEtSums::MISSING_ET_MAP) { + subBlock->setMissingEtHits(slice, et[slice]); + } else if (dataID == LVL1::CMMEtSums::SUM_ET_MAP) { + subBlock->setSumEtHits(slice, et[slice]); + } else if (dataID == LVL1::CMMEtSums::MISSING_ET_SIG_MAP) { + subBlock->setMissingEtSigHits(slice, et[slice]); + } else { + subBlock->setSubsums(slice, source, + ex[slice], ey[slice], et[slice], + exError, eyError, etError); + } + } + } + } + DataVector<CmmEnergySubBlock>::const_iterator pos; + pos = m_cmmEnergyBlocks.begin(); + for (; pos != m_cmmEnergyBlocks.end(); ++pos) { + CmmEnergySubBlock* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Energy sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Energy sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + + // CMM-Jet + + maxDataID = static_cast<int>(LVL1::CMMJetHits::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + if (summing == CmmSubBlock::CRATE && + dataID != LVL1::CMMJetHits::LOCAL_MAIN && + dataID != LVL1::CMMJetHits::LOCAL_FORWARD) continue; + switch (dataID) { + case LVL1::CMMJetHits::LOCAL_MAIN: + source = CmmJetSubBlock::LOCAL_MAIN; + break; + case LVL1::CMMJetHits::REMOTE_MAIN: + source = CmmJetSubBlock::REMOTE_MAIN; + break; + case LVL1::CMMJetHits::TOTAL_MAIN: + source = CmmJetSubBlock::TOTAL_MAIN; + break; + case LVL1::CMMJetHits::LOCAL_FORWARD: + source = CmmJetSubBlock::LOCAL_FORWARD; + break; + case LVL1::CMMJetHits::REMOTE_FORWARD: + source = CmmJetSubBlock::REMOTE_FORWARD; + break; + case LVL1::CMMJetHits::TOTAL_FORWARD: + source = CmmJetSubBlock::TOTAL_FORWARD; + break; + case LVL1::CMMJetHits::ET_MAP: + break; + default: + continue; + } + } + const LVL1::CMMJetHits* const ch = findCmmHits(crate, dataID); + if ( ch ) { + std::vector<unsigned int> hits; + std::vector<int> errs; + ModifySlices::data(ch->HitsVec(), hits, timeslicesNew); + ModifySlices::data(ch->ErrorVec(), errs, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError errBits(errs[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + CmmJetSubBlock* const subBlock = m_cmmJetBlocks[index]; + if (dataID == LVL1::CMMJetHits::ET_MAP) { + subBlock->setJetEtMap(slice, hits[slice]); + } else { + subBlock->setJetHits(slice, source, hits[slice], + errBits.get(LVL1::DataError::Parity)); + } + } + } + } + DataVector<CmmJetSubBlock>::const_iterator jos; + jos = m_cmmJetBlocks.begin(); + for (; jos != m_cmmJetBlocks.end(); ++jos) { + CmmJetSubBlock* const subBlock = *jos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Jet sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Jet sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& JepByteStreamTool::sourceIDs( + const std::string& sgKey) +{ + // Check if overlap jet element channels wanted + const std::string flag("Overlap"); + const std::string::size_type pos = sgKey.find(flag); + m_coreOverlap = + (pos == std::string::npos || pos != sgKey.length() - flag.length()) ? 0 : 1; + + if (m_sourceIDs.empty()) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 0; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + m_sourceIDs.push_back(robId); + } + } + } + return m_sourceIDs; +} + +// Convert bytestream to given container type + +StatusCode JepByteStreamTool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0 || + m_srcIdMap->slink(sourceID) >= m_slinks || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: ROD " + << MSG::hex << sourceID << " ROB " << robid + << MSG::dec << endreq; + } + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word should be User Header + if ( !L1CaloUserHeader::isValid(*payload) ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Invalid or missing user header" << endreq; + continue; + } + L1CaloUserHeader userHeader(*payload); + const int minorVersion = (*rob)->rod_version() & 0xffff; + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + // triggered slice offsets + int trigJem = userHeader.jem(); + int trigCmm = userHeader.jepCmm(); + if (debug) { + msg() << "Minor format version number: " << MSG::hex + << minorVersion << MSG::dec << endreq + << "JEM triggered slice offset: " << trigJem << endreq + << "CMM triggered slice offset: " << trigCmm << endreq; + } + if (trigJem != trigCmm) { + const int newTrig = (trigJem > trigCmm) ? trigJem : trigCmm; + trigJem = newTrig; + trigCmm = newTrig; + if (debug) msg() << "Changed both offsets to " << newTrig << endreq; + } + + // Loop over sub-blocks + + m_rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER) { + if (debug) msg() << "Unexpected data sequence" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MISSING_HEADER; + break; + } + if (CmmSubBlock::cmmBlock(*payload)) { + // CMMs + if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_JET) { + m_cmmJetSubBlock->clear(); + payload = m_cmmJetSubBlock->read(payload, payloadEnd); + if (m_cmmJetSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMM_HITS) { + decodeCmmJet(m_cmmJetSubBlock, trigCmm); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmmJet failed" << endreq; + break; + } + } + } else if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_ENERGY) { + m_cmmEnergySubBlock->clear(); + payload = m_cmmEnergySubBlock->read(payload, payloadEnd); + if (m_cmmEnergySubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMM_SUMS) { + decodeCmmEnergy(m_cmmEnergySubBlock, trigCmm); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmmEnergy failed" << endreq; + break; + } + } + } else { + if (debug) msg() << "Invalid CMM type in module field" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + } else { + // JEM + m_jemSubBlock->clear(); + payload = m_jemSubBlock->read(payload, payloadEnd); + if (m_jemSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == JET_ELEMENTS || collection == JET_HITS || + collection == ENERGY_SUMS) { + decodeJem(m_jemSubBlock, trigJem, collection); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeJem failed" << endreq; + break; + } + } + } + } + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, m_rodErr); + } + + return StatusCode::SUCCESS; +} + +// Unpack CMM-Energy sub-block + +void JepByteStreamTool::decodeCmmEnergy(CmmEnergySubBlock* subBlock, + int trigCmm) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmmPosition(); + const int firmware = subBlock->cmmFirmware(); + const int summing = subBlock->cmmSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMM-Energy: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigCmm) { + if (debug) msg() << "Triggered CMM slice from header " + << "inconsistent with number of slices: " + << trigCmm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMM-Energy sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSid = static_cast<int>(CmmEnergySubBlock::MAX_SOURCE_ID); + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Energy sums + + for (int source = 0; source < maxSid; ++source) { + int dataID = source; + if (source >= m_modules) { + if (summing == CmmSubBlock::CRATE && + source != CmmEnergySubBlock::LOCAL) continue; + switch (source) { + case CmmEnergySubBlock::LOCAL: + dataID = LVL1::CMMEtSums::LOCAL; + break; + case CmmEnergySubBlock::REMOTE: + dataID = LVL1::CMMEtSums::REMOTE; + break; + case CmmEnergySubBlock::TOTAL: + dataID = LVL1::CMMEtSums::TOTAL; + break; + default: + continue; + } + } + const unsigned int ex = subBlock->ex(slice, source); + const unsigned int ey = subBlock->ey(slice, source); + const unsigned int et = subBlock->et(slice, source); + int exErr = subBlock->exError(slice, source); + int eyErr = subBlock->eyError(slice, source); + int etErr = subBlock->etError(slice, source); + LVL1::DataError exErrBits(ssError); + LVL1::DataError eyErrBits(ssError); + LVL1::DataError etErrBits(ssError); + if (dataID == LVL1::CMMEtSums::LOCAL || + dataID == LVL1::CMMEtSums::REMOTE || + dataID == LVL1::CMMEtSums::TOTAL) { + exErrBits.set(LVL1::DataError::Overflow, exErr); + exErrBits.set(LVL1::DataError::Parity, exErr >> 1); + eyErrBits.set(LVL1::DataError::Overflow, eyErr); + eyErrBits.set(LVL1::DataError::Parity, eyErr >> 1); + etErrBits.set(LVL1::DataError::Overflow, etErr); + etErrBits.set(LVL1::DataError::Parity, etErr >> 1); + } else { + exErrBits.set(LVL1::DataError::Parity, exErr); + eyErrBits.set(LVL1::DataError::Parity, eyErr); + etErrBits.set(LVL1::DataError::Parity, etErr); + } + exErr = exErrBits.error(); + eyErr = eyErrBits.error(); + etErr = etErrBits.error(); + if (ex || ey || et || exErr || eyErr || etErr) { + LVL1::CMMEtSums* sums = findCmmSums(crate, dataID); + if ( ! sums ) { // create new CMM energy sums + m_exVec.assign(timeslices, 0); + m_eyVec.assign(timeslices, 0); + m_etVec.assign(timeslices, 0); + m_exErrVec.assign(timeslices, 0); + m_eyErrVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + m_exErrVec[slice] = exErr; + m_eyErrVec[slice] = eyErr; + m_etErrVec[slice] = etErr; + sums = new LVL1::CMMEtSums(swCrate, dataID, m_etVec, m_exVec, m_eyVec, + m_etErrVec, m_exErrVec, m_eyErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, sums)); + m_cmmEtCollection->push_back(sums); + } else { + m_exVec = sums->ExVec(); + m_eyVec = sums->EyVec(); + m_etVec = sums->EtVec(); + m_exErrVec = sums->ExErrorVec(); + m_eyErrVec = sums->EyErrorVec(); + m_etErrVec = sums->EtErrorVec(); + const int nsl = m_exVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_exVec[slice] != 0 || m_eyVec[slice] != 0 || m_etVec[slice] != 0 || + m_exErrVec[slice] != 0 || m_eyErrVec[slice] != 0 || + m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + m_exErrVec[slice] = exErr; + m_eyErrVec[slice] = eyErr; + m_etErrVec[slice] = etErr; + sums->addEx(m_exVec, m_exErrVec); + sums->addEy(m_eyVec, m_eyErrVec); + sums->addEt(m_etVec, m_etErrVec); + } + } + } + + // Hit maps - store as Et + + if (summing == CmmSubBlock::SYSTEM) { + const unsigned int missEt = subBlock->missingEtHits(slice); + if ( missEt || ssError ) { + const int dataID = LVL1::CMMEtSums::MISSING_ET_MAP; + LVL1::CMMEtSums* map = findCmmSums(crate, dataID); + if ( ! map ) { + m_etVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_etVec[slice] = missEt; + m_etErrVec[slice] = ssError; + map = new LVL1::CMMEtSums(swCrate, dataID, + m_etVec, m_etVec, m_etVec, + m_etErrVec, m_etErrVec, m_etErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, map)); + m_cmmEtCollection->push_back(map); + } else { + m_etVec = map->EtVec(); + m_etErrVec = map->EtErrorVec(); + const int nsl = m_etVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_etVec[slice] != 0 || m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_etVec[slice] = missEt; + m_etErrVec[slice] = ssError; + map->addEx(m_etVec, m_etErrVec); + map->addEy(m_etVec, m_etErrVec); + map->addEt(m_etVec, m_etErrVec); + } + } + const unsigned int sumEt = subBlock->sumEtHits(slice); + if ( sumEt || ssError ) { + const int dataID = LVL1::CMMEtSums::SUM_ET_MAP; + LVL1::CMMEtSums* map = findCmmSums(crate, dataID); + if ( ! map ) { + m_etVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_etVec[slice] = sumEt; + m_etErrVec[slice] = ssError; + map = new LVL1::CMMEtSums(swCrate, dataID, + m_etVec, m_etVec, m_etVec, + m_etErrVec, m_etErrVec, m_etErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, map)); + m_cmmEtCollection->push_back(map); + } else { + m_etVec = map->EtVec(); + m_etErrVec = map->EtErrorVec(); + const int nsl = m_etVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_etVec[slice] != 0 || m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_etVec[slice] = sumEt; + m_etErrVec[slice] = ssError; + map->addEx(m_etVec, m_etErrVec); + map->addEy(m_etVec, m_etErrVec); + map->addEt(m_etVec, m_etErrVec); + } + } + if (subBlock->version() > 1) { + const unsigned int missEtSig = subBlock->missingEtSigHits(slice); + if ( missEtSig || ssError ) { + const int dataID = LVL1::CMMEtSums::MISSING_ET_SIG_MAP; + LVL1::CMMEtSums* map = findCmmSums(crate, dataID); + if ( ! map ) { + m_etVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_etVec[slice] = missEtSig; + m_etErrVec[slice] = ssError; + map = new LVL1::CMMEtSums(swCrate, dataID, + m_etVec, m_etVec, m_etVec, + m_etErrVec, m_etErrVec, m_etErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, map)); + m_cmmEtCollection->push_back(map); + } else { + m_etVec = map->EtVec(); + m_etErrVec = map->EtErrorVec(); + const int nsl = m_etVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_etVec[slice] != 0 || m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_etVec[slice] = missEtSig; + m_etErrVec[slice] = ssError; + map->addEx(m_etVec, m_etErrVec); + map->addEy(m_etVec, m_etErrVec); + map->addEt(m_etVec, m_etErrVec); + } + } + } + } + } + + return; +} + +// Unpack CMM-Jet sub-block + +void JepByteStreamTool::decodeCmmJet(CmmJetSubBlock* subBlock, int trigCmm) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmmPosition(); + const int firmware = subBlock->cmmFirmware(); + const int summing = subBlock->cmmSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMM-Jet: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigCmm) { + if (debug) msg() << "Triggered CMM slice from header " + << "inconsistent with number of slices: " + << trigCmm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMM-Jet sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSid = static_cast<int>(CmmJetSubBlock::MAX_SOURCE_ID); + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Jet hit counts + + for (int source = 0; source < maxSid; ++source) { + int dataID = source; + if (source >= m_modules) { + if (summing == CmmSubBlock::CRATE && + source != CmmJetSubBlock::LOCAL_MAIN && + source != CmmJetSubBlock::LOCAL_FORWARD) continue; + switch (source) { + case CmmJetSubBlock::LOCAL_MAIN: + dataID = LVL1::CMMJetHits::LOCAL_MAIN; + break; + case CmmJetSubBlock::REMOTE_MAIN: + dataID = LVL1::CMMJetHits::REMOTE_MAIN; + break; + case CmmJetSubBlock::TOTAL_MAIN: + dataID = LVL1::CMMJetHits::TOTAL_MAIN; + break; + case CmmJetSubBlock::LOCAL_FORWARD: + dataID = LVL1::CMMJetHits::LOCAL_FORWARD; + break; + case CmmJetSubBlock::REMOTE_FORWARD: + dataID = LVL1::CMMJetHits::REMOTE_FORWARD; + break; + case CmmJetSubBlock::TOTAL_FORWARD: + dataID = LVL1::CMMJetHits::TOTAL_FORWARD; + break; + default: + continue; + } + } + const unsigned int hits = subBlock->jetHits(slice, source); + LVL1::DataError errBits(ssError); + errBits.set(LVL1::DataError::Parity, + subBlock->jetHitsError(slice, source)); + const int err = errBits.error(); + if (hits || err) { + LVL1::CMMJetHits* jh = findCmmHits(crate, dataID); + if ( ! jh ) { // create new CMM hits + m_hitsVec.assign(timeslices, 0); + m_errVec.assign(timeslices, 0); + m_hitsVec[slice] = hits; + m_errVec[slice] = err; + jh = new LVL1::CMMJetHits(swCrate, dataID, m_hitsVec, m_errVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmHitsMap.insert(std::make_pair(key, jh)); + m_cmmHitCollection->push_back(jh); + } else { + m_hitsVec = jh->HitsVec(); + m_errVec = jh->ErrorVec(); + const int nsl = m_hitsVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec[slice] != 0 || m_errVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec[slice] = hits; + m_errVec[slice] = err; + jh->addHits(m_hitsVec, m_errVec); + } + } + } + + // Hit map - store as hits + + if (summing == CmmSubBlock::SYSTEM) { + const unsigned int etMap = subBlock->jetEtMap(slice); + if ( etMap || ssError ) { + const int dataID = LVL1::CMMJetHits::ET_MAP; + LVL1::CMMJetHits* map = findCmmHits(crate, dataID); + if ( ! map ) { + m_hitsVec.assign(timeslices, 0); + m_errVec.assign(timeslices, 0); + m_hitsVec[slice] = etMap; + m_errVec[slice] = ssError; + map = new LVL1::CMMJetHits(swCrate, dataID, m_hitsVec, m_errVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmHitsMap.insert(std::make_pair(key, map)); + m_cmmHitCollection->push_back(map); + } else { + m_hitsVec = map->HitsVec(); + m_errVec = map->ErrorVec(); + const int nsl = m_hitsVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec[slice] != 0 || m_errVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec[slice] = etMap; + m_errVec[slice] = ssError; + map->addHits(m_hitsVec, m_errVec); + } + } + } + } + + return; +} + +// Unpack JEM sub-block + +void JepByteStreamTool::decodeJem(JemSubBlock* subBlock, int trigJem, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + const bool verbose = msgLvl(MSG::VERBOSE); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->module(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "JEM: Crate " << hwCrate + << " Module " << module + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigJem) { + if (debug) msg() << "Triggered JEM slice from header " + << "inconsistent with number of slices: " + << trigJem << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "JEM sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + std::vector<int> dummy(timeslices); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + if (collection == JET_ELEMENTS) { + + // Loop over jet element channels and fill jet elements + + for (int chan = 0; chan < m_channels; ++chan) { + const JemJetElement jetEle(subBlock->jetElement(slice, chan)); + if (jetEle.data() || ssError) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_jemMaps->mapping(crate, module, chan, eta, phi, layer)) { + if (layer == m_coreOverlap) { + LVL1::JetElement* je = findJetElement(eta, phi); + if ( ! je ) { // create new jet element + const unsigned int key = m_elementKey->jeKey(phi, eta); + je = new LVL1::JetElement(phi, eta, dummy, dummy, key, + dummy, dummy, dummy, trigJem); + m_jeMap.insert(std::make_pair(key, je)); + m_jeCollection->push_back(je); + } else { + const std::vector<int>& emEnergy(je->emEnergyVec()); + const std::vector<int>& hadEnergy(je->hadEnergyVec()); + const std::vector<int>& emError(je->emErrorVec()); + const std::vector<int>& hadError(je->hadErrorVec()); + const int nsl = emEnergy.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (emEnergy[slice] != 0 || hadEnergy[slice] != 0 || + emError[slice] != 0 || hadError[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + } + LVL1::DataError emErrBits(ssError); + LVL1::DataError hadErrBits(ssError); + const int linkError = jetEle.linkError(); + emErrBits.set(LVL1::DataError::Parity, jetEle.emParity()); + emErrBits.set(LVL1::DataError::LinkDown, linkError); + hadErrBits.set(LVL1::DataError::Parity, jetEle.hadParity()); + hadErrBits.set(LVL1::DataError::LinkDown, linkError >> 1); + je->addSlice(slice, jetEle.emData(), jetEle.hadData(), + emErrBits.error(), hadErrBits.error(), + linkError); + } + } else if (verbose && jetEle.data()) { + msg(MSG::VERBOSE) << "Non-zero data but no channel mapping for channel " + << chan << endreq; + msg(MSG::DEBUG); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No jet element data for channel " + << chan << " slice " << slice << endreq; + msg(MSG::DEBUG); + } + } + } else if (collection == JET_HITS) { + + // Get jet hits + + const unsigned int hits = subBlock->jetHits(slice); + if (hits) { + LVL1::JEMHits* jh = findJetHits(crate, module); + if ( ! jh ) { // create new jet hits + m_hitsVec.assign(timeslices, 0); + m_hitsVec[slice] = hits; + jh = new LVL1::JEMHits(swCrate, module, m_hitsVec, trigJem); + m_hitsMap.insert(std::make_pair(crate*m_modules+module, jh)); + m_hitCollection->push_back(jh); + } else { + m_hitsVec = jh->JetHitsVec(); + const int nsl = m_hitsVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec[slice] = hits; + jh->addJetHits(m_hitsVec); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No jet hits data for crate/module/slice " + << hwCrate << "/" << module << "/" << slice + << endreq; + msg(MSG::DEBUG); + } + } else if (collection == ENERGY_SUMS) { + + // Get energy subsums + + const unsigned int ex = subBlock->ex(slice); + const unsigned int ey = subBlock->ey(slice); + const unsigned int et = subBlock->et(slice); + if (ex | ey | et) { + LVL1::JEMEtSums* sums = findEnergySums(crate, module); + if ( ! sums ) { // create new energy sums + m_exVec.assign(timeslices, 0); + m_eyVec.assign(timeslices, 0); + m_etVec.assign(timeslices, 0); + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + sums = new LVL1::JEMEtSums(swCrate, module, m_etVec, m_exVec, m_eyVec, + trigJem); + m_etMap.insert(std::make_pair(crate*m_modules+module, sums)); + m_etCollection->push_back(sums); + } else { + m_exVec = sums->ExVec(); + m_eyVec = sums->EyVec(); + m_etVec = sums->EtVec(); + const int nsl = m_exVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_exVec[slice] != 0 || m_eyVec[slice] != 0 || m_etVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + sums->addEx(m_exVec); + sums->addEy(m_eyVec); + sums->addEt(m_etVec); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No energy sums data for crate/module/slice " + << hwCrate << "/" << module << "/" << slice + << endreq; + msg(MSG::DEBUG); + } + } + } + return; +} + +// Find a jet element given eta, phi + +LVL1::JetElement* JepByteStreamTool::findJetElement(const double eta, + const double phi) +{ + LVL1::JetElement* tt = 0; + const unsigned int key = m_elementKey->jeKey(phi, eta); + JetElementMap::const_iterator mapIter; + mapIter = m_jeMap.find(key); + if (mapIter != m_jeMap.end()) tt = mapIter->second; + return tt; +} + +// Find jet hits for given crate, module + +LVL1::JEMHits* JepByteStreamTool::findJetHits(const int crate, + const int module) +{ + LVL1::JEMHits* hits = 0; + JetHitsMap::const_iterator mapIter; + mapIter = m_hitsMap.find(crate*m_modules + module); + if (mapIter != m_hitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find energy sums for given crate, module + +LVL1::JEMEtSums* JepByteStreamTool::findEnergySums(const int crate, + const int module) +{ + LVL1::JEMEtSums* sums = 0; + EnergySumsMap::const_iterator mapIter; + mapIter = m_etMap.find(crate*m_modules + module); + if (mapIter != m_etMap.end()) sums = mapIter->second; + return sums; +} + +// Find CMM hits for given crate, dataID + +LVL1::CMMJetHits* JepByteStreamTool::findCmmHits(const int crate, + const int dataID) +{ + LVL1::CMMJetHits* hits = 0; + CmmHitsMap::const_iterator mapIter; + mapIter = m_cmmHitsMap.find(crate*100 + dataID); + if (mapIter != m_cmmHitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find CMM energy sums for given crate, module, dataID + +LVL1::CMMEtSums* JepByteStreamTool::findCmmSums(const int crate, + const int dataID) +{ + LVL1::CMMEtSums* sums = 0; + CmmSumsMap::const_iterator mapIter; + mapIter = m_cmmEtMap.find(crate*100 + dataID); + if (mapIter != m_cmmEtMap.end()) sums = mapIter->second; + return sums; +} + +// Set up jet element map + +void JepByteStreamTool::setupJeMap(const JetElementCollection* + const jeCollection) +{ + m_jeMap.clear(); + if (jeCollection) { + JetElementCollection::const_iterator pos = jeCollection->begin(); + JetElementCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JetElement* const je = *pos; + const unsigned int key = m_elementKey->jeKey(je->phi(), je->eta()); + m_jeMap.insert(std::make_pair(key, je)); + } + } +} + +// Set up jet hits map + +void JepByteStreamTool::setupHitsMap(const JetHitsCollection* + const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + JetHitsCollection::const_iterator pos = hitCollection->begin(); + JetHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JEMHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = m_modules * crate + hits->module(); + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up energy sums map + +void JepByteStreamTool::setupEtMap(const EnergySumsCollection* + const etCollection) +{ + m_etMap.clear(); + if (etCollection) { + EnergySumsCollection::const_iterator pos = etCollection->begin(); + EnergySumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JEMEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = m_modules * crate + sums->module(); + m_etMap.insert(std::make_pair(key, sums)); + } + } +} + +// Set up CMM hits map + +void JepByteStreamTool::setupCmmHitsMap(const CmmHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmHitsCollection::const_iterator pos = hitCollection->begin(); + CmmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMMJetHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = crate*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM energy sums map + +void JepByteStreamTool::setupCmmEtMap(const CmmSumsCollection* + const etCollection) +{ + m_cmmEtMap.clear(); + if (etCollection) { + CmmSumsCollection::const_iterator pos = etCollection->begin(); + CmmSumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMMEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = crate*100 + sums->dataID(); + m_cmmEtMap.insert(std::make_pair(key, sums)); + } + } +} + +// Get number of slices and triggered slice offset for next slink + +bool JepByteStreamTool::slinkSlices(const int crate, const int module, + const int modulesPerSlink, int& timeslices, int& trigJem) +{ + int slices = -1; + int trigJ = m_dfltSlices/2; + for (int mod = module; mod < module + modulesPerSlink; ++mod) { + for (int chan = 0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if ( !m_jemMaps->mapping(crate, mod, chan, eta, phi, layer)) continue; + const LVL1::JetElement* const je = findJetElement(eta, phi); + if ( !je ) continue; + const int numdat = 5; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((je->emEnergyVec()).begin(), + (je->emEnergyVec()).end(), 0); + sums[1] = std::accumulate((je->hadEnergyVec()).begin(), + (je->hadEnergyVec()).end(), 0); + sums[2] = std::accumulate((je->emErrorVec()).begin(), + (je->emErrorVec()).end(), 0); + sums[3] = std::accumulate((je->hadErrorVec()).begin(), + (je->hadErrorVec()).end(), 0); + sums[4] = std::accumulate((je->linkErrorVec()).begin(), + (je->linkErrorVec()).end(), 0); + sizes[0] = (je->emEnergyVec()).size(); + sizes[1] = (je->hadEnergyVec()).size(); + sizes[2] = (je->emErrorVec()).size(); + sizes[3] = (je->hadErrorVec()).size(); + sizes[4] = (je->linkErrorVec()).size(); + const int peak = je->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + const LVL1::JEMHits* const hits = findJetHits(crate, mod); + if (hits) { + const unsigned int sum = std::accumulate((hits->JetHitsVec()).begin(), + (hits->JetHitsVec()).end(), 0); + if (sum) { + const int size = (hits->JetHitsVec()).size(); + const int peak = hits->peak(); + if (slices < 0) { + slices = size; + trigJ = peak; + } else if (slices != size || trigJ != peak) return false; + } + } + const LVL1::JEMEtSums* const et = findEnergySums(crate, mod); + if (et) { + const int numdat = 3; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((et->ExVec()).begin(), + (et->ExVec()).end(), 0); + sums[1] = std::accumulate((et->EyVec()).begin(), + (et->EyVec()).end(), 0); + sums[2] = std::accumulate((et->EtVec()).begin(), + (et->EtVec()).end(), 0); + sizes[0] = (et->ExVec()).size(); + sizes[1] = (et->EyVec()).size(); + sizes[2] = (et->EtVec()).size(); + const int peak = et->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + } + // CMM last slink of crate + if (module/modulesPerSlink == m_slinks - 1) { + const int maxDataID1 = LVL1::CMMJetHits::MAXID; + const int maxDataID2 = LVL1::CMMEtSums::MAXID; + const int maxDataID = (maxDataID1 > maxDataID2) ? maxDataID1 : maxDataID2; + for (int dataID = 0; dataID < maxDataID; ++dataID) { + const int numdat = 6; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + const LVL1::CMMJetHits* hits = 0; + if (dataID < maxDataID1) hits = findCmmHits(crate, dataID); + if (hits) { + sums[0] = std::accumulate((hits->HitsVec()).begin(), + (hits->HitsVec()).end(), 0); + sums[1] = std::accumulate((hits->ErrorVec()).begin(), + (hits->ErrorVec()).end(), 0); + sizes[0] = (hits->HitsVec()).size(); + sizes[1] = (hits->ErrorVec()).size(); + const int peak = hits->peak(); + for (int i = 0; i < 2; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + const LVL1::CMMEtSums* et = 0; + if (dataID < maxDataID2) et = findCmmSums(crate, dataID); + if (et) { + sums[0] = std::accumulate((et->ExVec()).begin(), + (et->ExVec()).end(), 0); + sums[1] = std::accumulate((et->EyVec()).begin(), + (et->EyVec()).end(), 0); + sums[2] = std::accumulate((et->EtVec()).begin(), + (et->EtVec()).end(), 0); + sums[3] = std::accumulate((et->ExErrorVec()).begin(), + (et->ExErrorVec()).end(), 0); + sums[4] = std::accumulate((et->EyErrorVec()).begin(), + (et->EyErrorVec()).end(), 0); + sums[5] = std::accumulate((et->EtErrorVec()).begin(), + (et->EtErrorVec()).end(), 0); + sizes[0] = (et->ExVec()).size(); + sizes[1] = (et->EyVec()).size(); + sizes[2] = (et->EtVec()).size(); + sizes[3] = (et->ExErrorVec()).size(); + sizes[4] = (et->EyErrorVec()).size(); + sizes[5] = (et->EtErrorVec()).size(); + const int peak = et->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + } + } + if (slices < 0) slices = m_dfltSlices; + timeslices = slices; + trigJem = trigJ; + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamTool.h new file mode 100755 index 0000000000000000000000000000000000000000..8e307e6ec5e60f3f23278fb880a24989a7d804ab --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamTool.h @@ -0,0 +1,240 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPBYTESTREAMTOOL_H +#define TRIGT1CALOBYTESTREAM_JEPBYTESTREAMTOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <class T> class FullEventAssembler; + +namespace LVL1 { + class CMMJetHits; + class CMMEtSums; + class IL1CaloMappingTool; + class JEMHits; + class JEMEtSums; + class JEPBSCollection; + class JetElement; + class JetElementKey; +} + +namespace LVL1BS { + +class CmmEnergySubBlock; +class CmmJetSubBlock; +class JemSubBlock; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to jet elements, jet hits and energy sums, + * and JEP container to raw data conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class JepByteStreamTool : public AthAlgTool { + + public: + JepByteStreamTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~JepByteStreamTool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to jet elements + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JetElement>* jeCollection); + /// Convert ROB fragments to jet hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMHits>* hitCollection); + /// Convert ROB fragments to energy sums + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMEtSums>* etCollection); + /// Convert ROB fragments to CMM jet hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMJetHits>* hitCollection); + /// Convert ROB fragments to CMM energy sums + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMEtSums>* etCollection); + + /// Convert JEP Container to bytestream + StatusCode convert(const LVL1::JEPBSCollection* jep, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + enum CollectionType { JET_ELEMENTS, JET_HITS, ENERGY_SUMS, + CMM_HITS, CMM_SUMS }; + + typedef DataVector<LVL1::JetElement> JetElementCollection; + typedef DataVector<LVL1::JEMHits> JetHitsCollection; + typedef DataVector<LVL1::JEMEtSums> EnergySumsCollection; + typedef DataVector<LVL1::CMMJetHits> CmmHitsCollection; + typedef DataVector<LVL1::CMMEtSums> CmmSumsCollection; + typedef std::map<unsigned int, LVL1::JetElement*> JetElementMap; + typedef std::map<int, LVL1::JEMHits*> JetHitsMap; + typedef std::map<int, LVL1::JEMEtSums*> EnergySumsMap; + typedef std::map<int, LVL1::CMMJetHits*> CmmHitsMap; + typedef std::map<int, LVL1::CMMEtSums*> CmmSumsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + /// Unpack CMM-Energy sub-block + void decodeCmmEnergy(CmmEnergySubBlock* subBlock, int trigCmm); + /// Unpack CMM-Jet sub-block + void decodeCmmJet(CmmJetSubBlock* subBlock, int trigCmm); + /// Unpack JEM sub-block + void decodeJem(JemSubBlock* subBlock, int trigJem, + CollectionType collection); + + /// Find a jet element given eta, phi + LVL1::JetElement* findJetElement(double eta, double phi); + /// Find jet hits for given crate, module + LVL1::JEMHits* findJetHits(int crate, int module); + /// Find energy sums for given crate, module + LVL1::JEMEtSums* findEnergySums(int crate, int module); + /// Find CMM hits for given crate, data ID + LVL1::CMMJetHits* findCmmHits(int crate, int dataID); + /// Find CMM energy sums for given crate, data ID + LVL1::CMMEtSums* findCmmSums(int crate, int dataID); + + /// Set up jet element map + void setupJeMap(const JetElementCollection* jeCollection); + /// Set up jet hits map + void setupHitsMap(const JetHitsCollection* hitCollection); + /// Set up energy sums map + void setupEtMap(const EnergySumsCollection* enCollection); + /// Set up CMM hits map + void setupCmmHitsMap(const CmmHitsCollection* hitCollection); + /// Set up CMM energy sums map + void setupCmmEtMap(const CmmSumsCollection* enCollection); + + /// Get number of slices and triggered slice offset for next slink + bool slinkSlices(int crate, int module, int modulesPerSlink, + int& timeslices, int& trigJem); + + /// Channel mapping tool + ToolHandle<LVL1::IL1CaloMappingTool> m_jemMaps; + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of channels per module + int m_channels; + /// Number of crates + int m_crates; + /// Number of JEM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Default number of slices in simulation + int m_dfltSlices; + /// Force number of slices in bytestream + int m_forceSlices; + /// Jet elements to accept (0=Core, 1=Overlap) + int m_coreOverlap; + /// Unpacking error code + unsigned int m_rodErr; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Jet element key provider + LVL1::JetElementKey* m_elementKey; + /// JemSubBlock for unpacking + JemSubBlock* m_jemSubBlock; + /// CmmEnergySubBlock for unpacking + CmmEnergySubBlock* m_cmmEnergySubBlock; + /// CmmJetSubBlock for unpacking + CmmJetSubBlock* m_cmmJetSubBlock; + /// Ex vector for unpacking + std::vector<unsigned int> m_exVec; + /// Ey vector for unpacking + std::vector<unsigned int> m_eyVec; + /// Et vector for unpacking + std::vector<unsigned int> m_etVec; + /// Ex error vector for unpacking + std::vector<int> m_exErrVec; + /// Ex error vector for unpacking + std::vector<int> m_eyErrVec; + /// Ex error vector for unpacking + std::vector<int> m_etErrVec; + /// Hits vector for unpacking + std::vector<unsigned int> m_hitsVec; + /// Error vector for unpacking + std::vector<int> m_errVec; + /// Vector for current JEM sub-blocks + DataVector<JemSubBlock> m_jemBlocks; + /// Vector for current CMM-Energy sub-blocks + DataVector<CmmEnergySubBlock> m_cmmEnergyBlocks; + /// Vector for current CMM-Jet sub-blocks + DataVector<CmmJetSubBlock> m_cmmJetBlocks; + /// Current jet elements collection + JetElementCollection* m_jeCollection; + /// Current jet hits collection + JetHitsCollection* m_hitCollection; + /// Current energy sums collection + EnergySumsCollection* m_etCollection; + /// Current CMM hits collection + CmmHitsCollection* m_cmmHitCollection; + /// Current CMM energy sums collection + CmmSumsCollection* m_cmmEtCollection; + /// Jet element map + JetElementMap m_jeMap; + /// Jet hits map + JetHitsMap m_hitsMap; + /// Energy sums map + EnergySumsMap m_etMap; + /// CMM hits map + CmmHitsMap m_cmmHitsMap; + /// CMM energy sums map + CmmSumsMap m_cmmEtMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..338d7784d7d51a1e739123eb2d04d1506b5ce1f5 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Cnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/JEPBSCollectionV1.h" + +#include "JepByteStreamV1Cnv.h" +#include "JepByteStreamV1Tool.h" + +namespace LVL1BS { + +JepByteStreamV1Cnv::JepByteStreamV1Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepByteStreamV1Cnv"), + m_tool("LVL1BS::JepByteStreamV1Tool/JepByteStreamV1Tool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +JepByteStreamV1Cnv::~JepByteStreamV1Cnv() +{ +} + +// CLID + +const CLID& JepByteStreamV1Cnv::classID() +{ + return ClassID_traits<LVL1::JEPBSCollectionV1>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepByteStreamV1Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode JepByteStreamV1Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::JEPBSCollectionV1* jep = 0; + if( !SG::fromStorable( pObj, jep ) ) { + m_log << MSG::ERROR << " Cannot cast to JEPBSCollectionV1" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( jep, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..cb2fa92759d1043032ee79283b755206815e9728 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Cnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV1CNV_H +#define TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV1CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepByteStreamV1Tool; + +/** ByteStream converter for JEP container + * + * @author Peter Faulkner + */ + +class JepByteStreamV1Cnv: public Converter { + + friend class CnvFactory<JepByteStreamV1Cnv>; + +protected: + + JepByteStreamV1Cnv(ISvcLocator* svcloc); + +public: + + ~JepByteStreamV1Cnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from JEP Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepByteStreamV1Tool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..18c93477c36290bb224559da760e53eab1f08006 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Tool.cxx @@ -0,0 +1,1741 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/JEMHits.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JEPBSCollectionV1.h" +#include "TrigT1CaloEvent/JetElement.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/JetElementKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "CmmEnergySubBlock.h" +#include "CmmJetSubBlock.h" +#include "CmmSubBlock.h" +#include "JemJetElement.h" +#include "JemSubBlockV1.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "ModifySlices.h" + +#include "JepByteStreamV1Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IJepByteStreamV1Tool("JepByteStreamV1Tool", 1, 1); + +const InterfaceID& JepByteStreamV1Tool::interfaceID() +{ + return IID_IJepByteStreamV1Tool; +} + +// Constructor + +JepByteStreamV1Tool::JepByteStreamV1Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_jemMaps("LVL1::JemMappingTool/JemMappingTool"), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_channels(44), m_crates(2), m_modules(16), m_coreOverlap(0), + m_subDetector(eformat::TDAQ_CALO_JET_PROC_DAQ), + m_srcIdMap(0), m_elementKey(0), + m_jemSubBlock(0), m_cmmEnergySubBlock(0), m_cmmJetSubBlock(0), + m_rodStatus(0), m_fea(0) +{ + declareInterface<JepByteStreamV1Tool>(this); + + declareProperty("JemMappingTool", m_jemMaps, + "Crate/Module/Channel to Eta/Phi/Layer mapping tool"); + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 12, + "Offset of JEP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of JEP crate numbers in RDOs"); + declareProperty("SlinksPerCrate", m_slinks = 4, + "The number of S-Links per crate"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SimulSlices", m_dfltSlices = 1, + "The number of slices in the simulation"); + declareProperty("ForceSlices", m_forceSlices = 0, + "If >0, the number of slices in bytestream"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +JepByteStreamV1Tool::~JepByteStreamV1Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepByteStreamV1Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_jemMaps.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_jemMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_jemMaps << endreq; + + sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_elementKey = new LVL1::JetElementKey(); + m_jemSubBlock = new JemSubBlockV1(); + m_cmmEnergySubBlock = new CmmEnergySubBlock(); + m_cmmJetSubBlock = new CmmJetSubBlock(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JepByteStreamV1Tool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_cmmJetSubBlock; + delete m_cmmEnergySubBlock; + delete m_jemSubBlock; + delete m_elementKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to jet elements + +StatusCode JepByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JetElement>* const jeCollection) +{ + m_jeCollection = jeCollection; + m_jeMap.clear(); + return convertBs(robFrags, JET_ELEMENTS); +} + +// Conversion bytestream to jet hits + +StatusCode JepByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMHits>* const hitCollection) +{ + m_hitCollection = hitCollection; + m_hitsMap.clear(); + return convertBs(robFrags, JET_HITS); +} + +// Conversion bytestream to energy sums + +StatusCode JepByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMEtSums>* const etCollection) +{ + m_etCollection = etCollection; + m_etMap.clear(); + return convertBs(robFrags, ENERGY_SUMS); +} + +// Conversion bytestream to CMM hits + +StatusCode JepByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMJetHits>* const hitCollection) +{ + m_cmmHitCollection = hitCollection; + m_cmmHitsMap.clear(); + return convertBs(robFrags, CMM_HITS); +} + +// Conversion bytestream to CMM energy sums + +StatusCode JepByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMEtSums>* const etCollection) +{ + m_cmmEtCollection = etCollection; + m_cmmEtMap.clear(); + return convertBs(robFrags, CMM_SUMS); +} + +// Conversion of JEP container to bytestream + +StatusCode JepByteStreamV1Tool::convert(const LVL1::JEPBSCollectionV1* const jep, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersionPreLS1(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + setupJeMap(jep->JetElements()); + setupHitsMap(jep->JetHits()); + setupEtMap(jep->EnergySums()); + setupCmmHitsMap(jep->CmmHits()); + setupCmmEtMap(jep->CmmSums()); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + int timeslices = 1; + int trigJem = 0; + int timeslicesNew = 1; + int trigJemNew = 0; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + for (int module=0; module < m_modules; ++module) { + + // Pack required number of modules per slink + + if (module%modulesPerSlink == 0) { + const int daqOrRoi = 0; + const int slink = module/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq; + } + // Get number of JEM slices and triggered slice offset + // for this slink + if ( ! slinkSlices(crate, module, modulesPerSlink, + timeslices, trigJem)) { + msg(MSG::ERROR) << "Inconsistent number of slices or " + << "triggered slice offsets in data for crate " + << hwCrate << " slink " << slink << endreq; + return StatusCode::FAILURE; + } + timeslicesNew = (m_forceSlices) ? m_forceSlices : timeslices; + trigJemNew = ModifySlices::peak(trigJem, timeslices, timeslicesNew); + if (debug) { + msg() << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq + << "Slices/offset: " << timeslices << " " << trigJem; + if (timeslices != timeslicesNew) { + msg() << " modified to " << timeslicesNew << " " << trigJemNew; + } + msg() << endreq; + } + L1CaloUserHeader userHeader; + userHeader.setJem(trigJemNew); + const uint32_t rodIdJem = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdJem); + theROD->push_back(userHeader.header()); + m_rodStatusMap.insert(make_pair(rodIdJem, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block for each slice (except Neutral format) + + m_jemBlocks.clear(); + for (int slice = 0; slice < timeslicesNew; ++slice) { + JemSubBlockV1* const subBlock = new JemSubBlockV1(); + subBlock->setJemHeader(m_version, m_dataFormat, slice, + hwCrate, module, timeslicesNew); + m_jemBlocks.push_back(subBlock); + if (neutralFormat) break; + } + + // Find jet elements corresponding to each eta/phi pair and fill + // sub-blocks + + for (int chan=0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_jemMaps->mapping(crate, module, chan, eta, phi, layer)) { + const LVL1::JetElement* const je = findJetElement(eta, phi); + if (je ) { + std::vector<int> emData; + std::vector<int> hadData; + std::vector<int> emErrors; + std::vector<int> hadErrors; + ModifySlices::data(je->emEnergyVec(), emData, timeslicesNew); + ModifySlices::data(je->hadEnergyVec(), hadData, timeslicesNew); + ModifySlices::data(je->emErrorVec(), emErrors, timeslicesNew); + ModifySlices::data(je->hadErrorVec(), hadErrors, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError emErrBits(emErrors[slice]); + const LVL1::DataError hadErrBits(hadErrors[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlockV1* const subBlock = m_jemBlocks[index]; + const JemJetElement jetEle(chan, emData[slice], hadData[slice], + emErrBits.get(LVL1::DataError::Parity), + hadErrBits.get(LVL1::DataError::Parity), + emErrBits.get(LVL1::DataError::LinkDown) + + (hadErrBits.get(LVL1::DataError::LinkDown) << 1)); + subBlock->fillJetElement(slice, jetEle); + } + } + } + } + + // Add jet hits and energy subsums + + const LVL1::JEMHits* const hits = findJetHits(crate, module); + if (hits) { + std::vector<unsigned int> vec; + ModifySlices::data(hits->JetHitsVec(), vec, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlockV1* const subBlock = m_jemBlocks[index]; + subBlock->setJetHits(slice, vec[slice]); + } + } + const LVL1::JEMEtSums* const et = findEnergySums(crate, module); + if (et) { + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + ModifySlices::data(et->ExVec(), exVec, timeslicesNew); + ModifySlices::data(et->EyVec(), eyVec, timeslicesNew); + ModifySlices::data(et->EtVec(), etVec, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlockV1* const subBlock = m_jemBlocks[index]; + subBlock->setEnergySubsums(slice, exVec[slice], eyVec[slice], + etVec[slice]); + } + } + + // Pack and write the sub-blocks + + DataVector<JemSubBlockV1>::const_iterator pos; + for (pos = m_jemBlocks.begin(); pos != m_jemBlocks.end(); ++pos) { + JemSubBlockV1* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "JEM sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "JEM sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Append CMMs to last S-Link of the crate + + // Create a sub-block for each slice (except Neutral format) + + m_cmmEnergyBlocks.clear(); + m_cmmJetBlocks.clear(); + const int summing = (crate == m_crates - 1) ? CmmSubBlock::SYSTEM + : CmmSubBlock::CRATE; + for (int slice = 0; slice < timeslicesNew; ++slice) { + CmmEnergySubBlock* const enBlock = new CmmEnergySubBlock(); + const int cmmEnergyVersion = 2; // with Missing-ET-Sig + enBlock->setCmmHeader(cmmEnergyVersion, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_ENERGY, + CmmSubBlock::LEFT, timeslicesNew); + m_cmmEnergyBlocks.push_back(enBlock); + CmmJetSubBlock* const jetBlock = new CmmJetSubBlock(); + jetBlock->setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmmSubBlock::CMM_JET, + CmmSubBlock::RIGHT, timeslicesNew); + m_cmmJetBlocks.push_back(jetBlock); + if (neutralFormat) break; + } + + // CMM-Energy + + int maxDataID = static_cast<int>(LVL1::CMMEtSums::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + if (summing == CmmSubBlock::CRATE && + dataID != LVL1::CMMEtSums::LOCAL) continue; + switch (dataID) { + case LVL1::CMMEtSums::LOCAL: + source = CmmEnergySubBlock::LOCAL; + break; + case LVL1::CMMEtSums::REMOTE: + source = CmmEnergySubBlock::REMOTE; + break; + case LVL1::CMMEtSums::TOTAL: + source = CmmEnergySubBlock::TOTAL; + break; + case LVL1::CMMEtSums::MISSING_ET_MAP: + case LVL1::CMMEtSums::SUM_ET_MAP: + case LVL1::CMMEtSums::MISSING_ET_SIG_MAP: + break; + default: + continue; + } + } + const LVL1::CMMEtSums* const sums = findCmmSums(crate, dataID); + if ( sums ) { + std::vector<unsigned int> ex; + std::vector<unsigned int> ey; + std::vector<unsigned int> et; + std::vector<int> exErr; + std::vector<int> eyErr; + std::vector<int> etErr; + ModifySlices::data(sums->ExVec(), ex, timeslicesNew); + ModifySlices::data(sums->EyVec(), ey, timeslicesNew); + ModifySlices::data(sums->EtVec(), et, timeslicesNew); + ModifySlices::data(sums->ExErrorVec(), exErr, timeslicesNew); + ModifySlices::data(sums->EyErrorVec(), eyErr, timeslicesNew); + ModifySlices::data(sums->EtErrorVec(), etErr, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError exErrBits(exErr[slice]); + const LVL1::DataError eyErrBits(eyErr[slice]); + const LVL1::DataError etErrBits(etErr[slice]); + int exError = exErrBits.get(LVL1::DataError::Parity); + int eyError = eyErrBits.get(LVL1::DataError::Parity); + int etError = etErrBits.get(LVL1::DataError::Parity); + if (dataID == LVL1::CMMEtSums::LOCAL || + dataID == LVL1::CMMEtSums::REMOTE || + dataID == LVL1::CMMEtSums::TOTAL) { + exError = (exError << 1) + exErrBits.get(LVL1::DataError::Overflow); + eyError = (eyError << 1) + eyErrBits.get(LVL1::DataError::Overflow); + etError = (etError << 1) + etErrBits.get(LVL1::DataError::Overflow); + } + const int index = ( neutralFormat ) ? 0 : slice; + CmmEnergySubBlock* const subBlock = m_cmmEnergyBlocks[index]; + if (dataID == LVL1::CMMEtSums::MISSING_ET_MAP) { + subBlock->setMissingEtHits(slice, et[slice]); + } else if (dataID == LVL1::CMMEtSums::SUM_ET_MAP) { + subBlock->setSumEtHits(slice, et[slice]); + } else if (dataID == LVL1::CMMEtSums::MISSING_ET_SIG_MAP) { + subBlock->setMissingEtSigHits(slice, et[slice]); + } else { + subBlock->setSubsums(slice, source, + ex[slice], ey[slice], et[slice], + exError, eyError, etError); + } + } + } + } + DataVector<CmmEnergySubBlock>::const_iterator pos; + pos = m_cmmEnergyBlocks.begin(); + for (; pos != m_cmmEnergyBlocks.end(); ++pos) { + CmmEnergySubBlock* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Energy sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Energy sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + + // CMM-Jet + + maxDataID = static_cast<int>(LVL1::CMMJetHits::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + if (summing == CmmSubBlock::CRATE && + dataID != LVL1::CMMJetHits::LOCAL_MAIN && + dataID != LVL1::CMMJetHits::LOCAL_FORWARD) continue; + switch (dataID) { + case LVL1::CMMJetHits::LOCAL_MAIN: + source = CmmJetSubBlock::LOCAL_MAIN; + break; + case LVL1::CMMJetHits::REMOTE_MAIN: + source = CmmJetSubBlock::REMOTE_MAIN; + break; + case LVL1::CMMJetHits::TOTAL_MAIN: + source = CmmJetSubBlock::TOTAL_MAIN; + break; + case LVL1::CMMJetHits::LOCAL_FORWARD: + source = CmmJetSubBlock::LOCAL_FORWARD; + break; + case LVL1::CMMJetHits::REMOTE_FORWARD: + source = CmmJetSubBlock::REMOTE_FORWARD; + break; + case LVL1::CMMJetHits::TOTAL_FORWARD: + source = CmmJetSubBlock::TOTAL_FORWARD; + break; + case LVL1::CMMJetHits::ET_MAP: + break; + default: + continue; + } + } + const LVL1::CMMJetHits* const ch = findCmmHits(crate, dataID); + if ( ch ) { + std::vector<unsigned int> hits; + std::vector<int> errs; + ModifySlices::data(ch->HitsVec(), hits, timeslicesNew); + ModifySlices::data(ch->ErrorVec(), errs, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError errBits(errs[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + CmmJetSubBlock* const subBlock = m_cmmJetBlocks[index]; + if (dataID == LVL1::CMMJetHits::ET_MAP) { + subBlock->setJetEtMap(slice, hits[slice]); + } else { + subBlock->setJetHits(slice, source, hits[slice], + errBits.get(LVL1::DataError::Parity)); + } + } + } + } + DataVector<CmmJetSubBlock>::const_iterator jos; + jos = m_cmmJetBlocks.begin(); + for (; jos != m_cmmJetBlocks.end(); ++jos) { + CmmJetSubBlock* const subBlock = *jos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMM-Jet sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Jet sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& JepByteStreamV1Tool::sourceIDs( + const std::string& sgKey) +{ + // Check if overlap jet element channels wanted + const std::string flag("Overlap"); + const std::string::size_type pos = sgKey.find(flag); + m_coreOverlap = + (pos == std::string::npos || pos != sgKey.length() - flag.length()) ? 0 : 1; + + if (m_sourceIDs.empty()) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 0; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + m_sourceIDs.push_back(robId); + } + } + } + return m_sourceIDs; +} + +// Convert bytestream to given container type + +StatusCode JepByteStreamV1Tool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0 || + m_srcIdMap->slink(sourceID) >= m_slinks || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: ROD " + << MSG::hex << sourceID << " ROB " << robid + << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion > m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping post-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word should be User Header + if ( !L1CaloUserHeader::isValid(*payload) ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Invalid or missing user header" << endreq; + continue; + } + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + // triggered slice offsets + int trigJem = userHeader.jem(); + int trigCmm = userHeader.jepCmm(); + if (debug) { + msg() << "Minor format version number: " << MSG::hex + << minorVersion << MSG::dec << endreq + << "JEM triggered slice offset: " << trigJem << endreq + << "CMM triggered slice offset: " << trigCmm << endreq; + } + if (trigJem != trigCmm) { + const int newTrig = (trigJem > trigCmm) ? trigJem : trigCmm; + trigJem = newTrig; + trigCmm = newTrig; + if (debug) msg() << "Changed both offsets to " << newTrig << endreq; + } + + // Loop over sub-blocks + + m_rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER) { + if (debug) msg() << "Unexpected data sequence" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MISSING_HEADER; + break; + } + if (CmmSubBlock::cmmBlock(*payload)) { + // CMMs + if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_JET) { + m_cmmJetSubBlock->clear(); + payload = m_cmmJetSubBlock->read(payload, payloadEnd); + if (m_cmmJetSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMM_HITS) { + decodeCmmJet(m_cmmJetSubBlock, trigCmm); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmmJet failed" << endreq; + break; + } + } + } else if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_ENERGY) { + m_cmmEnergySubBlock->clear(); + payload = m_cmmEnergySubBlock->read(payload, payloadEnd); + if (m_cmmEnergySubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMM_SUMS) { + decodeCmmEnergy(m_cmmEnergySubBlock, trigCmm); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmmEnergy failed" << endreq; + break; + } + } + } else { + if (debug) msg() << "Invalid CMM type in module field" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + } else { + // JEM + m_jemSubBlock->clear(); + payload = m_jemSubBlock->read(payload, payloadEnd); + if (m_jemSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == JET_ELEMENTS || collection == JET_HITS || + collection == ENERGY_SUMS) { + decodeJem(m_jemSubBlock, trigJem, collection); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeJem failed" << endreq; + break; + } + } + } + } + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, m_rodErr); + } + + return StatusCode::SUCCESS; +} + +// Unpack CMM-Energy sub-block + +void JepByteStreamV1Tool::decodeCmmEnergy(CmmEnergySubBlock* subBlock, + int trigCmm) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmmPosition(); + const int firmware = subBlock->cmmFirmware(); + const int summing = subBlock->cmmSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMM-Energy: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigCmm) { + if (debug) msg() << "Triggered CMM slice from header " + << "inconsistent with number of slices: " + << trigCmm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMM-Energy sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSid = static_cast<int>(CmmEnergySubBlock::MAX_SOURCE_ID); + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Energy sums + + for (int source = 0; source < maxSid; ++source) { + int dataID = source; + if (source >= m_modules) { + if (summing == CmmSubBlock::CRATE && + source != CmmEnergySubBlock::LOCAL) continue; + switch (source) { + case CmmEnergySubBlock::LOCAL: + dataID = LVL1::CMMEtSums::LOCAL; + break; + case CmmEnergySubBlock::REMOTE: + dataID = LVL1::CMMEtSums::REMOTE; + break; + case CmmEnergySubBlock::TOTAL: + dataID = LVL1::CMMEtSums::TOTAL; + break; + default: + continue; + } + } + const unsigned int ex = subBlock->ex(slice, source); + const unsigned int ey = subBlock->ey(slice, source); + const unsigned int et = subBlock->et(slice, source); + int exErr = subBlock->exError(slice, source); + int eyErr = subBlock->eyError(slice, source); + int etErr = subBlock->etError(slice, source); + LVL1::DataError exErrBits(ssError); + LVL1::DataError eyErrBits(ssError); + LVL1::DataError etErrBits(ssError); + if (dataID == LVL1::CMMEtSums::LOCAL || + dataID == LVL1::CMMEtSums::REMOTE || + dataID == LVL1::CMMEtSums::TOTAL) { + exErrBits.set(LVL1::DataError::Overflow, exErr); + exErrBits.set(LVL1::DataError::Parity, exErr >> 1); + eyErrBits.set(LVL1::DataError::Overflow, eyErr); + eyErrBits.set(LVL1::DataError::Parity, eyErr >> 1); + etErrBits.set(LVL1::DataError::Overflow, etErr); + etErrBits.set(LVL1::DataError::Parity, etErr >> 1); + } else { + exErrBits.set(LVL1::DataError::Parity, exErr); + eyErrBits.set(LVL1::DataError::Parity, eyErr); + etErrBits.set(LVL1::DataError::Parity, etErr); + } + exErr = exErrBits.error(); + eyErr = eyErrBits.error(); + etErr = etErrBits.error(); + if (ex || ey || et || exErr || eyErr || etErr) { + LVL1::CMMEtSums* sums = findCmmSums(crate, dataID); + if ( ! sums ) { // create new CMM energy sums + m_exVec.assign(timeslices, 0); + m_eyVec.assign(timeslices, 0); + m_etVec.assign(timeslices, 0); + m_exErrVec.assign(timeslices, 0); + m_eyErrVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + m_exErrVec[slice] = exErr; + m_eyErrVec[slice] = eyErr; + m_etErrVec[slice] = etErr; + sums = new LVL1::CMMEtSums(swCrate, dataID, m_etVec, m_exVec, m_eyVec, + m_etErrVec, m_exErrVec, m_eyErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, sums)); + m_cmmEtCollection->push_back(sums); + } else { + m_exVec = sums->ExVec(); + m_eyVec = sums->EyVec(); + m_etVec = sums->EtVec(); + m_exErrVec = sums->ExErrorVec(); + m_eyErrVec = sums->EyErrorVec(); + m_etErrVec = sums->EtErrorVec(); + const int nsl = m_exVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_exVec[slice] != 0 || m_eyVec[slice] != 0 || m_etVec[slice] != 0 || + m_exErrVec[slice] != 0 || m_eyErrVec[slice] != 0 || + m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + m_exErrVec[slice] = exErr; + m_eyErrVec[slice] = eyErr; + m_etErrVec[slice] = etErr; + sums->addEx(m_exVec, m_exErrVec); + sums->addEy(m_eyVec, m_eyErrVec); + sums->addEt(m_etVec, m_etErrVec); + } + } + } + + // Hit maps - store as Et + + if (summing == CmmSubBlock::SYSTEM) { + const unsigned int missEt = subBlock->missingEtHits(slice); + if ( missEt || ssError ) { + const int dataID = LVL1::CMMEtSums::MISSING_ET_MAP; + LVL1::CMMEtSums* map = findCmmSums(crate, dataID); + if ( ! map ) { + m_etVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_etVec[slice] = missEt; + m_etErrVec[slice] = ssError; + map = new LVL1::CMMEtSums(swCrate, dataID, + m_etVec, m_etVec, m_etVec, + m_etErrVec, m_etErrVec, m_etErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, map)); + m_cmmEtCollection->push_back(map); + } else { + m_etVec = map->EtVec(); + m_etErrVec = map->EtErrorVec(); + const int nsl = m_etVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_etVec[slice] != 0 || m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_etVec[slice] = missEt; + m_etErrVec[slice] = ssError; + map->addEx(m_etVec, m_etErrVec); + map->addEy(m_etVec, m_etErrVec); + map->addEt(m_etVec, m_etErrVec); + } + } + const unsigned int sumEt = subBlock->sumEtHits(slice); + if ( sumEt || ssError ) { + const int dataID = LVL1::CMMEtSums::SUM_ET_MAP; + LVL1::CMMEtSums* map = findCmmSums(crate, dataID); + if ( ! map ) { + m_etVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_etVec[slice] = sumEt; + m_etErrVec[slice] = ssError; + map = new LVL1::CMMEtSums(swCrate, dataID, + m_etVec, m_etVec, m_etVec, + m_etErrVec, m_etErrVec, m_etErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, map)); + m_cmmEtCollection->push_back(map); + } else { + m_etVec = map->EtVec(); + m_etErrVec = map->EtErrorVec(); + const int nsl = m_etVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_etVec[slice] != 0 || m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_etVec[slice] = sumEt; + m_etErrVec[slice] = ssError; + map->addEx(m_etVec, m_etErrVec); + map->addEy(m_etVec, m_etErrVec); + map->addEt(m_etVec, m_etErrVec); + } + } + if (subBlock->version() > 1) { + const unsigned int missEtSig = subBlock->missingEtSigHits(slice); + if ( missEtSig || ssError ) { + const int dataID = LVL1::CMMEtSums::MISSING_ET_SIG_MAP; + LVL1::CMMEtSums* map = findCmmSums(crate, dataID); + if ( ! map ) { + m_etVec.assign(timeslices, 0); + m_etErrVec.assign(timeslices, 0); + m_etVec[slice] = missEtSig; + m_etErrVec[slice] = ssError; + map = new LVL1::CMMEtSums(swCrate, dataID, + m_etVec, m_etVec, m_etVec, + m_etErrVec, m_etErrVec, m_etErrVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmEtMap.insert(std::make_pair(key, map)); + m_cmmEtCollection->push_back(map); + } else { + m_etVec = map->EtVec(); + m_etErrVec = map->EtErrorVec(); + const int nsl = m_etVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_etVec[slice] != 0 || m_etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_etVec[slice] = missEtSig; + m_etErrVec[slice] = ssError; + map->addEx(m_etVec, m_etErrVec); + map->addEy(m_etVec, m_etErrVec); + map->addEt(m_etVec, m_etErrVec); + } + } + } + } + } + + return; +} + +// Unpack CMM-Jet sub-block + +void JepByteStreamV1Tool::decodeCmmJet(CmmJetSubBlock* subBlock, int trigCmm) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmmPosition(); + const int firmware = subBlock->cmmFirmware(); + const int summing = subBlock->cmmSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMM-Jet: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigCmm) { + if (debug) msg() << "Triggered CMM slice from header " + << "inconsistent with number of slices: " + << trigCmm << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMM-Jet sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSid = static_cast<int>(CmmJetSubBlock::MAX_SOURCE_ID); + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Jet hit counts + + for (int source = 0; source < maxSid; ++source) { + int dataID = source; + if (source >= m_modules) { + if (summing == CmmSubBlock::CRATE && + source != CmmJetSubBlock::LOCAL_MAIN && + source != CmmJetSubBlock::LOCAL_FORWARD) continue; + switch (source) { + case CmmJetSubBlock::LOCAL_MAIN: + dataID = LVL1::CMMJetHits::LOCAL_MAIN; + break; + case CmmJetSubBlock::REMOTE_MAIN: + dataID = LVL1::CMMJetHits::REMOTE_MAIN; + break; + case CmmJetSubBlock::TOTAL_MAIN: + dataID = LVL1::CMMJetHits::TOTAL_MAIN; + break; + case CmmJetSubBlock::LOCAL_FORWARD: + dataID = LVL1::CMMJetHits::LOCAL_FORWARD; + break; + case CmmJetSubBlock::REMOTE_FORWARD: + dataID = LVL1::CMMJetHits::REMOTE_FORWARD; + break; + case CmmJetSubBlock::TOTAL_FORWARD: + dataID = LVL1::CMMJetHits::TOTAL_FORWARD; + break; + default: + continue; + } + } + const unsigned int hits = subBlock->jetHits(slice, source); + LVL1::DataError errBits(ssError); + errBits.set(LVL1::DataError::Parity, + subBlock->jetHitsError(slice, source)); + const int err = errBits.error(); + if (hits || err) { + LVL1::CMMJetHits* jh = findCmmHits(crate, dataID); + if ( ! jh ) { // create new CMM hits + m_hitsVec.assign(timeslices, 0); + m_errVec.assign(timeslices, 0); + m_hitsVec[slice] = hits; + m_errVec[slice] = err; + jh = new LVL1::CMMJetHits(swCrate, dataID, m_hitsVec, m_errVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmHitsMap.insert(std::make_pair(key, jh)); + m_cmmHitCollection->push_back(jh); + } else { + m_hitsVec = jh->HitsVec(); + m_errVec = jh->ErrorVec(); + const int nsl = m_hitsVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec[slice] != 0 || m_errVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec[slice] = hits; + m_errVec[slice] = err; + jh->addHits(m_hitsVec, m_errVec); + } + } + } + + // Hit map - store as hits + + if (summing == CmmSubBlock::SYSTEM) { + const unsigned int etMap = subBlock->jetEtMap(slice); + if ( etMap || ssError ) { + const int dataID = LVL1::CMMJetHits::ET_MAP; + LVL1::CMMJetHits* map = findCmmHits(crate, dataID); + if ( ! map ) { + m_hitsVec.assign(timeslices, 0); + m_errVec.assign(timeslices, 0); + m_hitsVec[slice] = etMap; + m_errVec[slice] = ssError; + map = new LVL1::CMMJetHits(swCrate, dataID, m_hitsVec, m_errVec, trigCmm); + const int key = crate*100 + dataID; + m_cmmHitsMap.insert(std::make_pair(key, map)); + m_cmmHitCollection->push_back(map); + } else { + m_hitsVec = map->HitsVec(); + m_errVec = map->ErrorVec(); + const int nsl = m_hitsVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec[slice] != 0 || m_errVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec[slice] = etMap; + m_errVec[slice] = ssError; + map->addHits(m_hitsVec, m_errVec); + } + } + } + } + + return; +} + +// Unpack JEM sub-block + +void JepByteStreamV1Tool::decodeJem(JemSubBlockV1* subBlock, int trigJem, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + const bool verbose = msgLvl(MSG::VERBOSE); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->module(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "JEM: Crate " << hwCrate + << " Module " << module + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigJem) { + if (debug) msg() << "Triggered JEM slice from header " + << "inconsistent with number of slices: " + << trigJem << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "JEM sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + std::vector<int> dummy(timeslices); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + if (collection == JET_ELEMENTS) { + + // Loop over jet element channels and fill jet elements + + for (int chan = 0; chan < m_channels; ++chan) { + const JemJetElement jetEle(subBlock->jetElement(slice, chan)); + if (jetEle.data() || ssError) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_jemMaps->mapping(crate, module, chan, eta, phi, layer)) { + if (layer == m_coreOverlap) { + LVL1::JetElement* je = findJetElement(eta, phi); + if ( ! je ) { // create new jet element + const unsigned int key = m_elementKey->jeKey(phi, eta); + je = new LVL1::JetElement(phi, eta, dummy, dummy, key, + dummy, dummy, dummy, trigJem); + m_jeMap.insert(std::make_pair(key, je)); + m_jeCollection->push_back(je); + } else { + const std::vector<int>& emEnergy(je->emEnergyVec()); + const std::vector<int>& hadEnergy(je->hadEnergyVec()); + const std::vector<int>& emError(je->emErrorVec()); + const std::vector<int>& hadError(je->hadErrorVec()); + const int nsl = emEnergy.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (emEnergy[slice] != 0 || hadEnergy[slice] != 0 || + emError[slice] != 0 || hadError[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + } + LVL1::DataError emErrBits(ssError); + LVL1::DataError hadErrBits(ssError); + const int linkError = jetEle.linkError(); + emErrBits.set(LVL1::DataError::Parity, jetEle.emParity()); + emErrBits.set(LVL1::DataError::LinkDown, linkError); + hadErrBits.set(LVL1::DataError::Parity, jetEle.hadParity()); + hadErrBits.set(LVL1::DataError::LinkDown, linkError >> 1); + je->addSlice(slice, jetEle.emData(), jetEle.hadData(), + emErrBits.error(), hadErrBits.error(), + linkError); + } + } else if (verbose && jetEle.data()) { + msg(MSG::VERBOSE) << "Non-zero data but no channel mapping for channel " + << chan << endreq; + msg(MSG::DEBUG); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No jet element data for channel " + << chan << " slice " << slice << endreq; + msg(MSG::DEBUG); + } + } + } else if (collection == JET_HITS) { + + // Get jet hits + + const unsigned int hits = subBlock->jetHits(slice); + if (hits) { + LVL1::JEMHits* jh = findJetHits(crate, module); + if ( ! jh ) { // create new jet hits + m_hitsVec.assign(timeslices, 0); + m_hitsVec[slice] = hits; + jh = new LVL1::JEMHits(swCrate, module, m_hitsVec, trigJem); + m_hitsMap.insert(std::make_pair(crate*m_modules+module, jh)); + m_hitCollection->push_back(jh); + } else { + m_hitsVec = jh->JetHitsVec(); + const int nsl = m_hitsVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_hitsVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_hitsVec[slice] = hits; + jh->addJetHits(m_hitsVec); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No jet hits data for crate/module/slice " + << hwCrate << "/" << module << "/" << slice + << endreq; + msg(MSG::DEBUG); + } + } else if (collection == ENERGY_SUMS) { + + // Get energy subsums + + const unsigned int ex = subBlock->ex(slice); + const unsigned int ey = subBlock->ey(slice); + const unsigned int et = subBlock->et(slice); + if (ex | ey | et) { + LVL1::JEMEtSums* sums = findEnergySums(crate, module); + if ( ! sums ) { // create new energy sums + m_exVec.assign(timeslices, 0); + m_eyVec.assign(timeslices, 0); + m_etVec.assign(timeslices, 0); + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + sums = new LVL1::JEMEtSums(swCrate, module, m_etVec, m_exVec, m_eyVec, + trigJem); + m_etMap.insert(std::make_pair(crate*m_modules+module, sums)); + m_etCollection->push_back(sums); + } else { + m_exVec = sums->ExVec(); + m_eyVec = sums->EyVec(); + m_etVec = sums->EtVec(); + const int nsl = m_exVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (m_exVec[slice] != 0 || m_eyVec[slice] != 0 || m_etVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + m_exVec[slice] = ex; + m_eyVec[slice] = ey; + m_etVec[slice] = et; + sums->addEx(m_exVec); + sums->addEy(m_eyVec); + sums->addEt(m_etVec); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No energy sums data for crate/module/slice " + << hwCrate << "/" << module << "/" << slice + << endreq; + msg(MSG::DEBUG); + } + } + } + return; +} + +// Find a jet element given eta, phi + +LVL1::JetElement* JepByteStreamV1Tool::findJetElement(const double eta, + const double phi) +{ + LVL1::JetElement* tt = 0; + const unsigned int key = m_elementKey->jeKey(phi, eta); + JetElementMap::const_iterator mapIter; + mapIter = m_jeMap.find(key); + if (mapIter != m_jeMap.end()) tt = mapIter->second; + return tt; +} + +// Find jet hits for given crate, module + +LVL1::JEMHits* JepByteStreamV1Tool::findJetHits(const int crate, + const int module) +{ + LVL1::JEMHits* hits = 0; + JetHitsMap::const_iterator mapIter; + mapIter = m_hitsMap.find(crate*m_modules + module); + if (mapIter != m_hitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find energy sums for given crate, module + +LVL1::JEMEtSums* JepByteStreamV1Tool::findEnergySums(const int crate, + const int module) +{ + LVL1::JEMEtSums* sums = 0; + EnergySumsMap::const_iterator mapIter; + mapIter = m_etMap.find(crate*m_modules + module); + if (mapIter != m_etMap.end()) sums = mapIter->second; + return sums; +} + +// Find CMM hits for given crate, dataID + +LVL1::CMMJetHits* JepByteStreamV1Tool::findCmmHits(const int crate, + const int dataID) +{ + LVL1::CMMJetHits* hits = 0; + CmmHitsMap::const_iterator mapIter; + mapIter = m_cmmHitsMap.find(crate*100 + dataID); + if (mapIter != m_cmmHitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find CMM energy sums for given crate, module, dataID + +LVL1::CMMEtSums* JepByteStreamV1Tool::findCmmSums(const int crate, + const int dataID) +{ + LVL1::CMMEtSums* sums = 0; + CmmSumsMap::const_iterator mapIter; + mapIter = m_cmmEtMap.find(crate*100 + dataID); + if (mapIter != m_cmmEtMap.end()) sums = mapIter->second; + return sums; +} + +// Set up jet element map + +void JepByteStreamV1Tool::setupJeMap(const JetElementCollection* + const jeCollection) +{ + m_jeMap.clear(); + if (jeCollection) { + JetElementCollection::const_iterator pos = jeCollection->begin(); + JetElementCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JetElement* const je = *pos; + const unsigned int key = m_elementKey->jeKey(je->phi(), je->eta()); + m_jeMap.insert(std::make_pair(key, je)); + } + } +} + +// Set up jet hits map + +void JepByteStreamV1Tool::setupHitsMap(const JetHitsCollection* + const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + JetHitsCollection::const_iterator pos = hitCollection->begin(); + JetHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JEMHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = m_modules * crate + hits->module(); + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up energy sums map + +void JepByteStreamV1Tool::setupEtMap(const EnergySumsCollection* + const etCollection) +{ + m_etMap.clear(); + if (etCollection) { + EnergySumsCollection::const_iterator pos = etCollection->begin(); + EnergySumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JEMEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = m_modules * crate + sums->module(); + m_etMap.insert(std::make_pair(key, sums)); + } + } +} + +// Set up CMM hits map + +void JepByteStreamV1Tool::setupCmmHitsMap(const CmmHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmHitsCollection::const_iterator pos = hitCollection->begin(); + CmmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMMJetHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = crate*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM energy sums map + +void JepByteStreamV1Tool::setupCmmEtMap(const CmmSumsCollection* + const etCollection) +{ + m_cmmEtMap.clear(); + if (etCollection) { + CmmSumsCollection::const_iterator pos = etCollection->begin(); + CmmSumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMMEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = crate*100 + sums->dataID(); + m_cmmEtMap.insert(std::make_pair(key, sums)); + } + } +} + +// Get number of slices and triggered slice offset for next slink + +bool JepByteStreamV1Tool::slinkSlices(const int crate, const int module, + const int modulesPerSlink, int& timeslices, int& trigJem) +{ + int slices = -1; + int trigJ = m_dfltSlices/2; + for (int mod = module; mod < module + modulesPerSlink; ++mod) { + for (int chan = 0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if ( !m_jemMaps->mapping(crate, mod, chan, eta, phi, layer)) continue; + const LVL1::JetElement* const je = findJetElement(eta, phi); + if ( !je ) continue; + const int numdat = 5; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((je->emEnergyVec()).begin(), + (je->emEnergyVec()).end(), 0); + sums[1] = std::accumulate((je->hadEnergyVec()).begin(), + (je->hadEnergyVec()).end(), 0); + sums[2] = std::accumulate((je->emErrorVec()).begin(), + (je->emErrorVec()).end(), 0); + sums[3] = std::accumulate((je->hadErrorVec()).begin(), + (je->hadErrorVec()).end(), 0); + sums[4] = std::accumulate((je->linkErrorVec()).begin(), + (je->linkErrorVec()).end(), 0); + sizes[0] = (je->emEnergyVec()).size(); + sizes[1] = (je->hadEnergyVec()).size(); + sizes[2] = (je->emErrorVec()).size(); + sizes[3] = (je->hadErrorVec()).size(); + sizes[4] = (je->linkErrorVec()).size(); + const int peak = je->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + const LVL1::JEMHits* const hits = findJetHits(crate, mod); + if (hits) { + const unsigned int sum = std::accumulate((hits->JetHitsVec()).begin(), + (hits->JetHitsVec()).end(), 0); + if (sum) { + const int size = (hits->JetHitsVec()).size(); + const int peak = hits->peak(); + if (slices < 0) { + slices = size; + trigJ = peak; + } else if (slices != size || trigJ != peak) return false; + } + } + const LVL1::JEMEtSums* const et = findEnergySums(crate, mod); + if (et) { + const int numdat = 3; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((et->ExVec()).begin(), + (et->ExVec()).end(), 0); + sums[1] = std::accumulate((et->EyVec()).begin(), + (et->EyVec()).end(), 0); + sums[2] = std::accumulate((et->EtVec()).begin(), + (et->EtVec()).end(), 0); + sizes[0] = (et->ExVec()).size(); + sizes[1] = (et->EyVec()).size(); + sizes[2] = (et->EtVec()).size(); + const int peak = et->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + } + // CMM last slink of crate + if (module/modulesPerSlink == m_slinks - 1) { + const int maxDataID1 = LVL1::CMMJetHits::MAXID; + const int maxDataID2 = LVL1::CMMEtSums::MAXID; + const int maxDataID = (maxDataID1 > maxDataID2) ? maxDataID1 : maxDataID2; + for (int dataID = 0; dataID < maxDataID; ++dataID) { + const int numdat = 6; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + const LVL1::CMMJetHits* hits = 0; + if (dataID < maxDataID1) hits = findCmmHits(crate, dataID); + if (hits) { + sums[0] = std::accumulate((hits->HitsVec()).begin(), + (hits->HitsVec()).end(), 0); + sums[1] = std::accumulate((hits->ErrorVec()).begin(), + (hits->ErrorVec()).end(), 0); + sizes[0] = (hits->HitsVec()).size(); + sizes[1] = (hits->ErrorVec()).size(); + const int peak = hits->peak(); + for (int i = 0; i < 2; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + const LVL1::CMMEtSums* et = 0; + if (dataID < maxDataID2) et = findCmmSums(crate, dataID); + if (et) { + sums[0] = std::accumulate((et->ExVec()).begin(), + (et->ExVec()).end(), 0); + sums[1] = std::accumulate((et->EyVec()).begin(), + (et->EyVec()).end(), 0); + sums[2] = std::accumulate((et->EtVec()).begin(), + (et->EtVec()).end(), 0); + sums[3] = std::accumulate((et->ExErrorVec()).begin(), + (et->ExErrorVec()).end(), 0); + sums[4] = std::accumulate((et->EyErrorVec()).begin(), + (et->EyErrorVec()).end(), 0); + sums[5] = std::accumulate((et->EtErrorVec()).begin(), + (et->EtErrorVec()).end(), 0); + sizes[0] = (et->ExVec()).size(); + sizes[1] = (et->EyVec()).size(); + sizes[2] = (et->EtVec()).size(); + sizes[3] = (et->ExErrorVec()).size(); + sizes[4] = (et->EyErrorVec()).size(); + sizes[5] = (et->EtErrorVec()).size(); + const int peak = et->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + } + } + if (slices < 0) slices = m_dfltSlices; + timeslices = slices; + trigJem = trigJ; + return true; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..85e61f68d1eba84d6fcaad58f27076768511f1e7 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV1Tool.h @@ -0,0 +1,244 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV1TOOL_H +#define TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV1TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <class T> class FullEventAssembler; + +namespace LVL1 { + class CMMJetHits; + class CMMEtSums; + class IL1CaloMappingTool; + class JEMHits; + class JEMEtSums; + class JEPBSCollectionV1; + class JetElement; + class JetElementKey; +} + +namespace LVL1BS { + +class CmmEnergySubBlock; +class CmmJetSubBlock; +class JemSubBlockV1; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to jet elements, jet hits and energy sums, + * and JEP container to raw data conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class JepByteStreamV1Tool : public AthAlgTool { + + public: + JepByteStreamV1Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~JepByteStreamV1Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to jet elements + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JetElement>* jeCollection); + /// Convert ROB fragments to jet hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMHits>* hitCollection); + /// Convert ROB fragments to energy sums + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMEtSums>* etCollection); + /// Convert ROB fragments to CMM jet hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMJetHits>* hitCollection); + /// Convert ROB fragments to CMM energy sums + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMMEtSums>* etCollection); + + /// Convert JEP Container to bytestream + StatusCode convert(const LVL1::JEPBSCollectionV1* jep, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + enum CollectionType { JET_ELEMENTS, JET_HITS, ENERGY_SUMS, + CMM_HITS, CMM_SUMS }; + + typedef DataVector<LVL1::JetElement> JetElementCollection; + typedef DataVector<LVL1::JEMHits> JetHitsCollection; + typedef DataVector<LVL1::JEMEtSums> EnergySumsCollection; + typedef DataVector<LVL1::CMMJetHits> CmmHitsCollection; + typedef DataVector<LVL1::CMMEtSums> CmmSumsCollection; + typedef std::map<unsigned int, LVL1::JetElement*> JetElementMap; + typedef std::map<int, LVL1::JEMHits*> JetHitsMap; + typedef std::map<int, LVL1::JEMEtSums*> EnergySumsMap; + typedef std::map<int, LVL1::CMMJetHits*> CmmHitsMap; + typedef std::map<int, LVL1::CMMEtSums*> CmmSumsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + /// Unpack CMM-Energy sub-block + void decodeCmmEnergy(CmmEnergySubBlock* subBlock, int trigCmm); + /// Unpack CMM-Jet sub-block + void decodeCmmJet(CmmJetSubBlock* subBlock, int trigCmm); + /// Unpack JEM sub-block + void decodeJem(JemSubBlockV1* subBlock, int trigJem, + CollectionType collection); + + /// Find a jet element given eta, phi + LVL1::JetElement* findJetElement(double eta, double phi); + /// Find jet hits for given crate, module + LVL1::JEMHits* findJetHits(int crate, int module); + /// Find energy sums for given crate, module + LVL1::JEMEtSums* findEnergySums(int crate, int module); + /// Find CMM hits for given crate, data ID + LVL1::CMMJetHits* findCmmHits(int crate, int dataID); + /// Find CMM energy sums for given crate, data ID + LVL1::CMMEtSums* findCmmSums(int crate, int dataID); + + /// Set up jet element map + void setupJeMap(const JetElementCollection* jeCollection); + /// Set up jet hits map + void setupHitsMap(const JetHitsCollection* hitCollection); + /// Set up energy sums map + void setupEtMap(const EnergySumsCollection* enCollection); + /// Set up CMM hits map + void setupCmmHitsMap(const CmmHitsCollection* hitCollection); + /// Set up CMM energy sums map + void setupCmmEtMap(const CmmSumsCollection* enCollection); + + /// Get number of slices and triggered slice offset for next slink + bool slinkSlices(int crate, int module, int modulesPerSlink, + int& timeslices, int& trigJem); + + /// Channel mapping tool + ToolHandle<LVL1::IL1CaloMappingTool> m_jemMaps; + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of channels per module + int m_channels; + /// Number of crates + int m_crates; + /// Number of JEM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Default number of slices in simulation + int m_dfltSlices; + /// Force number of slices in bytestream + int m_forceSlices; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// Jet elements to accept (0=Core, 1=Overlap) + int m_coreOverlap; + /// Unpacking error code + unsigned int m_rodErr; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Jet element key provider + LVL1::JetElementKey* m_elementKey; + /// JemSubBlock for unpacking + JemSubBlockV1* m_jemSubBlock; + /// CmmEnergySubBlock for unpacking + CmmEnergySubBlock* m_cmmEnergySubBlock; + /// CmmJetSubBlock for unpacking + CmmJetSubBlock* m_cmmJetSubBlock; + /// Ex vector for unpacking + std::vector<unsigned int> m_exVec; + /// Ey vector for unpacking + std::vector<unsigned int> m_eyVec; + /// Et vector for unpacking + std::vector<unsigned int> m_etVec; + /// Ex error vector for unpacking + std::vector<int> m_exErrVec; + /// Ex error vector for unpacking + std::vector<int> m_eyErrVec; + /// Ex error vector for unpacking + std::vector<int> m_etErrVec; + /// Hits vector for unpacking + std::vector<unsigned int> m_hitsVec; + /// Error vector for unpacking + std::vector<int> m_errVec; + /// Vector for current JEM sub-blocks + DataVector<JemSubBlockV1> m_jemBlocks; + /// Vector for current CMM-Energy sub-blocks + DataVector<CmmEnergySubBlock> m_cmmEnergyBlocks; + /// Vector for current CMM-Jet sub-blocks + DataVector<CmmJetSubBlock> m_cmmJetBlocks; + /// Current jet elements collection + JetElementCollection* m_jeCollection; + /// Current jet hits collection + JetHitsCollection* m_hitCollection; + /// Current energy sums collection + EnergySumsCollection* m_etCollection; + /// Current CMM hits collection + CmmHitsCollection* m_cmmHitCollection; + /// Current CMM energy sums collection + CmmSumsCollection* m_cmmEtCollection; + /// Jet element map + JetElementMap m_jeMap; + /// Jet hits map + JetHitsMap m_hitsMap; + /// Energy sums map + EnergySumsMap m_etMap; + /// CMM hits map + CmmHitsMap m_cmmHitsMap; + /// CMM energy sums map + CmmSumsMap m_cmmEtMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..ce5a90a2cac0f0a7fb4013e8db985960510cd8b6 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Cnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/JEPBSCollectionV2.h" + +#include "JepByteStreamV2Cnv.h" +#include "JepByteStreamV2Tool.h" + +namespace LVL1BS { + +JepByteStreamV2Cnv::JepByteStreamV2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepByteStreamV2Cnv"), + m_tool("LVL1BS::JepByteStreamV2Tool/JepByteStreamV2Tool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +JepByteStreamV2Cnv::~JepByteStreamV2Cnv() +{ +} + +// CLID + +const CLID& JepByteStreamV2Cnv::classID() +{ + return ClassID_traits<LVL1::JEPBSCollectionV2>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepByteStreamV2Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode JepByteStreamV2Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::JEPBSCollectionV2* jep = 0; + if( !SG::fromStorable( pObj, jep ) ) { + m_log << MSG::ERROR << " Cannot cast to JEPBSCollectionV2" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( jep, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..d10fe52f8a36ed659a8da476d99b6d4beddefcfe --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Cnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV2CNV_H +#define TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepByteStreamV2Tool; + +/** ByteStream converter for JEP container post LS1 + * + * @author Peter Faulkner + */ + +class JepByteStreamV2Cnv: public Converter { + + friend class CnvFactory<JepByteStreamV2Cnv>; + +protected: + + JepByteStreamV2Cnv(ISvcLocator* svcloc); + +public: + + ~JepByteStreamV2Cnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from JEP Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepByteStreamV2Tool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..1036e4f8d146bab2de4369f40076436ac75391b5 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Tool.cxx @@ -0,0 +1,1783 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMXJetHits.h" +#include "TrigT1CaloEvent/CMXJetTob.h" +#include "TrigT1CaloEvent/CMXEtSums.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JEPBSCollectionV2.h" +#include "TrigT1CaloEvent/JetElement.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/JetElementKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "CmxEnergySubBlock.h" +#include "CmxJetSubBlock.h" +#include "CmxSubBlock.h" +#include "JemJetElement.h" +#include "JemSubBlockV2.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "ModifySlices.h" + +#include "JepByteStreamV2Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IJepByteStreamV2Tool("JepByteStreamV2Tool", 1, 1); + +const InterfaceID& JepByteStreamV2Tool::interfaceID() +{ + return IID_IJepByteStreamV2Tool; +} + +// Constructor + +JepByteStreamV2Tool::JepByteStreamV2Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_jemMaps("LVL1::JemMappingTool/JemMappingTool"), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_channels(44), m_crates(2), m_modules(16), m_frames(8), m_locations(4), + m_maxTobs(4), m_coreOverlap(0), + m_subDetector(eformat::TDAQ_CALO_JET_PROC_DAQ), + m_srcIdMap(0), m_elementKey(0), + m_jemSubBlock(0), m_cmxEnergySubBlock(0), m_cmxJetSubBlock(0), + m_rodStatus(0), m_fea(0) +{ + declareInterface<JepByteStreamV2Tool>(this); + + declareProperty("JemMappingTool", m_jemMaps, + "Crate/Module/Channel to Eta/Phi/Layer mapping tool"); + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 12, + "Offset of JEP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of JEP crate numbers in RDOs"); + declareProperty("SlinksPerCrate", m_slinks = 4, + "The number of S-Links per crate"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 2, //<<== CHECK + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SimulSlices", m_dfltSlices = 1, + "The number of slices in the simulation"); + declareProperty("ForceSlices", m_forceSlices = 0, + "If >0, the number of slices in bytestream"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +JepByteStreamV2Tool::~JepByteStreamV2Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepByteStreamV2Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_jemMaps.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_jemMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_jemMaps << endreq; + + sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_elementKey = new LVL1::JetElementKey(); + m_jemSubBlock = new JemSubBlockV2(); + m_cmxEnergySubBlock = new CmxEnergySubBlock(); + m_cmxJetSubBlock = new CmxJetSubBlock(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JepByteStreamV2Tool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_cmxJetSubBlock; + delete m_cmxEnergySubBlock; + delete m_jemSubBlock; + delete m_elementKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to jet elements + +StatusCode JepByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JetElement>* const jeCollection) +{ + m_jeCollection = jeCollection; + m_jeMap.clear(); + return convertBs(robFrags, JET_ELEMENTS); +} + +// Conversion bytestream to energy sums + +StatusCode JepByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMEtSums>* const etCollection) +{ + m_etCollection = etCollection; + m_etMap.clear(); + return convertBs(robFrags, ENERGY_SUMS); +} + +// Conversion bytestream to CMX TOBs + +StatusCode JepByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXJetTob>* const tobCollection) +{ + m_cmxTobCollection = tobCollection; + m_cmxTobMap.clear(); + return convertBs(robFrags, CMX_TOBS); +} + +// Conversion bytestream to CMX hits + +StatusCode JepByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXJetHits>* const hitCollection) +{ + m_cmxHitCollection = hitCollection; + m_cmxHitsMap.clear(); + return convertBs(robFrags, CMX_HITS); +} + +// Conversion bytestream to CMX energy sums + +StatusCode JepByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXEtSums>* const etCollection) +{ + m_cmxEtCollection = etCollection; + m_cmxEtMap.clear(); + return convertBs(robFrags, CMX_SUMS); +} + +// Conversion of JEP container to bytestream + +StatusCode JepByteStreamV2Tool::convert(const LVL1::JEPBSCollectionV2* const jep, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + setupJeMap(jep->JetElements()); + setupEtMap(jep->EnergySums()); + setupCmxTobMap(jep->CmxTobs()); + setupCmxHitsMap(jep->CmxHits()); + setupCmxEtMap(jep->CmxSums()); + + // Loop over data + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + const int modulesPerSlink = m_modules / m_slinks; + int timeslices = 1; + int trigJem = 0; + int timeslicesNew = 1; + int trigJemNew = 0; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + for (int module=0; module < m_modules; ++module) { + + // Pack required number of modules per slink + + if (module%modulesPerSlink == 0) { + const int daqOrRoi = 0; + const int slink = module/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq; + } + // Get number of JEM slices and triggered slice offset + // for this slink + if ( ! slinkSlices(crate, module, modulesPerSlink, + timeslices, trigJem)) { + msg(MSG::ERROR) << "Inconsistent number of slices or " + << "triggered slice offsets in data for crate " + << hwCrate << " slink " << slink << endreq; + return StatusCode::FAILURE; + } + timeslicesNew = (m_forceSlices) ? m_forceSlices : timeslices; + trigJemNew = ModifySlices::peak(trigJem, timeslices, timeslicesNew); + if (debug) { + msg() << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq + << "Slices/offset: " << timeslices << " " << trigJem; + if (timeslices != timeslicesNew) { + msg() << " modified to " << timeslicesNew << " " << trigJemNew; + } + msg() << endreq; + } + L1CaloUserHeader userHeader; + userHeader.setJem(trigJemNew); + const uint32_t rodIdJem = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdJem); + theROD->push_back(userHeader.header()); + m_rodStatusMap.insert(make_pair(rodIdJem, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Create a sub-block for each slice (except Neutral format) + + m_jemBlocks.clear(); + for (int slice = 0; slice < timeslicesNew; ++slice) { + JemSubBlockV2* const subBlock = new JemSubBlockV2(); + subBlock->setJemHeader(m_version, m_dataFormat, slice, + hwCrate, module, timeslicesNew); + m_jemBlocks.push_back(subBlock); + if (neutralFormat) break; + } + + // Find jet elements corresponding to each eta/phi pair and fill + // sub-blocks + + for (int chan=0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_jemMaps->mapping(crate, module, chan, eta, phi, layer)) { + const LVL1::JetElement* const je = findJetElement(eta, phi); + if (je ) { + std::vector<int> emData; + std::vector<int> hadData; + std::vector<int> emErrors; + std::vector<int> hadErrors; + ModifySlices::data(je->emEnergyVec(), emData, timeslicesNew); + ModifySlices::data(je->hadEnergyVec(), hadData, timeslicesNew); + ModifySlices::data(je->emErrorVec(), emErrors, timeslicesNew); + ModifySlices::data(je->hadErrorVec(), hadErrors, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError emErrBits(emErrors[slice]); + const LVL1::DataError hadErrBits(hadErrors[slice]); + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlockV2* const subBlock = m_jemBlocks[index]; + const JemJetElement jetEle(chan, emData[slice], hadData[slice], + emErrBits.get(LVL1::DataError::Parity), + hadErrBits.get(LVL1::DataError::Parity), + emErrBits.get(LVL1::DataError::LinkDown) + + (hadErrBits.get(LVL1::DataError::LinkDown) << 1)); + subBlock->fillJetElement(slice, jetEle); + if ((emErrBits.error() >> LVL1::DataError::GLinkParity)) { + int gLinkParity = emErrBits.get(LVL1::DataError::GLinkParity); + int gLinkProtocol = emErrBits.get(LVL1::DataError::GLinkProtocol); + int bCNMismatch = emErrBits.get(LVL1::DataError::BCNMismatch); + int fIFOOverflow = emErrBits.get(LVL1::DataError::FIFOOverflow); + int moduleError = emErrBits.get(LVL1::DataError::ModuleError); + int gLinkDown = emErrBits.get(LVL1::DataError::GLinkDown); + int gLinkTimeout = emErrBits.get(LVL1::DataError::GLinkTimeout); + uint32_t failingBCN = emErrBits.get(LVL1::DataError::FailingBCN); + subBlock->setStatus(failingBCN, gLinkTimeout, gLinkDown, + moduleError, fIFOOverflow, bCNMismatch, + gLinkProtocol, gLinkParity); + } + } + } + } + } + + // Add energy subsums + + const LVL1::JEMEtSums* const et = findEnergySums(crate, module); + if (et) { + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + ModifySlices::data(et->ExVec(), exVec, timeslicesNew); + ModifySlices::data(et->EyVec(), eyVec, timeslicesNew); + ModifySlices::data(et->EtVec(), etVec, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const int index = ( neutralFormat ) ? 0 : slice; + JemSubBlockV2* const subBlock = m_jemBlocks[index]; + subBlock->setEnergySubsums(slice, exVec[slice], eyVec[slice], + etVec[slice]); + } + } + + // Pack and write the sub-blocks + + DataVector<JemSubBlockV2>::const_iterator pos; + for (pos = m_jemBlocks.begin(); pos != m_jemBlocks.end(); ++pos) { + JemSubBlockV2* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "JEM sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "JEM sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Append CMXs to last S-Link of the crate + + // Create a sub-block for each slice (except Neutral format) + + m_cmxEnergyBlocks.clear(); + m_cmxJetBlocks.clear(); + const int summing = (crate == m_crates - 1) ? CmxSubBlock::SYSTEM + : CmxSubBlock::CRATE; + for (int slice = 0; slice < timeslicesNew; ++slice) { + CmxEnergySubBlock* const enBlock = new CmxEnergySubBlock(); + const int cmxEnergyVersion = 3; // <<== CHECK Make jo property for each sub-block? + enBlock->setCmxHeader(cmxEnergyVersion, m_dataFormat, slice, hwCrate, + summing, CmxSubBlock::CMX_ENERGY, + CmxSubBlock::LEFT, timeslicesNew); + m_cmxEnergyBlocks.push_back(enBlock); + CmxJetSubBlock* const jetBlock = new CmxJetSubBlock(); + jetBlock->setCmxHeader(m_version, m_dataFormat, slice, hwCrate, + summing, CmxSubBlock::CMX_JET, + CmxSubBlock::RIGHT, timeslicesNew); + m_cmxJetBlocks.push_back(jetBlock); + if (neutralFormat) break; + } + + // CMX-Energy + + int maxSource = static_cast<int>(LVL1::CMXEtSums::MAX_SOURCE); + for (int source = 0; source < maxSource; ++source) { + if (source >= m_modules) { + if (summing == CmxSubBlock::CRATE && + source != LVL1::CMXEtSums::LOCAL_STANDARD && + source != LVL1::CMXEtSums::LOCAL_RESTRICTED) continue; + } + const LVL1::CMXEtSums* const sums = findCmxSums(crate, source); + if ( sums ) { + std::vector<unsigned int> ex; + std::vector<unsigned int> ey; + std::vector<unsigned int> et; + std::vector<int> exErr; + std::vector<int> eyErr; + std::vector<int> etErr; + ModifySlices::data(sums->ExVec(), ex, timeslicesNew); + ModifySlices::data(sums->EyVec(), ey, timeslicesNew); + ModifySlices::data(sums->EtVec(), et, timeslicesNew); + ModifySlices::data(sums->ExErrorVec(), exErr, timeslicesNew); + ModifySlices::data(sums->EyErrorVec(), eyErr, timeslicesNew); + ModifySlices::data(sums->EtErrorVec(), etErr, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError exErrBits(exErr[slice]); + const LVL1::DataError eyErrBits(eyErr[slice]); + const LVL1::DataError etErrBits(etErr[slice]); + int exError = exErrBits.get(LVL1::DataError::Parity) << 1; + int eyError = eyErrBits.get(LVL1::DataError::Parity) << 1; + int etError = etErrBits.get(LVL1::DataError::Parity) << 1; + if (source >= m_modules) { + exError += exErrBits.get(LVL1::DataError::Overflow); + eyError += eyErrBits.get(LVL1::DataError::Overflow); + etError += etErrBits.get(LVL1::DataError::Overflow); + } + const int index = ( neutralFormat ) ? 0 : slice; + CmxEnergySubBlock* const subBlock = m_cmxEnergyBlocks[index]; + if (source < m_modules) { + subBlock->setSubsums(slice, source, + ex[slice], ey[slice], et[slice], + exError, eyError, etError); + } else { + CmxEnergySubBlock::SourceType srcType = CmxEnergySubBlock::MAX_SOURCE_TYPE; + CmxEnergySubBlock::SumType sumType = CmxEnergySubBlock::MAX_SUM_TYPE; + CmxEnergySubBlock::HitsType hitType = CmxEnergySubBlock::MAX_HITS_TYPE; + energySubBlockTypes(source, srcType, sumType, hitType); + if (srcType != CmxEnergySubBlock::MAX_SOURCE_TYPE) { + subBlock->setSubsums(slice, srcType, sumType, + ex[slice], ey[slice], et[slice], + exError, eyError, etError); + } else if (hitType != CmxEnergySubBlock::MAX_HITS_TYPE) { + subBlock->setEtHits(slice, hitType, sumType, et[slice]); + } + } + } + } + } + DataVector<CmxEnergySubBlock>::const_iterator pos; + pos = m_cmxEnergyBlocks.begin(); + for (; pos != m_cmxEnergyBlocks.end(); ++pos) { + CmxEnergySubBlock* const subBlock = *pos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMX-Energy sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMX-Energy sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + + // CMX-Jet TOBs + + for (int jem = 0; jem < m_modules; ++jem) { + for (int frame = 0; frame < m_frames; ++frame) { + for (int loc = 0; loc < m_locations; ++loc) { + const int key = tobKey(crate, jem, frame, loc); + const LVL1::CMXJetTob* const ct = findCmxTob(key); + if ( ct ) { + std::vector<int> energyLarge; + std::vector<int> energySmall; + std::vector<int> error; + std::vector<unsigned int> presence; + ModifySlices::data(ct->energyLgVec(), energyLarge, timeslicesNew); + ModifySlices::data(ct->energySmVec(), energySmall, timeslicesNew); + ModifySlices::data(ct->errorVec(), error, timeslicesNew); + ModifySlices::data(ct->presenceMapVec(), presence, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + const LVL1::DataError errBits(error[slice]); + int err0 = errBits.get(LVL1::DataError::Parity); + int err1 = errBits.get(LVL1::DataError::ParityPhase0); + err1 |= (errBits.get(LVL1::DataError::ParityPhase1))<<1; + err1 |= (errBits.get(LVL1::DataError::ParityPhase2))<<2; + err1 |= (errBits.get(LVL1::DataError::ParityPhase3))<<3; + const int index = ( neutralFormat ) ? 0 : slice; + CmxJetSubBlock* const subBlock = m_cmxJetBlocks[index]; + subBlock->setTob(slice, jem, frame, loc, energyLarge[slice], + energySmall[slice], err0); + subBlock->setParityBits(slice, jem, err1); // for neutral format + subBlock->setPresenceMap(slice, jem, presence[slice]); + } + } + } + } + } + + // CMX-Jet Hits + + maxSource = static_cast<int>(LVL1::CMXJetHits::MAX_SOURCE); + for (int source = 0; source < maxSource; ++source) { + if (summing == CmxSubBlock::CRATE && + (source == LVL1::CMXJetHits::REMOTE_MAIN || + source == LVL1::CMXJetHits::TOTAL_MAIN || + source == LVL1::CMXJetHits::REMOTE_FORWARD || + source == LVL1::CMXJetHits::TOTAL_FORWARD)) continue; + int sourceId = jetSubBlockSourceId(source); + if (sourceId == CmxJetSubBlock::MAX_SOURCE_ID) continue; + const LVL1::CMXJetHits* const ch = findCmxHits(crate, source); + if ( ch ) { + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + std::vector<int> err0; + std::vector<int> err1; + ModifySlices::data(ch->hitsVec0(), hits0, timeslicesNew); + ModifySlices::data(ch->hitsVec1(), hits1, timeslicesNew); + ModifySlices::data(ch->errorVec0(), err0, timeslicesNew); + ModifySlices::data(ch->errorVec1(), err1, timeslicesNew); + for (int slice = 0; slice < timeslicesNew; ++slice) { + int error = 0; + if (source != LVL1::CMXJetHits::TOPO_CHECKSUM && + source != LVL1::CMXJetHits::TOPO_OCCUPANCY_MAP && + source != LVL1::CMXJetHits::TOPO_OCCUPANCY_COUNTS) { + const LVL1::DataError errBits0(err0[slice]); + const LVL1::DataError errBits1(err1[slice]); + error = (errBits0.get(LVL1::DataError::Overflow) | + errBits1.get(LVL1::DataError::Overflow)) << 2; + if (source == LVL1::CMXJetHits::REMOTE_MAIN || + source == LVL1::CMXJetHits::REMOTE_FORWARD) { + error += (errBits0.get(LVL1::DataError::Parity) + + (errBits1.get(LVL1::DataError::Parity) << 1)); + } + } + const int index = ( neutralFormat ) ? 0 : slice; + CmxJetSubBlock* const subBlock = m_cmxJetBlocks[index]; + subBlock->setHits(slice, sourceId, 0, hits0[slice], error); + if (source != LVL1::CMXJetHits::TOPO_CHECKSUM && + source != LVL1::CMXJetHits::TOPO_OCCUPANCY_MAP) { + subBlock->setHits(slice, sourceId, 1, hits1[slice], error); + } + } + } + } + DataVector<CmxJetSubBlock>::const_iterator jos; + jos = m_cmxJetBlocks.begin(); + for (; jos != m_cmxJetBlocks.end(); ++jos) { + CmxJetSubBlock* const subBlock = *jos; + if ( !subBlock->pack()) { + msg(MSG::ERROR) << "CMX-Jet sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMX-Jet sub-block data words: " + << subBlock->dataWords() << endreq; + } + subBlock->write(theROD); + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& JepByteStreamV2Tool::sourceIDs( + const std::string& sgKey) +{ + // Check if overlap jet element channels wanted + const std::string flag("Overlap"); + const std::string::size_type pos = sgKey.find(flag); + m_coreOverlap = + (pos == std::string::npos || pos != sgKey.length() - flag.length()) ? 0 : 1; + + if (m_sourceIDs.empty()) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 0; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + m_sourceIDs.push_back(robId); + } + } + } + return m_sourceIDs; +} + +// Convert bytestream to given container type + +StatusCode JepByteStreamV2Tool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0 || + m_srcIdMap->slink(sourceID) >= m_slinks || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: ROD " + << MSG::hex << sourceID << " ROB " << robid + << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion <= m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping pre-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word should be User Header + if ( !L1CaloUserHeader::isValid(*payload) ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Invalid or missing user header" << endreq; + continue; + } + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + // triggered slice offsets + int trigJem = userHeader.jem(); + if (debug) { + msg() << "Minor format version number: " << MSG::hex + << minorVersion << MSG::dec << endreq + << "JEM triggered slice offset: " << trigJem << endreq; + } + + // Loop over sub-blocks + + m_rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER) { + if (debug) msg() << "Unexpected data sequence" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MISSING_HEADER; + break; + } + if (CmxSubBlock::cmxBlock(*payload)) { + // CMXs + if (CmxSubBlock::cmxType(*payload) == CmxSubBlock::CMX_JET) { + m_cmxJetSubBlock->clear(); + payload = m_cmxJetSubBlock->read(payload, payloadEnd); + if (m_cmxJetSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMX_HITS || collection == CMX_TOBS) { + decodeCmxJet(m_cmxJetSubBlock, trigJem, collection); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmxJet failed" << endreq; + break; + } + } + } else if (CmxSubBlock::cmxType(*payload) == CmxSubBlock::CMX_ENERGY) { + m_cmxEnergySubBlock->clear(); + payload = m_cmxEnergySubBlock->read(payload, payloadEnd); + if (m_cmxEnergySubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == CMX_SUMS) { + decodeCmxEnergy(m_cmxEnergySubBlock, trigJem); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeCmxEnergy failed" << endreq; + break; + } + } + } else { + if (debug) msg() << "Invalid CMX type in module field" << endreq; + m_rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + } else { + // JEM + m_jemSubBlock->clear(); + payload = m_jemSubBlock->read(payload, payloadEnd); + if (m_jemSubBlock->crate() != rodCrate) { + if (debug) msg() << "Inconsistent crate number in ROD source ID" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (collection == JET_ELEMENTS || collection == ENERGY_SUMS) { + decodeJem(m_jemSubBlock, trigJem, collection); + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) { + if (debug) msg() << "decodeJem failed" << endreq; + break; + } + } + } + } + if (m_rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, m_rodErr); + } + + return StatusCode::SUCCESS; +} + +// Unpack CMX-Energy sub-block + +void JepByteStreamV2Tool::decodeCmxEnergy(CmxEnergySubBlock* subBlock, + int trigJem) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmxPosition(); + const int firmware = subBlock->cmxFirmware(); + const int summing = subBlock->cmxSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMX-Energy: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigJem) { + if (debug) msg() << "Triggered CMX slice from header " + << "inconsistent with number of slices: " + << trigJem << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMX-Energy sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSource = static_cast<int>(LVL1::CMXEtSums::MAX_SOURCE); + std::vector<unsigned int>& exVec(m_uintVec0); + std::vector<unsigned int>& eyVec(m_uintVec1); + std::vector<unsigned int>& etVec(m_uintVec2); + std::vector<int>& exErrVec(m_intVec0); + std::vector<int>& eyErrVec(m_intVec1); + std::vector<int>& etErrVec(m_intVec2); + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Energy sums + + for (int source = 0; source < maxSource; ++source) { + if (source >= m_modules && summing == CmxSubBlock::CRATE && + source != LVL1::CMXEtSums::LOCAL_STANDARD && + source != LVL1::CMXEtSums::LOCAL_RESTRICTED) continue; + unsigned int ex = 0; + unsigned int ey = 0; + unsigned int et = 0; + int exErr = 0; + int eyErr = 0; + int etErr = 0; + LVL1::DataError exErrBits(ssError); + LVL1::DataError eyErrBits(ssError); + LVL1::DataError etErrBits(ssError); + if (source < m_modules) { + ex = subBlock->energy(slice, source, CmxEnergySubBlock::ENERGY_EX); + ey = subBlock->energy(slice, source, CmxEnergySubBlock::ENERGY_EY); + et = subBlock->energy(slice, source, CmxEnergySubBlock::ENERGY_ET); + exErr = subBlock->error(slice, source, CmxEnergySubBlock::ENERGY_EX); + eyErr = subBlock->error(slice, source, CmxEnergySubBlock::ENERGY_EY); + etErr = subBlock->error(slice, source, CmxEnergySubBlock::ENERGY_ET); + exErrBits.set(LVL1::DataError::Parity, exErr >> 1); + eyErrBits.set(LVL1::DataError::Parity, eyErr >> 1); + etErrBits.set(LVL1::DataError::Parity, etErr >> 1); + exErr = exErrBits.error(); + eyErr = eyErrBits.error(); + etErr = etErrBits.error(); + } else { + CmxEnergySubBlock::SourceType srcType = CmxEnergySubBlock::MAX_SOURCE_TYPE; + CmxEnergySubBlock::SumType sumType = CmxEnergySubBlock::MAX_SUM_TYPE; + CmxEnergySubBlock::HitsType hitType = CmxEnergySubBlock::MAX_HITS_TYPE; + energySubBlockTypes(source, srcType, sumType, hitType); + if (srcType != CmxEnergySubBlock::MAX_SOURCE_TYPE) { + ex = subBlock->energy(slice, srcType, sumType, CmxEnergySubBlock::ENERGY_EX); + ey = subBlock->energy(slice, srcType, sumType, CmxEnergySubBlock::ENERGY_EY); + et = subBlock->energy(slice, srcType, sumType, CmxEnergySubBlock::ENERGY_ET); + exErr = subBlock->error(slice, srcType, sumType, CmxEnergySubBlock::ENERGY_EX); + eyErr = subBlock->error(slice, srcType, sumType, CmxEnergySubBlock::ENERGY_EY); + etErr = subBlock->error(slice, srcType, sumType, CmxEnergySubBlock::ENERGY_ET); + exErrBits.set(LVL1::DataError::Overflow, exErr); + eyErrBits.set(LVL1::DataError::Overflow, eyErr); + etErrBits.set(LVL1::DataError::Overflow, etErr); + if (srcType == CmxEnergySubBlock::REMOTE) { + exErrBits.set(LVL1::DataError::Parity, exErr >> 1); + eyErrBits.set(LVL1::DataError::Parity, eyErr >> 1); + etErrBits.set(LVL1::DataError::Parity, etErr >> 1); + } + } else if (hitType != CmxEnergySubBlock::MAX_HITS_TYPE) { + ex = subBlock->hits(slice, hitType, sumType); + ey = ex; + et = ex; + } + } + exErr = exErrBits.error(); + eyErr = eyErrBits.error(); + etErr = etErrBits.error(); + if (ex || ey || et || exErr || eyErr || etErr) { + LVL1::CMXEtSums* sums = findCmxSums(crate, source); + if ( ! sums ) { // create new CMX energy sums + exVec.assign(timeslices, 0); + eyVec.assign(timeslices, 0); + etVec.assign(timeslices, 0); + exErrVec.assign(timeslices, 0); + eyErrVec.assign(timeslices, 0); + etErrVec.assign(timeslices, 0); + exVec[slice] = ex; + eyVec[slice] = ey; + etVec[slice] = et; + exErrVec[slice] = exErr; + eyErrVec[slice] = eyErr; + etErrVec[slice] = etErr; + sums = new LVL1::CMXEtSums(swCrate, source, etVec, exVec, eyVec, + etErrVec, exErrVec, eyErrVec, trigJem); + const int key = crate*100 + source; + m_cmxEtMap.insert(std::make_pair(key, sums)); + m_cmxEtCollection->push_back(sums); + } else { + exVec = sums->ExVec(); + eyVec = sums->EyVec(); + etVec = sums->EtVec(); + exErrVec = sums->ExErrorVec(); + eyErrVec = sums->EyErrorVec(); + etErrVec = sums->EtErrorVec(); + const int nsl = exVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (exVec[slice] != 0 || eyVec[slice] != 0 || etVec[slice] != 0 || + exErrVec[slice] != 0 || eyErrVec[slice] != 0 || + etErrVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + exVec[slice] = ex; + eyVec[slice] = ey; + etVec[slice] = et; + exErrVec[slice] = exErr; + eyErrVec[slice] = eyErr; + etErrVec[slice] = etErr; + sums->addEx(exVec, exErrVec); + sums->addEy(eyVec, eyErrVec); + sums->addEt(etVec, etErrVec); + } + } + } + } + + return; +} + +// Unpack CMX-Jet sub-block + +void JepByteStreamV2Tool::decodeCmxJet(CmxJetSubBlock* subBlock, int trigJem, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->cmxPosition(); + const int firmware = subBlock->cmxFirmware(); + const int summing = subBlock->cmxSumming(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "CMX-Jet: Crate " << hwCrate + << " Module " << module + << " Firmware " << firmware + << " Summing " << summing + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigJem) { + if (debug) msg() << "Triggered CMX slice from header " + << "inconsistent with number of slices: " + << trigJem << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "CMX-Jet sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + const int maxSource = static_cast<int>(LVL1::CMXJetHits::MAX_SOURCE); + std::vector<int>& energyLgVec(m_intVec0); + std::vector<int>& energySmVec(m_intVec1); + std::vector<int>& errorVec(m_intVec2); + std::vector<unsigned int>& presenceMapVec(m_uintVec0); + std::vector<unsigned int>& hit0Vec(m_uintVec0); + std::vector<unsigned int>& hit1Vec(m_uintVec1); + std::vector<int>& err0Vec(m_intVec0); + std::vector<int>& err1Vec(m_intVec1); + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + // Jet TOBs + + if (collection == CMX_TOBS) { + + for (int jem = 0; jem < m_modules; ++jem) { + const unsigned int presenceMap = subBlock->presenceMap(slice, jem); + for (int tob = 0; tob < m_maxTobs; ++tob) { + const int energyLarge = subBlock->energyLarge(slice, jem, tob); + const int energySmall = subBlock->energySmall(slice, jem, tob); + int error = subBlock->tobError(slice, jem, tob); + if (energyLarge == 0 && energySmall == 0 && error == 0) break; + const int loc = subBlock->localCoord(slice, jem, tob); + const int frame = subBlock->frame(slice, jem, tob); + LVL1::DataError errBits(ssError); + if (error) { + errBits.set(LVL1::DataError::Parity, error); + if (neutralFormat) { + const int parity = subBlock->parityBits(slice, jem); + errBits.set(LVL1::DataError::ParityPhase0, parity); + errBits.set(LVL1::DataError::ParityPhase1, (parity>>1)); + errBits.set(LVL1::DataError::ParityPhase2, (parity>>2)); + errBits.set(LVL1::DataError::ParityPhase3, (parity>>3)); + } + } + error = errBits.error(); + const int key = tobKey(crate, jem, frame, loc); + LVL1::CMXJetTob* tb = findCmxTob(key); + if ( ! tb ) { // create new CMX TOB + energyLgVec.assign(timeslices, 0); + energySmVec.assign(timeslices, 0); + errorVec.assign(timeslices, 0); + presenceMapVec.assign(timeslices, 0); + energyLgVec[slice] = energyLarge; + energySmVec[slice] = energySmall; + errorVec[slice] = error; + presenceMapVec[slice] = presenceMap; + tb = new LVL1::CMXJetTob(swCrate, jem, frame, loc, + energyLgVec, energySmVec, errorVec, + presenceMapVec, trigJem); + m_cmxTobMap.insert(std::make_pair(key, tb)); + m_cmxTobCollection->push_back(tb); + } else { + energyLgVec = tb->energyLgVec(); + energySmVec = tb->energySmVec(); + errorVec = tb->errorVec(); + presenceMapVec = tb->presenceMapVec(); + const int nsl = energyLgVec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (energyLgVec[slice] != 0 || energySmVec[slice] != 0 || + errorVec[slice] != 0 || presenceMapVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + energyLgVec[slice] = energyLarge; + energySmVec[slice] = energySmall; + errorVec[slice] = error; + presenceMapVec[slice] = presenceMap; + tb->addTob(energyLgVec, energySmVec, errorVec, presenceMapVec); + } + } + } + } + + // Jet hit counts and topo info + + else if (collection == CMX_HITS) { + + for (int source = 0; source < maxSource; ++source) { + if (summing == CmxSubBlock::CRATE && + (source == LVL1::CMXJetHits::REMOTE_MAIN || + source == LVL1::CMXJetHits::TOTAL_MAIN || + source == LVL1::CMXJetHits::REMOTE_FORWARD || + source == LVL1::CMXJetHits::TOTAL_FORWARD)) continue; + int sourceId = jetSubBlockSourceId(source); + if (sourceId == CmxJetSubBlock::MAX_SOURCE_ID) continue; + const unsigned int hit0 = subBlock->hits(slice, sourceId, 0); + const unsigned int hit1 = subBlock->hits(slice, sourceId, 1); + int err0 = subBlock->hitsError(slice, sourceId, 0); + int err1 = subBlock->hitsError(slice, sourceId, 1); + LVL1::DataError err0Bits(ssError); + LVL1::DataError err1Bits(ssError); + err0Bits.set(LVL1::DataError::Parity, err0); + err1Bits.set(LVL1::DataError::Parity, err1>>1); + err0Bits.set(LVL1::DataError::Overflow, err0>>2); + err1Bits.set(LVL1::DataError::Overflow, err1>>2); + err0 = err0Bits.error(); + err1 = err1Bits.error(); + if (hit0 || hit1 || err0 || err1) { + LVL1::CMXJetHits* jh = findCmxHits(crate, source); + if ( ! jh ) { // create new CMX hits + hit0Vec.assign(timeslices, 0); + hit1Vec.assign(timeslices, 0); + err0Vec.assign(timeslices, 0); + err1Vec.assign(timeslices, 0); + hit0Vec[slice] = hit0; + hit1Vec[slice] = hit1; + err0Vec[slice] = err0; + err1Vec[slice] = err1; + jh = new LVL1::CMXJetHits(swCrate, source, hit0Vec, hit1Vec, + err0Vec, err1Vec, trigJem); + const int key = crate*100 + source; + m_cmxHitsMap.insert(std::make_pair(key, jh)); + m_cmxHitCollection->push_back(jh); + } else { + hit0Vec = jh->hitsVec0(); + hit1Vec = jh->hitsVec1(); + err0Vec = jh->errorVec0(); + err1Vec = jh->errorVec1(); + const int nsl = hit0Vec.size(); + if (timeslices != nsl) { + if (debug) msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (hit0Vec[slice] != 0 || hit1Vec[slice] != 0 || + err0Vec[slice] != 0 || err1Vec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + hit0Vec[slice] = hit0; + hit1Vec[slice] = hit1; + err0Vec[slice] = err0; + err1Vec[slice] = err1; + jh->addHits(hit0Vec, hit1Vec, err0Vec, err1Vec); + } + } + } + } + } + + return; +} + +// Unpack JEM sub-block + +void JepByteStreamV2Tool::decodeJem(JemSubBlockV2* subBlock, int trigJem, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + const bool verbose = msgLvl(MSG::VERBOSE); + if (debug) msg(MSG::DEBUG); + + const int hwCrate = subBlock->crate(); + const int module = subBlock->module(); + const int timeslices = subBlock->timeslices(); + const int sliceNum = subBlock->slice(); + if (debug) { + msg() << "JEM: Crate " << hwCrate + << " Module " << module + << " Total slices " << timeslices + << " Slice " << sliceNum << endreq; + } + if (timeslices <= trigJem) { + if (debug) msg() << "Triggered JEM slice from header " + << "inconsistent with number of slices: " + << trigJem << ", " << timeslices << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (timeslices <= sliceNum) { + if (debug) msg() << "Total slices inconsistent with slice number: " + << timeslices << ", " << sliceNum << endreq; + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + // Unpack sub-block + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "JEM sub-block unpacking failed: " << errMsg << endreq; + } + m_rodErr = subBlock->unpackErrorCode(); + return; + } + + // Retrieve required data + + const bool neutralFormat = subBlock->format() == L1CaloSubBlock::NEUTRAL; + const int crate = hwCrate - m_crateOffsetHw; + const int swCrate = crate + m_crateOffsetSw; + std::vector<unsigned int>& exVec(m_uintVec0); + std::vector<unsigned int>& eyVec(m_uintVec1); + std::vector<unsigned int>& etVec(m_uintVec2); + LVL1::DataError derr; + derr.set(LVL1::DataError::SubStatusWord, subBlock->subStatus()); + const int ssError = derr.error(); + std::vector<int> dummy(timeslices); + const int sliceBeg = ( neutralFormat ) ? 0 : sliceNum; + const int sliceEnd = ( neutralFormat ) ? timeslices : sliceNum + 1; + for (int slice = sliceBeg; slice < sliceEnd; ++slice) { + + if (collection == JET_ELEMENTS) { + + // Loop over jet element channels and fill jet elements + + for (int chan = 0; chan < m_channels; ++chan) { + const JemJetElement jetEle(subBlock->jetElement(slice, chan)); + if (jetEle.data() || ssError) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_jemMaps->mapping(crate, module, chan, eta, phi, layer)) { + if (layer == m_coreOverlap) { + LVL1::JetElement* je = findJetElement(eta, phi); + if ( ! je ) { // create new jet element + const unsigned int key = m_elementKey->jeKey(phi, eta); + je = new LVL1::JetElement(phi, eta, dummy, dummy, key, + dummy, dummy, dummy, trigJem); + m_jeMap.insert(std::make_pair(key, je)); + m_jeCollection->push_back(je); + } else { + const std::vector<int>& emEnergy(je->emEnergyVec()); + const std::vector<int>& hadEnergy(je->hadEnergyVec()); + const std::vector<int>& emError(je->emErrorVec()); + const std::vector<int>& hadError(je->hadErrorVec()); + const int nsl = emEnergy.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (emEnergy[slice] != 0 || hadEnergy[slice] != 0 || + emError[slice] != 0 || hadError[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + } + LVL1::DataError emErrBits(ssError); + LVL1::DataError hadErrBits(ssError); + const int linkError = jetEle.linkError(); + emErrBits.set(LVL1::DataError::Parity, jetEle.emParity()); + emErrBits.set(LVL1::DataError::LinkDown, linkError); + hadErrBits.set(LVL1::DataError::Parity, jetEle.hadParity()); + hadErrBits.set(LVL1::DataError::LinkDown, linkError >> 1); + je->addSlice(slice, jetEle.emData(), jetEle.hadData(), + emErrBits.error(), hadErrBits.error(), + linkError); + } + } else if (verbose && jetEle.data()) { + msg(MSG::VERBOSE) << "Non-zero data but no channel mapping for channel " + << chan << endreq; + msg(MSG::DEBUG); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No jet element data for channel " + << chan << " slice " << slice << endreq; + msg(MSG::DEBUG); + } + } + } else if (collection == ENERGY_SUMS) { + + // Get energy subsums + + const unsigned int ex = subBlock->ex(slice); + const unsigned int ey = subBlock->ey(slice); + const unsigned int et = subBlock->et(slice); + if (ex | ey | et) { + LVL1::JEMEtSums* sums = findEnergySums(crate, module); + if ( ! sums ) { // create new energy sums + exVec.assign(timeslices, 0); + eyVec.assign(timeslices, 0); + etVec.assign(timeslices, 0); + exVec[slice] = ex; + eyVec[slice] = ey; + etVec[slice] = et; + sums = new LVL1::JEMEtSums(swCrate, module, etVec, exVec, eyVec, + trigJem); + m_etMap.insert(std::make_pair(crate*m_modules+module, sums)); + m_etCollection->push_back(sums); + } else { + exVec = sums->ExVec(); + eyVec = sums->EyVec(); + etVec = sums->EtVec(); + const int nsl = exVec.size(); + if (timeslices != nsl) { + if (debug) { + msg() << "Inconsistent number of slices in sub-blocks" + << endreq; + } + m_rodErr = L1CaloSubBlock::ERROR_SLICES; + return; + } + if (exVec[slice] != 0 || eyVec[slice] != 0 || etVec[slice] != 0) { + if (debug) msg() << "Duplicate data for slice " + << slice << endreq; + m_rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + return; + } + exVec[slice] = ex; + eyVec[slice] = ey; + etVec[slice] = et; + sums->addEx(exVec); + sums->addEy(eyVec); + sums->addEt(etVec); + } + } else if (verbose) { + msg(MSG::VERBOSE) << "No energy sums data for crate/module/slice " + << hwCrate << "/" << module << "/" << slice + << endreq; + msg(MSG::DEBUG); + } + } + } + return; +} + +// Find TOB map key for given crate, jem, frame, loc + +int JepByteStreamV2Tool::tobKey(const int crate, const int jem, + const int frame, const int loc) +{ + return ((((((crate<<4)+jem)<<3)+frame)<<2)+loc); +} + +// Find a jet element given eta, phi + +LVL1::JetElement* JepByteStreamV2Tool::findJetElement(const double eta, + const double phi) +{ + LVL1::JetElement* tt = 0; + const unsigned int key = m_elementKey->jeKey(phi, eta); + JetElementMap::const_iterator mapIter; + mapIter = m_jeMap.find(key); + if (mapIter != m_jeMap.end()) tt = mapIter->second; + return tt; +} + +// Find energy sums for given crate, module + +LVL1::JEMEtSums* JepByteStreamV2Tool::findEnergySums(const int crate, + const int module) +{ + LVL1::JEMEtSums* sums = 0; + EnergySumsMap::const_iterator mapIter; + mapIter = m_etMap.find(crate*m_modules + module); + if (mapIter != m_etMap.end()) sums = mapIter->second; + return sums; +} + +// Find CMX TOB for given crate, jem, frame, loc + +LVL1::CMXJetTob* JepByteStreamV2Tool::findCmxTob(const int key) +{ + LVL1::CMXJetTob* tob = 0; + CmxTobMap::const_iterator mapIter; + mapIter = m_cmxTobMap.find(key); + if (mapIter != m_cmxTobMap.end()) tob = mapIter->second; + return tob; +} + +// Find CMX hits for given crate, source + +LVL1::CMXJetHits* JepByteStreamV2Tool::findCmxHits(const int crate, + const int source) +{ + LVL1::CMXJetHits* hits = 0; + CmxHitsMap::const_iterator mapIter; + mapIter = m_cmxHitsMap.find(crate*100 + source); + if (mapIter != m_cmxHitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find CMX energy sums for given crate, module, source + +LVL1::CMXEtSums* JepByteStreamV2Tool::findCmxSums(const int crate, + const int source) +{ + LVL1::CMXEtSums* sums = 0; + CmxSumsMap::const_iterator mapIter; + mapIter = m_cmxEtMap.find(crate*100 + source); + if (mapIter != m_cmxEtMap.end()) sums = mapIter->second; + return sums; +} + +// Set up jet element map + +void JepByteStreamV2Tool::setupJeMap(const JetElementCollection* + const jeCollection) +{ + m_jeMap.clear(); + if (jeCollection) { + JetElementCollection::const_iterator pos = jeCollection->begin(); + JetElementCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JetElement* const je = *pos; + const unsigned int key = m_elementKey->jeKey(je->phi(), je->eta()); + m_jeMap.insert(std::make_pair(key, je)); + } + } +} + +// Set up energy sums map + +void JepByteStreamV2Tool::setupEtMap(const EnergySumsCollection* + const etCollection) +{ + m_etMap.clear(); + if (etCollection) { + EnergySumsCollection::const_iterator pos = etCollection->begin(); + EnergySumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + LVL1::JEMEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = m_modules * crate + sums->module(); + m_etMap.insert(std::make_pair(key, sums)); + } + } +} + +// Set up CMX TOB map + +void JepByteStreamV2Tool::setupCmxTobMap(const CmxTobCollection* + const tobCollection) +{ + m_cmxTobMap.clear(); + if (tobCollection) { + CmxTobCollection::const_iterator pos = tobCollection->begin(); + CmxTobCollection::const_iterator pose = tobCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMXJetTob* const tob = *pos; + const int crate = tob->crate() - m_crateOffsetSw; + const int jem = tob->jem(); + const int frame = tob->frame(); + const int loc = tob->location(); + const int key = tobKey(crate, jem, frame, loc); + m_cmxTobMap.insert(std::make_pair(key, tob)); + } + } +} + +// Set up CMX hits map + +void JepByteStreamV2Tool::setupCmxHitsMap(const CmxHitsCollection* + const hitCollection) +{ + m_cmxHitsMap.clear(); + if (hitCollection) { + CmxHitsCollection::const_iterator pos = hitCollection->begin(); + CmxHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMXJetHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = crate*100 + hits->source(); + m_cmxHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMX energy sums map + +void JepByteStreamV2Tool::setupCmxEtMap(const CmxSumsCollection* + const etCollection) +{ + m_cmxEtMap.clear(); + if (etCollection) { + CmxSumsCollection::const_iterator pos = etCollection->begin(); + CmxSumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMXEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = crate*100 + sums->source(); + m_cmxEtMap.insert(std::make_pair(key, sums)); + } + } +} + +// Get number of slices and triggered slice offset for next slink + +bool JepByteStreamV2Tool::slinkSlices(const int crate, const int module, + const int modulesPerSlink, int& timeslices, int& trigJem) +{ + int slices = -1; + int trigJ = m_dfltSlices/2; + for (int mod = module; mod < module + modulesPerSlink; ++mod) { + for (int chan = 0; chan < m_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if ( !m_jemMaps->mapping(crate, mod, chan, eta, phi, layer)) continue; + const LVL1::JetElement* const je = findJetElement(eta, phi); + if ( !je ) continue; + const int numdat = 5; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((je->emEnergyVec()).begin(), + (je->emEnergyVec()).end(), 0); + sums[1] = std::accumulate((je->hadEnergyVec()).begin(), + (je->hadEnergyVec()).end(), 0); + sums[2] = std::accumulate((je->emErrorVec()).begin(), + (je->emErrorVec()).end(), 0); + sums[3] = std::accumulate((je->hadErrorVec()).begin(), + (je->hadErrorVec()).end(), 0); + sums[4] = std::accumulate((je->linkErrorVec()).begin(), + (je->linkErrorVec()).end(), 0); + sizes[0] = (je->emEnergyVec()).size(); + sizes[1] = (je->hadEnergyVec()).size(); + sizes[2] = (je->emErrorVec()).size(); + sizes[3] = (je->hadErrorVec()).size(); + sizes[4] = (je->linkErrorVec()).size(); + const int peak = je->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + const LVL1::JEMEtSums* const et = findEnergySums(crate, mod); + if (et) { + const int numdat = 3; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((et->ExVec()).begin(), + (et->ExVec()).end(), 0); + sums[1] = std::accumulate((et->EyVec()).begin(), + (et->EyVec()).end(), 0); + sums[2] = std::accumulate((et->EtVec()).begin(), + (et->EtVec()).end(), 0); + sizes[0] = (et->ExVec()).size(); + sizes[1] = (et->EyVec()).size(); + sizes[2] = (et->EtVec()).size(); + const int peak = et->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + } + // CMX last slink of crate + if (module/modulesPerSlink == m_slinks - 1) { + for (int jem = module; jem < module + modulesPerSlink; ++jem) { + for (int frame = 0; frame < m_frames; ++frame) { + for (int loc = 0; loc < m_locations; ++loc) { + const int key = tobKey(crate, jem, frame, loc); + const LVL1::CMXJetTob* tob = findCmxTob(key); + if (tob) { + const int numdat = 4; + std::vector<int> sums(numdat); + std::vector<int> sizes(numdat); + sums[0] = std::accumulate((tob->energyLgVec()).begin(), + (tob->energyLgVec()).end(), 0); + sums[1] = std::accumulate((tob->energySmVec()).begin(), + (tob->energySmVec()).end(), 0); + sums[2] = std::accumulate((tob->errorVec()).begin(), + (tob->errorVec()).end(), 0); + sums[3] = std::accumulate((tob->presenceMapVec()).begin(), + (tob->presenceMapVec()).end(), 0); + sizes[0] = (tob->energyLgVec()).size(); + sizes[1] = (tob->energySmVec()).size(); + sizes[2] = (tob->errorVec()).size(); + sizes[3] = (tob->presenceMapVec()).size(); + const int peak = tob->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + } + } + } + const int maxDataID1 = LVL1::CMXJetHits::MAX_SOURCE; + const int maxDataID2 = LVL1::CMXEtSums::MAX_SOURCE; + const int maxDataID = (maxDataID1 > maxDataID2) ? maxDataID1 : maxDataID2; + for (int source = 0; source < maxDataID; ++source) { + const int numdat = 6; + std::vector<unsigned int> sums(numdat); + std::vector<int> sizes(numdat); + const LVL1::CMXJetHits* hits = 0; + if (source < maxDataID1) hits = findCmxHits(crate, source); + if (hits) { + sums[0] = std::accumulate((hits->hitsVec0()).begin(), + (hits->hitsVec0()).end(), 0); + sums[1] = std::accumulate((hits->hitsVec1()).begin(), + (hits->hitsVec1()).end(), 0); + sums[2] = std::accumulate((hits->errorVec0()).begin(), + (hits->errorVec0()).end(), 0); + sums[3] = std::accumulate((hits->errorVec1()).begin(), + (hits->errorVec1()).end(), 0); + sizes[0] = (hits->hitsVec0()).size(); + sizes[1] = (hits->hitsVec1()).size(); + sizes[2] = (hits->errorVec0()).size(); + sizes[3] = (hits->errorVec1()).size(); + const int peak = hits->peak(); + for (int i = 0; i < 4; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + const LVL1::CMXEtSums* et = 0; + if (source < maxDataID2) et = findCmxSums(crate, source); + if (et) { + sums[0] = std::accumulate((et->ExVec()).begin(), + (et->ExVec()).end(), 0); + sums[1] = std::accumulate((et->EyVec()).begin(), + (et->EyVec()).end(), 0); + sums[2] = std::accumulate((et->EtVec()).begin(), + (et->EtVec()).end(), 0); + sums[3] = std::accumulate((et->ExErrorVec()).begin(), + (et->ExErrorVec()).end(), 0); + sums[4] = std::accumulate((et->EyErrorVec()).begin(), + (et->EyErrorVec()).end(), 0); + sums[5] = std::accumulate((et->EtErrorVec()).begin(), + (et->EtErrorVec()).end(), 0); + sizes[0] = (et->ExVec()).size(); + sizes[1] = (et->EyVec()).size(); + sizes[2] = (et->EtVec()).size(); + sizes[3] = (et->ExErrorVec()).size(); + sizes[4] = (et->EyErrorVec()).size(); + sizes[5] = (et->EtErrorVec()).size(); + const int peak = et->peak(); + for (int i = 0; i < numdat; ++i) { + if (sums[i] == 0) continue; + if (slices < 0) { + slices = sizes[i]; + trigJ = peak; + } else if (slices != sizes[i] || trigJ != peak) return false; + } + } + } + } + if (slices < 0) slices = m_dfltSlices; + timeslices = slices; + trigJem = trigJ; + return true; +} + +// Get energy subBlock types from CMXEtSums source type + +void JepByteStreamV2Tool::energySubBlockTypes(const int source, + CmxEnergySubBlock::SourceType& srcType, + CmxEnergySubBlock::SumType& sumType, + CmxEnergySubBlock::HitsType& hitType) +{ + switch (source) { + case LVL1::CMXEtSums::REMOTE_STANDARD: + srcType = CmxEnergySubBlock::REMOTE; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::REMOTE_RESTRICTED: + srcType = CmxEnergySubBlock::REMOTE; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::LOCAL_STANDARD: + srcType = CmxEnergySubBlock::LOCAL; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::LOCAL_RESTRICTED: + srcType = CmxEnergySubBlock::LOCAL; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::TOTAL_STANDARD: + srcType = CmxEnergySubBlock::TOTAL; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::TOTAL_RESTRICTED: + srcType = CmxEnergySubBlock::TOTAL; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::SUM_ET_STANDARD: + hitType = CmxEnergySubBlock::SUM_ET; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::SUM_ET_RESTRICTED: + hitType = CmxEnergySubBlock::SUM_ET; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::MISSING_ET_STANDARD: + hitType = CmxEnergySubBlock::MISSING_ET; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::MISSING_ET_RESTRICTED: + hitType = CmxEnergySubBlock::MISSING_ET; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::MISSING_ET_SIG_STANDARD: + hitType = CmxEnergySubBlock::MISSING_ET_SIG; + sumType = CmxEnergySubBlock::STANDARD; + break; + default: + break; + } +} + +// Get jet hits subBlock source ID from CMXJetHits source type + +int JepByteStreamV2Tool::jetSubBlockSourceId(const int source) +{ + int sourceId = CmxJetSubBlock::MAX_SOURCE_ID; + switch (source) { + case LVL1::CMXJetHits::REMOTE_MAIN: + sourceId = CmxJetSubBlock::REMOTE_MAIN; + break; + case LVL1::CMXJetHits::LOCAL_MAIN: + sourceId = CmxJetSubBlock::LOCAL_MAIN; + break; + case LVL1::CMXJetHits::TOTAL_MAIN: + sourceId = CmxJetSubBlock::TOTAL_MAIN; + break; + case LVL1::CMXJetHits::REMOTE_FORWARD: + sourceId = CmxJetSubBlock::REMOTE_FORWARD; + break; + case LVL1::CMXJetHits::LOCAL_FORWARD: + sourceId = CmxJetSubBlock::LOCAL_FORWARD; + break; + case LVL1::CMXJetHits::TOTAL_FORWARD: + sourceId = CmxJetSubBlock::TOTAL_FORWARD; + break; + case LVL1::CMXJetHits::TOPO_CHECKSUM: + sourceId = CmxJetSubBlock::TOPO_CHECKSUM; + break; + case LVL1::CMXJetHits::TOPO_OCCUPANCY_MAP: + sourceId = CmxJetSubBlock::TOPO_OCCUPANCY_MAP; + break; + case LVL1::CMXJetHits::TOPO_OCCUPANCY_COUNTS: + sourceId = CmxJetSubBlock::TOPO_OCCUPANCY_COUNTS; + break; + default: + break; + } + return sourceId; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..082775ca03798791dc9362b7ab016729d92d4785 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepByteStreamV2Tool.h @@ -0,0 +1,257 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV2TOOL_H +#define TRIGT1CALOBYTESTREAM_JEPBYTESTREAMV2TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +#include "CmxEnergySubBlock.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <class T> class FullEventAssembler; + +namespace LVL1 { + class CMXJetHits; + class CMXJetTob; + class CMXEtSums; + class IL1CaloMappingTool; + class JEMEtSums; + class JEPBSCollectionV2; + class JetElement; + class JetElementKey; +} + +namespace LVL1BS { + +class CmxJetSubBlock; +class JemSubBlockV2; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to jet elements, jet hits and energy sums, + * and JEP container to raw data conversions. + * + * Based on ROD document version X_xxx. <<== CHECK + * + * @author Peter Faulkner + */ + +class JepByteStreamV2Tool : public AthAlgTool { + + public: + JepByteStreamV2Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~JepByteStreamV2Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to jet elements + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JetElement>* jeCollection); + /// Convert ROB fragments to energy sums + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMEtSums>* etCollection); + /// Convert ROB fragments to CMX TOBs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXJetTob>* tobCollection); + /// Convert ROB fragments to CMX jet hits + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXJetHits>* hitCollection); + /// Convert ROB fragments to CMX energy sums + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::CMXEtSums>* etCollection); + + /// Convert JEP Container to bytestream + StatusCode convert(const LVL1::JEPBSCollectionV2* jep, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + enum CollectionType { JET_ELEMENTS, ENERGY_SUMS, CMX_TOBS, + CMX_HITS, CMX_SUMS }; + + typedef DataVector<LVL1::JetElement> JetElementCollection; + typedef DataVector<LVL1::JEMEtSums> EnergySumsCollection; + typedef DataVector<LVL1::CMXJetTob> CmxTobCollection; + typedef DataVector<LVL1::CMXJetHits> CmxHitsCollection; + typedef DataVector<LVL1::CMXEtSums> CmxSumsCollection; + typedef std::map<unsigned int, LVL1::JetElement*> JetElementMap; + typedef std::map<int, LVL1::JEMEtSums*> EnergySumsMap; + typedef std::map<int, LVL1::CMXJetTob*> CmxTobMap; + typedef std::map<int, LVL1::CMXJetHits*> CmxHitsMap; + typedef std::map<int, LVL1::CMXEtSums*> CmxSumsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + /// Unpack CMX-Energy sub-block + void decodeCmxEnergy(CmxEnergySubBlock* subBlock, int trigJem); + /// Unpack CMX-Jet sub-block + void decodeCmxJet(CmxJetSubBlock* subBlock, int trigJem, + CollectionType collection); + /// Unpack JEM sub-block + void decodeJem(JemSubBlockV2* subBlock, int trigJem, + CollectionType collection); + + /// Find TOB map key for given crate, jem, frame, loc + int tobKey(int crate, int jem, int frame, int loc); + /// Find a jet element given eta, phi + LVL1::JetElement* findJetElement(double eta, double phi); + /// Find energy sums for given crate, module + LVL1::JEMEtSums* findEnergySums(int crate, int module); + /// Find CMX TOB for given key + LVL1::CMXJetTob* findCmxTob(int key); + /// Find CMX hits for given crate, source + LVL1::CMXJetHits* findCmxHits(int crate, int source); + /// Find CMX energy sums for given crate, source + LVL1::CMXEtSums* findCmxSums(int crate, int source); + + /// Set up jet element map + void setupJeMap(const JetElementCollection* jeCollection); + /// Set up energy sums map + void setupEtMap(const EnergySumsCollection* enCollection); + /// Set up CMX TOB map + void setupCmxTobMap(const CmxTobCollection* tobCollection); + /// Set up CMX hits map + void setupCmxHitsMap(const CmxHitsCollection* hitCollection); + /// Set up CMX energy sums map + void setupCmxEtMap(const CmxSumsCollection* enCollection); + + /// Get number of slices and triggered slice offset for next slink + bool slinkSlices(int crate, int module, int modulesPerSlink, + int& timeslices, int& trigJem); + /// Get energy subBlock types from CMXEtSums source type + void energySubBlockTypes(int source, + CmxEnergySubBlock::SourceType& srcType, + CmxEnergySubBlock::SumType& sumType, + CmxEnergySubBlock::HitsType& hitType); + /// Get jet hits subBlock source ID from CMXJetHits source type + int jetSubBlockSourceId(int source); + + /// Channel mapping tool + ToolHandle<LVL1::IL1CaloMappingTool> m_jemMaps; + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of channels per module + int m_channels; + /// Number of crates + int m_crates; + /// Number of JEM modules per crate + int m_modules; + /// Number of RoI frames + int m_frames; + /// Number of RoI locations + int m_locations; + /// Maximum number of TOBs per module + int m_maxTobs; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Default number of slices in simulation + int m_dfltSlices; + /// Force number of slices in bytestream + int m_forceSlices; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// Jet elements to accept (0=Core, 1=Overlap) + int m_coreOverlap; + /// Unpacking error code + unsigned int m_rodErr; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Jet element key provider + LVL1::JetElementKey* m_elementKey; + /// JemSubBlock for unpacking + JemSubBlockV2* m_jemSubBlock; + /// CmxEnergySubBlock for unpacking + CmxEnergySubBlock* m_cmxEnergySubBlock; + /// CmxJetSubBlock for unpacking + CmxJetSubBlock* m_cmxJetSubBlock; + /// Unsigned int unpacking vector 0 + std::vector<unsigned int> m_uintVec0; + /// Unsigned int unpacking vector 1 + std::vector<unsigned int> m_uintVec1; + /// Unsigned int unpacking vector 2 + std::vector<unsigned int> m_uintVec2; + /// Int unpacking vector 0 + std::vector<int> m_intVec0; + /// Int unpacking vector 1 + std::vector<int> m_intVec1; + /// Int unpacking vector 2 + std::vector<int> m_intVec2; + /// Vector for current JEM sub-blocks + DataVector<JemSubBlockV2> m_jemBlocks; + /// Vector for current CMX-Energy sub-blocks + DataVector<CmxEnergySubBlock> m_cmxEnergyBlocks; + /// Vector for current CMX-Jet sub-blocks + DataVector<CmxJetSubBlock> m_cmxJetBlocks; + /// Current jet elements collection + JetElementCollection* m_jeCollection; + /// Current energy sums collection + EnergySumsCollection* m_etCollection; + /// Current CMX TOB collection + CmxTobCollection* m_cmxTobCollection; + /// Current CMX hits collection + CmxHitsCollection* m_cmxHitCollection; + /// Current CMX energy sums collection + CmxSumsCollection* m_cmxEtCollection; + /// Jet element map + JetElementMap m_jeMap; + /// Energy sums map + EnergySumsMap m_etMap; + /// CMX TOB map + CmxTobMap m_cmxTobMap; + /// CMX hits map + CmxHitsMap m_cmxHitsMap; + /// CMX energy sums map + CmxSumsMap m_cmxEtMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..4556068a8e101252e77246a589fc3756d26d35ce --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamCnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepByteStreamTool; + +/** ByteStream converter for JEP component containers. + * + * @author Peter Faulkner + */ + +template <typename Container> +class JepReadByteStreamCnv: public Converter { + + friend class CnvFactory<JepReadByteStreamCnv<Container> >; + +protected: + + JepReadByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~JepReadByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<JepByteStreamTool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "JepReadByteStreamCnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamCnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamCnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..57cc50e057958db59307b50932e29ccb4ccbe7ba --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamCnv.icc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "JepByteStreamTool.h" + +namespace LVL1BS { + +template <typename Container> +JepReadByteStreamCnv<Container>::JepReadByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepReadByteStreamCnv"), + m_tool("LVL1BS::JepByteStreamTool/JepByteStreamTool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +JepReadByteStreamCnv<Container>::~JepReadByteStreamCnv() +{ +} + +// CLID + +template <typename Container> +const CLID& JepReadByteStreamCnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode JepReadByteStreamCnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode JepReadByteStreamCnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..07f0c0d66ffcc96248c1c5998349facd07048a4c --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1Cnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMV1CNV_H +#define TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMV1CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepByteStreamV1Tool; + +/** ByteStream converter for JEP component containers. + * + * @author Peter Faulkner + */ + +template <typename Container> +class JepReadByteStreamV1Cnv: public Converter { + + friend class CnvFactory<JepReadByteStreamV1Cnv<Container> >; + +protected: + + JepReadByteStreamV1Cnv(ISvcLocator* svcloc); + +public: + + ~JepReadByteStreamV1Cnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<JepByteStreamV1Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "JepReadByteStreamV1Cnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1Cnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1Cnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..51d5adedbd19e2dbf6a0cb6c7cc5be0caada5f27 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1Cnv.icc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "JepByteStreamV1Tool.h" + +namespace LVL1BS { + +template <typename Container> +JepReadByteStreamV1Cnv<Container>::JepReadByteStreamV1Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepReadByteStreamV1Cnv"), + m_tool("LVL1BS::JepByteStreamV1Tool/JepByteStreamV1Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +JepReadByteStreamV1Cnv<Container>::~JepReadByteStreamV1Cnv() +{ +} + +// CLID + +template <typename Container> +const CLID& JepReadByteStreamV1Cnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode JepReadByteStreamV1Cnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode JepReadByteStreamV1Cnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1V2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1V2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..9c0b17020bd89799991c3ea2a2c0dd5af43ab438 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1V2Cnv.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMV1V2CNV_H +#define TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMV1V2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepByteStreamV1Tool; +class JepByteStreamV2Tool; + +/** ByteStream converter for JEP component containers which are unchanged + * post-LS1. Allows for data containing pre- or post-LS1 format sub-blocks. + * For reading only. + * + * @author Peter Faulkner + */ + +template <typename Container> +class JepReadByteStreamV1V2Cnv: public Converter { + + friend class CnvFactory<JepReadByteStreamV1V2Cnv<Container> >; + +protected: + + JepReadByteStreamV1V2Cnv(ISvcLocator* svcloc); + +public: + + ~JepReadByteStreamV1V2Cnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work pre-LS1 + ToolHandle<LVL1BS::JepByteStreamV1Tool> m_tool1; + /// Tool that does the actual work post-LS1 + ToolHandle<LVL1BS::JepByteStreamV2Tool> m_tool2; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "JepReadByteStreamV1V2Cnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1V2Cnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1V2Cnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..29f7c2b464f91ae875a154a02e826131f5ed7515 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV1V2Cnv.icc @@ -0,0 +1,164 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "JepByteStreamV1Tool.h" +#include "JepByteStreamV2Tool.h" + +namespace LVL1BS { + +template <typename Container> +JepReadByteStreamV1V2Cnv<Container>::JepReadByteStreamV1V2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepReadByteStreamV1V2Cnv"), + m_tool1("LVL1BS::JepByteStreamV1Tool/JepByteStreamV1Tool"), + m_tool2("LVL1BS::JepByteStreamV2Tool/JepByteStreamV2Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +JepReadByteStreamV1V2Cnv<Container>::~JepReadByteStreamV1V2Cnv() +{ +} + +// CLID + +template <typename Container> +const CLID& JepReadByteStreamV1V2Cnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode JepReadByteStreamV1V2Cnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tools + sc = m_tool1.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool1 << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool1 << endreq; + sc = m_tool2.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool2 << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool2 << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::WARNING << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode JepReadByteStreamV1V2Cnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID1(m_tool1->sourceIDs(nm)); + const std::vector<uint32_t>& vID2(m_tool2->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags1; + m_robDataProvider->getROBData( vID1, robFrags1 ); + IROBDataProviderSvc::VROBFRAG robFrags2; + m_robDataProvider->getROBData( vID2, robFrags2 ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags1.size() + << ", " << robFrags2.size() << endreq; + } + if (robFrags1.size() == 0 && robFrags2.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + // Pre-LS1 data + if (robFrags1.size() > 0) { + StatusCode sc = m_tool1->convert(robFrags1, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + } + // Post-LS1 data + if (robFrags2.size() > 0) { + StatusCode sc = m_tool2->convert(robFrags2, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + } + + pObj = SG::asStorable(collection); + + return StatusCode::SUCCESS; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..babe217385f6f3424f29f32d387f6ec2cf90f90a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV2Cnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMV2CNV_H +#define TRIGT1CALOBYTESTREAM_JEPREADBYTESTREAMV2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepByteStreamV2Tool; + +/** ByteStream converter for JEP component containers post LS1. + * + * @author Peter Faulkner + */ + +template <typename Container> +class JepReadByteStreamV2Cnv: public Converter { + + friend class CnvFactory<JepReadByteStreamV2Cnv<Container> >; + +protected: + + JepReadByteStreamV2Cnv(ISvcLocator* svcloc); + +public: + + ~JepReadByteStreamV2Cnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<JepByteStreamV2Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "JepReadByteStreamV2Cnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV2Cnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV2Cnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..9aad45c04c12c1cb376acbb929f0b65536b98fe5 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepReadByteStreamV2Cnv.icc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "JepByteStreamV2Tool.h" + +namespace LVL1BS { + +template <typename Container> +JepReadByteStreamV2Cnv<Container>::JepReadByteStreamV2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepReadByteStreamV2Cnv"), + m_tool("LVL1BS::JepByteStreamV2Tool/JepByteStreamV2Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +JepReadByteStreamV2Cnv<Container>::~JepReadByteStreamV2Cnv() +{ +} + +// CLID + +template <typename Container> +const CLID& JepReadByteStreamV2Cnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode JepReadByteStreamV2Cnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode JepReadByteStreamV2Cnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamCnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..a643f5545dc4b84167d142467691e799c7eac72e --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamCnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/JEPRoIBSCollection.h" + +#include "JepRoiByteStreamCnv.h" +#include "JepRoiByteStreamTool.h" + +namespace LVL1BS { + +JepRoiByteStreamCnv::JepRoiByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepRoiByteStreamCnv"), + m_tool("LVL1BS::JepRoiByteStreamTool/JepRoiByteStreamTool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +JepRoiByteStreamCnv::~JepRoiByteStreamCnv() +{ +} + +// CLID + +const CLID& JepRoiByteStreamCnv::classID() +{ + return ClassID_traits<LVL1::JEPRoIBSCollection>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepRoiByteStreamCnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode JepRoiByteStreamCnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::JEPRoIBSCollection* jep = 0; + if( !SG::fromStorable( pObj, jep ) ) { + m_log << MSG::ERROR << " Cannot cast to JEPRoIBSCollection" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( jep, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..decd4d00cc63a4ee8fd37898eae25ba2d3f6e392 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamCnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepRoiByteStreamTool; + +/** ByteStream converter for JEP RoI container + * + * @author Peter Faulkner + */ + +class JepRoiByteStreamCnv: public Converter { + + friend class CnvFactory<JepRoiByteStreamCnv>; + +protected: + + JepRoiByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~JepRoiByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from JEP Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepRoiByteStreamTool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamTool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..53193184b2d903a634dbb44d3287e9a836c73229 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamTool.cxx @@ -0,0 +1,733 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/CMMRoI.h" +#include "TrigT1CaloEvent/JEMRoI.h" +#include "TrigT1CaloEvent/JEPRoIBSCollection.h" + +#include "CmmEnergySubBlock.h" +#include "CmmJetSubBlock.h" +#include "CmmSubBlock.h" +#include "JemRoiSubBlock.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" + +#include "JepRoiByteStreamTool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IJepRoiByteStreamTool("JepRoiByteStreamTool", + 1, 1); + +const InterfaceID& JepRoiByteStreamTool::interfaceID() +{ + return IID_IJepRoiByteStreamTool; +} + +// Constructor + +JepRoiByteStreamTool::JepRoiByteStreamTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_crates(2), m_modules(16), m_srcIdMap(0), m_subBlock(0), m_rodStatus(0), + m_fea(0) +{ + declareInterface<JepRoiByteStreamTool>(this); + + declareProperty("CrateOffsetHw", m_crateOffsetHw = 12, + "Offset of JEP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of JEP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + declareProperty("ROBSourceIDsRoIB", m_sourceIDsRoIB, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 1, + "The number of S-Links per crate"); + +} + +// Destructor + +JepRoiByteStreamTool::~JepRoiByteStreamTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepRoiByteStreamTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_subDetector = eformat::TDAQ_CALO_JET_PROC_ROI; + m_srcIdMap = new L1CaloSrcIdMap(); + m_subBlock = new JemRoiSubBlock(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JepRoiByteStreamTool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_subBlock; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to JEM RoI + +StatusCode JepRoiByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMRoI>* const jeCollection) +{ + m_jeCollection = jeCollection; + return convertBs(robFrags, JEM_ROI); +} + +// Conversion bytestream to CMM RoI + +StatusCode JepRoiByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + LVL1::CMMRoI* const cmCollection) +{ + m_cmCollection = cmCollection; + return convertBs(robFrags, CMM_ROI); +} + +// Conversion of JEP container to bytestream + +StatusCode JepRoiByteStreamTool::convert( + const LVL1::JEPRoIBSCollection* const jep, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + setupJemRoiMap(jep->JemRoi()); + JemRoiMap::const_iterator mapIter = m_roiMap.begin(); + JemRoiMap::const_iterator mapIterEnd = m_roiMap.end(); + if (neutralFormat) { + setupCmmHitsMap(jep->CmmHits()); + setupCmmEtMap(jep->CmmSums()); + } + + // Loop over JEM RoI data + + const int modulesPerSlink = m_modules / m_slinks; + for (int crate=0; crate < m_crates; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + for (int module=0; module < m_modules; ++module) { + + // Pack required number of modules per slink + + if (module%modulesPerSlink == 0) { + const int daqOrRoi = 1; + const int slink = module/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq + << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq; + } + const uint32_t rodIdJem = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdJem); + if (neutralFormat) { + const L1CaloUserHeader userHeader; + theROD->push_back(userHeader.header()); + } + m_rodStatusMap.insert(make_pair(rodIdJem, m_rodStatus)); + } + if (debug) msg() << "JEM Module " << module << endreq; + if (!theROD) break; // for coverity, shouldn't happen + + // Create a sub-block (Neutral format only) + + if (neutralFormat) { + m_subBlock->clear(); + m_subBlock->setRoiHeader(m_version, hwCrate, module); + } + + // Find JEM RoIs for this module + + for (; mapIter != mapIterEnd; ++mapIter) { + const LVL1::JEMRoI* const roi = mapIter->second; + if (roi->crate() < crate) continue; + if (roi->crate() > crate) break; + if (roi->jem() < module) continue; + if (roi->jem() > module) break; + if (roi->hits() || roi->error()) { + if (neutralFormat) m_subBlock->fillRoi(*roi); + else theROD->push_back(roi->roiWord()); + } + } + + // Pack and write the sub-block + + if (neutralFormat) { + if ( !m_subBlock->pack()) { + msg(MSG::ERROR) << "JEM RoI sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "JEM RoI sub-block data words: " + << m_subBlock->dataWords() << endreq; + } + m_subBlock->write(theROD); + } + } + if (!theROD) break; // for coverity, shouldn't happen + + // Append CMM RoIs to last S-Link of the system crate + + if (crate != m_crates - 1) continue; + + // Create sub-blocks for Neutral format + + if (neutralFormat) { + const int timeslices = 1; + const int slice = 0; + + // CMM-Energy + + CmmEnergySubBlock enBlock; + const int cmmEnergyVersion = 2; // with Missing-ET-Sig + enBlock.setCmmHeader(cmmEnergyVersion, m_dataFormat, slice, hwCrate, + CmmSubBlock::SYSTEM, CmmSubBlock::CMM_ENERGY, + CmmSubBlock::LEFT, timeslices); + int maxDataID = static_cast<int>(LVL1::CMMEtSums::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + switch (dataID) { + case LVL1::CMMEtSums::LOCAL: + source = CmmEnergySubBlock::LOCAL; + break; + case LVL1::CMMEtSums::REMOTE: + source = CmmEnergySubBlock::REMOTE; + break; + case LVL1::CMMEtSums::TOTAL: + source = CmmEnergySubBlock::TOTAL; + break; + case LVL1::CMMEtSums::MISSING_ET_MAP: + case LVL1::CMMEtSums::SUM_ET_MAP: + case LVL1::CMMEtSums::MISSING_ET_SIG_MAP: + break; + default: + continue; + } + } + const LVL1::CMMEtSums* const sums = findCmmSums(crate, dataID); + if ( sums ) { + const unsigned int ex = sums->Ex(); + const unsigned int ey = sums->Ey(); + const unsigned int et = sums->Et(); + const int exErr = sums->ExError(); + const int eyErr = sums->EyError(); + const int etErr = sums->EtError(); + if (dataID == LVL1::CMMEtSums::MISSING_ET_MAP) { + enBlock.setMissingEtHits(slice, et); + } else if (dataID == LVL1::CMMEtSums::SUM_ET_MAP) { + enBlock.setSumEtHits(slice, et); + } else if (dataID == LVL1::CMMEtSums::MISSING_ET_SIG_MAP) { + enBlock.setMissingEtSigHits(slice, et); + } else { + enBlock.setSubsums(slice, source, ex, ey, et, exErr, eyErr, etErr); + } + } + } + if ( !enBlock.pack()) { + msg(MSG::ERROR) << "CMM-Energy sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Energy sub-block data words: " + << enBlock.dataWords() << endreq; + } + enBlock.write(theROD); + + // CMM-Jet + + CmmJetSubBlock jetBlock; + jetBlock.setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + CmmSubBlock::SYSTEM, CmmSubBlock::CMM_JET, + CmmSubBlock::RIGHT, timeslices); + maxDataID = static_cast<int>(LVL1::CMMJetHits::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + switch (dataID) { + case LVL1::CMMJetHits::LOCAL_MAIN: + source = CmmJetSubBlock::LOCAL_MAIN; + break; + case LVL1::CMMJetHits::REMOTE_MAIN: + source = CmmJetSubBlock::REMOTE_MAIN; + break; + case LVL1::CMMJetHits::TOTAL_MAIN: + source = CmmJetSubBlock::TOTAL_MAIN; + break; + case LVL1::CMMJetHits::LOCAL_FORWARD: + source = CmmJetSubBlock::LOCAL_FORWARD; + break; + case LVL1::CMMJetHits::REMOTE_FORWARD: + source = CmmJetSubBlock::REMOTE_FORWARD; + break; + case LVL1::CMMJetHits::TOTAL_FORWARD: + source = CmmJetSubBlock::TOTAL_FORWARD; + break; + case LVL1::CMMJetHits::ET_MAP: + break; + default: + continue; + } + } + const LVL1::CMMJetHits* const ch = findCmmHits(crate, dataID); + if ( ch ) { + const unsigned int hits = ch->Hits(); + const int errs = ch->Error(); + if (dataID == LVL1::CMMJetHits::ET_MAP) { + jetBlock.setJetEtMap(slice, hits); + } else { + jetBlock.setJetHits(slice, source, hits, errs); + } + } + } + if ( !jetBlock.pack()) { + msg(MSG::ERROR) << "CMM-Jet sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Jet sub-block data words: " + << jetBlock.dataWords() << endreq; + } + jetBlock.write(theROD); + + } else { + + // Standard format + + const LVL1::CMMRoI* const roi = jep->CmmRoi(); + if ( roi ) { + // Make sure word IDs are correct + const LVL1::CMMRoI roid(roi->jetEtHits(), roi->sumEtHits(), + roi->missingEtHits(), roi->missingEtSigHits(), + roi->ex(), roi->ey(), roi->et(), + roi->jetEtError(), roi->sumEtError(), + roi->missingEtError(), roi->missingEtSigError(), + roi->exError(), roi->eyError(), roi->etError()); + if (roid.jetEtHits() || roid.jetEtError()) { + theROD->push_back(roid.jetEtRoiWord()); + } + // CMM-Energy RoIs are not zero-supressed unless all are zero + if (roid.sumEtHits() || roid.missingEtHits() || + roid.missingEtSigHits() || roid.ex() || roid.ey() || roid.et() || + roid.sumEtError() || roid.missingEtError() || + roid.missingEtSigError() || roid.exError() || roid.eyError() || + roid.etError()) { + theROD->push_back(roid.energyRoiWord0()); + theROD->push_back(roid.energyRoiWord1()); + theROD->push_back(roid.energyRoiWord2()); + } + } + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& JepRoiByteStreamTool::sourceIDs( + const std::string& sgKey) +{ + const std::string flag("RoIB"); + const std::string::size_type pos = sgKey.find(flag); + const bool roiDaq = + (pos == std::string::npos || pos != sgKey.length() - flag.length()); + const bool empty = (roiDaq) ? m_sourceIDs.empty() : m_sourceIDsRoIB.empty(); + if (empty) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 1; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + if (roiDaq) { + if (slink < 2) m_sourceIDs.push_back(robId); + } else if (slink >= 2) m_sourceIDsRoIB.push_back(robId); + } + } + } + return (roiDaq) ? m_sourceIDs : m_sourceIDsRoIB; +} + +// Convert bytestream to given container type + +StatusCode JepRoiByteStreamTool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + std::set<uint32_t> dupRoiCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 1 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: " + << MSG::hex << sourceID << MSG::dec << endreq; + } + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word may be User Header + if (L1CaloUserHeader::isValid(*payload)) { + L1CaloUserHeader userHeader(*payload); + const int minorVersion = (*rob)->rod_version() & 0xffff; + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + } + + // Loop over sub-blocks if there are any + + unsigned int rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER) { + const int slice = 0; + if (CmmSubBlock::cmmBlock(*payload)) { + // CMMs + if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_JET) { + CmmJetSubBlock subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == CMM_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "CMM-Jet sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const LVL1::CMMRoI roi(subBlock.jetEtMap(slice), + 0,0,0,0,0,0,0,0,0,0,0,0,0); + m_cmCollection->setRoiWord(roi.jetEtRoiWord()); + } + } else { + CmmEnergySubBlock subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == CMM_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "CMM-Energy sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const LVL1::CMMRoI roi(0, subBlock.sumEtHits(slice), + subBlock.missingEtHits(slice), + subBlock.missingEtSigHits(slice), + subBlock.ex(slice, CmmEnergySubBlock::TOTAL), + subBlock.ey(slice, CmmEnergySubBlock::TOTAL), + subBlock.et(slice, CmmEnergySubBlock::TOTAL), + 0, 0, 0, 0, + subBlock.exError(slice, CmmEnergySubBlock::TOTAL), + subBlock.eyError(slice, CmmEnergySubBlock::TOTAL), + subBlock.etError(slice, CmmEnergySubBlock::TOTAL)); + m_cmCollection->setRoiWord(roi.energyRoiWord0()); + m_cmCollection->setRoiWord(roi.energyRoiWord1()); + m_cmCollection->setRoiWord(roi.energyRoiWord2()); + } + } + } else { + // JEM RoI + JemRoiSubBlock subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == JEM_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "JEM RoI sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + for (int frame = 0; frame < 8; ++frame) { + for (int forward = 0; forward < 2; ++forward) { + const LVL1::JEMRoI roi = subBlock.roi(frame, forward); + if (roi.hits() || roi.error()) { + m_jeCollection->push_back(new LVL1::JEMRoI(roi)); + } + } + } + } + } + } else { + // Just RoI word + LVL1::JEMRoI jroi; + LVL1::CMMRoI croi; + if (jroi.setRoiWord(*payload)) { + if (collection == JEM_ROI) { + if (jroi.crate() != rodCrate - m_crateOffsetHw) { + if (debug) msg() << "Inconsistent RoI crate number: " + << jroi.crate() << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + const uint32_t location = (*payload) & 0xfffc0000; + if (dupRoiCheck.insert(location).second) { + if (jroi.hits() || jroi.error()) { + m_jeCollection->push_back(new LVL1::JEMRoI(*payload)); + } + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } + } else if (croi.setRoiWord(*payload)) { + if (collection == CMM_ROI) { + uint32_t roiType = (*payload) & 0xf0000000; + if ((roiType & 0xe0000000) == 0xa0000000) roiType = 0xa0000000; + if (dupRoiCheck.insert(roiType).second) { + m_cmCollection->setRoiWord(*payload); + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } + } else { + if (debug) msg() << "Invalid RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_ROI_TYPE; + break; + } + ++payload; + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, rodErr); + } + + return StatusCode::SUCCESS; +} + +// Find CMM hits for given crate, dataID + +const LVL1::CMMJetHits* JepRoiByteStreamTool::findCmmHits(const int crate, + const int dataID) +{ + const LVL1::CMMJetHits* hits = 0; + CmmHitsMap::const_iterator mapIter; + mapIter = m_cmmHitsMap.find(crate*100 + dataID); + if (mapIter != m_cmmHitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find CMM energy sums for given crate, module, dataID + +const LVL1::CMMEtSums* JepRoiByteStreamTool::findCmmSums(const int crate, + const int dataID) +{ + const LVL1::CMMEtSums* sums = 0; + CmmSumsMap::const_iterator mapIter; + mapIter = m_cmmEtMap.find(crate*100 + dataID); + if (mapIter != m_cmmEtMap.end()) sums = mapIter->second; + return sums; +} + +// Set up JEM RoIs map + +void JepRoiByteStreamTool::setupJemRoiMap(const JemRoiCollection* + const jeCollection) +{ + m_roiMap.clear(); + if (jeCollection) { + JemRoiCollection::const_iterator pos = jeCollection->begin(); + JemRoiCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +// Set up CMM hits map + +void JepRoiByteStreamTool::setupCmmHitsMap(const CmmHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmHitsCollection::const_iterator pos = hitCollection->begin(); + CmmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMJetHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = crate*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM energy sums map + +void JepRoiByteStreamTool::setupCmmEtMap(const CmmSumsCollection* + const etCollection) +{ + m_cmmEtMap.clear(); + if (etCollection) { + CmmSumsCollection::const_iterator pos = etCollection->begin(); + CmmSumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = crate*100 + sums->dataID(); + m_cmmEtMap.insert(std::make_pair(key, sums)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamTool.h new file mode 100755 index 0000000000000000000000000000000000000000..4d791c700341771590633ae3d3a79f1708ce8d38 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamTool.h @@ -0,0 +1,154 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMTOOL_H +#define TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMTOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <class T> class FullEventAssembler; + +namespace LVL1 { + class CMMJetHits; + class CMMEtSums; + class CMMRoI; + class JEMRoI; + class JEPRoIBSCollection; +} + +namespace LVL1BS { + +class CmmEnergySubBlock; +class CmmJetSubBlock; +class JemRoiSubBlock; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to JEM RoI and CMM RoI, + * and JEP RoI container to raw data conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class JepRoiByteStreamTool : public AthAlgTool { + + public: + JepRoiByteStreamTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~JepRoiByteStreamTool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to JEM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMRoI>* jeCollection); + /// Convert ROB fragments to CMM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + LVL1::CMMRoI* cmCollection); + + /// Convert JEP RoI Container to bytestream + StatusCode convert(const LVL1::JEPRoIBSCollection* jep, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + enum CollectionType { JEM_ROI, CMM_ROI }; + + typedef DataVector<LVL1::JEMRoI> JemRoiCollection; + typedef DataVector<LVL1::CMMJetHits> CmmHitsCollection; + typedef DataVector<LVL1::CMMEtSums> CmmSumsCollection; + typedef std::map<uint32_t, const LVL1::JEMRoI*> JemRoiMap; + typedef std::map<int, const LVL1::CMMJetHits*> CmmHitsMap; + typedef std::map<int, const LVL1::CMMEtSums*> CmmSumsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Find CMM hits for given crate, data ID + const LVL1::CMMJetHits* findCmmHits(int crate, int dataID); + /// Find CMM energy sums for given crate, data ID + const LVL1::CMMEtSums* findCmmSums(int crate, int dataID); + + /// Set up JEM RoIs map + void setupJemRoiMap(const JemRoiCollection* jeCollection); + /// Set up CMM hits map + void setupCmmHitsMap(const CmmHitsCollection* hitCollection); + /// Set up CMM energy sums map + void setupCmmEtMap(const CmmSumsCollection* enCollection); + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of crates + int m_crates; + /// Number of JEM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// ROB source IDs for RoIB + std::vector<uint32_t> m_sourceIDsRoIB; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Sub-block for neutral format + JemRoiSubBlock* m_subBlock; + /// Current JEM RoI collection + JemRoiCollection* m_jeCollection; + /// Current CMM RoI collection + LVL1::CMMRoI* m_cmCollection; + /// JEM RoI map + JemRoiMap m_roiMap; + /// CMM hits map + CmmHitsMap m_cmmHitsMap; + /// CMM energy sums map + CmmSumsMap m_cmmEtMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..f0d1facd3e3fc1ee0317ee86eb88ed6d050a63fe --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Cnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/JEPRoIBSCollectionV1.h" + +#include "JepRoiByteStreamV1Cnv.h" +#include "JepRoiByteStreamV1Tool.h" + +namespace LVL1BS { + +JepRoiByteStreamV1Cnv::JepRoiByteStreamV1Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepRoiByteStreamV1Cnv"), + m_tool("LVL1BS::JepRoiByteStreamV1Tool/JepRoiByteStreamV1Tool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +JepRoiByteStreamV1Cnv::~JepRoiByteStreamV1Cnv() +{ +} + +// CLID + +const CLID& JepRoiByteStreamV1Cnv::classID() +{ + return ClassID_traits<LVL1::JEPRoIBSCollectionV1>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepRoiByteStreamV1Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode JepRoiByteStreamV1Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::JEPRoIBSCollectionV1* jep = 0; + if( !SG::fromStorable( pObj, jep ) ) { + m_log << MSG::ERROR << " Cannot cast to JEPRoIBSCollectionV1" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( jep, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..11a168fbd9af84d7890d6824c1fd009888226e96 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Cnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV1CNV_H +#define TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV1CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepRoiByteStreamV1Tool; + +/** ByteStream converter for JEP RoI container + * + * @author Peter Faulkner + */ + +class JepRoiByteStreamV1Cnv: public Converter { + + friend class CnvFactory<JepRoiByteStreamV1Cnv>; + +protected: + + JepRoiByteStreamV1Cnv(ISvcLocator* svcloc); + +public: + + ~JepRoiByteStreamV1Cnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from JEP Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepRoiByteStreamV1Tool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..4e8ce822b5c1440a3d30b1785bfa69866e5857d3 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Tool.cxx @@ -0,0 +1,745 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/CMMRoI.h" +#include "TrigT1CaloEvent/JEMRoI.h" +#include "TrigT1CaloEvent/JEPRoIBSCollectionV1.h" + +#include "CmmEnergySubBlock.h" +#include "CmmJetSubBlock.h" +#include "CmmSubBlock.h" +#include "JemRoiSubBlockV1.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" + +#include "JepRoiByteStreamV1Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IJepRoiByteStreamV1Tool("JepRoiByteStreamV1Tool", + 1, 1); + +const InterfaceID& JepRoiByteStreamV1Tool::interfaceID() +{ + return IID_IJepRoiByteStreamV1Tool; +} + +// Constructor + +JepRoiByteStreamV1Tool::JepRoiByteStreamV1Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_crates(2), m_modules(16), m_srcIdMap(0), m_subBlock(0), m_rodStatus(0), + m_fea(0) +{ + declareInterface<JepRoiByteStreamV1Tool>(this); + + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + declareProperty("CrateOffsetHw", m_crateOffsetHw = 12, + "Offset of JEP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of JEP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + declareProperty("ROBSourceIDsRoIB", m_sourceIDsRoIB, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 1, + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 1, + "The number of S-Links per crate"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +JepRoiByteStreamV1Tool::~JepRoiByteStreamV1Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepRoiByteStreamV1Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_subDetector = eformat::TDAQ_CALO_JET_PROC_ROI; + m_srcIdMap = new L1CaloSrcIdMap(); + m_subBlock = new JemRoiSubBlockV1(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JepRoiByteStreamV1Tool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_subBlock; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to JEM RoI + +StatusCode JepRoiByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMRoI>* const jeCollection) +{ + m_jeCollection = jeCollection; + return convertBs(robFrags, JEM_ROI); +} + +// Conversion bytestream to CMM RoI + +StatusCode JepRoiByteStreamV1Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + LVL1::CMMRoI* const cmCollection) +{ + m_cmCollection = cmCollection; + return convertBs(robFrags, CMM_ROI); +} + +// Conversion of JEP container to bytestream + +StatusCode JepRoiByteStreamV1Tool::convert( + const LVL1::JEPRoIBSCollectionV1* const jep, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersionPreLS1(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + setupJemRoiMap(jep->JemRoi()); + JemRoiMap::const_iterator mapIter = m_roiMap.begin(); + JemRoiMap::const_iterator mapIterEnd = m_roiMap.end(); + if (neutralFormat) { + setupCmmHitsMap(jep->CmmHits()); + setupCmmEtMap(jep->CmmSums()); + } + + // Loop over JEM RoI data + + const int modulesPerSlink = m_modules / m_slinks; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + for (int module=0; module < m_modules; ++module) { + + // Pack required number of modules per slink + + if (module%modulesPerSlink == 0) { + const int daqOrRoi = 1; + const int slink = module/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq + << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq; + } + const uint32_t rodIdJem = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdJem); + if (neutralFormat) { + const L1CaloUserHeader userHeader; + theROD->push_back(userHeader.header()); + } + m_rodStatusMap.insert(make_pair(rodIdJem, m_rodStatus)); + } + if (debug) msg() << "JEM Module " << module << endreq; + if (!theROD) break; // for coverity, shouldn't happen + + // Create a sub-block (Neutral format only) + + if (neutralFormat) { + m_subBlock->clear(); + m_subBlock->setRoiHeader(m_version, hwCrate, module); + } + + // Find JEM RoIs for this module + + for (; mapIter != mapIterEnd; ++mapIter) { + const LVL1::JEMRoI* const roi = mapIter->second; + if (roi->crate() < crate) continue; + if (roi->crate() > crate) break; + if (roi->jem() < module) continue; + if (roi->jem() > module) break; + if (roi->hits() || roi->error()) { + if (neutralFormat) m_subBlock->fillRoi(*roi); + else theROD->push_back(roi->roiWord()); + } + } + + // Pack and write the sub-block + + if (neutralFormat) { + if ( !m_subBlock->pack()) { + msg(MSG::ERROR) << "JEM RoI sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "JEM RoI sub-block data words: " + << m_subBlock->dataWords() << endreq; + } + m_subBlock->write(theROD); + } + } + if (!theROD) break; // for coverity, shouldn't happen + + // Append CMM RoIs to last S-Link of the system crate + + if (crate != m_crates - 1) continue; + + // Create sub-blocks for Neutral format + + if (neutralFormat) { + const int timeslices = 1; + const int slice = 0; + + // CMM-Energy + + CmmEnergySubBlock enBlock; + const int cmmEnergyVersion = 2; // with Missing-ET-Sig + enBlock.setCmmHeader(cmmEnergyVersion, m_dataFormat, slice, hwCrate, + CmmSubBlock::SYSTEM, CmmSubBlock::CMM_ENERGY, + CmmSubBlock::LEFT, timeslices); + int maxDataID = static_cast<int>(LVL1::CMMEtSums::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + switch (dataID) { + case LVL1::CMMEtSums::LOCAL: + source = CmmEnergySubBlock::LOCAL; + break; + case LVL1::CMMEtSums::REMOTE: + source = CmmEnergySubBlock::REMOTE; + break; + case LVL1::CMMEtSums::TOTAL: + source = CmmEnergySubBlock::TOTAL; + break; + case LVL1::CMMEtSums::MISSING_ET_MAP: + case LVL1::CMMEtSums::SUM_ET_MAP: + case LVL1::CMMEtSums::MISSING_ET_SIG_MAP: + break; + default: + continue; + } + } + const LVL1::CMMEtSums* const sums = findCmmSums(crate, dataID); + if ( sums ) { + const unsigned int ex = sums->Ex(); + const unsigned int ey = sums->Ey(); + const unsigned int et = sums->Et(); + const int exErr = sums->ExError(); + const int eyErr = sums->EyError(); + const int etErr = sums->EtError(); + if (dataID == LVL1::CMMEtSums::MISSING_ET_MAP) { + enBlock.setMissingEtHits(slice, et); + } else if (dataID == LVL1::CMMEtSums::SUM_ET_MAP) { + enBlock.setSumEtHits(slice, et); + } else if (dataID == LVL1::CMMEtSums::MISSING_ET_SIG_MAP) { + enBlock.setMissingEtSigHits(slice, et); + } else { + enBlock.setSubsums(slice, source, ex, ey, et, exErr, eyErr, etErr); + } + } + } + if ( !enBlock.pack()) { + msg(MSG::ERROR) << "CMM-Energy sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Energy sub-block data words: " + << enBlock.dataWords() << endreq; + } + enBlock.write(theROD); + + // CMM-Jet + + CmmJetSubBlock jetBlock; + jetBlock.setCmmHeader(m_version, m_dataFormat, slice, hwCrate, + CmmSubBlock::SYSTEM, CmmSubBlock::CMM_JET, + CmmSubBlock::RIGHT, timeslices); + maxDataID = static_cast<int>(LVL1::CMMJetHits::MAXID); + for (int dataID = 0; dataID < maxDataID; ++dataID) { + int source = dataID; + if (dataID >= m_modules) { + switch (dataID) { + case LVL1::CMMJetHits::LOCAL_MAIN: + source = CmmJetSubBlock::LOCAL_MAIN; + break; + case LVL1::CMMJetHits::REMOTE_MAIN: + source = CmmJetSubBlock::REMOTE_MAIN; + break; + case LVL1::CMMJetHits::TOTAL_MAIN: + source = CmmJetSubBlock::TOTAL_MAIN; + break; + case LVL1::CMMJetHits::LOCAL_FORWARD: + source = CmmJetSubBlock::LOCAL_FORWARD; + break; + case LVL1::CMMJetHits::REMOTE_FORWARD: + source = CmmJetSubBlock::REMOTE_FORWARD; + break; + case LVL1::CMMJetHits::TOTAL_FORWARD: + source = CmmJetSubBlock::TOTAL_FORWARD; + break; + case LVL1::CMMJetHits::ET_MAP: + break; + default: + continue; + } + } + const LVL1::CMMJetHits* const ch = findCmmHits(crate, dataID); + if ( ch ) { + const unsigned int hits = ch->Hits(); + const int errs = ch->Error(); + if (dataID == LVL1::CMMJetHits::ET_MAP) { + jetBlock.setJetEtMap(slice, hits); + } else { + jetBlock.setJetHits(slice, source, hits, errs); + } + } + } + if ( !jetBlock.pack()) { + msg(MSG::ERROR) << "CMM-Jet sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMM-Jet sub-block data words: " + << jetBlock.dataWords() << endreq; + } + jetBlock.write(theROD); + + } else { + + // Standard format + + const LVL1::CMMRoI* const roi = jep->CmmRoi(); + if ( roi ) { + // Make sure word IDs are correct + const LVL1::CMMRoI roid(roi->jetEtHits(), roi->sumEtHits(), + roi->missingEtHits(), roi->missingEtSigHits(), + roi->ex(), roi->ey(), roi->et(), + roi->jetEtError(), roi->sumEtError(), + roi->missingEtError(), roi->missingEtSigError(), + roi->exError(), roi->eyError(), roi->etError()); + if (roid.jetEtHits() || roid.jetEtError()) { + theROD->push_back(roid.jetEtRoiWord()); + } + // CMM-Energy RoIs are not zero-supressed unless all are zero + if (roid.sumEtHits() || roid.missingEtHits() || + roid.missingEtSigHits() || roid.ex() || roid.ey() || roid.et() || + roid.sumEtError() || roid.missingEtError() || + roid.missingEtSigError() || roid.exError() || roid.eyError() || + roid.etError()) { + theROD->push_back(roid.energyRoiWord0()); + theROD->push_back(roid.energyRoiWord1()); + theROD->push_back(roid.energyRoiWord2()); + } + } + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& JepRoiByteStreamV1Tool::sourceIDs( + const std::string& sgKey) +{ + const std::string flag("RoIB"); + const std::string::size_type pos = sgKey.find(flag); + const bool roiDaq = + (pos == std::string::npos || pos != sgKey.length() - flag.length()); + const bool empty = (roiDaq) ? m_sourceIDs.empty() : m_sourceIDsRoIB.empty(); + if (empty) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 1; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + if (roiDaq) { + if (slink < 2) m_sourceIDs.push_back(robId); + } else if (slink >= 2) m_sourceIDsRoIB.push_back(robId); + } + } + } + return (roiDaq) ? m_sourceIDs : m_sourceIDsRoIB; +} + +// Convert bytestream to given container type + +StatusCode JepRoiByteStreamV1Tool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + std::set<uint32_t> dupRoiCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 1 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: " + << MSG::hex << sourceID << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion > m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping post-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word may be User Header + if (L1CaloUserHeader::isValid(*payload)) { + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + } + + // Loop over sub-blocks if there are any + + unsigned int rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER) { + const int slice = 0; + if (CmmSubBlock::cmmBlock(*payload)) { + // CMMs + if (CmmSubBlock::cmmType(*payload) == CmmSubBlock::CMM_JET) { + CmmJetSubBlock subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == CMM_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "CMM-Jet sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const LVL1::CMMRoI roi(subBlock.jetEtMap(slice), + 0,0,0,0,0,0,0,0,0,0,0,0,0); + m_cmCollection->setRoiWord(roi.jetEtRoiWord()); + } + } else { + CmmEnergySubBlock subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == CMM_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "CMM-Energy sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const LVL1::CMMRoI roi(0, subBlock.sumEtHits(slice), + subBlock.missingEtHits(slice), + subBlock.missingEtSigHits(slice), + subBlock.ex(slice, CmmEnergySubBlock::TOTAL), + subBlock.ey(slice, CmmEnergySubBlock::TOTAL), + subBlock.et(slice, CmmEnergySubBlock::TOTAL), + 0, 0, 0, 0, + subBlock.exError(slice, CmmEnergySubBlock::TOTAL), + subBlock.eyError(slice, CmmEnergySubBlock::TOTAL), + subBlock.etError(slice, CmmEnergySubBlock::TOTAL)); + m_cmCollection->setRoiWord(roi.energyRoiWord0()); + m_cmCollection->setRoiWord(roi.energyRoiWord1()); + m_cmCollection->setRoiWord(roi.energyRoiWord2()); + } + } + } else { + // JEM RoI + JemRoiSubBlockV1 subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == JEM_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "JEM RoI sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + for (int frame = 0; frame < 8; ++frame) { + for (int forward = 0; forward < 2; ++forward) { + const LVL1::JEMRoI roi = subBlock.roi(frame, forward); + if (roi.hits() || roi.error()) { + m_jeCollection->push_back(new LVL1::JEMRoI(roi)); + } + } + } + } + } + } else { + // Just RoI word + LVL1::JEMRoI jroi; + LVL1::CMMRoI croi; + if (jroi.setRoiWord(*payload)) { + if (collection == JEM_ROI) { + if (jroi.crate() != rodCrate - m_crateOffsetHw) { + if (debug) msg() << "Inconsistent RoI crate number: " + << jroi.crate() << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + const uint32_t location = (*payload) & 0xfffc0000; + if (dupRoiCheck.insert(location).second) { + if (jroi.hits() || jroi.error()) { + m_jeCollection->push_back(new LVL1::JEMRoI(*payload)); + } + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } + } else if (croi.setRoiWord(*payload)) { + if (collection == CMM_ROI) { + uint32_t roiType = (*payload) & 0xf0000000; + if ((roiType & 0xe0000000) == 0xa0000000) roiType = 0xa0000000; + if (dupRoiCheck.insert(roiType).second) { + m_cmCollection->setRoiWord(*payload); + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } + } else { + if (debug) msg() << "Invalid RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_ROI_TYPE; + break; + } + ++payload; + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, rodErr); + } + + return StatusCode::SUCCESS; +} + +// Find CMM hits for given crate, dataID + +const LVL1::CMMJetHits* JepRoiByteStreamV1Tool::findCmmHits(const int crate, + const int dataID) +{ + const LVL1::CMMJetHits* hits = 0; + CmmHitsMap::const_iterator mapIter; + mapIter = m_cmmHitsMap.find(crate*100 + dataID); + if (mapIter != m_cmmHitsMap.end()) hits = mapIter->second; + return hits; +} + +// Find CMM energy sums for given crate, module, dataID + +const LVL1::CMMEtSums* JepRoiByteStreamV1Tool::findCmmSums(const int crate, + const int dataID) +{ + const LVL1::CMMEtSums* sums = 0; + CmmSumsMap::const_iterator mapIter; + mapIter = m_cmmEtMap.find(crate*100 + dataID); + if (mapIter != m_cmmEtMap.end()) sums = mapIter->second; + return sums; +} + +// Set up JEM RoIs map + +void JepRoiByteStreamV1Tool::setupJemRoiMap(const JemRoiCollection* + const jeCollection) +{ + m_roiMap.clear(); + if (jeCollection) { + JemRoiCollection::const_iterator pos = jeCollection->begin(); + JemRoiCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +// Set up CMM hits map + +void JepRoiByteStreamV1Tool::setupCmmHitsMap(const CmmHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmHitsCollection::const_iterator pos = hitCollection->begin(); + CmmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMJetHits* const hits = *pos; + const int crate = hits->crate() - m_crateOffsetSw; + const int key = crate*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM energy sums map + +void JepRoiByteStreamV1Tool::setupCmmEtMap(const CmmSumsCollection* + const etCollection) +{ + m_cmmEtMap.clear(); + if (etCollection) { + CmmSumsCollection::const_iterator pos = etCollection->begin(); + CmmSumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = crate*100 + sums->dataID(); + m_cmmEtMap.insert(std::make_pair(key, sums)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..de988f341856c64d9c9d29fddc6f14afea7752da --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV1Tool.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV1TOOL_H +#define TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV1TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <class T> class FullEventAssembler; + +namespace LVL1 { + class CMMJetHits; + class CMMEtSums; + class CMMRoI; + class JEMRoI; + class JEPRoIBSCollectionV1; +} + +namespace LVL1BS { + +class CmmEnergySubBlock; +class CmmJetSubBlock; +class JemRoiSubBlockV1; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to JEM RoI and CMM RoI, + * and JEP RoI container to raw data conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class JepRoiByteStreamV1Tool : public AthAlgTool { + + public: + JepRoiByteStreamV1Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~JepRoiByteStreamV1Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to JEM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMRoI>* jeCollection); + /// Convert ROB fragments to CMM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + LVL1::CMMRoI* cmCollection); + + /// Convert JEP RoI Container to bytestream + StatusCode convert(const LVL1::JEPRoIBSCollectionV1* jep, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + enum CollectionType { JEM_ROI, CMM_ROI }; + + typedef DataVector<LVL1::JEMRoI> JemRoiCollection; + typedef DataVector<LVL1::CMMJetHits> CmmHitsCollection; + typedef DataVector<LVL1::CMMEtSums> CmmSumsCollection; + typedef std::map<uint32_t, const LVL1::JEMRoI*> JemRoiMap; + typedef std::map<int, const LVL1::CMMJetHits*> CmmHitsMap; + typedef std::map<int, const LVL1::CMMEtSums*> CmmSumsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Find CMM hits for given crate, data ID + const LVL1::CMMJetHits* findCmmHits(int crate, int dataID); + /// Find CMM energy sums for given crate, data ID + const LVL1::CMMEtSums* findCmmSums(int crate, int dataID); + + /// Set up JEM RoIs map + void setupJemRoiMap(const JemRoiCollection* jeCollection); + /// Set up CMM hits map + void setupCmmHitsMap(const CmmHitsCollection* hitCollection); + /// Set up CMM energy sums map + void setupCmmEtMap(const CmmSumsCollection* enCollection); + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of crates + int m_crates; + /// Number of JEM modules per crate + int m_modules; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// ROB source IDs for RoIB + std::vector<uint32_t> m_sourceIDsRoIB; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Sub-block for neutral format + JemRoiSubBlockV1* m_subBlock; + /// Current JEM RoI collection + JemRoiCollection* m_jeCollection; + /// Current CMM RoI collection + LVL1::CMMRoI* m_cmCollection; + /// JEM RoI map + JemRoiMap m_roiMap; + /// CMM hits map + CmmHitsMap m_cmmHitsMap; + /// CMM energy sums map + CmmSumsMap m_cmmEtMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Cnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Cnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..51c66370575956c6ff569e3b15245d18b1e4d6c6 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Cnv.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/JEPRoIBSCollectionV2.h" + +#include "JepRoiByteStreamV2Cnv.h" +#include "JepRoiByteStreamV2Tool.h" + +namespace LVL1BS { + +JepRoiByteStreamV2Cnv::JepRoiByteStreamV2Cnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepRoiByteStreamV2Cnv"), + m_tool("LVL1BS::JepRoiByteStreamV2Tool/JepRoiByteStreamV2Tool"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +JepRoiByteStreamV2Cnv::~JepRoiByteStreamV2Cnv() +{ +} + +// CLID + +const CLID& JepRoiByteStreamV2Cnv::classID() +{ + return ClassID_traits<LVL1::JEPRoIBSCollectionV2>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepRoiByteStreamV2Cnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return StatusCode::FAILURE; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createRep should create the bytestream from RDOs. + +StatusCode JepRoiByteStreamV2Cnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + LVL1::JEPRoIBSCollectionV2* jep = 0; + if( !SG::fromStorable( pObj, jep ) ) { + m_log << MSG::ERROR << " Cannot cast to JEPRoIBSCollectionV2" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( jep, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..c165db2f8e994ce03e864d7d36c70619e1399626 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Cnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV2CNV_H +#define TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepRoiByteStreamV2Tool; + +/** ByteStream converter for JEP RoI container post LS1 + * + * @author Peter Faulkner + */ + +class JepRoiByteStreamV2Cnv: public Converter { + + friend class CnvFactory<JepRoiByteStreamV2Cnv>; + +protected: + + JepRoiByteStreamV2Cnv(ISvcLocator* svcloc); + +public: + + ~JepRoiByteStreamV2Cnv(); + + virtual StatusCode initialize(); + /// Create ByteStream from JEP Container + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepRoiByteStreamV2Tool> m_tool; + + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Tool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..56caeb77712bf530a391e3b737dfb356e289f16d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Tool.cxx @@ -0,0 +1,698 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/CMXEtSums.h" +#include "TrigT1CaloEvent/CMXRoI.h" +#include "TrigT1CaloEvent/JEMTobRoI.h" +#include "TrigT1CaloEvent/JEPRoIBSCollectionV2.h" + +#include "CmxSubBlock.h" +#include "JemRoiSubBlockV2.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" + +#include "JepRoiByteStreamV2Tool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IJepRoiByteStreamV2Tool("JepRoiByteStreamV2Tool", + 1, 1); + +const InterfaceID& JepRoiByteStreamV2Tool::interfaceID() +{ + return IID_IJepRoiByteStreamV2Tool; +} + +// Constructor + +JepRoiByteStreamV2Tool::JepRoiByteStreamV2Tool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_crates(2), m_modules(16), m_frames(8), m_maxRoiWords(6), + m_srcIdMap(0), m_subBlock(0), m_rodStatus(0), m_fea(0) +{ + declareInterface<JepRoiByteStreamV2Tool>(this); + + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + declareProperty("CrateOffsetHw", m_crateOffsetHw = 12, + "Offset of JEP crate numbers in bytestream"); + declareProperty("CrateOffsetSw", m_crateOffsetSw = 0, + "Offset of JEP crate numbers in RDOs"); + + // Properties for reading bytestream only + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + declareProperty("ROBSourceIDsRoIB", m_sourceIDsRoIB, + "ROB fragment source identifiers"); + + // Properties for writing bytestream only + declareProperty("DataVersion", m_version = 2, //<<== CHECK + "Format version number in sub-block header"); + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-1) in sub-block header"); + declareProperty("SlinksPerCrate", m_slinks = 1, + "The number of S-Links per crate"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = m_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +JepRoiByteStreamV2Tool::~JepRoiByteStreamV2Tool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JepRoiByteStreamV2Tool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_subDetector = eformat::TDAQ_CALO_JET_PROC_ROI; + m_srcIdMap = new L1CaloSrcIdMap(); + m_subBlock = new JemRoiSubBlockV2(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JepRoiByteStreamV2Tool::finalize() +{ + delete m_fea; + delete m_rodStatus; + delete m_subBlock; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to JEM RoI + +StatusCode JepRoiByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMTobRoI>* const jeCollection) +{ + m_jeCollection = jeCollection; + return convertBs(robFrags, JEM_ROI); +} + +// Conversion bytestream to CMX RoI + +StatusCode JepRoiByteStreamV2Tool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + LVL1::CMXRoI* const cmCollection) +{ + m_cmCollection = cmCollection; + return convertBs(robFrags, CMX_ROI); +} + +// Conversion of JEP container to bytestream + +StatusCode JepRoiByteStreamV2Tool::convert( + const LVL1::JEPRoIBSCollectionV2* const jep, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersion(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up the container maps + + const bool neutralFormat = m_dataFormat == L1CaloSubBlock::NEUTRAL; + setupJemRoiMap(jep->JemRoi()); + JemRoiMap::const_iterator mapIter = m_roiMap.begin(); + JemRoiMap::const_iterator mapIterEnd = m_roiMap.end(); + if (neutralFormat) { + setupCmxEtMap(jep->CmxSums()); + } + + // Loop over JEM RoI data + + const int modulesPerSlink = m_modules / m_slinks; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + const int hwCrate = crate + m_crateOffsetHw; + + for (int module=0; module < m_modules; ++module) { + + // Pack required number of modules per slink + + if (module%modulesPerSlink == 0) { + const int daqOrRoi = 1; + const int slink = module/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << hwCrate + << " slink " << slink << endreq + << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq; + } + const uint32_t rodIdJem = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdJem); + if (neutralFormat) { + const L1CaloUserHeader userHeader; + theROD->push_back(userHeader.header()); + } + m_rodStatusMap.insert(make_pair(rodIdJem, m_rodStatus)); + } + if (debug) msg() << "JEM Module " << module << endreq; + if (!theROD) break; // for coverity, shouldn't happen + + // Create a sub-block (Neutral format only) + + if (neutralFormat) { + m_subBlock->clear(); + m_subBlock->setRoiHeader(m_version, hwCrate, module); + } + + // Find JEM RoIs for this module + + for (; mapIter != mapIterEnd; ++mapIter) { + const LVL1::JEMTobRoI* const roi = mapIter->second; + if (roi->crate() < crate) continue; + if (roi->crate() > crate) break; + if (roi->jem() < module) continue; + if (roi->jem() > module) break; + if (roi->energyLarge() || roi->energySmall()) { + if (neutralFormat) m_subBlock->fillRoi(*roi); + else theROD->push_back(roi->roiWord()); + } + } + + // Pack and write the sub-block + + if (neutralFormat) { + if ( !m_subBlock->pack()) { + msg(MSG::ERROR) << "JEM RoI sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "JEM RoI sub-block data words: " + << m_subBlock->dataWords() << endreq; + } + m_subBlock->write(theROD); + } + } + if (!theROD) break; // for coverity, shouldn't happen + + // Append CMX RoIs to last S-Link of the system crate + + if (crate != m_crates - 1) continue; + + // Create sub-blocks for Neutral format + + if (neutralFormat) { + const int timeslices = 1; + const int slice = 0; + + // CMX-Energy + + CmxEnergySubBlock subBlock; + const int cmxEnergyVersion = 3; //<<== CHECK + subBlock.setCmxHeader(cmxEnergyVersion, m_dataFormat, slice, hwCrate, + CmxSubBlock::SYSTEM, CmxSubBlock::CMX_ENERGY, + CmxSubBlock::LEFT, timeslices); + int maxSource = static_cast<int>(LVL1::CMXEtSums::MAX_SOURCE); + for (int source = 0; source < maxSource; ++source) { + const LVL1::CMXEtSums* const sums = findCmxSums(crate, source); + if ( sums ) { + const unsigned int ex = sums->Ex(); + const unsigned int ey = sums->Ey(); + const unsigned int et = sums->Et(); + const int exErr = sums->ExError(); + const int eyErr = sums->EyError(); + const int etErr = sums->EtError(); + if (source < m_modules) { + subBlock.setSubsums(slice, source, ex, ey, et, exErr, eyErr, etErr); + } else { + CmxEnergySubBlock::SourceType srcType = CmxEnergySubBlock::MAX_SOURCE_TYPE; + CmxEnergySubBlock::SumType sumType = CmxEnergySubBlock::MAX_SUM_TYPE; + CmxEnergySubBlock::HitsType hitType = CmxEnergySubBlock::MAX_HITS_TYPE; + energySubBlockTypes(source, srcType, sumType, hitType); + if (srcType != CmxEnergySubBlock::MAX_SOURCE_TYPE) { + subBlock.setSubsums(slice, srcType, sumType, ex, ey, et, + exErr, eyErr, etErr); + } else if (hitType != CmxEnergySubBlock::MAX_HITS_TYPE) { + subBlock.setEtHits(slice, hitType, sumType, et); + } + } + } + } + if ( !subBlock.pack()) { + msg(MSG::ERROR) << "CMX-Energy sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (debug) { + msg() << "CMX-Energy sub-block data words: " + << subBlock.dataWords() << endreq; + } + subBlock.write(theROD); + + } else { + + // Standard format + + const LVL1::CMXRoI* const roi = jep->CmxRoi(); + if ( roi ) { + // CMX-Energy RoIs are not zero-supressed unless all are zero + for (int word = 0; word < m_maxRoiWords; ++word) { + theROD->push_back(roi->roiWord(word)); + } + } + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& JepRoiByteStreamV2Tool::sourceIDs( + const std::string& sgKey) +{ + const std::string flag("RoIB"); + const std::string::size_type pos = sgKey.find(flag); + const bool roiDaq = + (pos == std::string::npos || pos != sgKey.length() - flag.length()); + const bool empty = (roiDaq) ? m_sourceIDs.empty() : m_sourceIDsRoIB.empty(); + if (empty) { + const int maxCrates = m_crates + m_crateOffsetHw; + const int maxSlinks = m_srcIdMap->maxSlinks(); + for (int hwCrate = m_crateOffsetHw; hwCrate < maxCrates; ++hwCrate) { + for (int slink = 0; slink < maxSlinks; ++slink) { + const int daqOrRoi = 1; + const uint32_t rodId = m_srcIdMap->getRodID(hwCrate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + if (roiDaq) { + if (slink < 2) m_sourceIDs.push_back(robId); + } else if (slink >= 2) m_sourceIDsRoIB.push_back(robId); + } + } + } + return (roiDaq) ? m_sourceIDs : m_sourceIDsRoIB; +} + +// Convert bytestream to given container type + +StatusCode JepRoiByteStreamV2Tool::convertBs( + const IROBDataProviderSvc::VROBFRAG& robFrags, + const CollectionType collection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + std::set<uint32_t> dupRoiCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 1 || + (m_srcIdMap->slink(sourceID) != 0 && m_srcIdMap->slink(sourceID) != 2) || + m_srcIdMap->crate(sourceID) < m_crateOffsetHw || + m_srcIdMap->crate(sourceID) >= m_crateOffsetHw + m_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: " + << MSG::hex << sourceID << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion <= m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping pre-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word may be User Header + if (L1CaloUserHeader::isValid(*payload)) { + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Unexpected number of user header words: " + << headerWords << endreq; + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + } + + // Loop over sub-blocks if there are any + + unsigned int rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER) { + const int slice = 0; + if (CmxSubBlock::cmxBlock(*payload)) { + // CMXs + if (CmxSubBlock::cmxType(*payload) == CmxSubBlock::CMX_ENERGY) { + CmxEnergySubBlock subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == CMX_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "CMX-Energy sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + const LVL1::CMXRoI roi( + subBlock.energy(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::STANDARD, + CmxEnergySubBlock::ENERGY_EX), + subBlock.energy(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::STANDARD, + CmxEnergySubBlock::ENERGY_EY), + subBlock.energy(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::STANDARD, + CmxEnergySubBlock::ENERGY_ET), + subBlock.error(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::STANDARD, + CmxEnergySubBlock::ENERGY_EX), + subBlock.error(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::STANDARD, + CmxEnergySubBlock::ENERGY_EY), + subBlock.error(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::STANDARD, + CmxEnergySubBlock::ENERGY_ET), + subBlock.hits(slice, CmxEnergySubBlock::SUM_ET, + CmxEnergySubBlock::STANDARD), + subBlock.hits(slice, CmxEnergySubBlock::MISSING_ET, + CmxEnergySubBlock::STANDARD), + subBlock.hits(slice, CmxEnergySubBlock::MISSING_ET_SIG, + CmxEnergySubBlock::STANDARD), + subBlock.energy(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::RESTRICTED_WEIGHTED, + CmxEnergySubBlock::ENERGY_EX), + subBlock.energy(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::RESTRICTED_WEIGHTED, + CmxEnergySubBlock::ENERGY_EY), + subBlock.energy(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::RESTRICTED_WEIGHTED, + CmxEnergySubBlock::ENERGY_ET), + subBlock.error(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::RESTRICTED_WEIGHTED, + CmxEnergySubBlock::ENERGY_EX), + subBlock.error(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::RESTRICTED_WEIGHTED, + CmxEnergySubBlock::ENERGY_EY), + subBlock.error(slice, CmxEnergySubBlock::TOTAL, + CmxEnergySubBlock::RESTRICTED_WEIGHTED, + CmxEnergySubBlock::ENERGY_ET), + subBlock.hits(slice, CmxEnergySubBlock::SUM_ET, + CmxEnergySubBlock::RESTRICTED_WEIGHTED), + subBlock.hits(slice, CmxEnergySubBlock::MISSING_ET, + CmxEnergySubBlock::RESTRICTED_WEIGHTED)); + for (int word = 0; word < m_maxRoiWords; ++word) { + m_cmCollection->setRoiWord(roi.roiWord(word)); + } + } + } + } else { + // JEM RoI + JemRoiSubBlockV2 subBlock; + payload = subBlock.read(payload, payloadEnd); + if (collection == JEM_ROI) { + if (subBlock.dataWords() && !subBlock.unpack()) { + if (debug) { + std::string errMsg(subBlock.unpackErrorMsg()); + msg() << "JEM RoI sub-block unpacking failed: " + << errMsg << endreq; + } + rodErr = m_subBlock->unpackErrorCode(); + break; + } + for (int frame = 0; frame < m_frames; ++frame) { + const LVL1::JEMTobRoI roi = subBlock.roi(frame); + if (roi.energyLarge() || roi.energySmall()) { + m_jeCollection->push_back(new LVL1::JEMTobRoI(roi)); + } + } + } + } + } else { + // Just RoI word + LVL1::JEMTobRoI jroi; + LVL1::CMXRoI croi; + if (jroi.setRoiWord(*payload)) { + if (collection == JEM_ROI) { + if (jroi.crate() != rodCrate - m_crateOffsetHw) { + if (debug) msg() << "Inconsistent RoI crate number: " + << jroi.crate() << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + const uint32_t location = (*payload) & 0xfff80000; + if (dupRoiCheck.insert(location).second) { + if (jroi.energyLarge() || jroi.energySmall()) { + m_jeCollection->push_back(new LVL1::JEMTobRoI(*payload)); + } + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } + } else if (croi.setRoiWord(*payload)) { + if (collection == CMX_ROI) { + const uint32_t roiType = (*payload) & 0xf8000000; + if (dupRoiCheck.insert(roiType).second) { + m_cmCollection->setRoiWord(*payload); + } else { + if (debug) msg() << "Duplicate RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + } + } else { + if (debug) msg() << "Invalid RoI word " + << MSG::hex << *payload << MSG::dec << endreq; + rodErr = L1CaloSubBlock::ERROR_ROI_TYPE; + break; + } + ++payload; + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, rodErr); + } + + return StatusCode::SUCCESS; +} + +// Find CMX energy sums for given crate, source + +const LVL1::CMXEtSums* JepRoiByteStreamV2Tool::findCmxSums(const int crate, + const int source) +{ + const LVL1::CMXEtSums* sums = 0; + CmxSumsMap::const_iterator mapIter; + mapIter = m_cmxEtMap.find(crate*100 + source); + if (mapIter != m_cmxEtMap.end()) sums = mapIter->second; + return sums; +} + +// Set up JEM RoIs map + +void JepRoiByteStreamV2Tool::setupJemRoiMap(const JemRoiCollection* + const jeCollection) +{ + m_roiMap.clear(); + if (jeCollection) { + JemRoiCollection::const_iterator pos = jeCollection->begin(); + JemRoiCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMTobRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +// Set up CMX energy sums map + +void JepRoiByteStreamV2Tool::setupCmxEtMap(const CmxSumsCollection* + const etCollection) +{ + m_cmxEtMap.clear(); + if (etCollection) { + CmxSumsCollection::const_iterator pos = etCollection->begin(); + CmxSumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMXEtSums* const sums = *pos; + const int crate = sums->crate() - m_crateOffsetSw; + const int key = crate*100 + sums->source(); + m_cmxEtMap.insert(std::make_pair(key, sums)); + } + } +} + +// Get energy subBlock types from CMXEtSums source type + +void JepRoiByteStreamV2Tool::energySubBlockTypes(const int source, + CmxEnergySubBlock::SourceType& srcType, + CmxEnergySubBlock::SumType& sumType, + CmxEnergySubBlock::HitsType& hitType) +{ + switch (source) { + case LVL1::CMXEtSums::REMOTE_STANDARD: + srcType = CmxEnergySubBlock::REMOTE; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::REMOTE_RESTRICTED: + srcType = CmxEnergySubBlock::REMOTE; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::LOCAL_STANDARD: + srcType = CmxEnergySubBlock::LOCAL; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::LOCAL_RESTRICTED: + srcType = CmxEnergySubBlock::LOCAL; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::TOTAL_STANDARD: + srcType = CmxEnergySubBlock::TOTAL; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::TOTAL_RESTRICTED: + srcType = CmxEnergySubBlock::TOTAL; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::SUM_ET_STANDARD: + hitType = CmxEnergySubBlock::SUM_ET; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::SUM_ET_RESTRICTED: + hitType = CmxEnergySubBlock::SUM_ET; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::MISSING_ET_STANDARD: + hitType = CmxEnergySubBlock::MISSING_ET; + sumType = CmxEnergySubBlock::STANDARD; + break; + case LVL1::CMXEtSums::MISSING_ET_RESTRICTED: + hitType = CmxEnergySubBlock::MISSING_ET; + sumType = CmxEnergySubBlock::RESTRICTED_WEIGHTED; + break; + case LVL1::CMXEtSums::MISSING_ET_SIG_STANDARD: + hitType = CmxEnergySubBlock::MISSING_ET_SIG; + sumType = CmxEnergySubBlock::STANDARD; + break; + default: + break; + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Tool.h new file mode 100755 index 0000000000000000000000000000000000000000..c89982d70ab7341d2f06c5d4315173795460c8aa --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiByteStreamV2Tool.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV2TOOL_H +#define TRIGT1CALOBYTESTREAM_JEPROIBYTESTREAMV2TOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" +#include "CmxEnergySubBlock.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +template <class T> class FullEventAssembler; + +namespace LVL1 { + class CMXEtSums; + class CMXRoI; + class JEMTobRoI; + class JEPRoIBSCollectionV2; +} + +namespace LVL1BS { + +class JemRoiSubBlockV2; +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to JEM RoI and CMX RoI, + * and JEP RoI container to raw data conversions. + * + * Based on ROD document version X_xxx. <<== CHECK + * + * @author Peter Faulkner + */ + +class JepRoiByteStreamV2Tool : public AthAlgTool { + + public: + JepRoiByteStreamV2Tool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~JepRoiByteStreamV2Tool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to JEM RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::JEMTobRoI>* jeCollection); + /// Convert ROB fragments to CMX RoIs + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + LVL1::CMXRoI* cmCollection); + + /// Convert JEP RoI Container to bytestream + StatusCode convert(const LVL1::JEPRoIBSCollectionV2* jep, RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + enum CollectionType { JEM_ROI, CMX_ROI }; + + typedef DataVector<LVL1::JEMTobRoI> JemRoiCollection; + typedef DataVector<LVL1::CMXEtSums> CmxSumsCollection; + typedef std::map<uint32_t, const LVL1::JEMTobRoI*> JemRoiMap; + typedef std::map<int, const LVL1::CMXEtSums*> CmxSumsMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Convert bytestream to given container type + StatusCode convertBs(const IROBDataProviderSvc::VROBFRAG& robFrags, + CollectionType collection); + + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// Find CMX energy sums for given crate, source + const LVL1::CMXEtSums* findCmxSums(int crate, int source); + + /// Set up JEM RoIs map + void setupJemRoiMap(const JemRoiCollection* jeCollection); + /// Set up CMX energy sums map + void setupCmxEtMap(const CmxSumsCollection* enCollection); + + /// Get energy subBlock types from CMXEtSums source type + void energySubBlockTypes(int source, + CmxEnergySubBlock::SourceType& srcType, + CmxEnergySubBlock::SumType& sumType, + CmxEnergySubBlock::HitsType& hitType); + + /// Hardware crate number offset + int m_crateOffsetHw; + /// Software crate number offset + int m_crateOffsetSw; + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Number of crates + int m_crates; + /// Number of JEM modules per crate + int m_modules; + /// Number of RoI frames + int m_frames; + /// Number of CMX energy RoI words + int m_maxRoiWords; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + /// ROB source IDs for RoIB + std::vector<uint32_t> m_sourceIDsRoIB; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Sub-block for neutral format + JemRoiSubBlockV2* m_subBlock; + /// Current JEM RoI collection + JemRoiCollection* m_jeCollection; + /// Current CMX RoI collection + LVL1::CMXRoI* m_cmCollection; + /// JEM RoI map + JemRoiMap m_roiMap; + /// CMX energy sums map + CmxSumsMap m_cmxEtMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..fc47779d44e6cb2fb5fa902a24102256d8947571 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamCnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIREADBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_JEPROIREADBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepRoiByteStreamTool; + +/** ByteStream converter for JEP component containers. + * + * @author Peter Faulkner + */ + +template <typename Container> +class JepRoiReadByteStreamCnv: public Converter { + + friend class CnvFactory<JepRoiReadByteStreamCnv<Container> >; + +protected: + + JepRoiReadByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~JepRoiReadByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepRoiByteStreamTool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "JepRoiReadByteStreamCnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamCnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamCnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..42f97957dae8e0722ebc2fde09a22991331d780a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamCnv.icc @@ -0,0 +1,141 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "JepRoiByteStreamTool.h" + +namespace LVL1BS { + +template <typename Container> +JepRoiReadByteStreamCnv<Container>::JepRoiReadByteStreamCnv( + ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepRoiReadByteStreamCnv"), + m_tool("LVL1BS::JepRoiByteStreamTool/JepRoiByteStreamTool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +JepRoiReadByteStreamCnv<Container>::~JepRoiReadByteStreamCnv() +{ +} + +// CLID + +template <typename Container> +const CLID& JepRoiReadByteStreamCnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode JepRoiReadByteStreamCnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode JepRoiReadByteStreamCnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Cannot cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV1Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV1Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..60e1ea9128d212dddc02ec5c12288cb01ac3fff1 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV1Cnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIREADBYTESTREAMV1CNV_H +#define TRIGT1CALOBYTESTREAM_JEPROIREADBYTESTREAMV1CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepRoiByteStreamV1Tool; + +/** ByteStream converter for JEP component containers. + * + * @author Peter Faulkner + */ + +template <typename Container> +class JepRoiReadByteStreamV1Cnv: public Converter { + + friend class CnvFactory<JepRoiReadByteStreamV1Cnv<Container> >; + +protected: + + JepRoiReadByteStreamV1Cnv(ISvcLocator* svcloc); + +public: + + ~JepRoiReadByteStreamV1Cnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepRoiByteStreamV1Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "JepRoiReadByteStreamV1Cnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV1Cnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV1Cnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..8cd3e21f28e4fcda3e7250c052b8d71a37cf4731 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV1Cnv.icc @@ -0,0 +1,141 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "JepRoiByteStreamV1Tool.h" + +namespace LVL1BS { + +template <typename Container> +JepRoiReadByteStreamV1Cnv<Container>::JepRoiReadByteStreamV1Cnv( + ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepRoiReadByteStreamV1Cnv"), + m_tool("LVL1BS::JepRoiByteStreamV1Tool/JepRoiByteStreamV1Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +JepRoiReadByteStreamV1Cnv<Container>::~JepRoiReadByteStreamV1Cnv() +{ +} + +// CLID + +template <typename Container> +const CLID& JepRoiReadByteStreamV1Cnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode JepRoiReadByteStreamV1Cnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode JepRoiReadByteStreamV1Cnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Cannot cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV2Cnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV2Cnv.h new file mode 100755 index 0000000000000000000000000000000000000000..5e7ca43e80f02bcc644fbffc99f486467127675b --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV2Cnv.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEPROIREADBYTESTREAMV2CNV_H +#define TRIGT1CALOBYTESTREAM_JEPROIREADBYTESTREAMV2CNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class JepRoiByteStreamV2Tool; + +/** ByteStream converter for JEP component containers post LS1. + * + * @author Peter Faulkner + */ + +template <typename Container> +class JepRoiReadByteStreamV2Cnv: public Converter { + + friend class CnvFactory<JepRoiReadByteStreamV2Cnv<Container> >; + +protected: + + JepRoiReadByteStreamV2Cnv(ISvcLocator* svcloc); + +public: + + ~JepRoiReadByteStreamV2Cnv(); + + virtual StatusCode initialize(); + /// Create Container from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::JepRoiByteStreamV2Tool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#include "JepRoiReadByteStreamV2Cnv.icc" + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV2Cnv.icc b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV2Cnv.icc new file mode 100755 index 0000000000000000000000000000000000000000..28db53b21cc56061409c448a7542c7f91e2f856c --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/JepRoiReadByteStreamV2Cnv.icc @@ -0,0 +1,141 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> +#include <typeinfo> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "JepRoiByteStreamV2Tool.h" + +namespace LVL1BS { + +template <typename Container> +JepRoiReadByteStreamV2Cnv<Container>::JepRoiReadByteStreamV2Cnv( + ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("JepRoiReadByteStreamV2Cnv"), + m_tool("LVL1BS::JepRoiByteStreamV2Tool/JepRoiByteStreamV2Tool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +template <typename Container> +JepRoiReadByteStreamV2Cnv<Container>::~JepRoiReadByteStreamV2Cnv() +{ +} + +// CLID + +template <typename Container> +const CLID& JepRoiReadByteStreamV2Cnv<Container>::classID() +{ + return ClassID_traits<Container>::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +template <typename Container> +StatusCode JepRoiReadByteStreamV2Cnv<Container>::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << "<" + << typeid(Container).name() << "> - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +template <typename Container> +StatusCode JepRoiReadByteStreamV2Cnv<Container>::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Cannot cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + Container* const collection = new Container; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(collection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, collection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete collection; + return sc; + } + + pObj = SG::asStorable(collection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamCnv.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9b4b0b2c06f025535562066ce5066f9fe3fc5341 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamCnv.cxx @@ -0,0 +1,104 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StlVectorClids.h" +#include "SGTools/StorableConversions.h" + +#include "L1CaloErrorByteStreamTool.h" + +#include "L1CaloErrorByteStreamCnv.h" + +namespace LVL1BS { + +L1CaloErrorByteStreamCnv::L1CaloErrorByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("L1CaloErrorByteStreamCnv"), + m_tool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +L1CaloErrorByteStreamCnv::~L1CaloErrorByteStreamCnv() +{ +} + +// CLID + +const CLID& L1CaloErrorByteStreamCnv::classID() +{ + return ClassID_traits<std::vector<unsigned int> >::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode L1CaloErrorByteStreamCnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +StatusCode L1CaloErrorByteStreamCnv::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + std::vector<unsigned int>* const errCollection = + new std::vector<unsigned int>; + + StatusCode sc = m_tool->errors(errCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete errCollection; + return sc; + } + + pObj = SG::asStorable(errCollection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamCnv.h new file mode 100644 index 0000000000000000000000000000000000000000..948634ad0c814dd72189250727aca443beb07560 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamCnv.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_L1CALOERRORBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_L1CALOERRORBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class L1CaloErrorByteStreamTool; + +/** Returns vector of errors detected during data unpacking + * + * @author Peter Faulkner + */ + +class L1CaloErrorByteStreamCnv: public Converter { + + friend class CnvFactory<L1CaloErrorByteStreamCnv>; + +protected: + + L1CaloErrorByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~L1CaloErrorByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create error vector from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_tool; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9a2b7b4d8e819cd1c0e041b1e4a2ebd6f18269a0 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamTool.cxx @@ -0,0 +1,110 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "L1CaloErrorByteStreamTool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IL1CaloErrorByteStreamTool( + "L1CaloErrorByteStreamTool", 1, 1); + +const InterfaceID& L1CaloErrorByteStreamTool::interfaceID() +{ + return IID_IL1CaloErrorByteStreamTool; +} + +// Constructor + +L1CaloErrorByteStreamTool::L1CaloErrorByteStreamTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent) +{ + declareInterface<L1CaloErrorByteStreamTool>(this); +} + +// Destructor + +L1CaloErrorByteStreamTool::~L1CaloErrorByteStreamTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode L1CaloErrorByteStreamTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode L1CaloErrorByteStreamTool::finalize() +{ + return StatusCode::SUCCESS; +} + +// Set ROB status error + +void L1CaloErrorByteStreamTool::robError(const uint32_t robid, + const unsigned int err) +{ + if (err && robMap.find(robid) == robMap.end()) { + robMap.insert(std::make_pair(robid, err)); + } + return; +} + +// Set ROD unpacking error + +void L1CaloErrorByteStreamTool::rodError(const uint32_t robid, + const unsigned int err) +{ + if (err && rodMap.find(robid) == rodMap.end()) { + rodMap.insert(std::make_pair(robid, err)); + } + return; +} + +// Fill vector with accumulated errors and reset + +StatusCode L1CaloErrorByteStreamTool::errors(std::vector<unsigned int>* + const errColl) +{ + if (!robMap.empty() || !rodMap.empty()) { + errColl->push_back(robMap.size()); + ErrorMap::const_iterator iter = robMap.begin(); + ErrorMap::const_iterator iterE = robMap.end(); + for (; iter != iterE; ++iter) { + errColl->push_back(iter->first); + errColl->push_back(iter->second); + } + robMap.clear(); + iter = rodMap.begin(); + iterE = rodMap.end(); + for (; iter != iterE; ++iter) { + errColl->push_back(iter->first); + errColl->push_back(iter->second); + } + rodMap.clear(); + } + return StatusCode::SUCCESS; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamTool.h new file mode 100644 index 0000000000000000000000000000000000000000..9a86c98b57a458768e4a9210a92f5d1445752416 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloErrorByteStreamTool.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_L1CALOERRORBYTESTREAMTOOL_H +#define TRIGT1CALOBYTESTREAM_L1CALOERRORBYTESTREAMTOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +namespace LVL1BS { + +/** Tool to accumulate ROB/ROD unpacking errors. + * + * @author Peter Faulkner + */ + +class L1CaloErrorByteStreamTool : public AthAlgTool { + + public: + L1CaloErrorByteStreamTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~L1CaloErrorByteStreamTool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Set ROB status error + void robError(uint32_t robid, unsigned int err); + /// Set ROD unpacking error + void rodError(uint32_t robid, unsigned int err); + /// Fill vector with accumulated errors and reset + StatusCode errors(std::vector<unsigned int>* errColl); + + private: + + // Maps of accumulated errors + typedef std::map<uint32_t, unsigned int> ErrorMap; + ErrorMap robMap; + ErrorMap rodMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSrcIdMap.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSrcIdMap.cxx new file mode 100755 index 0000000000000000000000000000000000000000..a74dd44723e7fbd9dd5dc8ff0c6c31f1477043ff --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSrcIdMap.cxx @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "L1CaloSrcIdMap.h" + +namespace LVL1BS { + +L1CaloSrcIdMap::L1CaloSrcIdMap() +{ +} + +// Make a ROD Source ID + +uint32_t L1CaloSrcIdMap::getRodID(int crate, int slink, int daqOrRoi, + eformat::SubDetector subdet) +{ + // module ID = r0sscccc (ROD-spec-version1_06d, P33) + uint16_t moduleId = (daqOrRoi << 7) | (slink << 4) | crate; + eformat::helper::SourceIdentifier helpID(subdet, moduleId); + return helpID.code(); +} + +// Make a ROB Source ID from a ROD source ID + +uint32_t L1CaloSrcIdMap::getRobID(uint32_t rod_id) +{ + return rod_id; +} + +// Make a ROS Source ID from a ROB source ID + +uint32_t L1CaloSrcIdMap::getRosID(uint32_t rob_id) +{ + eformat::helper::SourceIdentifier id(rob_id); + eformat::helper::SourceIdentifier id2(id.subdetector_id(), 0); + return id2.code(); +} + +// Make a SubDetector ID from ROS source ID + +uint32_t L1CaloSrcIdMap::getDetID(uint32_t ros_id) +{ + eformat::helper::SourceIdentifier id(ros_id); + eformat::helper::SourceIdentifier id2(id.subdetector_id(), 0); + return id2.code(); +} + +// Return crate from unpacked moduleID + +int L1CaloSrcIdMap::crate(uint32_t code) +{ + eformat::helper::SourceIdentifier id(code); + return id.module_id() & 0xf; +} + +// Return daqOrRoi from unpacked moduleID + +int L1CaloSrcIdMap::daqOrRoi(uint32_t code) +{ + eformat::helper::SourceIdentifier id(code); + return (id.module_id() >> 7) & 0x1; +} + +// Return slink from unpacked moduleID + +int L1CaloSrcIdMap::slink(uint32_t code) +{ + eformat::helper::SourceIdentifier id(code); + return (id.module_id() >> 4) & 0x3; +} + +// Return the maximum possible number of slinks given number of +// bits in module ID + +int L1CaloSrcIdMap::maxSlinks() +{ + return 4; +} + +// Return sub-detector for given ID + +eformat::SubDetector L1CaloSrcIdMap::subDet(uint32_t code) { + eformat::helper::SourceIdentifier id(code); + return id.subdetector_id(); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSrcIdMap.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSrcIdMap.h new file mode 100755 index 0000000000000000000000000000000000000000..329f47eabcd791298a6f7dc89aff3826ff2ee7d1 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSrcIdMap.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_L1CALOSRCIDMAP_H +#define TRIGT1CALOBYTESTREAM_L1CALOSRCIDMAP_H + +#include <stdint.h> + +#include "eformat/SourceIdentifier.h" + +namespace LVL1BS { + +/** This class provides conversion between Lower level Source ID to + * higher level source ID for L1Calo ByteStream fragments. + * + * This is to be used in assembling the fragments from ROD fragments + * + * @author Peter Faulkner + */ + +class L1CaloSrcIdMap { + +public: + L1CaloSrcIdMap(); + + /// Make a ROD Source ID + uint32_t getRodID (int crate, int slink, int daqOrRoi, + eformat::SubDetector subdet); + + /// Make a ROB Source ID from a ROD source ID + uint32_t getRobID (uint32_t rod_id); + + /// Make a ROS Source ID from a ROB source ID + uint32_t getRosID (uint32_t rob_id); + + /// Make a SubDetector ID from ROS source ID + uint32_t getDetID (uint32_t ros_id); + + /// Return crate from unpacked moduleID + int crate(uint32_t code); + + /// Return daqOrRoi from unpacked moduleID + int daqOrRoi(uint32_t code); + + /// Return slink from unpacked moduleID + int slink(uint32_t code); + + /// Return the maximum possible number of slinks + int maxSlinks(); + + /// Return sub-detector for given ID + eformat::SubDetector subDet(uint32_t code); + + /// Return ROD header minor version to use when writing BS + uint16_t minorVersion() {return 0x1004;} // Or may go up to 0x2000, CHECK + + /// Return last ROD header minor version for pre-LS1 data + uint16_t minorVersionPreLS1() {return 0x1003;} + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..d6d530067a4fff5ad32e74ccff45f74334f1c222 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSubBlock.cxx @@ -0,0 +1,478 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +// Static constant definitions + +const int L1CaloSubBlock::s_headerBit; +const int L1CaloSubBlock::s_statusBit; +const uint32_t L1CaloSubBlock::s_headerMask; +const uint32_t L1CaloSubBlock::s_statusMask; +const uint32_t L1CaloSubBlock::s_headerVal; +const uint32_t L1CaloSubBlock::s_statusVal; + +const int L1CaloSubBlock::s_ppmCrates; + +const int L1CaloSubBlock::s_wordIdBit; +const int L1CaloSubBlock::s_versionBit; +const int L1CaloSubBlock::s_formatBit; +const int L1CaloSubBlock::s_seqnoBit; +const int L1CaloSubBlock::s_crateBit; +const int L1CaloSubBlock::s_moduleBit; +const int L1CaloSubBlock::s_slices2Bit; +const int L1CaloSubBlock::s_slices1Bit; +const uint32_t L1CaloSubBlock::s_wordIdMask; +const uint32_t L1CaloSubBlock::s_versionMask; +const uint32_t L1CaloSubBlock::s_formatMask; +const uint32_t L1CaloSubBlock::s_seqnoMask; +const uint32_t L1CaloSubBlock::s_crateMask; +const uint32_t L1CaloSubBlock::s_moduleMask; +const uint32_t L1CaloSubBlock::s_slices2Mask; +const uint32_t L1CaloSubBlock::s_slices1Mask; + +const int L1CaloSubBlock::s_failingBcnBit; +const int L1CaloSubBlock::s_glinkTimeoutBit; +const int L1CaloSubBlock::s_glinkDownBit; +const int L1CaloSubBlock::s_upstreamErrorBit; +const int L1CaloSubBlock::s_daqOverflowBit; +const int L1CaloSubBlock::s_bcnMismatchBit; +const int L1CaloSubBlock::s_glinkProtocolBit; +const int L1CaloSubBlock::s_glinkParityBit; +const uint32_t L1CaloSubBlock::s_failingBcnMask; + +const int L1CaloSubBlock::s_maxWordBits; +const int L1CaloSubBlock::s_maxStreamedBits; +const uint32_t L1CaloSubBlock::s_maxWordMask; +const uint32_t L1CaloSubBlock::s_maxStreamedMask; + +const int L1CaloSubBlock::s_maxPins; +const uint32_t L1CaloSubBlock::s_glinkDavSet; + +L1CaloSubBlock::L1CaloSubBlock() : m_header(0), m_trailer(0), + m_bunchCrossing(0), + m_unpackError(UNPACK_NONE), + m_bitword(0), m_currentBit(0), + m_maxBits(s_maxWordBits), + m_maxMask(s_maxWordMask), + m_unpackerFlag(false), + m_currentPinBit(s_maxPins), + m_oddParity(s_maxPins, 1), + m_dataWords(0) +{ + // Initialize unpacking masks + m_unpackingMasks.assign(s_maxWordBits+1, 0); + for (int i = 1; i <= s_maxWordBits; ++i) { + m_unpackingMasks[i] = (m_unpackingMasks[i-1]<<1)|0x1; + } +} + +L1CaloSubBlock::~L1CaloSubBlock() +{ +} + +// Clear all data + +void L1CaloSubBlock::clear() +{ + m_header = 0; + m_trailer = 0; + m_bunchCrossing = 0; + m_unpackError = UNPACK_NONE; + m_bitword = 0; + m_currentBit = 0; + m_unpackerFlag = false; + m_currentPinBit.assign(s_maxPins, 0); + m_oddParity.assign(s_maxPins, 1); + m_dataWords = 0; + m_data.clear(); +} + +// Store header data + +void L1CaloSubBlock::setHeader(const int wordId, const int version, + const int format, const int seqno, + const int crate, const int module, + const int slices2, const int slices1) +{ + uint32_t word = 0; + word |= (wordId & s_wordIdMask) << s_wordIdBit; + word |= (version & s_versionMask) << s_versionBit; + word |= (format & s_formatMask) << s_formatBit; + word |= (seqno & s_seqnoMask) << s_seqnoBit; + word |= (crate & s_crateMask) << s_crateBit; + word |= (module & s_moduleMask) << s_moduleBit; + word |= (slices2 & s_slices2Mask) << s_slices2Bit; + word |= (slices1 & s_slices1Mask) << s_slices1Bit; + m_header = word; +} + +// Input complete packed sub-block from ROD vector + +OFFLINE_FRAGMENTS_NAMESPACE::PointerType L1CaloSubBlock::read( + const OFFLINE_FRAGMENTS_NAMESPACE::PointerType beg, + const OFFLINE_FRAGMENTS_NAMESPACE::PointerType end) +{ + m_dataWords = 0; + m_unpackerFlag = true; + OFFLINE_FRAGMENTS_NAMESPACE::PointerType pos(beg); + OFFLINE_FRAGMENTS_NAMESPACE::PointerType pose(end); + for (; pos != pose; ++pos) { + const uint32_t word = *pos; + const SubBlockWordType type = wordType(word); + if (type == HEADER) { + if (m_header) return pos; + m_header = word; + } else if (type == STATUS) { + // Word ID should be consistent with header + if (m_trailer || (wordId(word) != wordId()+1)) return pos; + m_trailer = word; + } else { + // Check data word IDs + const int id = wordId(word); + bool badId = false; + // All neutral format '0000' + if (format() == NEUTRAL) badId = (id != 0); + // Other PPM '0xxx' + else if (crate() < s_ppmCrates) badId = ((id & 0x8) != 0); + // Other CPM/JEM '01xx' or '10xx' + else if (wordId() == 0xc) badId = (((id & 0xc) != 0x4) && + ((id & 0xc) != 0x8)); + // Other CMM/CMX '00xx' + else badId = ((id & 0xc) != 0); + if (m_trailer || badId) return pos; + m_data.push_back(word); + ++m_dataWords; + } + } + return pose; +} + +// Output complete packed sub-block to ROD vector + +void L1CaloSubBlock::write( + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* const theROD) const +{ + theROD->push_back(m_header); + std::vector<uint32_t>::const_iterator pos; + for (pos = m_data.begin(); pos != m_data.end(); ++pos) { + theROD->push_back(*pos); + } + if (m_trailer) theROD->push_back(m_trailer); +} + +// Store error status trailer + +void L1CaloSubBlock::setStatus(const uint32_t failingBCN, + const bool glinkTimeout, const bool glinkDown, const bool upstreamError, + const bool daqOverflow, const bool bcnMismatch, + const bool glinkProtocol, const bool glinkParity) +{ + uint32_t word = 0; + word |= (failingBCN & s_failingBcnMask) << s_failingBcnBit; + word |= glinkTimeout << s_glinkTimeoutBit; + word |= glinkDown << s_glinkDownBit; + word |= upstreamError << s_upstreamErrorBit; + word |= daqOverflow << s_daqOverflowBit; + word |= bcnMismatch << s_bcnMismatchBit; + word |= glinkProtocol << s_glinkProtocolBit; + word |= glinkParity << s_glinkParityBit; + if (word) { + word |= (wordId() & s_wordIdMask) << s_wordIdBit; + word |= (s_statusVal & s_statusMask) << s_statusBit; + word |= (seqno() & s_seqnoMask) << s_seqnoBit; + word |= (crate() & s_crateMask) << s_crateBit; + word |= (module() & s_moduleMask) << s_moduleBit; + } + m_trailer = word; +} + +// Set DAQ FIFO Overflow bit in Sub-status word + +void L1CaloSubBlock::setDaqOverflow(const int bit) +{ + if (bit) { + if (m_trailer) m_trailer |= (1 << s_daqOverflowBit); + else setStatus(0, false, false, false, true, false, false, false); + } +} + +// Set G-Link Parity bit in Sub-status word + +void L1CaloSubBlock::setGlinkParity(const int bit) +{ + if (bit) { + if (m_trailer) m_trailer |= (1 << s_glinkParityBit); + else setStatus(0, false, false, false, false, false, false, true); + } +} + +// Return the unpacking error message for printing + +std::string L1CaloSubBlock::unpackErrorMsg() const +{ + std::string msg; + switch (m_unpackError) { + case UNPACK_NONE: + msg = "No error"; + break; + case UNPACK_VERSION: + msg = "Unsupported Data Version"; + break; + case UNPACK_FORMAT: + msg = "Unsupported Data Format"; + break; + case UNPACK_COMPRESSION_VERSION: + msg = "Unsupported Compression Version"; + break; + case UNPACK_COMPRESSION_SLICES: + msg = "Unsupported Number of Slices for Compression Version"; + break; + case UNPACK_DATA_TRUNCATED: + msg = "Premature End of Sub-block Data"; + break; + case UNPACK_EXCESS_DATA: + msg = "Excess Data in Sub-block"; + break; + case UNPACK_SOURCE_ID: + msg = "Invalid Source ID in Sub-block Data"; + break; + case UNPACK_EXCESS_TOBS: + msg = "Excess TOBs in Sub-block Data"; + break; + case UNPACK_DATA_ID: + msg = "Invalid word ID in Sub-block Data"; + break; + default: + msg = "Unknown Error Code"; + break; + } + return msg; +} + +// Packing utilities + +// Return the minimum number of bits needed for given data + +int L1CaloSubBlock::minBits(const uint32_t datum) const +{ + const int maxBits = 32; + int nbits = maxBits; + for (int i = 0; i < maxBits; ++i) { + if ( !(datum >> i)) { + nbits = i; + break; + } + } + return nbits; +} + +// Return the parity bit for given data + +int L1CaloSubBlock::parityBit(const int init, const uint32_t datum, + const int nbits) const +{ + // set init to 0/1 for even/odd parity + int parity = init; + for (int bit = 0; bit < nbits; ++bit) parity ^= (datum >> bit) & 0x1; + return parity; +} + +// Pack given data into given number of bits + +void L1CaloSubBlock::packer(const uint32_t datum, const int nbits) +{ + if (nbits > 0) { + uint32_t mask = m_unpackingMasks[nbits]; + m_bitword |= (datum & mask) << m_currentBit; + m_currentBit += nbits; + if (m_currentBit >= m_maxBits) { + m_bitword &= m_maxMask; + m_data.push_back(m_bitword); + ++m_dataWords; + const int bitsLeft = m_currentBit - m_maxBits; + if (bitsLeft > 0) { + m_bitword = (datum & mask) >> (nbits - bitsLeft); + m_currentBit = bitsLeft; + } else { + m_bitword = 0; + m_currentBit = 0; + } + } + } +} + +// Flush the current data word padded with zeros + +void L1CaloSubBlock::packerFlush() +{ + if (m_currentBit > 0) { + m_bitword &= m_maxMask; + m_data.push_back(m_bitword); + ++m_dataWords; + m_bitword = 0; + m_currentBit = 0; + } +} + +// Unpack given number of bits of data + +uint32_t L1CaloSubBlock::unpacker(const int nbits) +{ + uint32_t word = 0; + if (nbits > 0) { + if (m_dataPos == m_dataPosEnd) { + m_unpackerFlag = false; + return 0; + } + int nbitsDone = nbits; + if (nbitsDone > m_maxBits - m_currentBit) { + nbitsDone = m_maxBits - m_currentBit; + } + word = (m_bitword >> m_currentBit) & m_unpackingMasks[nbitsDone]; + m_currentBit += nbits; + if (m_currentBit >= m_maxBits) { + m_bitword = 0; + if (m_dataPos != m_dataPosEnd) { + ++m_dataPos; + if (m_dataPos != m_dataPosEnd) { + m_bitword = *m_dataPos; + } + } + m_currentBit = 0; + const int bitsLeft = nbits - nbitsDone; + if (bitsLeft > 0) { + if (m_dataPos == m_dataPosEnd) { + m_unpackerFlag = false; + return word; + } + word |= (m_bitword & m_unpackingMasks[bitsLeft]) << nbitsDone; + m_currentBit = bitsLeft; + } + } + } + return word; +} + +// Initialise unpacker + +void L1CaloSubBlock::unpackerInit() +{ + m_bitword = 0; + m_currentBit = 0; + m_unpackerFlag = true; + m_dataPos = m_data.begin(); + m_dataPosEnd = m_data.end(); + if (m_dataPos != m_dataPosEnd) m_bitword = *m_dataPos; +} + +// Pack given neutral data from given pin + +void L1CaloSubBlock::packerNeutral(const int pin, const uint32_t datum, + const int nbits) +{ + if (pin >= 0 && pin < s_maxPins && nbits > 0) { + if (m_currentPinBit[pin] + nbits > m_dataWords) { + m_dataWords = m_currentPinBit[pin] + nbits; + m_data.resize(m_dataWords, s_glinkDavSet); + } + for (int bit = 0; bit < nbits; ++bit) { + m_data[m_currentPinBit[pin] + bit] |= ((datum >> bit) & 0x1) << pin; + } + m_currentPinBit[pin] += nbits; + m_oddParity[pin] = parityBit(m_oddParity[pin], datum, nbits); + } +} + +// Pack current G-Link parity bit for given pin + +void L1CaloSubBlock::packerNeutralParity(const int pin) +{ + if (pin >= 0 && pin < s_maxPins) { + packerNeutral(pin, m_oddParity[pin], 1); + m_oddParity[pin] = 1; + } +} + +// Unpack given number of bits of neutral data for given pin + +uint32_t L1CaloSubBlock::unpackerNeutral(const int pin, const int nbits) +{ + uint32_t word = 0; + if (pin >= 0 && pin < s_maxPins && nbits > 0 + && m_currentPinBit[pin] + nbits <= m_dataWords) { + for (int bit = 0; bit < nbits; ++bit) { + word |= ((m_data[m_currentPinBit[pin] + bit] >> pin) & 0x1) << bit; + } + m_currentPinBit[pin] += nbits; + m_oddParity[pin] = parityBit(m_oddParity[pin], word, nbits); + } else m_unpackerFlag = false; + return word; +} + +// Unpack and test G-Link parity bit for given pin + +bool L1CaloSubBlock::unpackerNeutralParityError(const int pin) +{ + bool error = true; + if (pin >= 0 && pin < s_maxPins) { + int parity = m_oddParity[pin]; + int bit = unpackerNeutral(pin, 1); + m_oddParity[pin] = 1; + error = !(bit == parity); + } + return error; +} + +// Static function to determine word type + +L1CaloSubBlock::SubBlockWordType L1CaloSubBlock::wordType(const uint32_t word) +{ + SubBlockWordType type = DATA; + if (((word >> s_headerBit) & s_headerMask) == s_headerVal) { + if (((word >> s_statusBit) & s_statusMask) == s_statusVal) type = STATUS; + else type = HEADER; + } + return type; +} + +// Return wordID field from given header word + +int L1CaloSubBlock::wordId(const uint32_t word) +{ + return (word >> s_wordIdBit) & s_wordIdMask; +} + +// Return version number from given header word + +int L1CaloSubBlock::version(const uint32_t word) +{ + return (word >> s_versionBit) & s_versionMask; +} + +// Return data format from given header word + +int L1CaloSubBlock::format(const uint32_t word) +{ + return (word >> s_formatBit) & s_formatMask; +} + +// Return seqno field from given header word + +int L1CaloSubBlock::seqno(const uint32_t word) +{ + return (word >> s_seqnoBit) & s_seqnoMask; +} + +// Return module field from given header word + +int L1CaloSubBlock::module(const uint32_t word) +{ + return (word >> s_moduleBit) & s_moduleMask; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..3a38e85f3b2175b2ae4fa834da38133172b21476 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloSubBlock.h @@ -0,0 +1,365 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_L1CALOSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_L1CALOSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "L1CaloSrcIdMap.h" + +namespace LVL1BS { + +/** L1Calo Sub-Block base class. + * + * Provides common functionality for all L1Calo Sub-Block derived types. + * + * @author Peter Faulkner + */ + +class L1CaloSubBlock { + + public: + enum SubBlockWordType { HEADER, DATA, STATUS }; + enum DataFormats { NEUTRAL = 0, UNCOMPRESSED = 1, COMPRESSED = 2, + SUPERCOMPRESSED = 3 }; + // Errors detected before unpacking + enum DataErrorType { ERROR_NONE, ERROR_DUPLICATE_ROB, ERROR_ROD_ID, + ERROR_ROD_NSTATUS, ERROR_USER_HEADER, + ERROR_MISSING_HEADER, ERROR_MISSING_SUBBLOCK, + ERROR_CRATE_NUMBER, ERROR_MODULE_NUMBER, + ERROR_SLICES, ERROR_DUPLICATE_DATA, + ERROR_ROI_TYPE, ERROR_MAX }; + // Errors detected during unpacking + enum UnpackErrorType { UNPACK_NONE = ERROR_NONE, UNPACK_VERSION = ERROR_MAX, + UNPACK_FORMAT, UNPACK_COMPRESSION_VERSION, + UNPACK_COMPRESSION_SLICES, UNPACK_DATA_TRUNCATED, + UNPACK_EXCESS_DATA, UNPACK_SOURCE_ID, + UNPACK_EXCESS_TOBS, UNPACK_DATA_ID }; + + L1CaloSubBlock(); + ~L1CaloSubBlock(); + + /// Clear all data + void clear(); + + /// Return number of data words + int dataWords() const; + + /// Store header data + void setHeader(int wordId, int version, int format, int seqno, int crate, + int module, int slices2, int slices1); + + // Return unpacked header data + int wordId() const; + int version() const; + int format() const; + int seqno() const; + int slice() const; + int crate() const; + int module() const; + int slices2() const; + int slices1() const; + + // Return unpacked error status data + uint32_t failingBCN() const; + bool glinkTimeout() const; + bool glinkDown() const; + bool upstreamError() const; + bool daqOverflow() const; + bool bcnMismatch() const; + bool glinkProtocol() const; + bool glinkParity() const; + + /// Return Sub-status word + uint32_t subStatus() const; + + /// Set the Bunch Crossing number (neutral format only) + void setBunchCrossing(int bc); + /// Return the Bunch Crossing number (neutral format only) + int bunchCrossing() const; + + /// Input complete packed sub-block from ROD array + // (OFFLINE_FRAGMENTS_NAMESPACE::PointerType = uint32_t*) + OFFLINE_FRAGMENTS_NAMESPACE::PointerType read( + const OFFLINE_FRAGMENTS_NAMESPACE::PointerType beg, + const OFFLINE_FRAGMENTS_NAMESPACE::PointerType end); + + /// Output complete packed sub-block to ROD vector + // (FullEventAssembler<L1CaloSrcIdMap>::RODDATA = vector<uint32_t>) + void write(FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD) const; + + /// Store error status trailer + void setStatus(uint32_t failingBCN, bool glinkTimeout, bool glinkDown, + bool upstreamError, bool daqOverflow, bool bcnMismatch, + bool glinkProtocol, bool glinkParity); + + /// Set DAQ FIFO Overflow bit in Sub-status word + void setDaqOverflow(int bit = 1); + /// Set G-Link Parity bit in Sub-status word + void setGlinkParity(int bit = 1); + + /// Word identification + static SubBlockWordType wordType(uint32_t word); + /// Return wordID field from given header word + static int wordId(uint32_t word); + /// Return version number from given header word + static int version(uint32_t word); + /// Return data format from given header word + static int format(uint32_t word); + /// Return seqno field from given header word + static int seqno(uint32_t word); + /// Return module field from given header word + static int module(uint32_t word); + + // Unpacking error code. Set by derived classes + /// Set the unpacking error code + void setUnpackErrorCode(int code); + /// Return the unpacking error code + int unpackErrorCode() const; + /// Return the unpacking error message for printing + std::string unpackErrorMsg() const; + + // Packing utilities + /// Return the minimum number of bits needed for given data + int minBits(uint32_t datum) const; + /// Return the parity bit for given data + int parityBit(int init, uint32_t datum, int nbits) const; + /// Pack given data into given number of bits + void packer(uint32_t datum, int nbits); + /// Flush the current data word padded with zeros + void packerFlush(); + /// Set continuous bit streaming for compressed formats + void setStreamed(); + /// Unpack given number of bits of data + uint32_t unpacker(int nbits); + /// Initialise unpacker + void unpackerInit(); + /// Return unpacker success flag + bool unpackerSuccess() const; + + // Neutral format packing utilities + /// Pack given neutral data from given pin + void packerNeutral(int pin, uint32_t datum, int nbits); + /// Pack current G-Link parity bit for given pin + void packerNeutralParity(int pin); + /// Unpack given number of bits of neutral data for given pin + uint32_t unpackerNeutral(int pin, int nbits); + /// Unpack and test G-Link parity bit for given pin + bool unpackerNeutralParityError(int pin); + /// Return current pin bit for given pin + int currentPinBit(int pin) const; + + private: + // Constants. + // Header and status ID + static const int s_headerBit = 30; + static const int s_statusBit = 28; + static const uint32_t s_headerMask = 0x3; + static const uint32_t s_statusMask = 0x1; + static const uint32_t s_headerVal = 0x3; + static const uint32_t s_statusVal = 0x1; + // First non-PPM crate + static const int s_ppmCrates = 8; + // Header word data positions and masks + static const int s_wordIdBit = 28; + static const int s_versionBit = 25; + static const int s_formatBit = 22; + static const int s_seqnoBit = 16; + static const int s_crateBit = 12; + static const int s_moduleBit = 8; + static const int s_slices2Bit = 3; + static const int s_slices1Bit = 0; + static const uint32_t s_wordIdMask = 0xf; + static const uint32_t s_versionMask = 0x7; + static const uint32_t s_formatMask = 0x7; + static const uint32_t s_seqnoMask = 0x3f; + static const uint32_t s_crateMask = 0xf; + static const uint32_t s_moduleMask = 0xf; + static const uint32_t s_slices2Mask = 0x1f; + static const uint32_t s_slices1Mask = 0x7; + // Status word data positions and masks + static const int s_failingBcnBit = 22; + static const int s_glinkTimeoutBit = 7; + static const int s_glinkDownBit = 6; + static const int s_upstreamErrorBit = 4; + static const int s_daqOverflowBit = 3; + static const int s_bcnMismatchBit = 2; + static const int s_glinkProtocolBit = 1; + static const int s_glinkParityBit = 0; + static const uint32_t s_failingBcnMask = 0x3f; + // Packing word sizes and masks + static const int s_maxWordBits = 32; + static const int s_maxStreamedBits = 31; + static const uint32_t s_maxWordMask = 0xffffffff; + static const uint32_t s_maxStreamedMask = 0x7fffffff; + // Neutral packing + static const int s_maxPins = 20; + static const uint32_t s_glinkDavSet = 0x400000; + + /// Sub-Block Header + uint32_t m_header; + /// Sub-Block Status Trailer + uint32_t m_trailer; + /// Bunch Crossing number (neutral format only) + int m_bunchCrossing; + /// Unpacking error code + int m_unpackError; + // Used for bit-packing + uint32_t m_bitword; + int m_currentBit; + int m_maxBits; + uint32_t m_maxMask; + bool m_unpackerFlag; + std::vector<uint32_t>::const_iterator m_dataPos; + std::vector<uint32_t>::const_iterator m_dataPosEnd; + // Used for neutral bit packing + std::vector<int> m_currentPinBit; + std::vector<int> m_oddParity; + /// Current number of data words + int m_dataWords; + /// Sub-Block data + std::vector<uint32_t> m_data; + /// Unpacking masks + std::vector<uint32_t> m_unpackingMasks; + +}; + +inline int L1CaloSubBlock::dataWords() const +{ + return m_dataWords; +} + +inline int L1CaloSubBlock::wordId() const +{ + return (m_header >> s_wordIdBit) & s_wordIdMask; +} + +inline int L1CaloSubBlock::version() const +{ + return (m_header >> s_versionBit) & s_versionMask; +} + +inline int L1CaloSubBlock::format() const +{ + return (m_header >> s_formatBit) & s_formatMask; +} + +inline int L1CaloSubBlock::seqno() const +{ + return (m_header >> s_seqnoBit) & s_seqnoMask; +} + +inline int L1CaloSubBlock::slice() const +{ + return seqno(); +} + +inline int L1CaloSubBlock::crate() const +{ + return (m_header >> s_crateBit) & s_crateMask; +} + +inline int L1CaloSubBlock::module() const +{ + return (m_header >> s_moduleBit) & s_moduleMask; +} + +inline int L1CaloSubBlock::slices2() const +{ + return (m_header >> s_slices2Bit) & s_slices2Mask; +} + +inline int L1CaloSubBlock::slices1() const +{ + return (m_header >> s_slices1Bit) & s_slices1Mask; +} + +inline uint32_t L1CaloSubBlock::failingBCN() const +{ + return (m_trailer >> s_failingBcnBit) & s_failingBcnMask; +} + +inline bool L1CaloSubBlock::glinkTimeout() const +{ + return m_trailer & (0x1 << s_glinkTimeoutBit); +} + +inline bool L1CaloSubBlock::glinkDown() const +{ + return m_trailer & (0x1 << s_glinkDownBit); +} + +inline bool L1CaloSubBlock::upstreamError() const +{ + return m_trailer & (0x1 << s_upstreamErrorBit); +} + +inline bool L1CaloSubBlock::daqOverflow() const +{ + return m_trailer & (0x1 << s_daqOverflowBit); +} + +inline bool L1CaloSubBlock::bcnMismatch() const +{ + return m_trailer & (0x1 << s_bcnMismatchBit); +} + +inline bool L1CaloSubBlock::glinkProtocol() const +{ + return m_trailer & (0x1 << s_glinkProtocolBit); +} + +inline bool L1CaloSubBlock::glinkParity() const +{ + return m_trailer & (0x1 << s_glinkParityBit); +} + +inline uint32_t L1CaloSubBlock::subStatus() const +{ + return m_trailer; +} + +inline void L1CaloSubBlock::setBunchCrossing(const int bc) +{ + if (bc) m_bunchCrossing = bc; +} + +inline int L1CaloSubBlock::bunchCrossing() const +{ + return m_bunchCrossing; +} + +inline void L1CaloSubBlock::setUnpackErrorCode(const int code) +{ + m_unpackError = code; +} + +inline int L1CaloSubBlock::unpackErrorCode() const +{ + return m_unpackError; +} + +inline void L1CaloSubBlock::setStreamed() +{ + m_maxBits = s_maxStreamedBits; + m_maxMask = s_maxStreamedMask; +} + +inline bool L1CaloSubBlock::unpackerSuccess() const +{ + return m_unpackerFlag; +} + +inline int L1CaloSubBlock::currentPinBit(int pin) const +{ + return m_currentPinBit[pin]; +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloUserHeader.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloUserHeader.cxx new file mode 100755 index 0000000000000000000000000000000000000000..47b65ad6bdf19f8b4a1f48090133669bb5c8d7f2 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloUserHeader.cxx @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "L1CaloUserHeader.h" + +namespace LVL1BS { + +// Static constant definitions + +const int L1CaloUserHeader::s_jepCmmBit; +//const int L1CaloUserHeader::s_cpCmmBit; +const int L1CaloUserHeader::s_jemBit; +const int L1CaloUserHeader::s_cpmBit; +const int L1CaloUserHeader::s_ppmLutBit; +const int L1CaloUserHeader::s_ppmFadcBit; +const int L1CaloUserHeader::s_lowerBoundBit; +const int L1CaloUserHeader::s_ppmLutBitV2; +const int L1CaloUserHeader::s_ppmFadcBitV2; +const uint32_t L1CaloUserHeader::s_mask; +const uint32_t L1CaloUserHeader::s_lowerBoundMask; +const uint32_t L1CaloUserHeader::s_ppmLutMaskV2; +const uint32_t L1CaloUserHeader::s_ppmFadcMaskV2; +const int L1CaloUserHeader::s_version1; + +// Constructor + +L1CaloUserHeader::L1CaloUserHeader(uint32_t header) : m_header(header), + m_version2(true) +{ +} + +// Test for valid header word + +bool L1CaloUserHeader::isValid(const uint32_t word) +{ + return ((word >> s_wordIdBit) & s_mask) == s_mask; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloUserHeader.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloUserHeader.h new file mode 100755 index 0000000000000000000000000000000000000000..4b50d5d4b81f8f998486068ce4d00ff296ca252f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/L1CaloUserHeader.h @@ -0,0 +1,183 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_L1CALOUSERHEADER_H +#define TRIGT1CALOBYTESTREAM_L1CALOUSERHEADER_H + +#include <stdint.h> + +namespace LVL1BS { + +/** L1Calo User Header class. + * + * The User Header is the first word of the ROD data and contains + * Triggered slice offsets for all the sub-detector types. + * + * @author Peter Faulkner + */ + // Remove pre version 2 stuff ? +class L1CaloUserHeader { + + public: + + /// Constructor - default just sets word ID and number of header words + L1CaloUserHeader(uint32_t header = 0xf0000001); + + /// Return packed header + uint32_t header() const; + + /// Return number of header words (should be one) + int words() const; + + // Return triggered slice offsets + int jepCmm() const; + int cpCmm() const; + int jem() const; + int cpm() const; + int ppmLut() const; + int ppmFadc() const; + + /// Return FADC lower bound + int lowerBound() const; + + // Set triggered slice offsets + void setJepCmm(int offset); + void setCpCmm(int offset); + void setJem(int offset); + void setCpm(int offset); + void setPpmLut(int offset); + void setPpmFadc(int offset); + + /// Set FADC lower bound + void setLowerBound(int bound); + + /// Set version flag + void setVersion(int minorVersion); + + /// Test for valid header word + static bool isValid(uint32_t word); + + private: + // Packed word bit positions version 1 + static const int s_wordIdBit = 28; + static const int s_jepCmmBit = 24; + static const int s_cpCmmBit = 20; + static const int s_jemBit = 16; + static const int s_cpmBit = 12; + static const int s_ppmLutBit = 8; + static const int s_ppmFadcBit = 4; + // Packed word bit positions version 2 (no cmms) + static const int s_lowerBoundBit = 20; + static const int s_ppmLutBitV2 = 9; + static const int s_ppmFadcBitV2 = 4; + /// Field mask + static const uint32_t s_mask = 0xf; + // Version 2 masks + static const uint32_t s_lowerBoundMask = 0xff; + static const uint32_t s_ppmLutMaskV2 = 0x7; + static const uint32_t s_ppmFadcMaskV2 = 0x1f; + /// Version 1 minor format version number + static const int s_version1 = 0x1001; + /// Packed Header + uint32_t m_header; + /// Version flag + bool m_version2; + +}; + +inline uint32_t L1CaloUserHeader::header() const +{ + return m_header; +} + +inline int L1CaloUserHeader::words() const +{ + return m_header & s_mask; +} + +inline int L1CaloUserHeader::jepCmm() const +{ + return (m_version2) ? (m_header >> s_jemBit ) & s_mask + : (m_header >> s_jepCmmBit) & s_mask; +} + +inline int L1CaloUserHeader::cpCmm() const +{ + return (m_version2) ? (m_header >> s_cpmBit ) & s_mask + : (m_header >> s_cpCmmBit) & s_mask; +} + +inline int L1CaloUserHeader::jem() const +{ + return (m_header >> s_jemBit) & s_mask; +} + +inline int L1CaloUserHeader::cpm() const +{ + return (m_header >> s_cpmBit) & s_mask; +} + +inline int L1CaloUserHeader::ppmLut() const +{ + return (m_version2) ? (m_header >> s_ppmLutBitV2) & s_ppmLutMaskV2 + : (m_header >> s_ppmLutBit ) & s_mask; +} + +inline int L1CaloUserHeader::ppmFadc() const +{ + return (m_version2) ? (m_header >> s_ppmFadcBitV2) & s_ppmFadcMaskV2 + : (m_header >> s_ppmFadcBit ) & s_mask; +} + +inline int L1CaloUserHeader::lowerBound() const +{ + return (m_version2) ? (m_header >> s_lowerBoundBit) & s_lowerBoundMask + : 0; +} + +inline void L1CaloUserHeader::setJepCmm(const int offset) +{ + if (!m_version2) m_header |= (s_mask & offset) << s_jepCmmBit; +} + +inline void L1CaloUserHeader::setCpCmm(const int offset) +{ + if (!m_version2) m_header |= (s_mask & offset) << s_cpCmmBit; +} + +inline void L1CaloUserHeader::setJem(const int offset) +{ + m_header |= (s_mask & offset) << s_jemBit; +} + +inline void L1CaloUserHeader::setCpm(const int offset) +{ + m_header |= (s_mask & offset) << s_cpmBit; +} + +inline void L1CaloUserHeader::setPpmLut(const int offset) +{ + m_header |= (m_version2) ? (s_ppmLutMaskV2 & offset) << s_ppmLutBitV2 + : (s_mask & offset) << s_ppmLutBit; +} + +inline void L1CaloUserHeader::setPpmFadc(const int offset) +{ + m_header |= (m_version2) ? (s_ppmFadcMaskV2 & offset) << s_ppmFadcBitV2 + : (s_mask & offset) << s_ppmFadcBit; +} + +inline void L1CaloUserHeader::setLowerBound(const int bound) +{ + if (m_version2) m_header |= (s_lowerBoundMask & bound) << s_lowerBoundBit; +} + +inline void L1CaloUserHeader::setVersion(const int minorVersion) +{ + m_version2 = (minorVersion > s_version1); +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/ModifySlices.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/ModifySlices.cxx new file mode 100755 index 0000000000000000000000000000000000000000..c61d284b51a28a087008fdcb3373de3300b2a638 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/ModifySlices.cxx @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "ModifySlices.h" + +namespace LVL1BS { + +// Return new triggered slice offset + +int ModifySlices::peak(const int oldPeak, const int oldSlices, + const int newSlices) +{ + return oldPeak + (newSlices - oldSlices)/2; +} + +// Return modified data vector<int> + +void ModifySlices::data(const std::vector<int>& oldVec, + std::vector<int>& newVec, const int newSlices) +{ + const int oldSlices = oldVec.size(); + const int offset = (newSlices - oldSlices)/2; + newVec.resize(newSlices); + for (int sl = 0; sl < newSlices; ++sl) { + const int oldSl = sl - offset; + if (oldSl < 0) newVec[sl] = oldVec[0]; + else if (oldSl >= oldSlices) newVec[sl] = oldVec[oldSlices - 1]; + else newVec[sl] = oldVec[oldSl]; + } +} + +// Return modified data vector<unsigned int> + +void ModifySlices::data(const std::vector<unsigned int>& oldVec, + std::vector<unsigned int>& newVec, + const int newSlices) +{ + const int oldSlices = oldVec.size(); + const int offset = (newSlices - oldSlices)/2; + newVec.resize(newSlices); + for (int sl = 0; sl < newSlices; ++sl) { + const int oldSl = sl - offset; + if (oldSl < 0) newVec[sl] = oldVec[0]; + else if (oldSl >= oldSlices) newVec[sl] = oldVec[oldSlices - 1]; + else newVec[sl] = oldVec[oldSl]; + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/ModifySlices.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/ModifySlices.h new file mode 100755 index 0000000000000000000000000000000000000000..ef95f05a2f01d4ccab9155adb18e68def63b1177 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/ModifySlices.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_MODIFYSLICES_H +#define TRIGT1CALOBYTESTREAM_MODIFYSLICES_H + +#include <vector> + +namespace LVL1BS { + +/** Utility to modify the number of slices. + * + * @author Peter Faulkner + */ + +class ModifySlices { + + public: + ModifySlices(); + ~ModifySlices(); + + /// Return new triggered slice offset + static int peak(int oldPeak, int oldSlices, int newSlices); + /// Return modified data vector<int> + static void data(const std::vector<int>& oldVec, + std::vector<int>& newVec, int newSlices); + /// Return modified data vector<unsigned int> + static void data(const std::vector<unsigned int>& oldVec, + std::vector<unsigned int>& newVec, int newSlices); + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamCnv.cxx new file mode 100755 index 0000000000000000000000000000000000000000..3d69374363ec9a8ed4ab45a5f5b405314e7d0eb4 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamCnv.cxx @@ -0,0 +1,179 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/TriggerTower.h" + +#include "PpmByteStreamCnv.h" +#include "PpmByteStreamTool.h" + +namespace LVL1BS { + +PpmByteStreamCnv::PpmByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("PpmByteStreamCnv"), + m_tool("LVL1BS::PpmByteStreamTool/PpmByteStreamTool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_ByteStreamEventAccess("ByteStreamCnvSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +PpmByteStreamCnv::~PpmByteStreamCnv() +{ +} + +// CLID + +const CLID& PpmByteStreamCnv::classID() +{ + return ClassID_traits<DataVector<LVL1::TriggerTower> >::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode PpmByteStreamCnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + //Get ByteStreamCnvSvc + sc = m_ByteStreamEventAccess.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_ByteStreamEventAccess << endreq; + return sc; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_ByteStreamEventAccess << endreq; + } + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::WARNING << "Failed to retrieve service " + << m_robDataProvider << endreq; + // return is disabled for Write BS which does not require ROBDataProviderSvc + // return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +StatusCode PpmByteStreamCnv::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + DataVector<LVL1::TriggerTower>* const ttCollection = + new DataVector<LVL1::TriggerTower>(SG::VIEW_ELEMENTS); + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(ttCollection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, ttCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete ttCollection; + return sc; + } + + pObj = SG::asStorable(ttCollection); + + return sc; +} + +// createRep should create the bytestream from RDOs. + +StatusCode PpmByteStreamCnv::createRep( DataObject* pObj, + IOpaqueAddress*& pAddr ) +{ + if (m_debug) m_log << MSG::DEBUG << "createRep() called" << endreq; + + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + + DataVector<LVL1::TriggerTower>* ttCollection = 0; + if( !SG::fromStorable( pObj, ttCollection ) ) { + m_log << MSG::ERROR << " Cannot cast to DataVector<TriggerTower>" << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = pObj->registry()->name(); + + ByteStreamAddress* addr = new ByteStreamAddress( classID(), nm, "" ); + + pAddr = addr; + + // Convert to ByteStream + return m_tool->convert( ttCollection, re ); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamCnv.h new file mode 100755 index 0000000000000000000000000000000000000000..7d7278050824e132464e8085b67551ff195db03c --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamCnv.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_PPMBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IByteStreamEventAccess; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class PpmByteStreamTool; + +/** ByteStream converter for Pre-processor Module DAQ data / TriggerTowers. + * + * @author Peter Faulkner + */ + +class PpmByteStreamCnv: public Converter { + + friend class CnvFactory<PpmByteStreamCnv>; + +protected: + + PpmByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~PpmByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create TriggerTowers from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + /// Create ByteStream from TriggerTowers + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::PpmByteStreamTool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + /// Service for writing bytestream + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamSubsetTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamSubsetTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..946290f8cbe5cb44d6f8da55c304cbeb20f8a759 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamSubsetTool.cxx @@ -0,0 +1,630 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "TrigT1CaloEvent/TriggerTower.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "PpmSubBlock.h" + +#include "PpmByteStreamSubsetTool.h" + +namespace LVL1BS { + +// Constructor + +PpmByteStreamSubsetTool::PpmByteStreamSubsetTool(const std::string& type, + const std::string& name, const IInterface* parent) + : AthAlgTool(type, name, parent), + m_ppmMaps("LVL1::PpmMappingTool/PpmMappingTool"), + m_channels(64), m_crates(8), m_modules(16), + m_subDetector(eformat::TDAQ_CALO_PREPROC), + m_srcIdMap(0), m_towerKey(0), m_errorBlock(0) +{ + declareInterface<IPpmByteStreamSubsetTool>(this); + + declareProperty("PpmMappingTool", m_ppmMaps); + + declareProperty("ZeroSuppress", m_zeroSuppress = true, + "Only make trigger towers with non-zero EM or Had energy"); +} + +// Destructor + +PpmByteStreamSubsetTool::~PpmByteStreamSubsetTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode PpmByteStreamSubsetTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + // Retrieve mapping tool + + StatusCode sc = m_ppmMaps.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_ppmMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_ppmMaps << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_towerKey = new LVL1::TriggerTowerKey(); + + m_ttMap.clear(); + + // if you retrieved it nicely, build tables + // See that all mapping is now done by channel number + // leading to the unique_idx we have bellow. + // See also that the EM and Had parts will be a single + // tt pointer + unsigned int maxkey=0; + for(int crate = 0; crate<m_crates; crate++) + for(int module = 0; module<m_modules; module++) + for(int channel = 0; channel<m_channels; channel++){ + double eta = 0; + double phi = 0; + int layer = 0; + LVL1::TriggerTower* tt=0; + if(m_ppmMaps->mapping(crate, module, channel, eta, phi, layer)){ + tt = findTriggerTower(eta, phi); + if ( !tt ) { + const unsigned int key = m_towerKey->ttKey(phi, eta); + tt = new LVL1::TriggerTower(phi, eta, key); + m_ttMap.insert(std::make_pair(key, tt)); + } + } + unsigned int unique_idx = channel; + unique_idx+=module*m_channels; + unique_idx+=crate*m_channels*m_modules; + etamap[unique_idx] = eta; + phimap[unique_idx] = phi; + layermap[unique_idx] = layer; + ttpool[unique_idx] = tt; + if (tt && tt->key()> maxkey) maxkey=tt->key(); + } + ttTemp.reserve(8192); + m_ppmBlocks.reserve(4); + // Make an array (pool) of SubBlock objects to help + for(size_t ii=0; ii<size_t(10);++ii){ + PpmSubBlock* const subBlock = new PpmSubBlock(); + m_ppmBlocksPool[ii] = subBlock; + } + + m_event = 0xffffffff; + m_first=true; + for(int i=0;i<8192;i++) + uniqueness[i]=0xffffffff; + + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode PpmByteStreamSubsetTool::finalize() +{ + for(int crate = 0; crate<m_crates; crate++) + for(int module = 0; module<m_modules; module++) + for(int channel = 0; channel<m_channels; channel++){ + unsigned int unique_idx = channel; + unique_idx+=module*m_channels; + unique_idx+=crate*m_channels*m_modules; + if ( ttpool[unique_idx] && layermap[unique_idx] ){ + delete ttpool[unique_idx]; + ttpool[unique_idx] = NULL; + } + } + for(size_t ii=0; ii<size_t(10);++ii){ + delete m_ppmBlocksPool[ii]; + } + + + delete m_errorBlock; + delete m_towerKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to trigger towers + +StatusCode PpmByteStreamSubsetTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::TriggerTower>* const ttCollection, + const std::vector<unsigned int>& chanIds) +{ + std::vector<int> lut; + std::vector<int> fadc; + std::vector<int> bcidLut; + std::vector<int> bcidFadc; + lut .reserve(10); + fadc .reserve(10); + bcidLut .reserve(10); + bcidFadc.reserve(10); + + + const bool debug = msgLvl(MSG::DEBUG); +#ifndef NDEBUG + const bool verbose = msgLvl(MSG::VERBOSE); +#endif + if (debug) msg(MSG::DEBUG); + + // Index wanted channels by crate/module + + std::vector<unsigned int>::const_iterator pos ; + std::vector<unsigned int>::const_iterator posE; + std::vector<unsigned int>::const_iterator posB; + bool full = ( chanIds.size() == 7168 ); // hardcoded number + if ( full && m_first ){ + pos = chanIds.begin(); + posE = chanIds.end(); + posB = pos; + unsigned int lastKey = (pos != posE) ? (*pos)/64 : 9999; + for (; pos != posE; ++pos) { + const unsigned int key = (*pos)/64; + if (key != lastKey) { + if (debug) msg() << "Adding key to index: " << lastKey << endreq; + chanMapFull.insert(std::make_pair(lastKey, std::make_pair(posB, pos))); + lastKey = key; + posB = pos; + } + } + if (lastKey != 9999) { + if (debug) msg() << "Adding key to index: " << lastKey << endreq; + chanMapFull.insert(std::make_pair(lastKey, std::make_pair(posB, posE))); + } + if (debug) { + msg() << "Number of channels wanted: " << chanIds.size() + << " Channel map size: " << chanMapFull.size() << endreq; + } + m_first = false; + } + else if ( !full ) { + pos = chanIds.begin(); + posE = chanIds.end(); + posB = pos; + unsigned int lastKey = (pos != posE) ? (*pos)/64 : 9999; + for (; pos != posE; ++pos) { + const unsigned int key = (*pos)/64; + if (key != lastKey) { + if (debug) msg() << "Adding key to index: " << lastKey << endreq; + chanMap.insert(std::make_pair(lastKey, std::make_pair(posB, pos))); + lastKey = key; + posB = pos; + } + } + if (lastKey != 9999) { + if (debug) msg() << "Adding key to index: " << lastKey << endreq; + chanMap.insert(std::make_pair(lastKey, std::make_pair(posB, posE))); + } + if (debug) { + msg() << "Number of channels wanted: " << chanIds.size() + << " Channel map size: " << chanMap.size() << endreq; + } + } + + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) msg() << "Treating ROB fragment " << ++robCount << endreq; + + // Skip fragments with ROB status errors + + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + uint32_t robid = (*rob)->source_id(); + if (!dupCheck.insert(robid).second) { + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (debug) { + if (m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0) { + msg() << "Wrong source identifier in data: " + << MSG::hex << sourceID << MSG::dec << endreq; + } + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word is User Header + L1CaloUserHeader userHeader(*payload); + const int minorVersion = (*rob)->rod_version() & 0xffff; + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1 && debug) { + msg() << "Unexpected number of user header words: " + << headerWords << endreq; + } + payload+=headerWords; + // triggered slice offsets + const int trigLut = userHeader.ppmLut(); + const int trigFadc = userHeader.ppmFadc(); + // FADC baseline lower bound + const int fadcBaseline = userHeader.lowerBound(); + if (debug) { + msg() << "Minor format version number: " + << MSG::hex << minorVersion << MSG::dec << endreq + << "LUT triggered slice offset: " << trigLut << endreq + << "FADC triggered slice offset: " << trigFadc << endreq + << "FADC baseline lower bound: " << fadcBaseline << endreq; + } + const int runNumber = (*rob)->rod_run_no() & 0xffffff; + + // Find the number of channels per sub-block + + int chanPerSubBlock = 0; + if (payload != payloadEnd) { + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER) { + if (debug) msg() << "Missing Sub-block header" << endreq; + continue; + } + testBlock.clear(); + + payload = testBlock.read(payload, payloadEnd); + if (payload == payloadEnd) { + if (debug) msg() << "Keep coverity happy" << endreq; + } + chanPerSubBlock = testBlock.channelsPerSubBlock(); + if (chanPerSubBlock == 0) { + if (debug) msg() << "Unsupported version/data format: " + << testBlock.version() << "/" + << testBlock.format() << endreq; + continue; + } + if (m_channels%chanPerSubBlock != 0) { + if (debug) msg() << "Invalid channels per sub-block: " + << chanPerSubBlock << endreq; + continue; + } + if (debug) { + msg() << "Channels per sub-block: " << chanPerSubBlock << endreq; + } + } else { + if (debug) msg() << "ROB fragment contains user header only" << endreq; + continue; + } + const int numSubBlocks = m_channels/chanPerSubBlock; + + // Loop over PPMs + + payload = payloadBeg; + payload+=headerWords; + bool isErr = false; + while (payload != payloadEnd) { + + // Get all sub-blocks for one PPM + + int crate = 0; + int module = 0; + m_ppmBlocks.clear(); + int pool = 0; + for (int block = 0; block < numSubBlocks; ++block) { + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER + || PpmSubBlock::errorBlock(*payload)) { + if (debug) msg() << "Unexpected data sequence" << endreq; + isErr = true; + break; + } + if (chanPerSubBlock != m_channels && + L1CaloSubBlock::seqno(*payload) != block * chanPerSubBlock) { + if (debug) { + msg() << "Unexpected channel sequence number: " + << L1CaloSubBlock::seqno(*payload) << " expected " + << block * chanPerSubBlock << endreq; + } + isErr = true; + break; + } + PpmSubBlock* const subBlock = m_ppmBlocksPool[pool]; + subBlock->clear(); + m_ppmBlocks.push_back(( m_ppmBlocksPool[pool++] )); + payload = subBlock->read(payload, payloadEnd); + if (block == 0) { + crate = subBlock->crate(); + module = subBlock->module(); + if (debug) { + msg() << "Module " << module << endreq; + if (crate != rodCrate) { + msg() << "Inconsistent crate number in ROD source ID" << endreq; + } + } + } else { + if (subBlock->crate() != crate) { + if (debug) msg() << "Inconsistent crate number in sub-blocks" + << endreq; + isErr = true; + break; + } + if (subBlock->module() != module) { + if (debug) msg() << "Inconsistent module number in sub-blocks" + << endreq; + isErr = true; + break; + } + } + if (payload == payloadEnd && block != numSubBlocks - 1) { + if (debug) msg() << "Premature end of data" << endreq; + break; + } + } + if (isErr) break; + + // Is there an error block? + + delete m_errorBlock; + m_errorBlock = 0; + if (payload != payloadEnd) { + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER + && PpmSubBlock::errorBlock(*payload)) { + if (debug) msg() << "Error block found" << endreq; + m_errorBlock = new PpmSubBlock(); + payload = m_errorBlock->read(payload, payloadEnd); + if (m_errorBlock->crate() != crate) { + if (debug) msg() << "Inconsistent crate number in error block" + << endreq; + isErr = true; + break; + } + if (m_errorBlock->module() != module) { + if (debug) msg() << "Inconsistent module number in error block" + << endreq; + isErr = true; + break; + } + if (m_errorBlock->dataWords() && !m_errorBlock->unpack()) { + if (debug) { + std::string errMsg(m_errorBlock->unpackErrorMsg()); + msg() << "Unpacking error block failed: " << errMsg << endreq; + } + isErr = true; + break; + } + } + } + + // Loop over wanted channels and fill trigger towers + + const int actualSubBlocks = m_ppmBlocks.size(); + int lastBlock = -1; + unsigned int key = crate*16 + module; + ChannelMap::iterator mapIter = full ? chanMapFull.find(key) : chanMap.find(key); + if (full && mapIter == chanMapFull.end()) { + if (debug) msg() << "Key not found: " << key << endreq; + continue; + } + if (!full && mapIter == chanMap.end()) { + if (debug) msg() << "Key not found: " << key << endreq; + continue; + } + IteratorPair ipair = mapIter->second; + pos = ipair.first; + posE = ipair.second; + PpmSubBlock* subBlock = 0; + unsigned int cratemod_idx = module*m_channels; + cratemod_idx+=crate*m_channels*m_modules; + for (; pos != posE; ++pos) { + const int channel = (*pos) % 64; + const int block = channel/chanPerSubBlock; + if (block >= actualSubBlocks) { + if (debug) { + msg() << "channel/block/actualSubBlocks: " + << channel << "/" << block << "/" << actualSubBlocks + << endreq; + } + break; + } + if (block != lastBlock) { + lastBlock = block; + subBlock = m_ppmBlocks[block]; + subBlock->setLutOffset(trigLut); + subBlock->setFadcOffset(trigFadc); + subBlock->setFadcBaseline(fadcBaseline); + subBlock->setRunNumber(runNumber); + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "Unpacking PPM sub-block failed: " << errMsg << endreq; + } + isErr = true; + break; + } + } + if (!subBlock) { + if (debug) msg() << "Logic error" << endreq; + break; + } + subBlock->ppmData(channel, lut, fadc, bcidLut, bcidFadc); + int trigLutKeep = trigLut; + int trigFadcKeep = trigFadc; + if (lut.size() < size_t(trigLut + 1)) { + if (debug) { + msg() << "Triggered LUT slice from header " + << "inconsistent with number of slices: " + << trigLut << ", " << lut.size() << ", reset to 0" << endreq; + } + trigLutKeep = 0; + } + if (fadc.size() < size_t(trigFadc + 1)) { + if (debug) { + msg() << "Triggered FADC slice from header " + << "inconsistent with number of slices: " + << trigFadc << ", " << fadc.size() << ", reset to 0" + << endreq; + } + trigFadcKeep = 0; + } + LVL1::DataError errorBits(0); + if (m_errorBlock) { + errorBits.set(LVL1::DataError::PPMErrorWord, + m_errorBlock->ppmError(channel)); + errorBits.set(LVL1::DataError::SubStatusWord, + m_errorBlock->subStatus()); + } else { + errorBits.set(LVL1::DataError::PPMErrorWord, + subBlock->ppmError(channel)); + const PpmSubBlock* const lastBlock = + m_ppmBlocks[actualSubBlocks - 1]; + errorBits.set(LVL1::DataError::SubStatusWord, + lastBlock->subStatus()); + } + // Wrong bit set for compressed formats 1.01 to 1.03 + if (subBlock->format() > 1 && subBlock->seqno() < 4) { + errorBits.set(LVL1::DataError::ModuleError, + (errorBits.error() >> (LVL1::DataError::ModuleError+1)) & 0x1); + } + const int error = errorBits.error(); + + // Only save non-zero data + + const bool any = + std::accumulate(lut.begin(), lut.end(), 0) || + std::accumulate(fadc.begin(), fadc.end(), 0) || + std::accumulate(bcidLut.begin(), bcidLut.end(), 0) || + std::accumulate(bcidFadc.begin(), bcidFadc.end(), 0); + + if (any || error) { +#ifndef NDEBUG + if (verbose) { + msg(MSG::VERBOSE) << "channel/LUT/FADC/bcidLUT/bcidFADC/error: " + << channel << "/"; + printVec(lut); + printVec(fadc); + printVec(bcidLut); + printVec(bcidFadc); + msg() << MSG::hex << error << MSG::dec << "/"; + } +#endif + // See that there is no call to m_ppmMaps->mapping here + // all is addressed by channel number and crate/module + // as prepared in the initialize. Also, no more calls to + // findTriggerTower in the loop + unsigned int unique_idx = cratemod_idx+channel; + LVL1::TriggerTower* tt = ttpool[unique_idx]; + if ( !tt ) continue; +#ifndef NDEBUG + if (verbose) { + // eta/phi are only used here + double eta = etamap[unique_idx]; + double phi = phimap[unique_idx]; + int layer = layermap[unique_idx]; + msg() << " eta/phi/layer: " << eta << "/" << phi << "/" + << layer << "/" << endreq; + msg(MSG::DEBUG); + } +#endif + // tt is filled during unpacking, NOT here. + if ( uniqueness[tt->key()] != m_event ){ + ttTemp.push_back(tt); + uniqueness[tt->key()] = m_event; + } + + if (layermap[unique_idx]) { // EM + tt->addHad(fadc, lut, bcidFadc, bcidLut, error, + trigLutKeep, trigFadcKeep); + } else { // Had + tt->addEM(fadc, lut, bcidFadc, bcidLut, error, + trigLutKeep, trigFadcKeep); + } + } + } + if (isErr) break; + } + } + + // Swap wanted trigger towers into final container + + const int size = ttTemp.size(); + for (int index = 0; index < size; ++index) { + if ( !m_zeroSuppress || ttTemp[index]->emEnergy() + || ttTemp[index]->hadEnergy() ) { + ttCollection->push_back(ttTemp[index]); + } + } + ttTemp.clear(); + for(int i=0;i<8192;i++) + uniqueness[i]=0xffffffff; + + return StatusCode::SUCCESS; +} + +// Find a trigger tower given eta, phi + +LVL1::TriggerTower* PpmByteStreamSubsetTool::findTriggerTower(const double eta, + const double phi) +{ + LVL1::TriggerTower* tt = 0; + const unsigned int key = m_towerKey->ttKey(phi, eta); + TriggerTowerMap::const_iterator mapIter; + mapIter = m_ttMap.find(key); + if (mapIter != m_ttMap.end()) tt = mapIter->second; + return tt; +} + +// Print a vector + +void PpmByteStreamSubsetTool::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamSubsetTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamSubsetTool.h new file mode 100644 index 0000000000000000000000000000000000000000..323364dcd95cb5fbbf3128b5a1adec70bcd7ef32 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamSubsetTool.h @@ -0,0 +1,130 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMBYTESTREAMSUBSETTOOL_H +#define TRIGT1CALOBYTESTREAM_PPMBYTESTREAMSUBSETTOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +#include "IPpmByteStreamSubsetTool.h" +#include "PpmSubBlock.h" + +class IInterface; +class StatusCode; + +namespace LVL1 { + class IL1CaloMappingTool; + class TriggerTower; + class TriggerTowerKey; +} + +namespace LVL1BS { + +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to trigger towers conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class PpmByteStreamSubsetTool : virtual public IPpmByteStreamSubsetTool, + public AthAlgTool { + + public: + PpmByteStreamSubsetTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~PpmByteStreamSubsetTool(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to trigger towers + virtual StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::TriggerTower>* ttCollection, + const std::vector<unsigned int>& chanIds); + virtual void eventNumber(const unsigned int eN ) { m_event=eN;}; + + private: + typedef DataVector<LVL1::TriggerTower> TriggerTowerCollection; + typedef std::map<unsigned int, LVL1::TriggerTower*> TriggerTowerMap; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + typedef std::pair<std::vector<unsigned int>::const_iterator, + std::vector<unsigned int>::const_iterator> IteratorPair; + typedef std::map<unsigned int, IteratorPair> ChannelMap; + + /// Find a trigger tower given eta, phi + LVL1::TriggerTower* findTriggerTower(double eta, double phi); + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + + /// Tool for mappings + ToolHandle<LVL1::IL1CaloMappingTool> m_ppmMaps; + + /// Number of channels per module (may not all be used) + int m_channels; + /// Number of crates + int m_crates; + /// Number of modules per crate (may not all exist) + int m_modules; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Zero suppression on input + bool m_zeroSuppress; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Trigger tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// Current error block + PpmSubBlock* m_errorBlock; + /// Trigger tower map for conversion from bytestream + TriggerTowerMap m_ttMap; + /// Vector for current PPM sub-blocks. Changed type + std::vector<PpmSubBlock*> m_ppmBlocks; + /// Pool for current PPM sub-blocks + PpmSubBlock* m_ppmBlocksPool[10]; + // To simplify life, let's prepare maps beforehand + // Organized by crate (8), module (16) and channel (64) + // eta and phi maps could be avoided. Only used in DEBUG + // building of the code + double etamap[8192]; + double phimap[8192]; + int layermap [8192]; + unsigned int uniqueness[8192]; + // The same for new tt addresses (no mem allocation) + LVL1::TriggerTower* ttpool[8192]; + // Cache temporary vector + std::vector<LVL1::TriggerTower*> ttTemp; + // Cache channel map + ChannelMap chanMap; + ChannelMap chanMapFull; + // Get channel maps for full calo unpack + bool m_first; + // Caching some variables + PpmSubBlock testBlock; + // counter of present event + unsigned int m_event; + + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamTool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..caf837f60f9b1673d899c50dc56d59b6143b486f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamTool.cxx @@ -0,0 +1,1121 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <set> +#include <utility> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/SegMemSvc.h" + +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +#include "TrigT1CaloEvent/TriggerTower.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "CmmSubBlock.h" +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" +#include "L1CaloUserHeader.h" +#include "ModifySlices.h" +#include "PpmSubBlock.h" + +#include "PpmByteStreamTool.h" + +namespace LVL1BS { + +const int PpmByteStreamTool::s_crates; +const int PpmByteStreamTool::s_modules; +const int PpmByteStreamTool::s_channels; +const int PpmByteStreamTool::s_dataSize; + +// Interface ID + +static const InterfaceID IID_IPpmByteStreamTool("PpmByteStreamTool", 1, 1); + +const InterfaceID& PpmByteStreamTool::interfaceID() +{ + return IID_IPpmByteStreamTool; +} + +// Constructor + +PpmByteStreamTool::PpmByteStreamTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_ppmMaps("LVL1::PpmMappingTool/PpmMappingTool"), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_sms("SegMemSvc/SegMemSvc", name), + m_version(1), m_compVers(4), + m_dataChannels(true), m_spareChannels(false), m_muonChannels(false), + m_subDetector(eformat::TDAQ_CALO_PREPROC), + m_srcIdMap(0), m_towerKey(0), m_errorBlock(0), m_rodStatus(0), m_fea(0) +{ + declareInterface<PpmByteStreamTool>(this); + + declareProperty("PpmMappingTool", m_ppmMaps, + "Crate/Module/Channel to Eta/Phi/Layer mapping tool"); + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + + declareProperty("PrintCompStats", m_printCompStats = 0, + "Print compressed format statistics"); + declareProperty("SlinksPerCrate", m_slinks = 4, + "The number of S-Links per crate"); + + // Properties for reading bytestream only + declareProperty("ZeroSuppress", m_zeroSuppress = 0, + "Only make trigger towers with non-zero EM or Had energy"); + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers"); + declareProperty("PedestalValue", m_pedestal = 10, + "Pedestal value - needed for compressed formats 0,1 only"); + + // Properties for writing bytestream only + declareProperty("DataFormat", m_dataFormat = 1, + "Format identifier (0-3) in sub-block header"); + declareProperty("FADCBaseline", m_fadcBaseline = 0, + "FADC baseline lower bound for compressed formats"); + declareProperty("FADCThreshold", m_fadcThreshold = 1, + "FADC threshold for super-compressed format"); + declareProperty("SimulSlicesLUT", m_dfltSlicesLut = 1, + "The number of LUT slices in the simulation"); + declareProperty("SimulSlicesFADC", m_dfltSlicesFadc = 7, + "The number of FADC slices in the simulation"); + declareProperty("ForceSlicesLUT", m_forceSlicesLut = 0, + "If >0, the number of LUT slices in bytestream"); + declareProperty("ForceSlicesFADC", m_forceSlicesFadc = 0, + "If >0, the number of FADC slices in bytestream"); + declareProperty("CrateMin", m_crateMin = 0, + "Minimum crate number, allows partial output"); + declareProperty("CrateMax", m_crateMax = s_crates-1, + "Maximum crate number, allows partial output"); + +} + +// Destructor + +PpmByteStreamTool::~PpmByteStreamTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode PpmByteStreamTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_ppmMaps.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_ppmMaps << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_ppmMaps << endreq; + + sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + sc = m_sms.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve service " << m_sms << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved service " << m_sms << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + m_towerKey = new LVL1::TriggerTowerKey(); + m_rodStatus = new std::vector<uint32_t>(2); + m_fea = new FullEventAssembler<L1CaloSrcIdMap>(); + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode PpmByteStreamTool::finalize() +{ + if (m_printCompStats && msgLvl(MSG::INFO)) { + msg(MSG::INFO); + printCompStats(); + } + delete m_fea; + delete m_rodStatus; + delete m_errorBlock; + delete m_towerKey; + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to trigger towers + +StatusCode PpmByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::TriggerTower>* const ttCollection) +{ + const bool debug = msgLvl(MSG::DEBUG); + const bool verbose = msgLvl(MSG::VERBOSE); + if (debug) msg(MSG::DEBUG); + + // Set up TriggerTower pool and mappings + // (NB. This assumes mappings won't change during the course of a job) + const int maxChannels = s_crates * s_modules * s_channels; + const int chanBitVecSize = maxChannels/32; + if (m_ttData.empty()) { + const int spareSize = maxChannels - 2*s_dataSize; + const int muonSize = 2*s_channels; + const int modBitVecSize = (s_crates * s_modules)/32; + m_ttData.reserve(s_dataSize); + m_ttSpare.reserve(spareSize); + m_ttMuon.reserve(muonSize); + m_ttPos.resize(maxChannels); + m_chanLayer.resize(chanBitVecSize); + m_dataChan.resize(chanBitVecSize); + m_spareChan.resize(chanBitVecSize); + m_muonChan.resize(chanBitVecSize); + m_dataMod.resize(modBitVecSize); + m_spareMod.resize(modBitVecSize); + m_muonMod.resize(modBitVecSize); + TriggerTowerMap ttMap; + TriggerTowerMap::iterator itt; + std::vector<int> dummyS; + std::vector<int> dummyL(1); + std::vector<int> dummyF(5); + int dataCount = 0; + int spareCount = 0; + for (int crate = 0; crate < s_crates; ++crate) { + for (int module = 0; module < s_modules; ++module) { + const int index2 = (crate<<4) + module; + const int word2 = index2/32; + const int bit2 = index2%32; + for (int channel = 0; channel < s_channels; ++channel) { + const int index = (crate<<10) + (module<<6) + channel; + const int word = index/32; + const int bit = index%32; + double eta = 0.; + double phi = 0.; + int layer = 0; + unsigned int key = 0; + if (m_ppmMaps->mapping(crate, module, channel, eta, phi, layer)) { + // Data channels + key = m_towerKey->ttKey(phi, eta); + itt = ttMap.find(key); + if (itt == ttMap.end()) { + LVL1::TriggerTower* tt = + new (m_sms->allocate<LVL1::TriggerTower>(SegMemSvc::JOB)) + LVL1::TriggerTower(phi, eta, key, + dummyF, dummyL, dummyF, dummyL, 0, 0, 0, + dummyF, dummyL, dummyF, dummyL, 0, 0, 0); + m_ttData.push_back(tt); + const int count = dataCount++; + m_ttPos[index] = count; + ttMap.insert(std::make_pair(key,count)); + } else { + m_ttPos[index] = itt->second; + } + m_chanLayer[word] |= (layer<<bit); + m_dataChan[word] |= (1<<bit); + m_dataMod[word2] |= (1<<bit2); + } else { + // Spare channels + const int pin = channel%16; + const int asic = channel/16; + eta = 16*crate + module; + phi = 4*pin + asic; + layer = 0; + const int type = 1; + key = (crate<<24) | (type<<20) | (module<<16) | (pin<<8) | asic; // CoolID + LVL1::TriggerTower* tt = + new (m_sms->allocate<LVL1::TriggerTower>(SegMemSvc::JOB)) + LVL1::TriggerTower(phi, eta, key, + dummyF, dummyL, dummyF, dummyL, 0, 0, 0, + dummyS, dummyS, dummyS, dummyS, 0, 0, 0); + m_ttSpare.push_back(tt); + m_ttPos[index] = spareCount++; + m_chanLayer[word] |= (layer<<bit); + m_spareChan[word] |= (1<<bit); + m_spareMod[word2] |= (1<<bit2); + if ((crate == 2 || crate == 3) && (module == 0)) { + m_ttMuon.push_back(tt); + m_muonChan[word] |= (1<<bit); + m_muonMod[word2] |= (1<<bit2); + } + } + } + } + } + } + + // Set up according to the collection we want + + TriggerTowerVector& ttCol((m_dataChannels) ? m_ttData + : (m_spareChannels) + ? m_ttSpare + : m_ttMuon); + TriggerTowerVector& ttColRef((m_dataChannels) ? m_ttData + : m_ttSpare); + ChannelBitVector& colChan((m_dataChannels) ? m_dataChan + : (m_spareChannels) + ? m_spareChan + : m_muonChan); + ChannelBitVector& colMod((m_dataChannels) ? m_dataMod + : (m_spareChannels) + ? m_spareMod + : m_muonMod); + const int colSize = (m_dataChannels) ? 2*ttCol.size() + : ttCol.size(); + m_foundChan.assign(chanBitVecSize, 0); + int ttCount = 0; + + // Vectors to unpack into + std::vector<int> lut; + std::vector<int> fadc; + std::vector<int> bcidLut; + std::vector<int> bcidFadc; + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD data (slinks) + + RODPointer payloadBeg; + RODPointer payload; + RODPointer payloadEnd; + (*rob)->rod_data(payloadBeg); + payloadEnd = payloadBeg + (*rob)->rod_ndata(); + payload = payloadBeg; + if (payload == payloadEnd) { + if (debug) msg() << "ROB fragment empty" << endreq; + continue; + } + + // Check identifier + const uint32_t sourceID = (*rob)->rod_source_id(); + if (m_srcIdMap->getRobID(sourceID) != robid || + m_srcIdMap->subDet(sourceID) != m_subDetector || + m_srcIdMap->daqOrRoi(sourceID) != 0 || + m_srcIdMap->slink(sourceID) >= m_slinks || + m_srcIdMap->crate(sourceID) >= s_crates) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_ID); + if (debug) { + msg() << "Wrong source identifier in data: ROD " + << MSG::hex << sourceID << " ROB " << robid + << MSG::dec << endreq; + } + continue; + } + + // Check minor version + const int minorVersion = (*rob)->rod_version() & 0xffff; + if (minorVersion > m_srcIdMap->minorVersionPreLS1()) { + if (debug) msg() << "Skipping post-LS1 data" << endreq; + continue; + } + const int rodCrate = m_srcIdMap->crate(sourceID); + if (debug) { + msg() << "Treating crate " << rodCrate + << " slink " << m_srcIdMap->slink(sourceID) << endreq; + } + + // First word should be User Header + if ( !L1CaloUserHeader::isValid(*payload) ) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) msg() << "Invalid or missing user header" << endreq; + continue; + } + L1CaloUserHeader userHeader(*payload); + userHeader.setVersion(minorVersion); + const int headerWords = userHeader.words(); + if (headerWords != 1) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_USER_HEADER); + if (debug) { + msg() << "Unexpected number of user header words: " + << headerWords << endreq; + } + continue; + } + for (int i = 0; i < headerWords; ++i) ++payload; + // triggered slice offsets + const int trigLut = userHeader.ppmLut(); + const int trigFadc = userHeader.ppmFadc(); + // FADC baseline lower bound + m_fadcBaseline = userHeader.lowerBound(); + if (debug) { + msg() << "Minor format version number: " + << MSG::hex << minorVersion << MSG::dec << endreq + << "LUT triggered slice offset: " << trigLut << endreq + << "FADC triggered slice offset: " << trigFadc << endreq + << "FADC baseline lower bound: " << m_fadcBaseline << endreq; + } + const int runNumber = (*rob)->rod_run_no() & 0xffffff; + + // Find the number of channels per sub-block + + int chanPerSubBlock = 0; + bool firstBlock = false; + uint32_t firstWord = 0; + RODPointer payloadFirst; + if (payload != payloadEnd) { + if (L1CaloSubBlock::wordType(*payload) != L1CaloSubBlock::HEADER + || CmmSubBlock::cmmBlock(*payload)) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_MISSING_HEADER); + if (debug) msg() << "Missing Sub-block header" << endreq; + continue; + } + firstBlock = true; + firstWord = *payload; + if (m_ppmBlocks.empty()) { + m_ppmBlocks.push_back(new PpmSubBlock()); + } + PpmSubBlock* const subBlock = m_ppmBlocks[0]; + subBlock->clear(); + payloadFirst = subBlock->read(payload, payloadEnd); + chanPerSubBlock = subBlock->channelsPerSubBlock(); + if (chanPerSubBlock == 0) { + m_errorTool->rodError(robid, subBlock->unpackErrorCode()); + if (debug) msg() << "Unsupported version/data format: " + << subBlock->version() << "/" + << subBlock->format() << endreq; + continue; + } + if (debug) msg() << "Channels per sub-block: " + << chanPerSubBlock << endreq; + } else { + if (debug) msg() << "ROB fragment contains user header only" << endreq; + continue; + } + const int numSubBlocks = s_channels/chanPerSubBlock; + const int size = m_ppmBlocks.size(); + if (numSubBlocks > size) { + for (int i = size; i < numSubBlocks; ++i) { + m_ppmBlocks.push_back(new PpmSubBlock()); + } + } + + // Loop over PPMs + + payload = payloadBeg; + for (int i = 0; i < headerWords; ++i) ++payload; + unsigned int rodErr = L1CaloSubBlock::ERROR_NONE; + while (payload != payloadEnd) { + + // Get all sub-blocks for one PPM (first already read in above) + + int crate = 0; + int module = 0; + int nPpmBlocks = 0; + for (int block = 0; block < numSubBlocks; ++block) { + const uint32_t word = (firstBlock) ? firstWord : *payload; + if (L1CaloSubBlock::wordType(word) != L1CaloSubBlock::HEADER + || CmmSubBlock::cmmBlock(word) + || PpmSubBlock::errorBlock(word)) { + if (debug) msg() << "Unexpected data sequence" << endreq; + rodErr = L1CaloSubBlock::ERROR_MISSING_HEADER; + break; + } + if (chanPerSubBlock != s_channels && + L1CaloSubBlock::seqno(word) != block * chanPerSubBlock) { + if (debug) { + msg() << "Unexpected channel sequence number: " + << L1CaloSubBlock::seqno(word) << " expected " + << block * chanPerSubBlock << endreq; + } + rodErr = L1CaloSubBlock::ERROR_MISSING_SUBBLOCK; + break; + } + PpmSubBlock* const subBlock = m_ppmBlocks[block]; + nPpmBlocks++; + if (firstBlock) { + payload = payloadFirst; + firstBlock = false; + } else { + subBlock->clear(); + payload = subBlock->read(payload, payloadEnd); + } + if (block == 0) { + crate = subBlock->crate(); + module = subBlock->module(); + if (debug) { + msg() << "Crate " << crate << " Module " << module << endreq; + } + if (crate != rodCrate) { + if (debug) { + msg() << "Inconsistent crate number in ROD source ID" << endreq; + } + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + } else { + if (subBlock->crate() != crate) { + if (debug) msg() << "Inconsistent crate number in sub-blocks" + << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (subBlock->module() != module) { + if (debug) msg() << "Inconsistent module number in sub-blocks" + << endreq; + rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + } + if (payload == payloadEnd && block != numSubBlocks - 1) { + if (debug) msg() << "Premature end of data" << endreq; + rodErr = L1CaloSubBlock::ERROR_MISSING_SUBBLOCK; + break; + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) break; + + // Is there an error block? + + bool isErrBlock = false; + if (payload != payloadEnd) { + if (L1CaloSubBlock::wordType(*payload) == L1CaloSubBlock::HEADER + && !CmmSubBlock::cmmBlock(*payload) + && PpmSubBlock::errorBlock(*payload)) { + if (debug) msg() << "Error block found" << endreq; + if (!m_errorBlock) m_errorBlock = new PpmSubBlock(); + else m_errorBlock->clear(); + isErrBlock = true; + payload = m_errorBlock->read(payload, payloadEnd); + if (m_errorBlock->crate() != crate) { + if (debug) msg() << "Inconsistent crate number in error block" + << endreq; + rodErr = L1CaloSubBlock::ERROR_CRATE_NUMBER; + break; + } + if (m_errorBlock->module() != module) { + if (debug) msg() << "Inconsistent module number in error block" + << endreq; + rodErr = L1CaloSubBlock::ERROR_MODULE_NUMBER; + break; + } + if (m_errorBlock->dataWords() && !m_errorBlock->unpack()) { + if (debug) { + std::string errMsg(m_errorBlock->unpackErrorMsg()); + msg() << "Unpacking error block failed: " << errMsg << endreq; + } + rodErr = m_errorBlock->unpackErrorCode(); + break; + } + } + } + + // Don't bother unpacking modules that aren't used for required collection + + const int index2 = (crate<<4) + module; + const int word2 = index2/32; + const int bit2 = index2%32; + if (!((colMod[word2]>>bit2)&1)) continue; + + // Loop over sub-blocks and fill trigger towers + + for (int block = 0; block < nPpmBlocks; ++block) { + PpmSubBlock* const subBlock = m_ppmBlocks[block]; + subBlock->setLutOffset(trigLut); + subBlock->setFadcOffset(trigFadc); + subBlock->setPedestal(m_pedestal); + subBlock->setFadcBaseline(m_fadcBaseline); + subBlock->setRunNumber(runNumber); + if (debug) { + msg() << "Unpacking sub-block version/format/seqno: " + << subBlock->version() << "/" << subBlock->format() << "/" + << subBlock->seqno() << endreq; + } + if (subBlock->dataWords() && !subBlock->unpack()) { + if (debug) { + std::string errMsg(subBlock->unpackErrorMsg()); + msg() << "Unpacking PPM sub-block failed: " << errMsg << endreq; + } + rodErr = subBlock->unpackErrorCode(); + break; + } + if (m_printCompStats) addCompStats(subBlock->compStats()); + for (int chan = 0; chan < chanPerSubBlock; ++chan) { + const int channel = block*chanPerSubBlock + chan; + const int index = (crate<<10) + (module<<6) + channel; + const int word = index/32; + const int bit = index%32; + if (!((colChan[word]>>bit)&1)) continue; // skip unwanted channels + if (((m_foundChan[word]>>bit)&1)) { + if (debug) msg() << "Duplicate data for crate/module/channel: " + << crate << "/" << module << "/" << channel + << endreq; + rodErr = L1CaloSubBlock::ERROR_DUPLICATE_DATA; + break; + } + lut.clear(); + fadc.clear(); + bcidLut.clear(); + bcidFadc.clear(); + subBlock->ppmData(channel, lut, fadc, bcidLut, bcidFadc); + if (lut.size() < size_t(trigLut + 1)) { + if (debug) { + msg() << "Triggered LUT slice from header " + << "inconsistent with number of slices: " + << trigLut << ", " << lut.size() << endreq; + } + rodErr = L1CaloSubBlock::ERROR_SLICES; + break; + } + if (fadc.size() < size_t(trigFadc + 1)) { + if (debug) { + msg() << "Triggered FADC slice from header " + << "inconsistent with number of slices: " + << trigFadc << ", " << fadc.size() << endreq; + } + rodErr = L1CaloSubBlock::ERROR_SLICES; + break; + } + LVL1::DataError errorBits(0); + if (isErrBlock) { + errorBits.set(LVL1::DataError::PPMErrorWord, + m_errorBlock->ppmError(channel)); + errorBits.set(LVL1::DataError::SubStatusWord, + m_errorBlock->subStatus()); + } else { + errorBits.set(LVL1::DataError::PPMErrorWord, + subBlock->ppmError(channel)); + const PpmSubBlock* const lastBlock = + m_ppmBlocks[nPpmBlocks - 1]; + errorBits.set(LVL1::DataError::SubStatusWord, + lastBlock->subStatus()); + } + // Wrong bit set for compressed formats 1.01 to 1.03 + if (subBlock->format() > 1 && subBlock->seqno() < 4) { + errorBits.set(LVL1::DataError::ModuleError, + (errorBits.error() >> (LVL1::DataError::ModuleError+1)) & 0x1); + } + const int error = errorBits.error(); + + // Save to TriggerTower + + if (verbose) { + msg(MSG::VERBOSE) << "channel/LUT/FADC/bcidLUT/bcidFADC/error: " + << channel << "/"; + printVec(lut); + printVec(fadc); + printVec(bcidLut); + printVec(bcidFadc); + msg() << MSG::hex << error << MSG::dec << "/"; + } + m_foundChan[word] |= (1<<bit); + ++ttCount; + LVL1::TriggerTower* tt = ttColRef[m_ttPos[index]]; + const int layer = ((m_chanLayer[word]>>bit)&1); + if (layer == 0) { // EM + tt->addEM(fadc, lut, bcidFadc, bcidLut, error, trigLut, trigFadc); + } else { // Had + tt->addHad(fadc, lut, bcidFadc, bcidLut, error, trigLut, trigFadc); + } + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) break; + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) break; + } + if (rodErr != L1CaloSubBlock::ERROR_NONE) + m_errorTool->rodError(robid, rodErr); + } + + // Reset any missing channels (should be rare) + + if (ttCount != colSize) { + if (debug) { + msg() << "Found " << ttCount << " channels, expected " << colSize << endreq; + } + std::vector<int> dummy(1); + for (int word = 0; word < chanBitVecSize; ++word) { + if (m_foundChan[word] != colChan[word]) { + for (int bit = 0; bit < 32; ++bit) { + if (((m_foundChan[word]>>bit)&1) != ((colChan[word]>>bit)&1)) { + const int index = word*32 + bit; + LVL1::TriggerTower* tt = ttColRef[m_ttPos[index]]; + const int layer = ((m_chanLayer[word]>>bit)&1); + if (layer == 0) { // EM + tt->addEM(dummy, dummy, dummy, dummy, 0, 0, 0); + } else if (m_dataChannels) { // Had + tt->addHad(dummy, dummy, dummy, dummy, 0, 0, 0); + } + } + } + } + } + } + + // And copy into output collection + + if (m_zeroSuppress) { + TriggerTowerVector::iterator itr = ttCol.begin(); + TriggerTowerVector::iterator itrE = ttCol.end(); + for (; itr != itrE; ++itr) { + if ((*itr)->emEnergy() || (m_dataChannels && (*itr)->hadEnergy())) { + ttCollection->push_back(*itr); + } + } + } else { + ttCollection->assign(ttCol.begin(), ttCol.end()); + } + + return StatusCode::SUCCESS; +} + +// Conversion of trigger towers to bytestream + +StatusCode PpmByteStreamTool::convert( + const DataVector<LVL1::TriggerTower>* const ttCollection, + RawEventWrite* const re) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Clear the event assembler + + m_fea->clear(); + const uint16_t minorVersion = m_srcIdMap->minorVersionPreLS1(); + m_fea->setRodMinorVersion(minorVersion); + m_rodStatusMap.clear(); + + // Pointer to ROD data vector + + FullEventAssembler<L1CaloSrcIdMap>::RODDATA* theROD = 0; + + // Set up trigger tower maps + + setupTTMaps(ttCollection); + + // Create the sub-blocks to do the packing + + PpmSubBlock subBlock; + const int chanPerSubBlock = subBlock.channelsPerSubBlock(m_version, + m_dataFormat); + if (chanPerSubBlock == 0) { + msg(MSG::ERROR) << "Unsupported version/data format: " + << m_version << "/" << m_dataFormat << endreq; + return StatusCode::FAILURE; + } + PpmSubBlock errorBlock; + + int slicesLut = 1; + int slicesFadc = 1; + int trigLut = 0; + int trigFadc = 0; + int slicesLutNew = 1; + int slicesFadcNew = 1; + int trigLutNew = 0; + int trigFadcNew = 0; + const int modulesPerSlink = s_modules / m_slinks; + for (int crate = m_crateMin; crate <= m_crateMax; ++crate) { + for (int module=0; module < s_modules; ++module) { + + // Pack required number of modules per slink + + if (module%modulesPerSlink == 0) { + const int daqOrRoi = 0; + const int slink = module/modulesPerSlink; + if (debug) { + msg() << "Treating crate " << crate << " slink " << slink << endreq; + } + // Get number of slices and triggered slice offsets + // for this slink + if ( ! slinkSlices(crate, module, modulesPerSlink, + slicesLut, slicesFadc, trigLut, trigFadc)) { + msg(MSG::ERROR) << "Inconsistent number of slices or " + << "triggered slice offsets in data for crate " + << crate << " slink " << slink << endreq; + return StatusCode::FAILURE; + } + slicesLutNew = (m_forceSlicesLut) ? m_forceSlicesLut : slicesLut; + slicesFadcNew = (m_forceSlicesFadc) ? m_forceSlicesFadc : slicesFadc; + trigLutNew = ModifySlices::peak(trigLut, slicesLut, slicesLutNew); + trigFadcNew = ModifySlices::peak(trigFadc, slicesFadc, slicesFadcNew); + if (debug) { + msg() << "Data Version/Format: " << m_version + << " " << m_dataFormat << endreq + << "LUT slices/offset: " << slicesLut << " " << trigLut; + if (slicesLut != slicesLutNew) { + msg() << " modified to " << slicesLutNew << " " << trigLutNew; + } + msg() << endreq + << "FADC slices/offset: " << slicesFadc << " " << trigFadc; + if (slicesFadc != slicesFadcNew) { + msg() << " modified to " << slicesFadcNew << " " << trigFadcNew; + } + msg() << endreq; + } + L1CaloUserHeader userHeader; + userHeader.setPpmLut(trigLutNew); + userHeader.setPpmFadc(trigFadcNew); + userHeader.setLowerBound(m_fadcBaseline); + const uint32_t rodIdPpm = m_srcIdMap->getRodID(crate, slink, daqOrRoi, + m_subDetector); + theROD = m_fea->getRodData(rodIdPpm); + theROD->push_back(userHeader.header()); + m_rodStatusMap.insert(make_pair(rodIdPpm, m_rodStatus)); + } + if (debug) msg() << "Module " << module << endreq; + + // Find trigger towers corresponding to each eta/phi pair and fill + // sub-blocks + + bool upstreamError = false; + for (int channel=0; channel < s_channels; ++channel) { + const int chan = channel % chanPerSubBlock; + if (channel == 0 && m_dataFormat == L1CaloSubBlock::UNCOMPRESSED) { + errorBlock.clear(); + errorBlock.setPpmErrorHeader(m_version, m_dataFormat, crate, + module, slicesFadcNew, slicesLutNew); + } + if (chan == 0) { + subBlock.clear(); + if (m_dataFormat >= L1CaloSubBlock::COMPRESSED) { + subBlock.setPpmHeader(m_version, m_dataFormat, m_compVers, crate, + module, slicesFadcNew, slicesLutNew); + } else { + subBlock.setPpmHeader(m_version, m_dataFormat, channel, crate, + module, slicesFadcNew, slicesLutNew); + } + subBlock.setLutOffset(trigLutNew); + subBlock.setFadcOffset(trigFadcNew); + subBlock.setFadcBaseline(m_fadcBaseline); + subBlock.setFadcThreshold(m_fadcThreshold); + } + const LVL1::TriggerTower* tt = 0; + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_ppmMaps->mapping(crate, module, channel, eta, phi, layer)) { + tt = findLayerTriggerTower(eta, phi, layer); + } + if (tt ) { + int err = 0; + std::vector<int> lut; + std::vector<int> fadc; + std::vector<int> bcidLut; + std::vector<int> bcidFadc; + if (layer == 0) { // em + ModifySlices::data(tt->emLUT(), lut, slicesLutNew); + ModifySlices::data(tt->emADC(), fadc, slicesFadcNew); + ModifySlices::data(tt->emBCIDvec(), bcidLut, slicesLutNew); + ModifySlices::data(tt->emBCIDext(), bcidFadc, slicesFadcNew); + err = tt->emError(); + } else { // had + ModifySlices::data(tt->hadLUT(), lut, slicesLutNew); + ModifySlices::data(tt->hadADC(), fadc, slicesFadcNew); + ModifySlices::data(tt->hadBCIDvec(), bcidLut, slicesLutNew); + ModifySlices::data(tt->hadBCIDext(), bcidFadc, slicesFadcNew); + err = tt->hadError(); + } + subBlock.fillPpmData(channel, lut, fadc, bcidLut, bcidFadc); + if (err) { + const LVL1::DataError errorBits(err); + const int errpp = errorBits.get(LVL1::DataError::PPMErrorWord); + if (m_dataFormat == L1CaloSubBlock::UNCOMPRESSED) { + errorBlock.fillPpmError(channel, errpp); + } else subBlock.fillPpmError(channel, errpp); + if (errpp >> 2) upstreamError = true; + } + } + if (chan == chanPerSubBlock - 1) { + // output the packed sub-block + if ( !subBlock.pack()) { + msg(MSG::ERROR) << "PPM sub-block packing failed" << endreq; + return StatusCode::FAILURE; + } + if (m_printCompStats) addCompStats(subBlock.compStats()); + if (channel != s_channels - 1) { + // Only put errors in last sub-block + subBlock.setStatus(0, false, false, false, false, + false, false, false); + if (debug) { + msg() << "PPM sub-block data words: " + << subBlock.dataWords() << endreq; + } + subBlock.write(theROD); + } else { + // Last sub-block - write error block + bool glinkTimeout = false; + bool daqOverflow = false; + bool bcnMismatch = false; + bool glinkParity = false; + if (m_dataFormat == L1CaloSubBlock::UNCOMPRESSED) { + glinkTimeout = errorBlock.mcmAbsent() || + errorBlock.timeout(); + daqOverflow = errorBlock.asicFull() || + errorBlock.fpgaCorrupt(); + bcnMismatch = errorBlock.eventMismatch() || + errorBlock.bunchMismatch(); + glinkParity = errorBlock.glinkPinParity(); + } else { + glinkTimeout = subBlock.mcmAbsent() || + subBlock.timeout(); + daqOverflow = subBlock.asicFull() || + subBlock.fpgaCorrupt(); + bcnMismatch = subBlock.eventMismatch() || + subBlock.bunchMismatch(); + glinkParity = subBlock.glinkPinParity(); + } + subBlock.setStatus(0, glinkTimeout, false, upstreamError, + daqOverflow, bcnMismatch, false, glinkParity); + if (debug) { + msg() << "PPM sub-block data words: " + << subBlock.dataWords() << endreq; + } + subBlock.write(theROD); + // Only uncompressed format has a separate error block + if (m_dataFormat == L1CaloSubBlock::UNCOMPRESSED) { + if ( ! errorBlock.pack()) { + msg(MSG::ERROR) << "PPM error block packing failed" << endreq; + return StatusCode::FAILURE; + } + errorBlock.setStatus(0, glinkTimeout, false, upstreamError, + daqOverflow, bcnMismatch, false, glinkParity); + errorBlock.write(theROD); + if (debug) { + msg() << "PPM error block data words: " + << errorBlock.dataWords() << endreq; + } + } + } + } + } + } + } + + // Fill the raw event + + m_fea->fill(re, msg()); + + // Set ROD status words + + //L1CaloRodStatus::setStatus(re, m_rodStatusMap, m_srcIdMap); + + return StatusCode::SUCCESS; +} + +// Add compression stats to totals + +void PpmByteStreamTool::addCompStats(const std::vector<uint32_t>& stats) +{ + if (stats.empty()) return; + const int n = stats.size(); + if (m_compStats.empty()) m_compStats.resize(n); + for (int i = 0; i < n; ++i) m_compStats[i] += stats[i]; +} + +// Print compression stats + +void PpmByteStreamTool::printCompStats() const +{ + msg() << "Compression stats format/count: "; + const int n = m_compStats.size(); + for (int i = 0; i < n; ++i) { + msg() << " " << i << "/" << m_compStats[i]; + } + msg() << endreq; +} + +// Find a trigger tower using separate layer maps + +const LVL1::TriggerTower* PpmByteStreamTool::findLayerTriggerTower( + const double eta, const double phi, const int layer) +{ + const LVL1::TriggerTower* tt = 0; + const unsigned int key = m_towerKey->ttKey(phi, eta); + TriggerTowerMapConst::const_iterator mapIter; + if (layer == 0) { + mapIter = m_ttEmMap.find(key); + if (mapIter != m_ttEmMap.end()) tt = mapIter->second; + } else { + mapIter = m_ttHadMap.find(key); + if (mapIter != m_ttHadMap.end()) tt = mapIter->second; + } + return tt; +} + +// Set up trigger tower maps + +void PpmByteStreamTool::setupTTMaps(const TriggerTowerCollection* + const ttCollection) +{ + using std::accumulate; + + m_ttEmMap.clear(); + m_ttHadMap.clear(); + TriggerTowerCollection::const_iterator pos = ttCollection->begin(); + TriggerTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::TriggerTower* tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + // Ignore any with zero data + // EM + if (accumulate((tt->emLUT()).begin(), (tt->emLUT()).end(), 0) || + accumulate((tt->emADC()).begin(), (tt->emADC()).end(), 0) || + accumulate((tt->emBCIDvec()).begin(), (tt->emBCIDvec()).end(), 0) || + accumulate((tt->emBCIDext()).begin(), (tt->emBCIDext()).end(), 0) || + tt->emError()) { + m_ttEmMap.insert(std::make_pair(key, tt)); + } + // Had + if (accumulate((tt->hadLUT()).begin(), (tt->hadLUT()).end(), 0) || + accumulate((tt->hadADC()).begin(), (tt->hadADC()).end(), 0) || + accumulate((tt->hadBCIDvec()).begin(), (tt->hadBCIDvec()).end(), 0) || + accumulate((tt->hadBCIDext()).begin(), (tt->hadBCIDext()).end(), 0) || + tt->hadError()) { + m_ttHadMap.insert(std::make_pair(key, tt)); + } + } +} + +// Get number of slices and triggered slice offsets for next slink + +bool PpmByteStreamTool::slinkSlices(const int crate, const int module, + const int modulesPerSlink, int& slicesLut, int& slicesFadc, + int& trigLut, int& trigFadc) +{ + int sliceL = -1; + int sliceF = m_dfltSlicesFadc; + int trigL = m_dfltSlicesLut/2; + int trigF = m_dfltSlicesFadc/2; + for (int mod = module; mod < module + modulesPerSlink; ++mod) { + for (int chan = 0; chan < s_channels; ++chan) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (!m_ppmMaps->mapping(crate, mod, chan, + eta, phi, layer)) continue; + const LVL1::TriggerTower* const tt = findLayerTriggerTower( + eta, phi, layer); + if ( !tt ) continue; + if (layer == 0) { + if (sliceL < 0) { // initialise + sliceL = (tt->emLUT()).size(); + sliceF = (tt->emADC()).size(); + trigL = tt->emPeak(); + trigF = tt->emADCPeak(); + } else { // check consistent + if ((tt->emLUT()).size() != size_t(sliceL) || + (tt->emADC()).size() != size_t(sliceF) || + tt->emPeak() != trigL || tt->emADCPeak() != trigF) { + return false; + } + } + } else { + if (sliceL < 0) { + sliceL = (tt->hadLUT()).size(); + sliceF = (tt->hadADC()).size(); + trigL = tt->hadPeak(); + trigF = tt->hadADCPeak(); + } else { + if ((tt->hadLUT()).size() != size_t(sliceL) || + (tt->hadADC()).size() != size_t(sliceF) || + tt->hadPeak() != trigL || tt->hadADCPeak() != trigF) { + return false; + } + } + } + } + } + if (sliceL < 0) sliceL = m_dfltSlicesLut; + slicesLut = sliceL; + slicesFadc = sliceF; + trigLut = trigL; + trigFadc = trigF; + return true; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& PpmByteStreamTool::sourceIDs( + const std::string& sgKey) +{ + // Check if spare channels wanted + const std::string flag("Spare"); + const std::string::size_type pos = sgKey.find(flag); + m_spareChannels = + (pos != std::string::npos && pos == (sgKey.length() - flag.length())); + // Check if Tile Muon channels wanted + const std::string flag2("Muon"); + const std::string::size_type pos2 = sgKey.find(flag2); + m_muonChannels = + (pos2 != std::string::npos && pos2 == (sgKey.length() - flag2.length())); + m_dataChannels = (!m_spareChannels && !m_muonChannels); + if (m_sourceIDs.empty()) { + const int maxlinks = m_srcIdMap->maxSlinks(); + for (int crate = 0; crate < s_crates; ++crate) { + for (int slink = 0; slink < maxlinks; ++slink) { + const int daqOrRoi = 0; + const uint32_t rodId = m_srcIdMap->getRodID(crate, slink, daqOrRoi, + m_subDetector); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + m_sourceIDs.push_back(robId); + if (crate > 1 && crate < 6) { + m_sourceIDsSpare.push_back(robId); + if (crate < 4 && slink == 0) m_sourceIDsMuon.push_back(robId); + } + } + } + } + if (m_spareChannels) return m_sourceIDsSpare; + if (m_muonChannels) return m_sourceIDsMuon; + return m_sourceIDs; +} + +// Print a vector + +void PpmByteStreamTool::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamTool.h new file mode 100755 index 0000000000000000000000000000000000000000..1c34d0a2b798efb50ebc33270454711daa3f19d6 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmByteStreamTool.h @@ -0,0 +1,198 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMBYTESTREAMTOOL_H +#define TRIGT1CALOBYTESTREAM_PPMBYTESTREAMTOOL_H + +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class IInterface; +class InterfaceID; +class StatusCode; +class SegMemSvc; + +template <class T> class FullEventAssembler; + +namespace LVL1 { + class IL1CaloMappingTool; + class TriggerTower; + class TriggerTowerKey; +} + +namespace LVL1BS { + +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; +class PpmSubBlock; + +/** Tool to perform ROB fragments to trigger towers and trigger towers + * to raw data conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class PpmByteStreamTool : public AthAlgTool { + + public: + PpmByteStreamTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~PpmByteStreamTool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to trigger towers + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::TriggerTower>* ttCollection); + + /// Convert trigger towers to bytestream + StatusCode convert(const DataVector<LVL1::TriggerTower>* ttCollection, + RawEventWrite* re); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + + typedef DataVector<LVL1::TriggerTower> TriggerTowerCollection; + typedef std::vector<LVL1::TriggerTower*> TriggerTowerVector; + typedef std::map<unsigned int, int> TriggerTowerMap; + typedef std::map<unsigned int, const LVL1::TriggerTower*> + TriggerTowerMapConst; + typedef std::vector<uint32_t> ChannelBitVector; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Add compression stats to totals + void addCompStats(const std::vector<uint32_t>& stats); + /// Print compression stats + void printCompStats() const; + + /// Find a trigger tower using separate layer maps + const LVL1::TriggerTower* findLayerTriggerTower(double eta, double phi, + int layer); + /// Set up separate Em and Had trigger tower maps + void setupTTMaps(const TriggerTowerCollection* ttCollection); + + /// Get number of slices and triggered slice offsets for next slink + bool slinkSlices(int crate, int module, int modulesPerSlink, + int& slicesLut, int& slicesFadc, int& trigLut, int& trigFadc); + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + + /// Channel mapping tool + ToolHandle<LVL1::IL1CaloMappingTool> m_ppmMaps; + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + /// Memory pool service + ServiceHandle<SegMemSvc> m_sms; + + /// Sub_block header version + int m_version; + /// Data compression format + int m_dataFormat; + /// Compression version + int m_compVers; + /// Compression statistics print flag + int m_printCompStats; + /// Number of slinks per crate when writing out bytestream + int m_slinks; + /// Default number of LUT slices in simulation + int m_dfltSlicesLut; + /// Default number of FADC slices in simulation + int m_dfltSlicesFadc; + /// Force number of LUT slices in bytestream + int m_forceSlicesLut; + /// Force number of FADC slices in bytestream + int m_forceSlicesFadc; + /// Minimum crate number when writing out bytestream + int m_crateMin; + /// Maximum crate number when writing out bytestream + int m_crateMax; + /// Pedestal value + int m_pedestal; + /// FADC baseline lower bound + int m_fadcBaseline; + /// FADC threshold for super-compressed format + int m_fadcThreshold; + /// Zero suppression on input + int m_zeroSuppress; + /// Data channel flag + bool m_dataChannels; + /// Spare channel flag + bool m_spareChannels; + /// Tile Muon channel flag + bool m_muonChannels; + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + std::vector<uint32_t> m_sourceIDsSpare; + std::vector<uint32_t> m_sourceIDsMuon; + /// Sub-detector type + eformat::SubDetector m_subDetector; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// Trigger tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// Current error block + PpmSubBlock* m_errorBlock; + /// Vector for current PPM sub-blocks + DataVector<PpmSubBlock> m_ppmBlocks; + /// Vector for compression statistics + std::vector<uint32_t> m_compStats; + /// Trigger tower map for conversion from bytestream + TriggerTowerMap m_ttMap; + /// Trigger tower map for conversion EM to bytestream + TriggerTowerMapConst m_ttEmMap; + /// Trigger tower map for conversion Had to bytestream + TriggerTowerMapConst m_ttHadMap; + /// ROD Status words + std::vector<uint32_t>* m_rodStatus; + /// ROD status map + std::map<uint32_t, std::vector<uint32_t>* > m_rodStatusMap; + /// Event assembler + FullEventAssembler<L1CaloSrcIdMap>* m_fea; + /// TriggerTower pool vectors + TriggerTowerVector m_ttData; + TriggerTowerVector m_ttSpare; + TriggerTowerVector m_ttMuon; + std::vector<int> m_ttPos; + /// Mapping vectors + ChannelBitVector m_chanLayer; + ChannelBitVector m_dataChan; + ChannelBitVector m_spareChan; + ChannelBitVector m_muonChan; + ChannelBitVector m_dataMod; + ChannelBitVector m_spareMod; + ChannelBitVector m_muonMod; + ChannelBitVector m_foundChan; + + static const int s_crates = 8; + static const int s_modules = 16; + static const int s_channels = 64; + static const int s_dataSize = 3584; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmCompression.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmCompression.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1c1bb8f4bd2842815a33ffd3621e0e9a136ef923 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmCompression.cxx @@ -0,0 +1,659 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <stdint.h> +#include <algorithm> +#include <vector> + +#include "L1CaloSubBlock.h" +#include "PpmCompression.h" +#include "PpmSubBlock.h" + +namespace LVL1BS { + +// Static constants + +const int PpmCompression::s_formatsV0; +const int PpmCompression::s_lowerRange; +const int PpmCompression::s_upperRange; +const int PpmCompression::s_formats; +const int PpmCompression::s_fadcRange; +const int PpmCompression::s_peakOnly; +const int PpmCompression::s_lutDataBits; +const int PpmCompression::s_lutBcidBits; +const int PpmCompression::s_fadcDataBits; +const int PpmCompression::s_glinkPins; +const int PpmCompression::s_statusBits; +const int PpmCompression::s_errorBits; +const int PpmCompression::s_statusMask; + +// Pack data + +bool PpmCompression::pack(PpmSubBlock& subBlock) +{ + const int dataFormat = subBlock.format(); + if (dataFormat != L1CaloSubBlock::COMPRESSED && + dataFormat != L1CaloSubBlock::SUPERCOMPRESSED) return false; + const int sliceL = subBlock.slicesLut(); + const int sliceF = subBlock.slicesFadc(); + if (sliceL != 1 || sliceF != 5) return false; + const int trigOffset = subBlock.fadcOffset() - subBlock.lutOffset(); + const int fadcBaseline = subBlock.fadcBaseline(); + const int fadcThreshold = subBlock.fadcThreshold(); + const int channels = subBlock.channelsPerSubBlock(); + subBlock.setStreamed(); + std::vector<uint32_t> compStats(s_formats); + std::vector<int> fadcDout(sliceF-1); + std::vector<int> fadcLens(sliceF-1); + for (int chan = 0; chan < channels; ++chan) { + std::vector<int> lutData; + std::vector<int> lutBcid; + std::vector<int> fadcData; + std::vector<int> fadcBcid; + subBlock.ppmData(chan, lutData, fadcData, lutBcid, fadcBcid); + if (dataFormat == L1CaloSubBlock::SUPERCOMPRESSED) { + int dataPresent = lutData[0] || lutBcid[0]; + if ( !dataPresent ) { + for (int sl = 0; sl < sliceF; ++sl) { + if (fadcData[sl] >= fadcThreshold || fadcBcid[sl]) { + dataPresent = 1; + break; + } + } + } + subBlock.packer(dataPresent, 1); + if ( !dataPresent ) continue; + } + const int lutLen = subBlock.minBits(lutData[0]); + int minFadc = 0; + int minOffset = 0; + bool fadcSame = true; + for (int sl = 0; sl < sliceF; ++sl) { + if (sl == 0) minFadc = fadcData[sl]; + if (fadcData[sl] < minFadc) { + minFadc = fadcData[sl]; + minOffset = sl; + } + if (fadcData[sl] != fadcData[0] || fadcBcid[sl] != 0) fadcSame = false; + } + if (minOffset) std::swap(fadcData[0], fadcData[minOffset]); + + int format = 0; + if (lutData[0] == 0 && lutBcid[0] == 0 && fadcSame) { // format 6 + const int header = 15; + subBlock.packer(header, 4); + if (fadcData[0]) { + subBlock.packer(1, 1); + subBlock.packer(fadcData[0], s_fadcDataBits); + } else subBlock.packer(0, 1); + format = 6; + } else { + const bool minFadcInRange = minFadc >= fadcBaseline && + minFadc <= fadcBaseline + s_fadcRange; + int anyFadcBcid = 0; + int maxFadcLen = 0; + int idx = 0; + for (int sl = 0; sl < sliceF; ++sl) { + if (sl != 0) { + fadcDout[idx] = fadcData[sl] - minFadc; + fadcLens[idx] = subBlock.minBits(fadcDout[idx]); + if (idx == 0 || fadcLens[idx] > maxFadcLen) { + maxFadcLen = fadcLens[idx]; + } + ++idx; + } + if (sl != trigOffset) anyFadcBcid |= fadcBcid[sl]; + else if (fadcBcid[sl] != (lutBcid[0] & 0x1)) anyFadcBcid |= 1; + } + if (lutData[0] == 0 && lutBcid[0] == 0 && + !anyFadcBcid && minFadcInRange && maxFadcLen < 4) { + // formats 0,1 + int header = minOffset; + if (maxFadcLen == 3) header += 5; + subBlock.packer(header, 4); + minFadc -= fadcBaseline; + subBlock.packer(minFadc, 4); + if (maxFadcLen < 2) maxFadcLen = 2; + for (int idx = 0; idx < sliceF-1; ++idx) { + subBlock.packer(fadcDout[idx], maxFadcLen); + } + format = maxFadcLen - 2; + } else if (lutLen <= 3 && ((lutData[0] == 0 && lutBcid[0] == 0) || + (lutData[0] > 0 && lutBcid[0] == s_peakOnly)) + && !anyFadcBcid && minFadcInRange && maxFadcLen <= 4) { + // format 2 + const int header = minOffset + 10; + subBlock.packer(header, 4); + format = 2; + subBlock.packer(format - 2, 2); + if (lutData[0]) { + subBlock.packer(1, 1); + subBlock.packer(lutData[0], 3); + } else subBlock.packer(0, 1); + minFadc -= fadcBaseline; + subBlock.packer(minFadc, 4); + for (int idx = 0; idx < sliceF-1; ++idx) { + subBlock.packer(fadcDout[idx], 4); + } + } else { + // formats 3,4,5 + const int header = minOffset + 10; + subBlock.packer(header, 4); + if ( !minFadcInRange) { + const int minFadcLen = subBlock.minBits(minFadc); + if (minFadcLen > maxFadcLen) maxFadcLen = minFadcLen; + } + format = 5; + if (maxFadcLen <= 8) format = 4; + if (maxFadcLen <= 6) format = 3; + subBlock.packer(format - 2, 2); + if (lutData[0] || lutBcid[0]) subBlock.packer(1, 1); + else subBlock.packer(0, 1); + subBlock.packer(anyFadcBcid, 1); + if (lutData[0] || lutBcid[0]) { + subBlock.packer(lutData[0], s_lutDataBits); + subBlock.packer(lutBcid[0], s_lutBcidBits); + } + if (anyFadcBcid) { + for (int idx = 0; idx < sliceF; ++idx) { + subBlock.packer(fadcBcid[idx], 1); + } + } + if (minFadcInRange) { + subBlock.packer(0, 1); + minFadc -= fadcBaseline; + subBlock.packer(minFadc, 4); + } else { + subBlock.packer(1, 1); + subBlock.packer(minFadc, format * 2); + } + for (int idx = 0; idx < sliceF-1; ++idx) { + if (fadcLens[idx] <= 4) { + subBlock.packer(0, 1); + subBlock.packer(fadcDout[idx], 4); + } else { + subBlock.packer(1, 1); + subBlock.packer(fadcDout[idx], format * 2); + } + } + } + } + ++compStats[format]; + } + // Errors + std::vector<int> status(s_glinkPins); + std::vector<int> error(s_glinkPins); + int statusBit = 0; + int errorBit = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + const int errorWord = subBlock.ppmPinError(pin); + status[pin] = errorWord & s_statusMask; + error[pin] = errorWord >> s_statusBits; + if (status[pin]) statusBit = 1; + if (error[pin]) errorBit = 1; + } + subBlock.packer(statusBit, 1); + subBlock.packer(errorBit, 1); + if (statusBit || errorBit) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (status[pin] || error[pin]) subBlock.packer(1, 1); + else subBlock.packer(0, 1); + } + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (status[pin] || error[pin]) { + if (statusBit) subBlock.packer(status[pin], s_statusBits); + if (errorBit) subBlock.packer(error[pin], s_errorBits); + } + } + } + subBlock.packerFlush(); + subBlock.setCompStats(compStats); + return true; +} + +// Unpack data + +bool PpmCompression::unpack(PpmSubBlock& subBlock) +{ + bool rc = false; + switch (subBlock.seqno()) { + case 0: + rc = unpackV100(subBlock); + break; + case 1: + rc = unpackV101(subBlock); + break; + case 2: + case 3: + case 4: + case 5: // runs 88701-24 only + rc = unpackV104(subBlock); + break; + default: + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_COMPRESSION_VERSION); + break; + } + return rc; +} + +// Unpack data - version 1.00 + +bool PpmCompression::unpackV100(PpmSubBlock& subBlock) +{ + if (subBlock.format() != L1CaloSubBlock::COMPRESSED) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_FORMAT); + return false; + } + const int sliceL = subBlock.slicesLut(); + const int sliceF = subBlock.slicesFadc(); + if (sliceL != 1 || sliceF != 5) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_COMPRESSION_SLICES); + return false; + } + const int trigOffset = subBlock.fadcOffset(); + const int pedestal = subBlock.pedestal(); + const int channels = subBlock.channelsPerSubBlock(); + subBlock.setStreamed(); + subBlock.unpackerInit(); + std::vector<uint32_t> compStats(s_formatsV0); + std::vector<int> lutData; + std::vector<int> lutBcid; + std::vector<int> fadcData; + std::vector<int> fadcBcid; + for (int chan = 0; chan < channels; ++chan) { + lutData.clear(); + lutBcid.clear(); + fadcData.clear(); + fadcBcid.clear(); + int format = 0; + const int header = subBlock.unpacker(4); + if (header < 10) { + // formats 0,1 - LUT zero, FADC around pedestal + const int minOffset = header % 5; + format = header / 5; + // LUT = 0 + lutData.push_back(0); + lutBcid.push_back(0); + // FADC + const uint32_t minFadc = subBlock.unpacker(4) + pedestal - s_lowerRange; + for (int sl = 0; sl < sliceF; ++sl) { + if (sl == minOffset) fadcData.push_back(minFadc); + else fadcData.push_back(subBlock.unpacker(format + 2) + minFadc); + fadcBcid.push_back(0); + } + } else { + // formats 2-5 + const int minOffset = header - 10; + format = subBlock.unpacker(2) + 2; + const int anyLut = subBlock.unpacker(1); + int lut = 0; + int bcid = 0; + if (format == 2) { + // LUT + if (anyLut) { + lut = subBlock.unpacker(3); + bcid = s_peakOnly; // just peak-finding BCID set + } + lutData.push_back(lut); + lutBcid.push_back(bcid); + // FADC as formats 0,1 + const int minFadc = subBlock.unpacker(4) + pedestal - s_lowerRange; + for (int sl = 0; sl < sliceF; ++sl) { + if (sl == minOffset) fadcData.push_back(minFadc); + else fadcData.push_back(subBlock.unpacker(format + 2) + minFadc); + fadcBcid.push_back(0); + } + } else { + // formats 3,4,5 - full LUT word, variable FADC + const int anyBcid = subBlock.unpacker(1); + // LUT + if (anyLut) { + lut = subBlock.unpacker(s_lutDataBits); + bcid = subBlock.unpacker(s_lutBcidBits); + } + lutData.push_back(lut); + lutBcid.push_back(bcid); + // FADC + for (int sl = 0; sl < sliceF; ++sl) { + int fbcid = 0; + if (sl == trigOffset) fbcid = bcid & 0x1; // take from LUT word + else if (anyBcid) fbcid = subBlock.unpacker(1); + fadcBcid.push_back(fbcid); + } + int minFadc = 0; + if (subBlock.unpacker(1)) minFadc = subBlock.unpacker(format * 2); + else minFadc = subBlock.unpacker(4) + pedestal - s_lowerRange; + for (int sl = 0; sl < sliceF; ++sl) { + int fadc = minFadc; + if (sl != minOffset) { + if (subBlock.unpacker(1)) fadc += subBlock.unpacker(format * 2); + else fadc += subBlock.unpacker(4); + } + fadcData.push_back(fadc); + } + } + } + subBlock.fillPpmData(chan, lutData, fadcData, lutBcid, fadcBcid); + ++compStats[format]; + } + subBlock.setCompStats(compStats); + const bool rc = subBlock.unpackerSuccess(); + if (!rc) subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack data - version 1.01 + +bool PpmCompression::unpackV101(PpmSubBlock& subBlock) +{ + if (subBlock.format() != L1CaloSubBlock::COMPRESSED) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_FORMAT); + return false; + } + const int sliceL = subBlock.slicesLut(); + const int sliceF = subBlock.slicesFadc(); + if (sliceL != 1 || sliceF != 5) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_COMPRESSION_SLICES); + return false; + } + const int trigOffset = subBlock.fadcOffset(); + const int pedestal = subBlock.pedestal(); + const int channels = subBlock.channelsPerSubBlock(); + subBlock.setStreamed(); + subBlock.unpackerInit(); + std::vector<uint32_t> compStats(s_formats); + std::vector<int> lutData; + std::vector<int> lutBcid; + std::vector<int> fadcData; + std::vector<int> fadcBcid; + for (int chan = 0; chan < channels; ++chan) { + lutData.clear(); + lutBcid.clear(); + fadcData.clear(); + fadcBcid.clear(); + int format = 0; + const int header = subBlock.unpacker(4); + if (header < 10) { + // formats 0,1 - LUT zero, FADC around pedestal + const int minOffset = header % 5; + format = header / 5; + // LUT = 0 + lutData.push_back(0); + lutBcid.push_back(0); + // FADC + const int minFadc = subBlock.unpacker(4) + pedestal - s_lowerRange; + fadcData.push_back(minFadc); + fadcBcid.push_back(0); + for (int sl = 1; sl < sliceF; ++sl) { + fadcData.push_back(subBlock.unpacker(format + 2) + minFadc); + fadcBcid.push_back(0); + } + if (minOffset) std::swap(fadcData[0], fadcData[minOffset]); + } else if (header < 15) { + // formats 2-5 + const int minOffset = header - 10; + format = subBlock.unpacker(2) + 2; + const int anyLut = subBlock.unpacker(1); + int lut = 0; + int bcid = 0; + if (format == 2) { + // LUT + if (anyLut) { + lut = subBlock.unpacker(3); + bcid = s_peakOnly; // just peak-finding BCID set + } + lutData.push_back(lut); + lutBcid.push_back(bcid); + // FADC as formats 0,1 + const int minFadc = subBlock.unpacker(4) + pedestal - s_lowerRange; + fadcData.push_back(minFadc); + fadcBcid.push_back(0); + for (int sl = 1; sl < sliceF; ++sl) { + fadcData.push_back(subBlock.unpacker(format + 2) + minFadc); + fadcBcid.push_back(0); + } + if (minOffset) std::swap(fadcData[0], fadcData[minOffset]); + } else { + // formats 3,4,5 - full LUT word, variable FADC + const int anyBcid = subBlock.unpacker(1); + // LUT + if (anyLut) { + lut = subBlock.unpacker(s_lutDataBits); + bcid = subBlock.unpacker(s_lutBcidBits); + } + lutData.push_back(lut); + lutBcid.push_back(bcid); + // FADC + for (int sl = 0; sl < sliceF; ++sl) { + int fbcid = 0; + if (sl == trigOffset) fbcid = bcid & 0x1; // take from LUT word + else if (anyBcid) fbcid = subBlock.unpacker(1); + fadcBcid.push_back(fbcid); + } + int minFadc = 0; + if (subBlock.unpacker(1)) minFadc = subBlock.unpacker(format * 2); + else minFadc = subBlock.unpacker(4) + pedestal - s_lowerRange; + fadcData.push_back(minFadc); + for (int sl = 1; sl < sliceF; ++sl) { + int len = 4; + if (subBlock.unpacker(1)) len = format * 2; + fadcData.push_back(subBlock.unpacker(len) + minFadc); + } + if (minOffset) std::swap(fadcData[0], fadcData[minOffset]); + } + } else { + // format 6 - LUT zero, FADC all equal + format = 6; + // LUT + lutData.push_back(0); + lutBcid.push_back(0); + // FADC + int fadc = 0; + if (subBlock.unpacker(1)) fadc = subBlock.unpacker(s_fadcDataBits); + for (int sl = 0; sl < sliceF; ++sl) { + fadcData.push_back(fadc); + fadcBcid.push_back(0); + } + } + subBlock.fillPpmData(chan, lutData, fadcData, lutBcid, fadcBcid); + ++compStats[format]; + } + // Errors + const int statusBit = subBlock.unpacker(1); + const int errorBit = subBlock.unpacker(1); + if (statusBit || errorBit) { + std::vector<int> err(s_glinkPins); + for (int pin = 0; pin < s_glinkPins; ++pin) { + err[pin] = subBlock.unpacker(1); + } + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (err[pin]) { + int status = 0; + int error = 0; + if (statusBit) status = subBlock.unpacker(s_statusBits-1); + if (errorBit) error = subBlock.unpacker(s_errorBits+1); + subBlock.fillPpmPinError(pin, (error << (s_statusBits-1)) | status); + } + } + } + subBlock.setCompStats(compStats); + const bool rc = subBlock.unpackerSuccess(); + if (!rc) subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_DATA_TRUNCATED); + return rc; +} + +// Unpack data - versions 1.02, 1.03, 1.04, 1.05 (by mistake for a few runs) + +bool PpmCompression::unpackV104(PpmSubBlock& subBlock) +{ + const int dataFormat = subBlock.format(); + if (dataFormat != L1CaloSubBlock::COMPRESSED && + dataFormat != L1CaloSubBlock::SUPERCOMPRESSED) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_FORMAT); + return false; + } + const int compressionVersion = subBlock.seqno(); + if (compressionVersion == 2 && dataFormat != L1CaloSubBlock::COMPRESSED) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_FORMAT); + return false; + } + if (compressionVersion == 5) { + const int run = subBlock.runNumber(); + if (run < 88701 || run > 88724) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_COMPRESSION_VERSION); + return false; + } + } + const int sliceL = subBlock.slicesLut(); + const int sliceF = subBlock.slicesFadc(); + if (sliceL != 1 || sliceF != 5) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_COMPRESSION_SLICES); + return false; + } + const int trigOffset = subBlock.fadcOffset() - subBlock.lutOffset(); + const int fadcBaseline = subBlock.fadcBaseline(); + const int channels = subBlock.channelsPerSubBlock(); + subBlock.setStreamed(); + subBlock.unpackerInit(); + std::vector<uint32_t> compStats(s_formats); + std::vector<int> lutData; + std::vector<int> lutBcid; + std::vector<int> fadcData; + std::vector<int> fadcBcid; + for (int chan = 0; chan < channels; ++chan) { + if (dataFormat == L1CaloSubBlock::SUPERCOMPRESSED) { + if ( !subBlock.unpacker(1) ) continue; + } + lutData.clear(); + lutBcid.clear(); + fadcData.clear(); + fadcBcid.clear(); + int format = 0; + const int header = subBlock.unpacker(4); + if (header < 10) { + // formats 0,1 - LUT zero, FADC around pedestal + const int minOffset = header % 5; + format = header / 5; + // LUT = 0 + lutData.push_back(0); + lutBcid.push_back(0); + // FADC + const int minFadc = subBlock.unpacker(4) + fadcBaseline; + fadcData.push_back(minFadc); + fadcBcid.push_back(0); + for (int sl = 1; sl < sliceF; ++sl) { + fadcData.push_back(subBlock.unpacker(format + 2) + minFadc); + fadcBcid.push_back(0); + } + if (minOffset) std::swap(fadcData[0], fadcData[minOffset]); + } else if (header < 15) { + // formats 2-5 + const int minOffset = header - 10; + format = subBlock.unpacker(2) + 2; + const int anyLut = subBlock.unpacker(1); + int lut = 0; + int bcid = 0; + if (format == 2) { + // LUT + if (anyLut) { + lut = subBlock.unpacker(3); + bcid = s_peakOnly; // just peak-finding BCID set + } + lutData.push_back(lut); + lutBcid.push_back(bcid); + // FADC as formats 0,1 + const int minFadc = subBlock.unpacker(4) + fadcBaseline; + fadcData.push_back(minFadc); + fadcBcid.push_back(0); + for (int sl = 1; sl < sliceF; ++sl) { + fadcData.push_back(subBlock.unpacker(format + 2) + minFadc); + fadcBcid.push_back(0); + } + if (minOffset) std::swap(fadcData[0], fadcData[minOffset]); + } else { + // formats 3,4,5 - full LUT word, variable FADC + const int anyBcid = subBlock.unpacker(1); + // LUT + if (anyLut) { + lut = subBlock.unpacker(s_lutDataBits); + bcid = subBlock.unpacker(s_lutBcidBits); + } + lutData.push_back(lut); + lutBcid.push_back(bcid); + // FADC + for (int sl = 0; sl < sliceF; ++sl) { + int fbcid = 0; + if (anyBcid) fbcid = subBlock.unpacker(1); + else if (sl == trigOffset) fbcid = bcid & 0x1; // take from LUT word + fadcBcid.push_back(fbcid); + } + int minFadc = 0; + if (subBlock.unpacker(1)) minFadc = subBlock.unpacker(format * 2); + else minFadc = subBlock.unpacker(4) + fadcBaseline; + fadcData.push_back(minFadc); + for (int sl = 1; sl < sliceF; ++sl) { + int len = 4; + if (subBlock.unpacker(1)) len = format * 2; + fadcData.push_back(subBlock.unpacker(len) + minFadc); + } + if (minOffset) std::swap(fadcData[0], fadcData[minOffset]); + } + } else { + // format 6 - LUT zero, FADC all equal + format = 6; + // LUT + lutData.push_back(0); + lutBcid.push_back(0); + // FADC + int fadc = 0; + if (subBlock.unpacker(1)) fadc = subBlock.unpacker(s_fadcDataBits); + for (int sl = 0; sl < sliceF; ++sl) { + fadcData.push_back(fadc); + fadcBcid.push_back(0); + } + } + subBlock.fillPpmData(chan, lutData, fadcData, lutBcid, fadcBcid); + ++compStats[format]; + } + // Errors + const int statusBit = subBlock.unpacker(1); + const int errorBit = subBlock.unpacker(1); + const bool mcmAbsentIsError = compressionVersion < 4; + const int sBits = (mcmAbsentIsError) ? s_statusBits - 1 : s_statusBits; + const int eBits = (mcmAbsentIsError) ? s_errorBits + 1 : s_errorBits; + if (statusBit || errorBit) { + std::vector<int> err(s_glinkPins); + for (int pin = 0; pin < s_glinkPins; ++pin) { + err[pin] = subBlock.unpacker(1); + } + for (int pin = 0; pin < s_glinkPins; ++pin) { + if (err[pin]) { + int status = 0; + int error = 0; + if (statusBit) status = subBlock.unpacker(sBits); + if (errorBit) error = subBlock.unpacker(eBits); + subBlock.fillPpmPinError(pin, (error << sBits) | status); + } + } + // There is a bug in versions < 4 but if I've understood it correctly + // it is not possible to detect it reliably in data. + } + subBlock.setCompStats(compStats); + bool rc = subBlock.unpackerSuccess(); + if (!rc) subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_DATA_TRUNCATED); + else { + // Check no more non-zero data - indicates corruption + while (subBlock.unpackerSuccess()) { + if (subBlock.unpacker(31)) { + subBlock.setUnpackErrorCode(L1CaloSubBlock::UNPACK_EXCESS_DATA); + rc = false; + break; + } + } + } + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmCompression.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmCompression.h new file mode 100644 index 0000000000000000000000000000000000000000..e4c858a8d2f4856c144a49a4061cf4e7c8650ec3 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmCompression.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMCOMPRESSION_H +#define TRIGT1CALOBYTESTREAM_PPMCOMPRESSION_H + +namespace LVL1BS { + +class PpmSubBlock; + +/** PPM Compressed Format Version 1.04 packing and unpacking utilities. + * + * Based on: + * + * "ATLAS L1Calo Pre-processor compressed S-Link data formats", + * Version 1.7, D.P.C.Sankey. + * + * @author Peter Faulkner + */ + +class PpmCompression { + + public: + PpmCompression(); + ~PpmCompression(); + + /// Pack data + static bool pack(PpmSubBlock& subBlock); + /// Unpack data + static bool unpack(PpmSubBlock& subBlock); + + private: + static const int s_formatsV0 = 6; + static const int s_lowerRange = 12; + static const int s_upperRange = 3; + static const int s_formats = 7; + static const int s_fadcRange = 15; + static const int s_peakOnly = 4; + static const int s_lutDataBits = 8; + static const int s_lutBcidBits = 3; + static const int s_fadcDataBits = 10; + static const int s_glinkPins = 16; + static const int s_statusBits = 5; + static const int s_errorBits = 6; + static const int s_statusMask = 0x1f; + + static bool unpackV100(PpmSubBlock& subBlock); + static bool unpackV101(PpmSubBlock& subBlock); + static bool unpackV104(PpmSubBlock& subBlock); + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmSubBlock.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmSubBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..c3dc35fa2bd9e3801f2b25456e299933877d79b3 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmSubBlock.cxx @@ -0,0 +1,493 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "PpmCompression.h" +#include "PpmSubBlock.h" + +namespace LVL1BS { + +// Constant definitions + +const uint32_t PpmSubBlock::s_wordIdVal; +const int PpmSubBlock::s_errorMarker; + +const int PpmSubBlock::s_wordLen; +const int PpmSubBlock::s_lutBit; +const int PpmSubBlock::s_bcidLutBit; +const int PpmSubBlock::s_fadcBit; +const int PpmSubBlock::s_bcidFadcBit; +const uint32_t PpmSubBlock::s_lutMask; +const uint32_t PpmSubBlock::s_bcidLutMask; +const uint32_t PpmSubBlock::s_fadcMask; +const uint32_t PpmSubBlock::s_bcidFadcMask; + +const int PpmSubBlock::s_channels; +const int PpmSubBlock::s_glinkPins; +const int PpmSubBlock::s_asicChannels; +const int PpmSubBlock::s_dataBits; +const int PpmSubBlock::s_errorBits; +const int PpmSubBlock::s_bunchCrossingBits; + +const uint32_t PpmSubBlock::s_errorMask; +const int PpmSubBlock::s_glinkPinParityBit; +const int PpmSubBlock::s_fpgaCorruptBit; +const int PpmSubBlock::s_bunchMismatchBit; +const int PpmSubBlock::s_eventMismatchBit; +const int PpmSubBlock::s_asicFullBit; +const int PpmSubBlock::s_timeoutBit; +const int PpmSubBlock::s_mcmAbsentBit; +const int PpmSubBlock::s_channelDisabledBit; + +PpmSubBlock::PpmSubBlock() : m_globalError(0), m_globalDone(false), + m_lutOffset(-1), m_fadcOffset(-1), + m_pedestal(10), m_fadcBaseline(0), + m_fadcThreshold(0), m_runNumber(0) +{ +} + +PpmSubBlock::~PpmSubBlock() +{ +} + +// Clear all data + +void PpmSubBlock::clear() +{ + L1CaloSubBlock::clear(); + m_globalError = 0; + m_globalDone = false; + m_lutOffset = -1; + m_fadcOffset = -1; + m_datamap.clear(); + m_errormap.clear(); +} + +// Store PPM header + +void PpmSubBlock::setPpmHeader(const int version, const int format, + const int seqno, const int crate, + const int module, const int slicesFadc, + const int slicesLut) +{ + setHeader(s_wordIdVal, version, format, seqno, crate, module, + slicesFadc, slicesLut); +} + +// Store PPM error block header + +void PpmSubBlock::setPpmErrorHeader(const int version, const int format, + const int crate, const int module, + const int slicesFadc, const int slicesLut) +{ + setHeader(s_wordIdVal, version, format, s_errorMarker, crate, module, + slicesFadc, slicesLut); +} + +// Return the number of FADC slices + +int PpmSubBlock::slicesFadc() const +{ + int slices = slices2(); + if (slices == 0 && format() == NEUTRAL) { + slices = dataWords()/(s_asicChannels*s_dataBits) - slicesLut(); + } + if (slices <= 0) slices = 1; + return slices; +} + +// Return the number of LUT slices + +int PpmSubBlock::slicesLut() const +{ + int slices = slices1(); + if (slices == 0) slices = 1; + return slices; +} + +// Store PPM data for later packing + +void PpmSubBlock::fillPpmData(const int chan, const std::vector<int>& lut, + const std::vector<int>& fadc, + const std::vector<int>& bcidLut, + const std::vector<int>& bcidFadc) +{ + const int sliceL = slicesLut(); + const int sliceF = slicesFadc(); + const int slices = sliceL + sliceF; + const int chanPerSubBlock = channelsPerSubBlock(); + int dataSize = m_datamap.size(); + if (dataSize == 0) { + dataSize = slices * chanPerSubBlock; + m_datamap.resize(dataSize); + } + int offset = (chan % chanPerSubBlock) * slices; + if (offset + slices <= dataSize) { + for (int pos = 0; pos < sliceL; ++pos) { + uint32_t datum = (lut[pos] & s_lutMask) << s_lutBit; + datum |= (bcidLut[pos] & s_bcidLutMask) << s_bcidLutBit; + m_datamap[offset + pos] = datum; + } + offset += sliceL; + for (int pos = 0; pos < sliceF; ++pos) { + const int adc = (fadc[pos] > 0) ? fadc[pos] : 0; + uint32_t datum = (adc & s_fadcMask) << s_fadcBit; + datum |= (bcidFadc[pos] & s_bcidFadcMask) << s_bcidFadcBit; + m_datamap[offset + pos] = datum; + } + } +} + +// Return unpacked data for given channel + +void PpmSubBlock::ppmData(const int chan, std::vector<int>& lut, + std::vector<int>& fadc, + std::vector<int>& bcidLut, + std::vector<int>& bcidFadc) +{ + lut.clear(); + fadc.clear(); + bcidLut.clear(); + bcidFadc.clear(); + const int sliceL = slicesLut(); + const int sliceF = slicesFadc(); + int beg = (chan % channelsPerSubBlock()) * (sliceL + sliceF); + int end = beg + sliceL; + if (size_t(end + sliceF) <= m_datamap.size()) { + for (int pos = beg; pos < end; ++pos) { + const uint32_t word = m_datamap[pos]; + lut.push_back((word >> s_lutBit) & s_lutMask); + bcidLut.push_back((word >> s_bcidLutBit) & s_bcidLutMask); + } + beg += sliceL; + end += sliceF; + for (int pos = beg; pos < end; ++pos) { + const uint32_t word = m_datamap[pos]; + fadc.push_back((word >> s_fadcBit) & s_fadcMask); + bcidFadc.push_back((word >> s_bcidFadcBit) & s_bcidFadcMask); + } + } else { + lut.resize(sliceL); + fadc.resize(sliceF); + bcidLut.resize(sliceL); + bcidFadc.resize(sliceF); + } +} + +// Store an error word corresponding to a data channel + +void PpmSubBlock::fillPpmError(const int chan, const int errorWord) +{ + if (m_errormap.empty()) m_errormap.resize(s_glinkPins); + // Expand one ASIC channel disabled bit to four + const uint32_t chanDisabled = (errorWord & 0x1) << asic(chan); + m_errormap[pin(chan)] |= (((errorWord >> 1) << s_asicChannels) + | chanDisabled) & s_errorMask; +} + +// Store an error word corresponding to a G-Link pin + +void PpmSubBlock::fillPpmPinError(const int pin, const int errorWord) +{ + if (m_errormap.empty()) m_errormap.resize(s_glinkPins); + m_errormap[pin] = errorWord & s_errorMask; +} + +// Return the error word for a data channel + +int PpmSubBlock::ppmError(const int chan) const +{ + int err = 0; + if ( !m_errormap.empty()) { + // Replace the four ASIC channel disabled bits with just the one + // corresponding to the data channel + err = (((m_errormap[pin(chan)] & s_errorMask) >> s_asicChannels) << 1) + | channelDisabled(chan); + } + return err; +} + +// Return the error word for a G-Link pin + +int PpmSubBlock::ppmPinError(const int pin) const +{ + int err = 0; + if ( !m_errormap.empty()) err = m_errormap[pin] & s_errorMask; + return err; +} + +// Return global error bit + +bool PpmSubBlock::errorBit(const int bit) const +{ + if ( ! m_globalDone) { + std::vector<uint32_t>::const_iterator pos; + for (pos = m_errormap.begin(); pos != m_errormap.end(); ++pos) { + m_globalError |= *pos; + } + m_globalDone = true; + } + return m_globalError & (0x1 << bit); +} + +// Packing/Unpacking routines + +bool PpmSubBlock::pack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = packNeutral(); + break; + case UNCOMPRESSED: + switch (seqno()) { + case s_errorMarker: + rc = packUncompressedErrors(); + break; + default: + rc = packUncompressedData(); + break; + } + break; + case COMPRESSED: + case SUPERCOMPRESSED: + rc = PpmCompression::pack(*this); + break; + default: + break; + } + break; + default: + break; + } + return rc; +} + +bool PpmSubBlock::unpack() +{ + bool rc = false; + switch (version()) { + case 1: + switch (format()) { + case NEUTRAL: + rc = unpackNeutral(); + break; + case UNCOMPRESSED: + switch (seqno()) { + case s_errorMarker: + rc = unpackUncompressedErrors(); + break; + default: + rc = unpackUncompressedData(); + break; + } + break; + case COMPRESSED: + case SUPERCOMPRESSED: + rc = PpmCompression::unpack(*this); + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return rc; +} + +// Pack neutral data + +bool PpmSubBlock::packNeutral() +{ + const int slices = slicesLut() + slicesFadc(); + const int channels = channelsPerSubBlock(); + if (m_datamap.empty()) m_datamap.resize(slices * channels); + // Bunch crossing number + for (int pin = 0; pin < s_glinkPins; ++pin) { + uint32_t bc = 0; + if (pin < s_bunchCrossingBits) bc = (bunchCrossing() >> pin) & 0x1; + packerNeutral(pin, bc, 1); + } + // Data + std::vector<uint32_t>::const_iterator pos = m_datamap.begin(); + for (int asic = 0; asic < s_asicChannels; ++asic) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + for (int sl = 0; sl < slices; ++sl) { + packerNeutral(pin, *pos, s_dataBits); + ++pos; + } + } + } + // Errors, including GP + if (m_errormap.empty()) m_errormap.resize(s_glinkPins); + pos = m_errormap.begin(); + for (int pin = 0; pin < s_glinkPins; ++pin) { + packerNeutral(pin, *pos, s_errorBits); + packerNeutralParity(pin); + ++pos; + } + return true; +} + +// Pack uncompressed data + +bool PpmSubBlock::packUncompressedData() +{ + const int slices = slicesLut() + slicesFadc(); + const int channels = channelsPerSubBlock(); + if (m_datamap.empty()) m_datamap.resize(slices * channels); + for (int sl = 0; sl < slices; ++sl) { + for (int chan = 0; chan < channels; ++chan) { + packer(m_datamap[sl + chan*slices], s_wordLen); + } + } + packerFlush(); + return true; +} + +// Pack uncompressed error data + +bool PpmSubBlock::packUncompressedErrors() +{ + if (m_errormap.empty()) m_errormap.resize(s_glinkPins); + for (int pin = 0; pin < s_glinkPins; ++pin) { + packer(m_errormap[pin], s_wordLen); + } + packerFlush(); + return true; +} + +// Unpack neutral data + +bool PpmSubBlock::unpackNeutral() +{ + const int slices = slicesLut() + slicesFadc(); + m_datamap.clear(); + // Bunch Crossing number + int bunchCrossing = 0; + for (int pin = 0; pin < s_glinkPins; ++pin) { + const int bc = unpackerNeutral(pin, 1); + if (pin < s_bunchCrossingBits) bunchCrossing |= bc << pin; + } + setBunchCrossing(bunchCrossing); + // Data + for (int asic = 0; asic < s_asicChannels; ++asic) { + for (int pin = 0; pin < s_glinkPins; ++pin) { + for (int sl = 0; sl < slices; ++sl) { + m_datamap.push_back(unpackerNeutral(pin, s_dataBits)); + } + } + } + const bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + // Errors + m_errormap.clear(); + for (int pin = 0; pin < s_glinkPins; ++pin) { + uint32_t error = unpackerNeutral(pin, s_errorBits); + error |= unpackerNeutralParityError(pin) << s_errorBits; + m_errormap.push_back(error); + } + return rc; +} + +// Unpack uncompressed data + +bool PpmSubBlock::unpackUncompressedData() +{ + const int slices = slicesLut() + slicesFadc(); + const int channels = channelsPerSubBlock(); + m_datamap.resize(slices * channels); + unpackerInit(); + for (int sl = 0; sl < slices; ++sl) { + for (int chan = 0; chan < channels; ++chan) { + m_datamap[sl + chan*slices] = unpacker(s_wordLen); + } + } + bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + else { + // Check no more non-zero data + while (unpackerSuccess()) { + if (unpacker(s_wordLen)) { + setUnpackErrorCode(UNPACK_EXCESS_DATA); + rc = false; + break; + } + } + } + return rc; +} + +// Unpack uncompressed error data + +bool PpmSubBlock::unpackUncompressedErrors() +{ + unpackerInit(); + m_errormap.clear(); + for (int pin = 0; pin < s_glinkPins; ++pin) { + m_errormap.push_back(unpacker(s_wordLen)); + } + bool rc = unpackerSuccess(); + if (!rc) setUnpackErrorCode(UNPACK_DATA_TRUNCATED); + else { + while (unpackerSuccess()) { + if (unpacker(s_wordLen)) { + setUnpackErrorCode(UNPACK_EXCESS_DATA); + rc = false; + break; + } + } + } + return rc; +} + +// Return the number of channels per sub-block + +int PpmSubBlock::channelsPerSubBlock(const int version, const int format) +{ + int chan = 0; + switch (version) { + case 1: + switch (format) { + case UNCOMPRESSED: + chan = s_channels/s_asicChannels; + break; + case NEUTRAL: + case COMPRESSED: + case SUPERCOMPRESSED: + chan = s_channels; + break; + default: + setUnpackErrorCode(UNPACK_FORMAT); + break; + } + break; + default: + setUnpackErrorCode(UNPACK_VERSION); + break; + } + return chan; +} + +int PpmSubBlock::channelsPerSubBlock() +{ + return channelsPerSubBlock(version(), format()); +} + +// Check if a header word is for an error block + +bool PpmSubBlock::errorBlock(const uint32_t word) +{ + bool rc = false; + if (format(word) == UNCOMPRESSED && + seqno(word) == s_errorMarker) rc = true; + return rc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmSubBlock.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmSubBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..8bcb12533f97202554faab61db9eeae3fa562812 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/PpmSubBlock.h @@ -0,0 +1,400 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMSUBBLOCK_H +#define TRIGT1CALOBYTESTREAM_PPMSUBBLOCK_H + +#include <stdint.h> +#include <vector> + +#include "L1CaloSubBlock.h" + +namespace LVL1BS { + +/** Sub-Block class for PPM data. + * + * @author Peter Faulkner + */ + +class PpmSubBlock : public L1CaloSubBlock { + + public: + PpmSubBlock(); + ~PpmSubBlock(); + + /// Clear all data + void clear(); + + /// Store PPM header + void setPpmHeader(int version, int format, int seqno, int crate, + int module, int slicesFadc, int slicesLut); + /// Store PPM error block header + void setPpmErrorHeader(int version, int format, int crate, + int module, int slicesFadc, int slicesLut); + + // Return PPM-specific header data + int slicesFadc() const; + int slicesLut() const; + + /// Store PPM data for later packing + void fillPpmData(int chan, const std::vector<int>& lut, + const std::vector<int>& fadc, + const std::vector<int>& bcidLut, + const std::vector<int>& bcidFadc); + /// Return unpacked data for given channel + void ppmData(int chan, std::vector<int>& lut, + std::vector<int>& fadc, + std::vector<int>& bcidLut, + std::vector<int>& bcidFadc); + + /// Store an error word corresponding to a data channel + void fillPpmError(int chan, int errorWord); + /// Store an error word corresponding to a G-Link pin + void fillPpmPinError(int pin, int errorWord); + + /// Return the error word for a data channel + int ppmError(int chan) const; + /// Return the error word for a G-Link pin + int ppmPinError(int pin) const; + + // Return individual error bits + bool glinkPinParity(int chan) const; + bool fpgaCorrupt(int chan) const; + bool bunchMismatch(int chan) const; + bool eventMismatch(int chan) const; + bool asicFull(int chan) const; + bool timeout(int chan) const; + bool mcmAbsent(int chan) const; + bool channelDisabled(int chan) const; + bool channelDisabledA(int pin) const; + bool channelDisabledB(int pin) const; + bool channelDisabledC(int pin) const; + bool channelDisabledD(int pin) const; + // Ditto ORed over all pins + bool glinkPinParity() const; + bool fpgaCorrupt() const; + bool bunchMismatch() const; + bool eventMismatch() const; + bool asicFull() const; + bool timeout() const; + bool mcmAbsent() const; + bool channelDisabledA() const; + bool channelDisabledB() const; + bool channelDisabledC() const; + bool channelDisabledD() const; + + // Set triggered slice offsets, pedestal value + void setLutOffset(int offset); + void setFadcOffset(int offset); + void setPedestal(int pedval); + void setFadcBaseline(int baseline); + void setFadcThreshold(int threshold); + void setRunNumber(int run); + // Return triggered slice offsets, pedestal value + int lutOffset() const; + int fadcOffset() const; + int pedestal() const; + int fadcBaseline() const; + int fadcThreshold() const; + int runNumber() const; + + /// Pack data + bool pack(); + /// Unpack data + bool unpack(); + + /// Return the number of channels per sub-block + int channelsPerSubBlock(int version, int format); + int channelsPerSubBlock(); + + /// Check if a header word is for an error block + static bool errorBlock(uint32_t word); + + /// Set compression stats + void setCompStats(const std::vector<uint32_t>& stats); + /// Return reference to compression stats + const std::vector<uint32_t>& compStats() const; + + private: + // Header word data + static const uint32_t s_wordIdVal = 0xc; + static const int s_errorMarker = 63; + // Data word positions and masks + static const int s_wordLen = 16; + static const int s_lutBit = 0; + static const int s_bcidLutBit = 8; + static const int s_fadcBit = 1; + static const int s_bcidFadcBit = 0; + static const uint32_t s_lutMask = 0xff; + static const uint32_t s_bcidLutMask = 0x7; + static const uint32_t s_fadcMask = 0x3ff; + static const uint32_t s_bcidFadcMask = 0x1; + // For neutral format + static const int s_channels = 64; + static const int s_glinkPins = 16; + static const int s_asicChannels = 4; + static const int s_dataBits = 11; + static const int s_errorBits = 10; + static const int s_bunchCrossingBits = 12; + // Error word masks and bit positions + static const uint32_t s_errorMask = 0x7ff; + static const int s_glinkPinParityBit = 10; + static const int s_fpgaCorruptBit = 9; + static const int s_bunchMismatchBit = 8; + static const int s_eventMismatchBit = 7; + static const int s_asicFullBit = 6; + static const int s_timeoutBit = 5; + static const int s_mcmAbsentBit = 4; + static const int s_channelDisabledBit = 0; + + /// Return the ASIC channel corresponding to a data channel + int asic(int chan) const; + /// Return the G-Link pin corresponding to a data channel + int pin(int chan) const; + + /// Error bit extraction + bool errorBit(int pin, int bit) const; + /// Global error bit extraction + bool errorBit(int bit) const; + + // Packing/unpacking for specific formats + /// Pack neutral data + bool packNeutral(); + /// Pack uncompressed data + bool packUncompressedData(); + /// Pack uncompressed error data + bool packUncompressedErrors(); + /// Unpack neutral data + bool unpackNeutral(); + /// Unpack uncompressed data + bool unpackUncompressedData(); + /// Unpack uncompressed error data + bool unpackUncompressedErrors(); + + // Global error flags + mutable uint32_t m_globalError; + mutable bool m_globalDone; + + // Triggered slice offsets, pedestal value + int m_lutOffset; + int m_fadcOffset; + int m_pedestal; + int m_fadcBaseline; + int m_fadcThreshold; + int m_runNumber; + + /// Vector for compression statistics + std::vector<uint32_t> m_compStats; + + /// Vector for intermediate data + std::vector<uint32_t> m_datamap; + + /// Vector for intermediate error data + std::vector<uint32_t> m_errormap; + +}; + +inline bool PpmSubBlock::glinkPinParity(const int chan) const +{ + return errorBit(pin(chan), s_glinkPinParityBit); +} + +inline bool PpmSubBlock::fpgaCorrupt(const int chan) const +{ + return errorBit(pin(chan), s_fpgaCorruptBit); +} + +inline bool PpmSubBlock::bunchMismatch(const int chan) const +{ + return errorBit(pin(chan), s_bunchMismatchBit); +} + +inline bool PpmSubBlock::eventMismatch(const int chan) const +{ + return errorBit(pin(chan), s_eventMismatchBit); +} + +inline bool PpmSubBlock::asicFull(const int chan) const +{ + return errorBit(pin(chan), s_asicFullBit); +} + +inline bool PpmSubBlock::timeout(const int chan) const +{ + return errorBit(pin(chan), s_timeoutBit); +} + +inline bool PpmSubBlock::mcmAbsent(const int chan) const +{ + return errorBit(pin(chan), s_mcmAbsentBit); +} + +inline bool PpmSubBlock::channelDisabled(const int chan) const +{ + return errorBit(pin(chan), s_channelDisabledBit + asic(chan)); +} + +inline bool PpmSubBlock::channelDisabledA(const int pin) const +{ + return errorBit(pin, s_channelDisabledBit); +} + +inline bool PpmSubBlock::channelDisabledB(const int pin) const +{ + return errorBit(pin, s_channelDisabledBit + 1); +} + +inline bool PpmSubBlock::channelDisabledC(const int pin) const +{ + return errorBit(pin, s_channelDisabledBit + 2); +} + +inline bool PpmSubBlock::channelDisabledD(const int pin) const +{ + return errorBit(pin, s_channelDisabledBit + 3); +} + +inline bool PpmSubBlock::glinkPinParity() const +{ + return errorBit(s_glinkPinParityBit); +} + +inline bool PpmSubBlock::fpgaCorrupt() const +{ + return errorBit(s_fpgaCorruptBit); +} + +inline bool PpmSubBlock::bunchMismatch() const +{ + return errorBit(s_bunchMismatchBit); +} + +inline bool PpmSubBlock::eventMismatch() const +{ + return errorBit(s_eventMismatchBit); +} + +inline bool PpmSubBlock::asicFull() const +{ + return errorBit(s_asicFullBit); +} + +inline bool PpmSubBlock::timeout() const +{ + return errorBit(s_timeoutBit); +} + +inline bool PpmSubBlock::mcmAbsent() const +{ + return errorBit(s_mcmAbsentBit); +} + +inline bool PpmSubBlock::channelDisabledA() const +{ + return errorBit(s_channelDisabledBit); +} + +inline bool PpmSubBlock::channelDisabledB() const +{ + return errorBit(s_channelDisabledBit + 1); +} + +inline bool PpmSubBlock::channelDisabledC() const +{ + return errorBit(s_channelDisabledBit + 2); +} + +inline bool PpmSubBlock::channelDisabledD() const +{ + return errorBit(s_channelDisabledBit + 3); +} + +inline void PpmSubBlock::setLutOffset(const int offset) +{ + m_lutOffset = offset; +} + +inline void PpmSubBlock::setFadcOffset(const int offset) +{ + m_fadcOffset = offset; +} + +inline void PpmSubBlock::setPedestal(const int pedval) +{ + m_pedestal = pedval; +} + +inline void PpmSubBlock::setFadcBaseline(const int baseline) +{ + m_fadcBaseline = baseline; +} + +inline void PpmSubBlock::setFadcThreshold(const int threshold) +{ + m_fadcThreshold = threshold; +} + +inline void PpmSubBlock::setRunNumber(const int run) +{ + m_runNumber = run; +} + +inline int PpmSubBlock::lutOffset() const +{ + return (m_lutOffset < 0) ? slicesLut()/2 : m_lutOffset; +} + +inline int PpmSubBlock::fadcOffset() const +{ + return (m_fadcOffset < 0) ? slicesFadc()/2 : m_fadcOffset; +} + +inline int PpmSubBlock::pedestal() const +{ + return m_pedestal; +} + +inline int PpmSubBlock::fadcBaseline() const +{ + return m_fadcBaseline; +} + +inline int PpmSubBlock::fadcThreshold() const +{ + return m_fadcThreshold; +} + +inline int PpmSubBlock::runNumber() const +{ + return m_runNumber; +} + +inline const std::vector<uint32_t>& PpmSubBlock::compStats() const +{ + return m_compStats; +} + +inline void PpmSubBlock::setCompStats(const std::vector<uint32_t>& stats) +{ + m_compStats = stats; +} + +inline int PpmSubBlock::asic(const int chan) const +{ + return chan / s_glinkPins; +} + +inline int PpmSubBlock::pin(const int chan) const +{ + return chan % s_glinkPins; +} + +inline bool PpmSubBlock::errorBit(const int pin, const int bit) const +{ + return m_errormap[pin] & (0x1 << bit); +} + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamCnv.cxx new file mode 100644 index 0000000000000000000000000000000000000000..083d4f28a99fbc7a904644db282c4db29acada4b --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamCnv.cxx @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <vector> +#include <stdint.h> + +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" + +#include "ByteStreamData/RawEvent.h" +#include "ByteStreamData/ROBData.h" + +#include "DataModel/DataVector.h" + +#include "GaudiKernel/CnvFactory.h" +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IOpaqueAddress.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/StatusCode.h" + +#include "SGTools/ClassID_traits.h" +#include "SGTools/StorableConversions.h" + +#include "TrigT1CaloEvent/RODHeader.h" + +#include "RodHeaderByteStreamTool.h" + +#include "RodHeaderByteStreamCnv.h" + +namespace LVL1BS { + +RodHeaderByteStreamCnv::RodHeaderByteStreamCnv( ISvcLocator* svcloc ) + : Converter( ByteStream_StorageType, classID(), svcloc ), + m_name("RodHeaderByteStreamCnv"), + m_tool("LVL1BS::RodHeaderByteStreamTool/RodHeaderByteStreamTool"), + m_robDataProvider("ROBDataProviderSvc", m_name), + m_log(msgSvc(), m_name), m_debug(false) +{ +} + +RodHeaderByteStreamCnv::~RodHeaderByteStreamCnv() +{ +} + +// CLID + +const CLID& RodHeaderByteStreamCnv::classID() +{ + return ClassID_traits<DataVector<LVL1::RODHeader> >::ID(); +} + +// Init method gets all necessary services etc. + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode RodHeaderByteStreamCnv::initialize() +{ + m_debug = msgSvc()->outputLevel(m_name) <= MSG::DEBUG; + m_log << MSG::DEBUG << "Initializing " << m_name << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = Converter::initialize(); + if ( sc.isFailure() ) + return sc; + + // Retrieve Tool + sc = m_tool.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve tool " << m_tool << endreq; + return sc; + } else m_log << MSG::DEBUG << "Retrieved tool " << m_tool << endreq; + + // Get ROBDataProvider + sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << "Failed to retrieve service " + << m_robDataProvider << endreq; + return sc ; + } else { + m_log << MSG::DEBUG << "Retrieved service " + << m_robDataProvider << endreq; + } + + return StatusCode::SUCCESS; +} + +// createObj should create the RDO from bytestream. + +StatusCode RodHeaderByteStreamCnv::createObj( IOpaqueAddress* pAddr, + DataObject*& pObj ) +{ + if (m_debug) m_log << MSG::DEBUG << "createObj() called" << endreq; + + ByteStreamAddress *pBS_Addr; + pBS_Addr = dynamic_cast<ByteStreamAddress *>( pAddr ); + if ( !pBS_Addr ) { + m_log << MSG::ERROR << " Can not cast to ByteStreamAddress " << endreq; + return StatusCode::FAILURE; + } + + const std::string nm = *( pBS_Addr->par() ); + + if (m_debug) m_log << MSG::DEBUG << " Creating Objects " << nm << endreq; + + // get SourceIDs + const std::vector<uint32_t>& vID(m_tool->sourceIDs(nm)); + + // get ROB fragments + IROBDataProviderSvc::VROBFRAG robFrags; + m_robDataProvider->getROBData( vID, robFrags ); + + // size check + DataVector<LVL1::RODHeader>* const rhCollection = + new DataVector<LVL1::RODHeader>; + if (m_debug) { + m_log << MSG::DEBUG << " Number of ROB fragments is " << robFrags.size() + << endreq; + } + if (robFrags.size() == 0) { + pObj = SG::asStorable(rhCollection) ; + return StatusCode::SUCCESS; + } + + StatusCode sc = m_tool->convert(robFrags, rhCollection); + if ( sc.isFailure() ) { + m_log << MSG::ERROR << " Failed to create Objects " << nm << endreq; + delete rhCollection; + return sc; + } + + pObj = SG::asStorable(rhCollection); + + return sc; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamCnv.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamCnv.h new file mode 100644 index 0000000000000000000000000000000000000000..26d9c875d48793739f00b080edaeaec996ac2107 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamCnv.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_RODHEADERBYTESTREAMCNV_H +#define TRIGT1CALOBYTESTREAM_RODHEADERBYTESTREAMCNV_H + +#include <string> + +#include "GaudiKernel/ClassID.h" +#include "GaudiKernel/Converter.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +class DataObject; +class IOpaqueAddress; +class IROBDataProviderSvc; +class ISvcLocator; +class StatusCode; + +template <typename> class CnvFactory; + +// Externals +extern long ByteStream_StorageType; + +namespace LVL1BS { + +class RodHeaderByteStreamTool; + +/** ByteStream converter for L1Calo ROD header info + * + * @author Peter Faulkner + */ + +class RodHeaderByteStreamCnv: public Converter { + + friend class CnvFactory<RodHeaderByteStreamCnv>; + +protected: + + RodHeaderByteStreamCnv(ISvcLocator* svcloc); + +public: + + ~RodHeaderByteStreamCnv(); + + virtual StatusCode initialize(); + /// Create RodHeaders from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID + virtual long repSvcType() const { return ByteStream_StorageType;} + static long storageType(){ return ByteStream_StorageType; } + static const CLID& classID(); + +private: + + /// Converter name + std::string m_name; + + /// Tool that does the actual work + ToolHandle<LVL1BS::RodHeaderByteStreamTool> m_tool; + + /// Service for reading bytestream + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + + /// Message log + mutable MsgStream m_log; + bool m_debug; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1e6ddcd30306ddadc1b7c8e18418e874db873ec8 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamTool.cxx @@ -0,0 +1,300 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <algorithm> +#include <set> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "TrigT1CaloEvent/RODHeader.h" + +#include "L1CaloErrorByteStreamTool.h" +#include "L1CaloSrcIdMap.h" +#include "L1CaloSubBlock.h" + +#include "RodHeaderByteStreamTool.h" + +namespace LVL1BS { + +// Interface ID + +static const InterfaceID IID_IRodHeaderByteStreamTool("RodHeaderByteStreamTool", 1, 1); + +const InterfaceID& RodHeaderByteStreamTool::interfaceID() +{ + return IID_IRodHeaderByteStreamTool; +} + +// Constructor + +RodHeaderByteStreamTool::RodHeaderByteStreamTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"), + m_srcIdMap(0) +{ + declareInterface<RodHeaderByteStreamTool>(this); + + declareProperty("ErrorTool", m_errorTool, + "Tool to collect errors for monitoring"); + declareProperty("ROBSourceIDs", m_sourceIDs, + "ROB fragment source identifiers - All except RoIB"); + declareProperty("ROBSourceIDsPP", m_sourceIDsPP, + "ROB fragment source identifiers - PP only"); + declareProperty("ROBSourceIDsCP", m_sourceIDsCP, + "ROB fragment source identifiers - CP DAQ only"); + declareProperty("ROBSourceIDsJEP", m_sourceIDsJEP, + "ROB fragment source identifiers - JEP DAQ only"); + declareProperty("ROBSourceIDsCPRoI", m_sourceIDsCPRoI, + "ROB fragment source identifiers - CP RoI only"); + declareProperty("ROBSourceIDsJEPRoI", m_sourceIDsJEPRoI, + "ROB fragment source identifiers - JEP RoI only"); + declareProperty("ROBSourceIDsCPRoIB", m_sourceIDsCPRoIB, + "ROB fragment source identifiers - CP RoIB only"); + declareProperty("ROBSourceIDsJEPRoIB", m_sourceIDsJEPRoIB, + "ROB fragment source identifiers - JEP RoIB only"); + +} + +// Destructor + +RodHeaderByteStreamTool::~RodHeaderByteStreamTool() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode RodHeaderByteStreamTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + StatusCode sc = m_errorTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_errorTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_errorTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode RodHeaderByteStreamTool::finalize() +{ + delete m_srcIdMap; + return StatusCode::SUCCESS; +} + +// Conversion bytestream to RODHeaders + +StatusCode RodHeaderByteStreamTool::convert( + const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::RODHeader>* const rhCollection) +{ + const bool debug = msgLvl(MSG::DEBUG); + if (debug) msg(MSG::DEBUG); + + // Loop over ROB fragments + + int robCount = 0; + std::set<uint32_t> dupCheck; + ROBIterator rob = robFrags.begin(); + ROBIterator robEnd = robFrags.end(); + for (; rob != robEnd; ++rob) { + + if (debug) { + ++robCount; + msg() << "Treating ROB fragment " << robCount << endreq; + } + + // Skip fragments with ROB status errors + + uint32_t robid = (*rob)->source_id(); + if ((*rob)->nstatus() > 0) { + ROBPointer robData; + (*rob)->status(robData); + if (*robData != 0) { + m_errorTool->robError(robid, *robData); + if (debug) msg() << "ROB status error - skipping fragment" << endreq; + continue; + } + } + + // Skip duplicate fragments + + if (!dupCheck.insert(robid).second) { + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_DUPLICATE_ROB); + if (debug) msg() << "Skipping duplicate ROB fragment" << endreq; + continue; + } + + // Unpack ROD header info + + const uint32_t version = (*rob)->rod_version(); + const uint32_t sourceId = (*rob)->rod_source_id(); + const uint32_t run = (*rob)->rod_run_no(); + const uint32_t lvl1Id = (*rob)->rod_lvl1_id(); + const uint32_t bcId = (*rob)->rod_bc_id(); + const uint32_t trigType = (*rob)->rod_lvl1_trigger_type(); + const uint32_t detType = (*rob)->rod_detev_type(); + const uint32_t nData = (*rob)->rod_ndata(); + + // Unpack status words + + std::vector<uint32_t> statusWords; + unsigned int nstatus = (*rob)->rod_nstatus(); + if (nstatus <= 2) { + RODPointer status; + RODPointer statusEnd; + (*rob)->rod_status(status); + statusEnd = status + nstatus; + for (; status != statusEnd; ++status) statusWords.push_back(*status); + } else { // Likely corruption + m_errorTool->rodError(robid, L1CaloSubBlock::ERROR_ROD_NSTATUS); + continue; + } + + // Save + + rhCollection->push_back(new LVL1::RODHeader(version, sourceId, run, lvl1Id, + bcId, trigType, detType, statusWords, nData)); + if (debug) { + msg() << MSG::hex + << "ROD Header version/sourceId/run/lvl1Id/bcId/trigType/detType/nData: " + << version << "/" << sourceId << "/" << run << "/" << lvl1Id << "/" + << bcId << "/" << trigType << "/" << detType << "/" << nData + << endreq << "ROD Status Words:"; + std::vector<uint32_t>::const_iterator pos = statusWords.begin(); + std::vector<uint32_t>::const_iterator pose = statusWords.end(); + for (; pos != pose; ++pos) msg() << " " << *pos; + msg() << MSG::dec << endreq; + } + } + + return StatusCode::SUCCESS; +} + +// Return reference to vector with all possible Source Identifiers + +const std::vector<uint32_t>& RodHeaderByteStreamTool::sourceIDs( + const std::string& sgKey) +{ + const bool pp = isAppended(sgKey, "PP"); + const bool cp = isAppended(sgKey, "CP"); + const bool jep = isAppended(sgKey, "JEP"); + const bool cpRoi = isAppended(sgKey, "CPRoI"); + const bool jepRoi = isAppended(sgKey, "JEPRoI"); + const bool cpRoib = isAppended(sgKey, "CPRoIB"); + const bool jepRoib = isAppended(sgKey, "JEPRoIB"); + const bool all = !(pp || cp || jep || cpRoi || jepRoi || cpRoib || jepRoib); + if (all && !m_sourceIDs.empty()) return m_sourceIDs; + if (pp && !m_sourceIDsPP.empty()) return m_sourceIDsPP; + if (cp && !m_sourceIDsCP.empty()) return m_sourceIDsCP; + if (jep && !m_sourceIDsJEP.empty()) return m_sourceIDsJEP; + if (cpRoi && !m_sourceIDsCPRoI.empty()) return m_sourceIDsCPRoI; + if (jepRoi && !m_sourceIDsJEPRoI.empty()) return m_sourceIDsJEPRoI; + if (cpRoib && !m_sourceIDsCPRoIB.empty()) return m_sourceIDsCPRoIB; + if (jepRoib && !m_sourceIDsJEPRoIB.empty()) return m_sourceIDsJEPRoIB; + // PP + if (all || pp) { + std::vector<int> slinks(4); + for (int i = 1; i < 4; ++i) slinks[i] = i; + fillRobIds(all, 8, 0, slinks, 0, eformat::TDAQ_CALO_PREPROC, + m_sourceIDsPP); + if (pp) return m_sourceIDsPP; + } + // CP + if (all || cp) { + std::vector<int> slinks(2); + slinks[1] = 2; + fillRobIds(all, 4, 8, slinks, 0, eformat::TDAQ_CALO_CLUSTER_PROC_DAQ, + m_sourceIDsCP); + if (cp) return m_sourceIDsCP; + } + // CP RoI + if (all || cpRoi) { + const std::vector<int> slinks(1); + fillRobIds(all, 4, 8, slinks, 1, eformat::TDAQ_CALO_CLUSTER_PROC_ROI, + m_sourceIDsCPRoI); + if (cpRoi) return m_sourceIDsCPRoI; + } + // JEP + if (all || jep) { + std::vector<int> slinks(4); + for (int i = 1; i < 4; ++i) slinks[i] = i; + fillRobIds(all, 2, 12, slinks, 0, eformat::TDAQ_CALO_JET_PROC_DAQ, + m_sourceIDsJEP); + if (jep) return m_sourceIDsJEP; + } + // JEP RoI + if (all || jepRoi) { + const std::vector<int> slinks(1); + fillRobIds(all, 2, 12, slinks, 1, eformat::TDAQ_CALO_JET_PROC_ROI, + m_sourceIDsJEPRoI); + if (jepRoi) return m_sourceIDsJEPRoI; + } + // Don't include RoIBs (LVL2) in complete set + // CP RoIB + if (cpRoib) { + const std::vector<int> slinks(1, 2); + fillRobIds(false, 4, 8, slinks, 1, eformat::TDAQ_CALO_CLUSTER_PROC_ROI, + m_sourceIDsCPRoIB); + return m_sourceIDsCPRoIB; + } + // JEP RoIB + if (jepRoib) { + const std::vector<int> slinks(1, 2); + fillRobIds(false, 2, 12, slinks, 1, eformat::TDAQ_CALO_JET_PROC_ROI, + m_sourceIDsJEPRoIB); + return m_sourceIDsJEPRoIB; + } + return m_sourceIDs; +} + +// Fill vector with ROB IDs for given sub-detector + +void RodHeaderByteStreamTool::fillRobIds(const bool all, const int numCrates, + const int crateOffset, + const std::vector<int>& slinks, + const int daqOrRoi, + const eformat::SubDetector subdet, + std::vector<uint32_t>& detSourceIDs) +{ + if (all && !detSourceIDs.empty()) { + std::copy(detSourceIDs.begin(), detSourceIDs.end(), + std::back_inserter(m_sourceIDs)); + } else { + for (int crate = 0; crate < numCrates; ++crate) { + const int numSlinks = slinks.size(); + for (int i = 0; i < numSlinks; ++i) { + const uint32_t rodId = m_srcIdMap->getRodID(crate + crateOffset, + slinks[i], daqOrRoi, subdet); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + if (all) m_sourceIDs.push_back(robId); + else detSourceIDs.push_back(robId); + } + } + } +} + +// Return true if StoreGate key ends in given string + +bool RodHeaderByteStreamTool::isAppended(const std::string& sgKey, + const std::string& flag) const +{ + const std::string::size_type pos = sgKey.find(flag); + return (pos != std::string::npos && pos == sgKey.length() - flag.length()); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamTool.h new file mode 100644 index 0000000000000000000000000000000000000000..3f68df5ffa80f447eb218d1ffa866786e1619281 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/RodHeaderByteStreamTool.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_RODHEADERBYTESTREAMTOOL_H +#define TRIGT1CALOBYTESTREAM_RODHEADERBYTESTREAMTOOL_H + +#include <stdint.h> + +#include <string> +#include <vector> + +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/ToolHandle.h" + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" + +class IInterface; +class InterfaceID; +class StatusCode; + +namespace LVL1 { + class RODHeader; +} + +namespace LVL1BS { + +class L1CaloErrorByteStreamTool; +class L1CaloSrcIdMap; + +/** Tool to perform ROB fragments to ROD Header conversions. + * + * Based on ROD document version 1_09h. + * + * @author Peter Faulkner + */ + +class RodHeaderByteStreamTool : public AthAlgTool { + + public: + RodHeaderByteStreamTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~RodHeaderByteStreamTool(); + + /// AlgTool InterfaceID + static const InterfaceID& interfaceID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Convert ROB fragments to RODHeaders + StatusCode convert(const IROBDataProviderSvc::VROBFRAG& robFrags, + DataVector<LVL1::RODHeader>* rhCollection); + + /// Return reference to vector with all possible Source Identifiers + const std::vector<uint32_t>& sourceIDs(const std::string& sgKey); + + private: + typedef DataVector<LVL1::RODHeader> RodHeaderCollection; + typedef IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer; + typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer; + + /// Fill vector with ROB IDs for given sub-detector + void fillRobIds(bool all, int numCrates, int crateOffset, + const std::vector<int>& slinks, int daqOrRoi, + eformat::SubDetector subdet, + std::vector<uint32_t>& detSourceIDs); + + /// Return true if StoreGate key ends in given string + bool isAppended(const std::string& sgKey, const std::string& flag) const; + + /// Error collection tool + ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool; + + /// ROB source IDs + std::vector<uint32_t> m_sourceIDs; + std::vector<uint32_t> m_sourceIDsPP; + std::vector<uint32_t> m_sourceIDsCP; + std::vector<uint32_t> m_sourceIDsJEP; + std::vector<uint32_t> m_sourceIDsCPRoI; + std::vector<uint32_t> m_sourceIDsJEPRoI; + std::vector<uint32_t> m_sourceIDsCPRoIB; + std::vector<uint32_t> m_sourceIDsJEPRoIB; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/TrigT1CaloDataAccess.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/TrigT1CaloDataAccess.cxx new file mode 100644 index 0000000000000000000000000000000000000000..44f9f7ab8a1ed01b3155d56f9733888a21ef772a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/TrigT1CaloDataAccess.cxx @@ -0,0 +1,234 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <stdint.h> + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h" +#include "TrigT1CaloEvent/TriggerTower.h" +#include "TrigT1CaloEvent/JetElement.h" + +#include "IPpmByteStreamSubsetTool.h" +#include "JepByteStreamV2Tool.h" +#include "ITriggerTowerSelectionTool.h" + +#include "TrigT1CaloDataAccess.h" + +namespace LVL1BS { + +// Constructor + +TrigT1CaloDataAccess::TrigT1CaloDataAccess(const std::string& type, + const std::string& name, const IInterface* parent) + : AthAlgTool(type, name, parent), + m_robDataProvider("ROBDataProviderSvc/ROBDataProviderSvc", name), + m_selectionTool("LVL1BS::TriggerTowerSelectionTool/TriggerTowerSelectionTool"), + m_ppmBSConverter("LVL1BS::PpmByteStreamSubsetTool/PpmByteStreamSubsetTool"), + m_JetConverter("LVL1BS::JepByteStreamV2Tool/JepByteStreamV2Tool"), + m_ttCol(0), m_jetCol(0) +{ + declareInterface<ITrigT1CaloDataAccess>(this); + + declareProperty("ROBDataProviderSvc", m_robDataProvider); + declareProperty("TriggerTowerSelectionTool", m_selectionTool); + declareProperty("PpmByteStreamSubsetTool", m_ppmBSConverter); + declareProperty("JepByteStreamV2Tool", m_JetConverter); + +} + +// Destructor + +TrigT1CaloDataAccess::~TrigT1CaloDataAccess() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode TrigT1CaloDataAccess::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + // Retrieve data provider service + + StatusCode sc = m_robDataProvider.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve service " << m_robDataProvider + << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved service " << m_robDataProvider << endreq; + + // Retrieve selection tool + + sc = m_selectionTool.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_selectionTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_selectionTool << endreq; + + // Retrieve PPM converter tool + + sc = m_ppmBSConverter.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_ppmBSConverter << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_ppmBSConverter << endreq; + + sc = m_JetConverter.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_JetConverter << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_JetConverter << endreq; + + IIncidentSvc* p_incSvc; + if ( service("IncidentSvc",p_incSvc, true).isFailure() ) { + msg(MSG::ERROR) << "Unable to get the IncidentSvc" << endreq; + }else{ + // Will use the new event for caching purposes + p_incSvc->addListener(this, "BeginEvent",100); + } + + + m_robs_full_je.push_back(0x0074000c); m_robs_full_je.push_back(0x0074000d); + m_robs_full_je.push_back(0x0074001c); m_robs_full_je.push_back(0x0074001d); + m_robs_full_je.push_back(0x0074002c); m_robs_full_je.push_back(0x0074002d); + m_robs_full_je.push_back(0x0074003c); m_robs_full_je.push_back(0x0074003d); + + m_ttCol = new DataVector<LVL1::TriggerTower>(SG::VIEW_ELEMENTS); + // Better reserve the space. Some objects will be used for full + // unpacking and will be build in the first full event request + m_ttCol->reserve(5300); + m_chanIds.reserve(100); + m_chanIds_full.reserve(7400); + m_robs.reserve(36); + m_robs_full.reserve(36); + // First event selection + m_jetCol = new DataVector<LVL1::JetElement>; + m_jetCol->reserve(150); + m_first=true; + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode TrigT1CaloDataAccess::finalize() +{ + m_chanIds.clear(); + m_chanIds_full.clear(); + m_robs_full_je.clear(); + m_robs_full.clear(); + m_robs.clear(); + m_ttCol->clear(); + delete m_ttCol; + m_jetCol->clear(); + delete m_jetCol; + return StatusCode::SUCCESS; +} + +// Return iterators to required trigger towers + +StatusCode TrigT1CaloDataAccess::loadCollection( + DataVector<LVL1::TriggerTower>::const_iterator& beg, + DataVector<LVL1::TriggerTower>::const_iterator& end, + const double etaMin, const double etaMax, + const double phiMin, const double phiMax, const bool full=true) +{ + + beg=end; + // It is possible to save good time for full scan using special + // pre-prepared tables. You have to state full=true + if ( !full ) { m_chanIds.clear(); m_robs.clear(); } + // Get PPM sub-block channel IDs for wanted TriggerTowers + if ( m_first && full ) + m_selectionTool->channelIDs(-5., 5., 0, 2*M_PI, m_chanIds_full); + if ( ! full ) + m_selectionTool->channelIDs(etaMin, etaMax, phiMin, phiMax, m_chanIds); + + // Get ROB IDs for wanted TriggerTowers + if ( m_first && full ) + m_selectionTool->robIDs(m_chanIds_full, m_robs_full); + if ( ! full ) + m_selectionTool->robIDs(m_chanIds, m_robs); + + // Get data + m_robFrags.clear(); + + if ( full ){ + m_robDataProvider->addROBData(m_robs_full); + m_robDataProvider->getROBData(m_robs_full, m_robFrags); + }else{ + m_robDataProvider->addROBData(m_robs); + m_robDataProvider->getROBData(m_robs, m_robFrags); + } + + // Convert to TriggerTowers + m_ttCol->clear(); + StatusCode sc; + if ( full ) sc = m_ppmBSConverter->convert(m_robFrags, m_ttCol, m_chanIds_full); + else sc = m_ppmBSConverter->convert(m_robFrags, m_ttCol, m_chanIds); + if (sc.isFailure() ) { + msg(MSG::ERROR) << "PPM bytestream conversion failed" << endreq; + m_ttCol->clear(); + } + beg = m_ttCol->begin(); + end = m_ttCol->end(); + + if ( full && m_first ) m_first=false; + return sc; + + +} + +StatusCode TrigT1CaloDataAccess::loadCollection( + DataVector<LVL1::JetElement>::const_iterator& beg, + DataVector<LVL1::JetElement>::const_iterator& end){ + + beg=end; + if ( m_present_event != m_lC_Jet ){ + // Get data + m_robFrags.clear(); + m_robDataProvider->addROBData(m_robs_full_je); + m_robDataProvider->getROBData(m_robs_full_je, m_robFrags); + + m_jetCol->clear(); + StatusCode sc = m_JetConverter->convert(m_robFrags, m_jetCol); + if (sc.isFailure() ) { + msg(MSG::ERROR) << "JET bytestream conversion failed" << endreq; + return sc; + } + m_lC_Jet = m_present_event; + } + beg = m_jetCol->begin(); + end = m_jetCol->end(); + + + return StatusCode::SUCCESS; +} + +void TrigT1CaloDataAccess::handle(const Incident & inc ) { + const EventIncident* eventInc = dynamic_cast<const EventIncident*>(&inc); + if(!eventInc) { + std::cout << " Unable to get EventInfo from either EventStore or BeginRun incident" << std::endl; + return; + } + else { + const EventInfo* evt; + evt = &eventInc->eventInfo(); + m_present_event = (evt->event_ID()->event_number()); + m_ppmBSConverter->eventNumber(m_present_event); + } +} + + + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/TrigT1CaloDataAccess.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/TrigT1CaloDataAccess.h new file mode 100644 index 0000000000000000000000000000000000000000..51557ce07ba83b34121d6b5166f5d7c74ef028c7 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/TrigT1CaloDataAccess.h @@ -0,0 +1,112 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_TRIGT1CALODATAACCESS_H +#define TRIGT1CALOBYTESTREAM_TRIGT1CALODATAACCESS_H + +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "ByteStreamData/RawEvent.h" +#include "DataModel/DataVector.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" + +#include "TrigT1CaloByteStream/ITrigT1CaloDataAccess.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/IIncidentListener.h" +#include "GaudiKernel/Incident.h" +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventID.h" +#include "EventInfo/EventIncident.h" + +class IInterface; +class IROBDataProviderSvc; +class StatusCode; + +namespace LVL1 { + class TriggerTower; + class JetElement; +} + +namespace LVL1BS { + +class JepByteStreamV2Tool; +class IPpmByteStreamSubsetTool; +class ITriggerTowerSelectionTool; + +/** Tool to retrieve TriggerTowers corresponding to a given eta/phi range + * from bytestream. + * + * @author Peter Faulkner + */ + +class TrigT1CaloDataAccess : virtual public ITrigT1CaloDataAccess, + public AthAlgTool, virtual public IIncidentListener { + + public: + TrigT1CaloDataAccess(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~TrigT1CaloDataAccess(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Return iterators to required trigger towers + virtual StatusCode loadCollection( + DataVector<LVL1::TriggerTower>::const_iterator& beg, + DataVector<LVL1::TriggerTower>::const_iterator& end, + double etaMin, double etaMax, + double phiMin, double phiMax,const bool full); + + virtual StatusCode loadCollection( + DataVector<LVL1::JetElement>::const_iterator& beg, + DataVector<LVL1::JetElement>::const_iterator& end); + + /** handle to init a new event */ + void handle (const Incident& ); + + private: + + /// Data fetching service + ServiceHandle<IROBDataProviderSvc> m_robDataProvider; + /// Tool for selections + ToolHandle<LVL1BS::ITriggerTowerSelectionTool> m_selectionTool; + /// Tool for bytestream conversion + ToolHandle<LVL1BS::IPpmByteStreamSubsetTool> m_ppmBSConverter; + /// Tool for Jep bytestream conversion + ToolHandle<LVL1BS::JepByteStreamV2Tool> m_JetConverter; + + /// ROB fragment pointers + std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> m_robFrags; + /// Current TriggerTower sub-collection + DataVector<LVL1::TriggerTower>* m_ttCol; + /// Current JetElements sub-collection + DataVector<LVL1::JetElement>* m_jetCol; + // save loads of memory for re-use + // Get PPM sub-block channel IDs for wanted TriggerTowers + std::vector<unsigned int> m_chanIds; + // Get ROB IDs for wanted TriggerTowers + std::vector<uint32_t> m_robs; + // Get PPM sub-block channel IDs for wanted TriggerTowers + std::vector<unsigned int> m_chanIds_full; + // Get ROB IDs for wanted TriggerTowers + std::vector<uint32_t> m_robs_full; + // Get ROB IDs for wanted JetElements + std::vector<uint32_t> m_robs_full_je; + // First time full runs, we should cache everything + bool m_first; + // Help caching + unsigned int m_lC_Jet; + // Present Event Number + unsigned int m_present_event; + + + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/TriggerTowerSelectionTool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/TriggerTowerSelectionTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..57d0d0b9abd3055a34a1c930572052201efc7b71 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/TriggerTowerSelectionTool.cxx @@ -0,0 +1,156 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cmath> +#include <set> + +#include "eformat/SourceIdentifier.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "L1CaloSrcIdMap.h" + +#include "TriggerTowerSelectionTool.h" + +namespace LVL1BS { + +TriggerTowerSelectionTool::TriggerTowerSelectionTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool(type, name, parent), + m_mappingTool("LVL1::PpmMappingTool/PpmMappingTool"), + m_srcIdMap(0) +{ + declareInterface<ITriggerTowerSelectionTool>(this); + + declareProperty("PpmMappingTool", m_mappingTool); + + // Initialise m_etaBins + double base = -4.9; + const double width = 0.425; + const double offset1 = width/2.; + for (int i = 0; i < 4; ++i) { + m_etaBins.push_back(base + double(i)*width + offset1); + } + m_etaBins.push_back(-3.15); + m_etaBins.push_back(-3.0); + m_etaBins.push_back(-2.8); + m_etaBins.push_back(-2.6); + const double offset2 = 0.05; + for (int i = -25; i < 25; ++i) { + m_etaBins.push_back(double(i)/10. + offset2); + } + m_etaBins.push_back(2.6); + m_etaBins.push_back(2.8); + m_etaBins.push_back(3.0); + m_etaBins.push_back(3.15); + base = 3.2; + for (int i = 0; i < 4; ++i) { + m_etaBins.push_back(base + double(i)*width + offset1); + } +} + +TriggerTowerSelectionTool::~TriggerTowerSelectionTool() +{ +} + +// Initialisation + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode TriggerTowerSelectionTool::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << PACKAGE_VERSION << endreq; + + // Retrieve mapping tool + + StatusCode sc = m_mappingTool.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_mappingTool << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_mappingTool << endreq; + + m_srcIdMap = new L1CaloSrcIdMap(); + + return StatusCode::SUCCESS; +} + +StatusCode TriggerTowerSelectionTool::finalize() +{ + delete m_srcIdMap; + + return StatusCode::SUCCESS; +} + +// Return a list of TT channel IDs for given eta/phi range + +void TriggerTowerSelectionTool::channelIDs(const double etaMin, + const double etaMax, + const double phiMin, + const double phiMax, + std::vector<unsigned int>& chanIds) +{ + std::set<unsigned int> chanSet; + std::vector<double>::const_iterator etaPos = m_etaBins.begin(); + std::vector<double>::const_iterator etaPosE = m_etaBins.end(); + for (; etaPos != etaPosE; ++etaPos) { + const double eta = *etaPos; + if (eta < etaMin) continue; + if (eta > etaMax) break; + const double absEta = (eta < 0.) ? -eta : eta; + const int phiBins = (absEta > 3.2) ? 16 : (absEta > 2.5) ? 32 : 64; + const double phiGran = 2.*M_PI/phiBins; + for (int bin = 0; bin < phiBins; ++bin) { + const double phi = phiGran*(double(bin) + 0.5); + if (phi < phiMin) continue; + if (phi > phiMax) break; + int crate, module, channel; + m_mappingTool->mapping(eta, phi, 0, crate, module, channel); + unsigned int id = (crate * 16 + module) * 64 + channel; + chanSet.insert(id); + m_mappingTool->mapping(eta, phi, 1, crate, module, channel); + id = (crate * 16 + module) * 64 + channel; + chanSet.insert(id); + } + } + std::set<unsigned int>::const_iterator setPos = chanSet.begin(); + std::set<unsigned int>::const_iterator setPosE = chanSet.end(); + for (; setPos != setPosE; ++setPos) chanIds.push_back(*setPos); +} + +// Return a list of ROB IDs for given list of TT channel IDs + +void TriggerTowerSelectionTool::robIDs(const std::vector<unsigned int>& chanIds, + std::vector<uint32_t>& robs) +{ + const int channels = 64; + const int modules = 16; + const int slinks = 4; + const int daqOrRoi = 0; + std::set<uint32_t> robSet; + std::vector<unsigned int>::const_iterator pos = chanIds.begin(); + std::vector<unsigned int>::const_iterator posE = chanIds.end(); + for (; pos != posE; ++pos) { + const int chanId = *pos; + const int crate = chanId / (channels * modules); + const int module = (chanId / channels) % modules; + const int slink = module / slinks; + const uint32_t rodId = m_srcIdMap->getRodID(crate, slink, daqOrRoi, + eformat::TDAQ_CALO_PREPROC); + const uint32_t robId = m_srcIdMap->getRobID(rodId); + robSet.insert(robId); + } + std::set<uint32_t>::const_iterator setPos = robSet.begin(); + std::set<uint32_t>::const_iterator setPosE = robSet.end(); + for (; setPos != setPosE; ++setPos) robs.push_back(*setPos); +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/TriggerTowerSelectionTool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/TriggerTowerSelectionTool.h new file mode 100644 index 0000000000000000000000000000000000000000..e8ca8151b0d547d1d21895eded4bbd28aa74099d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/TriggerTowerSelectionTool.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_TRIGGERTOWERSELECTIONTOOL_H +#define TRIGT1CALOBYTESTREAM_TRIGGERTOWERSELECTIONTOOL_H + +#include <stdint.h> +#include <vector> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" + +#include "ITriggerTowerSelectionTool.h" + +class IInterface; +class StatusCode; + +namespace LVL1 { + class IL1CaloMappingTool; +} + +namespace LVL1BS { + +class L1CaloSrcIdMap; + +/** TriggerTower subset selection for bytestream. + * + * @author Peter Faulkner + */ + +class TriggerTowerSelectionTool : virtual public ITriggerTowerSelectionTool, + public AthAlgTool { + + public: + + TriggerTowerSelectionTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~TriggerTowerSelectionTool(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + /// Return a list of TT channel IDs for given eta/phi range + virtual void channelIDs(double etaMin, double etaMax, + double phiMin, double phiMax, + std::vector<unsigned int>& chanIds); + /// Return a list of ROB IDs for given list of TT channel IDs + virtual void robIDs(const std::vector<unsigned int>& chanIds, + std::vector<uint32_t>& robs); + + private: + + /// Tool for mappings + ToolHandle<LVL1::IL1CaloMappingTool> m_mappingTool; + /// Source ID converter + L1CaloSrcIdMap* m_srcIdMap; + /// TT eta bins + std::vector<double> m_etaBins; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/components/TrigT1CaloByteStream_entries.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/components/TrigT1CaloByteStream_entries.cxx new file mode 100755 index 0000000000000000000000000000000000000000..a77649f788ff4793fd633564e97870d91d76e703 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/components/TrigT1CaloByteStream_entries.cxx @@ -0,0 +1,215 @@ + +#include "DataModel/DataVector.h" +#include "GaudiKernel/DeclareFactoryEntries.h" + +// Post-LS1 +#include "TrigT1CaloEvent/CMXCPTob.h" +#include "TrigT1CaloEvent/CMXCPHits.h" +#include "TrigT1CaloEvent/CMXEtSums.h" +#include "TrigT1CaloEvent/CMXJetTob.h" +#include "TrigT1CaloEvent/CMXJetHits.h" +#include "TrigT1CaloEvent/CMXRoI.h" +#include "TrigT1CaloEvent/JEMTobRoI.h" +// Pre-LS1 +#include "TrigT1CaloEvent/CPMHits.h" +#include "TrigT1CaloEvent/CMMCPHits.h" +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMRoI.h" +#include "TrigT1CaloEvent/JEMHits.h" +#include "TrigT1CaloEvent/JEMRoI.h" +// Both +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JetElement.h" + +// Post-LS1 +#include "../CpByteStreamV2Cnv.h" +#include "../CpmRoiByteStreamV2Cnv.h" +#include "../CpReadByteStreamV2Cnv.h" +#include "../JepByteStreamV2Cnv.h" +#include "../JepReadByteStreamV2Cnv.h" +#include "../JepRoiByteStreamV2Cnv.h" +#include "../JepRoiReadByteStreamV2Cnv.h" +// Pre-LS1 +#include "../CpByteStreamV1Cnv.h" +#include "../CpmRoiByteStreamV1Cnv.h" +#include "../CpReadByteStreamV1Cnv.h" +#include "../JepByteStreamV1Cnv.h" +#include "../JepReadByteStreamV1Cnv.h" +#include "../JepRoiByteStreamV1Cnv.h" +#include "../JepRoiReadByteStreamV1Cnv.h" +// Both +#include "../CpReadByteStreamV1V2Cnv.h" +#include "../JepReadByteStreamV1V2Cnv.h" +#include "../PpmByteStreamCnv.h" +#include "../RodHeaderByteStreamCnv.h" +#include "../L1CaloErrorByteStreamCnv.h" + +// Post-LS1 +#include "../CpByteStreamV2Tool.h" +#include "../CpmRoiByteStreamV2Tool.h" +#include "../JepByteStreamV2Tool.h" +#include "../JepRoiByteStreamV2Tool.h" +// Pre-LS1 +#include "../CpByteStreamV1Tool.h" +#include "../CpmRoiByteStreamV1Tool.h" +#include "../JepByteStreamV1Tool.h" +#include "../JepRoiByteStreamV1Tool.h" +// Both +#include "../PpmByteStreamTool.h" +#include "../RodHeaderByteStreamTool.h" +#include "../L1CaloErrorByteStreamTool.h" + +#include "../PpmByteStreamSubsetTool.h" +#include "../TriggerTowerSelectionTool.h" +#include "../TrigT1CaloDataAccess.h" + +namespace LVL1BS { + +// Post-LS1 +typedef DataVector<LVL1::CMXCPTob> CMXCPTobCollection; +typedef DataVector<LVL1::CMXCPHits> CMXCPHitsCollection; +typedef DataVector<LVL1::CMXJetTob> CMXJetTobCollection; +typedef DataVector<LVL1::CMXJetHits> CMXJetHitsCollection; +typedef DataVector<LVL1::CMXEtSums> CMXEtSumsCollection; +typedef DataVector<LVL1::JEMTobRoI> JEMTobRoICollection; +// Pre-LS1 +typedef DataVector<LVL1::CPMHits> CPMHitsCollection; +typedef DataVector<LVL1::CMMCPHits> CMMCPHitsCollection; +typedef DataVector<LVL1::CMMJetHits> CMMJetHitsCollection; +typedef DataVector<LVL1::CMMEtSums> CMMEtSumsCollection; +typedef DataVector<LVL1::JEMHits> JEMHitsCollection; +typedef DataVector<LVL1::JEMRoI> JEMRoICollection; +// Both +typedef DataVector<LVL1::CPMTower> CPMTowerCollection; +typedef DataVector<LVL1::JetElement> JetElementCollection; +typedef DataVector<LVL1::JEMEtSums> JEMEtSumsCollection; + +// Post-LS1 +typedef CpReadByteStreamV2Cnv<CMXCPTobCollection> CpReadCRByteStreamV2CnvT; +typedef CpReadByteStreamV2Cnv<CMXCPHitsCollection> CpReadCCByteStreamV2CnvT; +typedef JepReadByteStreamV2Cnv<CMXJetTobCollection> JepReadCTByteStreamV2CnvT; +typedef JepReadByteStreamV2Cnv<CMXJetHitsCollection> JepReadCJByteStreamV2CnvT; +typedef JepReadByteStreamV2Cnv<CMXEtSumsCollection> JepReadCEByteStreamV2CnvT; +typedef JepRoiReadByteStreamV2Cnv<JEMTobRoICollection> JepRoiReadJRByteStreamV2CnvT; +typedef JepRoiReadByteStreamV2Cnv<LVL1::CMXRoI> JepRoiReadCRByteStreamV2CnvT; +// Pre-LS1 +typedef CpReadByteStreamV1Cnv<CPMHitsCollection> CpReadCHByteStreamV1CnvT; +typedef CpReadByteStreamV1Cnv<CMMCPHitsCollection> CpReadCCByteStreamV1CnvT; +typedef JepReadByteStreamV1Cnv<CMMJetHitsCollection> JepReadCJByteStreamV1CnvT; +typedef JepReadByteStreamV1Cnv<CMMEtSumsCollection> JepReadCEByteStreamV1CnvT; +typedef JepReadByteStreamV1Cnv<JEMHitsCollection> JepReadJHByteStreamV1CnvT; +typedef JepRoiReadByteStreamV1Cnv<JEMRoICollection> JepRoiReadJRByteStreamV1CnvT; +typedef JepRoiReadByteStreamV1Cnv<LVL1::CMMRoI> JepRoiReadCRByteStreamV1CnvT; +// Both +typedef JepReadByteStreamV1V2Cnv<JetElementCollection> JepReadJEByteStreamV1V2CnvT; +typedef JepReadByteStreamV1V2Cnv<JEMEtSumsCollection> JepReadESByteStreamV1V2CnvT; +} + +// declare +// Post-LS1 +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpmRoiByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCRByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCCByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCTByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCJByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCEByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadJRByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadCRByteStreamV2CnvT ) +// Pre-LS1 +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpmRoiByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCHByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCCByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCJByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCEByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadJHByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadJRByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadCRByteStreamV1CnvT ) +// Both +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadByteStreamV1V2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadJEByteStreamV1V2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadESByteStreamV1V2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, PpmByteStreamCnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, RodHeaderByteStreamCnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, L1CaloErrorByteStreamCnv ) + +// Post-LS1 +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpByteStreamV2Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpmRoiByteStreamV2Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepByteStreamV2Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepRoiByteStreamV2Tool ) +// Pre-LS1 +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpByteStreamV1Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpmRoiByteStreamV1Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepByteStreamV1Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepRoiByteStreamV1Tool ) +// Both +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, PpmByteStreamTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, RodHeaderByteStreamTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, L1CaloErrorByteStreamTool ) + +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, PpmByteStreamSubsetTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, TriggerTowerSelectionTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, TrigT1CaloDataAccess ) + +DECLARE_FACTORY_ENTRIES( TrigT1CaloByteStream ) +{ + // Post-LS1 + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpmRoiByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCRByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCCByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCTByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCJByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCEByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadJRByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadCRByteStreamV2CnvT ) + // Pre-LS1 + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpmRoiByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCHByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCCByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCJByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCEByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadJHByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadJRByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadCRByteStreamV1CnvT ) + // Both + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadByteStreamV1V2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadJEByteStreamV1V2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadESByteStreamV1V2CnvT ) + // Both + DECLARE_NAMESPACE_CONVERTER( LVL1BS, PpmByteStreamCnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, RodHeaderByteStreamCnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, L1CaloErrorByteStreamCnv ) + + // Post-LS1 + DECLARE_NAMESPACE_TOOL( LVL1BS, CpByteStreamV2Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, CpmRoiByteStreamV2Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepByteStreamV2Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepRoiByteStreamV2Tool ) + // Pre-LS1 + DECLARE_NAMESPACE_TOOL( LVL1BS, CpByteStreamV1Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, CpmRoiByteStreamV1Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepByteStreamV1Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepRoiByteStreamV1Tool ) + // Both + DECLARE_NAMESPACE_TOOL( LVL1BS, PpmByteStreamTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, RodHeaderByteStreamTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, L1CaloErrorByteStreamTool ) + + DECLARE_NAMESPACE_TOOL( LVL1BS, PpmByteStreamSubsetTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, TriggerTowerSelectionTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, TrigT1CaloDataAccess ) +} diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/components/TrigT1CaloByteStream_load.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/components/TrigT1CaloByteStream_load.cxx new file mode 100755 index 0000000000000000000000000000000000000000..f713087d5d67558f722ea8b708eaa09389bc6958 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/components/TrigT1CaloByteStream_load.cxx @@ -0,0 +1,5 @@ + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(TrigT1CaloByteStream) + diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmErrors.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmErrors.cxx new file mode 100755 index 0000000000000000000000000000000000000000..9e6f65544d37cffc604dfee4a51047206597a290 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmErrors.cxx @@ -0,0 +1,483 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ISvcLocator.h" +#include "StoreGate/StoreGateSvc.h" +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventID.h" + +#include "TrigT1CaloEvent/CMXCPTob.h" +#include "TrigT1CaloEvent/CMXCPHits.h" +#include "TrigT1CaloEvent/CPMTobRoI.h" +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloUtils/CoordToHardware.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1Interfaces/Coordinate.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "CpmErrors.h" + +namespace LVL1BS { + +CpmErrors::CpmErrors(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_doneThisEvent(false), + m_doneEmParity(false), + m_doneHadParity(false), + m_doneEmLinkDown(false), + m_doneHadLinkDown(false), + m_doneEmReadoutA(false), + m_doneEmReadoutB(false), + m_doneEmReadoutC(false), + m_doneHadReadoutA(false), + m_doneHadReadoutB(false), + m_doneHadReadoutC(false), + m_doneCmxTobParityM(false), + m_doneCmxTobParity0(false), + m_doneCmxTobParity1(false), + m_doneCmxTobParity2(false), + m_doneCmxTobParity3(false), + m_doneTobEnReadoutA(false), + m_doneTobEnReadoutB(false), + m_doneTobEnReadoutC(false), + m_doneTobIsReadoutA(false), + m_doneTobIsReadoutB(false), + m_doneTobIsReadoutC(false), + m_doneCmxHitsParity0(false), + m_doneCmxHitsParity1(false) + +{ + declareProperty("CPMTowerLocation", + m_cpmTowerLocation = LVL1::TrigT1CaloDefs::CPMTowerLocation); + declareProperty("CMXCPTobLocation", + m_cmxCpTobLocation = LVL1::TrigT1CaloDefs::CMXCPTobLocation); + declareProperty("CMXCPHitsLocation", + m_cmxCpHitsLocation = LVL1::TrigT1CaloDefs::CMXCPHitsLocation); + declareProperty("CPMTobRoILocation", + m_cpmTobRoiLocation = LVL1::TrigT1CaloDefs::CPMTobRoILocation); + declareProperty("CPMTowerLocationOut", + m_cpmTowerLocationOut = LVL1::TrigT1CaloDefs::CPMTowerLocation+"Errors"); + declareProperty("CMXCPTobLocationOut", + m_cmxCpTobLocationOut = LVL1::TrigT1CaloDefs::CMXCPTobLocation+"Errors"); + declareProperty("CMXCPHitsLocationOut", + m_cmxCpHitsLocationOut = LVL1::TrigT1CaloDefs::CMXCPHitsLocation+"Errors"); + declareProperty("CPMTobRoILocationOut", + m_cpmTobRoiLocationOut = LVL1::TrigT1CaloDefs::CPMTobRoILocation+"Errors"); + + declareProperty("CPMTowerErrors", m_cpmTowerErrors = 0xffff); + declareProperty("CMXCPTobErrors", m_cmxTobErrors = 0xffff); + declareProperty("CMXCPHitsErrors", m_cmxHitsErrors = 0xffff); + declareProperty("CPMTobRoIErrors", m_cpmTobRoiErrors = 0xffff); + +} + +CpmErrors::~CpmErrors() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmErrors::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + // Initialise individual error flags + + m_doneEmParity = ((m_cpmTowerErrors&Error1) == 0); + m_doneHadParity = ((m_cpmTowerErrors&Error2) == 0); + m_doneEmLinkDown = ((m_cpmTowerErrors&Error3) == 0); + m_doneHadLinkDown = ((m_cpmTowerErrors&Error4) == 0); + m_doneEmReadoutA = ((m_cpmTowerErrors&Error5) == 0); + m_doneEmReadoutB = ((m_cpmTowerErrors&Error6) == 0); + m_doneEmReadoutC = ((m_cpmTowerErrors&Error7) == 0); + m_doneHadReadoutA = ((m_cpmTowerErrors&Error8) == 0); + m_doneHadReadoutB = ((m_cpmTowerErrors&Error9) == 0); + m_doneHadReadoutC = ((m_cpmTowerErrors&Error10) == 0); + m_doneCpmSubStatus = ((m_cpmTowerErrors&Error11) == 0); + + m_doneCmxTobParityM = ((m_cmxTobErrors&Error1) == 0); + m_doneCmxTobParity0 = ((m_cmxTobErrors&Error2) == 0); + m_doneCmxTobParity1 = ((m_cmxTobErrors&Error3) == 0); + m_doneCmxTobParity2 = ((m_cmxTobErrors&Error4) == 0); + m_doneCmxTobParity3 = ((m_cmxTobErrors&Error5) == 0); + m_doneTobEnReadoutA = ((m_cmxTobErrors&Error6) == 0); + m_doneTobEnReadoutB = ((m_cmxTobErrors&Error7) == 0); + m_doneTobEnReadoutC = ((m_cmxTobErrors&Error8) == 0); + m_doneTobIsReadoutA = ((m_cmxTobErrors&Error9) == 0); + m_doneTobIsReadoutB = ((m_cmxTobErrors&Error10) == 0); + m_doneTobIsReadoutC = ((m_cmxTobErrors&Error11) == 0); + + m_doneCmxHitsParity0 = ((m_cmxHitsErrors&Error1) == 0); + m_doneCmxHitsParity1 = ((m_cmxHitsErrors&Error2) == 0); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode CpmErrors::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + m_doneThisEvent = false; + + if (m_cpmTowerErrors) { + + // Find CPM towers + + const CpmTowerCollection* cpCollection = 0; + StatusCode sc = evtStore()->retrieve(cpCollection, m_cpmTowerLocation); + if (sc.isFailure() || !cpCollection || cpCollection->empty()) { + msg() << "No CP Elements found" << endreq; + cpCollection = 0; + } + + // Generate CPM tower errors + + CpmTowerCollection* errCollection = new CpmTowerCollection; + if (cpCollection) { + cpmTowerErrors(cpCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_cpmTowerLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CPMTower container in TDS " << endreq; + return sc; + } + } + + if (m_cmxTobErrors) { + + // Find CMX TOBs + + const CmxCpTobCollection* tobCollection = 0; + StatusCode sc = evtStore()->retrieve(tobCollection, m_cmxCpTobLocation); + if (sc.isFailure() || !tobCollection || tobCollection->empty()) { + msg() << "No CMX TOBs found" << endreq; + tobCollection = 0; + } + + // Generate CMX TOB errors + + CmxCpTobCollection* errCollection = new CmxCpTobCollection; + if (tobCollection) { + cmxTobErrors(tobCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_cmxCpTobLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CMXCPTob container in TDS " << endreq; + return sc; + } + } + + if (m_cmxHitsErrors) { + + // Find CMX hits + + const CmxCpHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmxCpHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMX Hits found" << endreq; + hitCollection = 0; + } + + // Generate CMX Hits errors + + CmxCpHitsCollection* errCollection = new CmxCpHitsCollection; + if (hitCollection) { + cmxHitsErrors(hitCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_cmxCpHitsLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CMXCPHits container in TDS " << endreq; + return sc; + } + } +/* + if (m_cpmTobRoiErrors) { + + // Find CPM TOB RoIs + + const CpmTobRoiCollection* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cpmTobRoiLocation); + if (sc.isFailure() || !jcCollection || crCollection->empty()) { + msg() << "No CPM TOB RoIs found" << endreq; + crCollection = 0; + } + + // Generate CPM RoI errors + + CpmTobRoiCollection* errCollection = new CpmTobRoiCollection; + if (crCollection) { + cpmTobRoiErrors(crCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_cpmTobRoiLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CPMTobRoI container in TDS " << endreq; + return sc; + } + } +*/ + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpmErrors::finalize() +{ + return StatusCode::SUCCESS; +} + +// Generate CPMTower errors + +void CpmErrors::cpmTowerErrors(const CpmTowerCollection* cpCollection, + CpmTowerCollection* errCollection) +{ + LVL1::CoordToHardware converter; + CpmTowerCollection::const_iterator iter = cpCollection->begin(); + CpmTowerCollection::const_iterator iterEnd = cpCollection->end(); + for (; iter != iterEnd; ++iter) { + const LVL1::CPMTower* const cp = *iter; + const double eta = cp->eta(); + const double phi = cp->phi(); + const LVL1::Coordinate coord(phi, eta); + const bool overlap = (converter.cpCrateOverlap(coord) <= 3); + const int peak = cp->peak(); + std::vector<int> emEnergy(cp->emEnergyVec()); + std::vector<int> hadEnergy(cp->hadEnergyVec()); + std::vector<int> emError(cp->emErrorVec()); + std::vector<int> hadError(cp->hadErrorVec()); + if (!m_doneThisEvent && !overlap) { + std::string errorType = ""; + if (!m_doneEmParity) { + emError[peak] |= (1 << LVL1::DataError::Parity); + errorType = "EM Parity"; + m_doneEmParity = true; + } else if (!m_doneHadParity) { + hadError[peak] |= (1 << LVL1::DataError::Parity); + errorType = "Had Parity"; + m_doneHadParity = true; + } else if (!m_doneEmLinkDown) { + emError[peak] |= (1 << LVL1::DataError::LinkDown); + errorType = "EM Link Down"; + m_doneEmLinkDown = true; + } else if (!m_doneHadLinkDown) { + hadError[peak] |= (1 << LVL1::DataError::LinkDown); + errorType = "Had Link Down"; + m_doneHadLinkDown = true; + } else if (!m_doneEmReadoutA && emEnergy[peak] != 0 && + emEnergy[peak] < (s_saturation-1)) { + emEnergy[peak] += 1; + errorType = "EM readout non-zero mismatch"; + m_doneEmReadoutA = true; + } else if (!m_doneEmReadoutB && emEnergy[peak] == 0) { + emEnergy[peak] = 1; + errorType = "EM readout sim zero mismatch"; + m_doneEmReadoutB = true; + } else if (!m_doneEmReadoutC && emEnergy[peak] != 0 && + hadEnergy[peak] != 0) { + emEnergy[peak] = 0; + errorType = "EM readout data zero mismatch"; + m_doneEmReadoutC = true; + } else if (!m_doneHadReadoutA && hadEnergy[peak] != 0 && + hadEnergy[peak] < (s_saturation-1)) { + hadEnergy[peak] += 1; + errorType = "Had readout non-zero mismatch"; + m_doneHadReadoutA = true; + } else if (!m_doneHadReadoutB && hadEnergy[peak] == 0) { + hadEnergy[peak] = 1; + errorType = "Had readout sim zero mismatch"; + m_doneHadReadoutB = true; + } else if (!m_doneHadReadoutC && hadEnergy[peak] != 0 && + emEnergy[peak] != 0) { + hadEnergy[peak] = 0; + errorType = "Had readout data zero mismatch"; + m_doneHadReadoutC = true; + } else if (!m_doneCpmSubStatus) { + emError[peak] |= (1 << LVL1::DataError::BCNMismatch); + hadError[peak] |= (1 << LVL1::DataError::BCNMismatch); + errorType = "SubStatus"; + m_doneCpmSubStatus = true; + } + if (errorType != "") { + errorMessage("CPMTowers " + errorType); + m_doneThisEvent = true; + } + } + LVL1::CPMTower* err = new LVL1::CPMTower(phi, eta, emEnergy, emError, + hadEnergy, hadError, peak); + errCollection->push_back(err); + } +} + +// Generate CMXCPTob errors + +void CpmErrors::cmxTobErrors(const CmxCpTobCollection* tobCollection, + CmxCpTobCollection* errCollection) +{ + CmxCpTobCollection::const_iterator iter = tobCollection->begin(); + CmxCpTobCollection::const_iterator iterEnd = tobCollection->end(); + for (; iter != iterEnd; ++iter) { + const LVL1::CMXCPTob* const tob = *iter; + const int crate = tob->crate(); + const int cmx = tob->cmx(); + const int cpm = tob->cpm(); + int chip = tob->chip(); + int loc = tob->location(); + const int peak = tob->peak(); + std::vector<int> energy(tob->energyVec()); + std::vector<int> isolation(tob->isolationVec()); + std::vector<int> error(tob->errorVec()); + std::vector<unsigned int> presence(tob->presenceMapVec()); + if (!m_doneThisEvent) { + std::string errorType = ""; + if (!m_doneCmxTobParityM && chip != 0) { + // NB. Changes real data path + error[peak] |= (1 << LVL1::DataError::ParityMerge); + chip = 0; + loc = 0; + energy[peak] = 0; + isolation[peak] = 0; + errorType = "CMX-CP TOB Parity Merge"; + m_doneCmxTobParityM = true; + } else if (!m_doneCmxTobParity0) { + error[peak] |= (1 << LVL1::DataError::ParityPhase0); + errorType = "CMX-CP TOB Parity Phase 0"; + m_doneCmxTobParity0 = true; + } else if (!m_doneCmxTobParity1) { + error[peak] |= (1 << LVL1::DataError::ParityPhase1); + errorType = "CMX-CP TOB Parity Phase 1"; + m_doneCmxTobParity1 = true; + } else if (!m_doneCmxTobParity2) { + error[peak] |= (1 << LVL1::DataError::ParityPhase2); + errorType = "CMX-CP TOB Parity Phase 2"; + m_doneCmxTobParity2 = true; + } else if (!m_doneCmxTobParity3) { + error[peak] |= (1 << LVL1::DataError::ParityPhase3); + errorType = "CMX-CP TOB Parity Phase 3"; + m_doneCmxTobParity3 = true; + } else if (!m_doneTobEnReadoutA && energy[peak] != 0) { + energy[peak] += 1; + errorType = "CMX-CP TOB Energy readout non-zero mismatch"; + m_doneTobEnReadoutA = true; + } else if (!m_doneTobEnReadoutB && energy[peak] == 0) { // never happen? + energy[peak] = 1; + errorType = "CMX-CP TOB Energy readout sim zero mismatch"; + m_doneTobEnReadoutB = true; + } else if (!m_doneTobEnReadoutC && energy[peak] != 0) { + energy[peak] = 0; + errorType = "CMX-CP TOB Energy readout data zero mismatch"; + m_doneTobEnReadoutC = true; + } else if (!m_doneTobIsReadoutA && isolation[peak] != 0) { + isolation[peak] += 1; + errorType = "CMX-CP TOB Isolation readout non-zero mismatch"; + m_doneTobIsReadoutA = true; + } else if (!m_doneTobIsReadoutB && isolation[peak] == 0) { + isolation[peak] = 1; + errorType = "CMX-CP TOB Isolation readout sim zero mismatch"; + m_doneTobIsReadoutB = true; + } else if (!m_doneTobIsReadoutC && isolation[peak] != 0) { + isolation[peak] = 0; + errorType = "CMX-CP TOB Isolation readout data zero mismatch"; + m_doneTobIsReadoutC = true; + } + if (errorType != "") { + errorMessage("CMXCPTob " + errorType); + m_doneThisEvent = true; + } + } + LVL1::CMXCPTob* err = new LVL1::CMXCPTob(crate, cmx, cpm, chip, loc, + energy, isolation, error, + presence, peak); + errCollection->push_back(err); + } +} + +// Generate CMXCPHits errors + +void CpmErrors::cmxHitsErrors(const CmxCpHitsCollection* hitCollection, + CmxCpHitsCollection* errCollection) +{ + CmxCpHitsCollection::const_iterator iter = hitCollection->begin(); + CmxCpHitsCollection::const_iterator iterEnd = hitCollection->end(); + for (; iter != iterEnd; ++iter) { + const LVL1::CMXCPHits* const hits = *iter; + const int crate = hits->crate(); + const int cmx = hits->cmx(); + const int source = hits->source(); + const int peak = hits->peak(); + std::vector<unsigned int> hits0(hits->hitsVec0()); + std::vector<unsigned int> hits1(hits->hitsVec1()); + std::vector<int> error0(hits->errorVec0()); + std::vector<int> error1(hits->errorVec1()); + if (!m_doneThisEvent) { + std::string errorType = ""; + if (!m_doneCmxHitsParity0 && source == LVL1::CMXCPHits::REMOTE_0) { + error0[peak] |= (1 << LVL1::DataError::Parity); + errorType = "CMX-CP Hits Parity Phase 0"; + m_doneCmxHitsParity0 = true; + } else if (!m_doneCmxHitsParity1 && source == LVL1::CMXCPHits::REMOTE_2) { + error1[peak] |= (1 << LVL1::DataError::Parity); + errorType = "CMX-CP Hits Parity Phase 1"; + m_doneCmxHitsParity1 = true; + } + /* + * Add hit readout errors here + */ + if (errorType != "") { + errorMessage("CMXCPHits " + errorType); + m_doneThisEvent = true; + } + } + LVL1::CMXCPHits* err = new LVL1::CMXCPHits(crate, cmx, source, + hits0, hits1, error0, error1, + peak); + errCollection->push_back(err); + } +} + +// Generate CPM TOB RoI errors + +void CpmErrors::cpmTobRoiErrors(const CpmTobRoiCollection* /*crCollection*/, + CpmTobRoiCollection* /*errCollection*/) +{ +} + +// Print a message when error generated + +void CpmErrors::errorMessage(const std::string& errmsg) +{ + int eventNumber = 0; + const EventInfo* evInfo = 0; + StatusCode sc = evtStore()->retrieve(evInfo); + if (sc.isFailure()) { + msg(MSG::ERROR) << "No EventInfo found" << endreq; + } else { + const EventID* evID = evInfo->event_ID(); + if (evID) eventNumber = evID->event_number(); + } + msg(MSG::INFO) << "Event " << eventNumber + << " has error " << errmsg << endreq; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmErrors.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmErrors.h new file mode 100755 index 0000000000000000000000000000000000000000..07dad1749eb68bc3d7ebe13db56e2091d923c629 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmErrors.h @@ -0,0 +1,137 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMERRORS_H +#define TRIGT1CALOBYTESTREAM_CPMERRORS_H + +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CPMTower; + class CPMTobRoI; + class CMXCPTob; + class CMXCPHits; +} + +namespace LVL1BS { + +/** Algorithm to add errors to CPM data for testing bytestream converters + * and monitoring. + * + * NB. Doesn't pretent to be rigorous so read back data may not be identical + * to written (eg. SubStatus errors in single CPMTower on output will be in + * multiple CPMTowers on subsequent input, ie. all from the relevant sub-block). + * + * + * @author Peter Faulkner + */ + +class CpmErrors : public AthAlgorithm { + + public: + CpmErrors(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~CpmErrors(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + enum ErrorBits { Error1 = 0x1, Error2 = 0x2, Error3 = 0x4, Error4 = 0x8, + Error5 = 0x10, Error6 = 0x20, Error7 = 0x40, Error8 = 0x80, + Error9 = 0x100, Error10 = 0x200, Error11 = 0x400, + Error12 = 0x800, Error13 = 0x1000, Error14 = 0x2000, + Error15 = 0x4000, Error16 = 0x8000 }; + + typedef DataVector<LVL1::CPMTower> CpmTowerCollection; + typedef DataVector<LVL1::CMXCPTob> CmxCpTobCollection; + typedef DataVector<LVL1::CMXCPHits> CmxCpHitsCollection; + typedef DataVector<LVL1::CPMTobRoI> CpmTobRoiCollection; + + /// Generate CPMTowers errors + void cpmTowerErrors(const CpmTowerCollection* cpCollection, + CpmTowerCollection* errCollection); + /// Generate CMXCPTob errors + void cmxTobErrors(const CmxCpTobCollection* tobCollection, + CmxCpTobCollection* errCollection); + /// Generate CMXCPHits errors + void cmxHitsErrors(const CmxCpHitsCollection* hitCollection, + CmxCpHitsCollection* errCollection); + /// Generate CPM TOB RoI errors + void cpmTobRoiErrors(const CpmTobRoiCollection* crCollection, + CpmTobRoiCollection* errCollection); + + /// Print a message when error generated + void errorMessage(const std::string& msg); + + /// CP element container input StoreGate key + std::string m_cpmTowerLocation; + /// CMX TOB container input StoreGate key + std::string m_cmxCpTobLocation; + /// CMX hits container input StoreGate key + std::string m_cmxCpHitsLocation; + /// CPM TOB RoI container input StoreGate key + std::string m_cpmTobRoiLocation; + /// CP element container output StoreGate key + std::string m_cpmTowerLocationOut; + /// CMX TOB container output StoreGate key + std::string m_cmxCpTobLocationOut; + /// CMX hits container output StoreGate key + std::string m_cmxCpHitsLocationOut; + /// CPM TOB RoI container output StoreGate key + std::string m_cpmTobRoiLocationOut; + /// CPM towers errors flag + int m_cpmTowerErrors; + /// CMX TOB errors flag + int m_cmxTobErrors; + /// CMX hits errors flag + int m_cmxHitsErrors; + /// CPM TOB RoI errors flag + int m_cpmTobRoiErrors; + + /// Individual error done flags + bool m_doneThisEvent; + /// CPMTowers + bool m_doneEmParity; + bool m_doneHadParity; + bool m_doneEmLinkDown; + bool m_doneHadLinkDown; + bool m_doneEmReadoutA; + bool m_doneEmReadoutB; + bool m_doneEmReadoutC; + bool m_doneHadReadoutA; + bool m_doneHadReadoutB; + bool m_doneHadReadoutC; + bool m_doneCpmSubStatus; + /// CMXCPTob + bool m_doneCmxTobParityM; + bool m_doneCmxTobParity0; + bool m_doneCmxTobParity1; + bool m_doneCmxTobParity2; + bool m_doneCmxTobParity3; + bool m_doneTobEnReadoutA; + bool m_doneTobEnReadoutB; + bool m_doneTobEnReadoutC; + bool m_doneTobIsReadoutA; + bool m_doneTobIsReadoutB; + bool m_doneTobIsReadoutC; + /// CMXCPHits + bool m_doneCmxHitsParity0; + bool m_doneCmxHitsParity1; + /// CPMTobRoI + + static const int s_saturation = 255; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTester.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTester.cxx new file mode 100755 index 0000000000000000000000000000000000000000..c0f79adda93c626791302dd2bbdbcd6175352bb5 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTester.cxx @@ -0,0 +1,437 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <utility> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/CMMCPHits.h" +#include "TrigT1CaloEvent/CPMHits.h" +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/CPMRoI.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "CpmTester.h" +#include "../src/ModifySlices.h" + +namespace LVL1BS { + +CpmTester::CpmTester(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_towerKey(0) +{ + declareProperty("CPMTowerLocation", + m_cpmTowerLocation = LVL1::TrigT1CaloDefs::CPMTowerLocation); + declareProperty("CPMHitsLocation", + m_cpmHitsLocation = LVL1::TrigT1CaloDefs::CPMHitsLocation); + declareProperty("CMMCPHitsLocation", + m_cmmCpHitsLocation = LVL1::TrigT1CaloDefs::CMMCPHitsLocation); + declareProperty("CPMRoILocation", + m_cpmRoiLocation = LVL1::TrigT1CaloDefs::CPMRoILocation); + declareProperty("CPMRoILocationRoIB", + m_cpmRoiLocationRoib = + LVL1::TrigT1CaloDefs::CPMRoILocation + "RoIB"); + declareProperty("CPMTowerLocationOverlap", + m_cpmTowerLocationOverlap = + LVL1::TrigT1CaloDefs::CPMTowerLocation + "Overlap"); + + declareProperty("ForceSlicesCPM", m_forceSlicesCpm = 0); + declareProperty("ForceSlicesCMM", m_forceSlicesCmm = 0); + + // By default print everything except RoIB RoIs and Tower overlap + declareProperty("CPMTowerPrint", m_cpmTowerPrint = 1); + declareProperty("CPMHitsPrint", m_cpmHitsPrint = 1); + declareProperty("CMMCPHitsPrint", m_cmmCpHitsPrint = 1); + declareProperty("CPMRoIPrint", m_cpmRoiPrint = 1); + declareProperty("CPMRoIPrintRoIB", m_cpmRoiPrintRoib = 0); + declareProperty("CPMTowerPrintOverlap", m_cpmTowerPrintOverlap = 0); +} + +CpmTester::~CpmTester() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmTester::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + m_towerKey = new LVL1::TriggerTowerKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode CpmTester::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + if (m_cpmTowerPrint) { + + // Find CPM towers + + const CpmTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_cpmTowerLocation); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No core CPM towers found" << endreq; + } else { + + // Order by eta, phi + + setupCpmTowerMap(ttCollection); + + // Print the CPM towers + + printCpmTowers("core"); + } + } + + if (m_cpmTowerPrintOverlap) { + + // Find overlap CPM towers + + const CpmTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_cpmTowerLocationOverlap); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No overlap CPM towers found" << endreq; + } else { + + // Order by eta, phi + + setupCpmTowerMap(ttCollection); + + // Print the overlap CPM towers + + printCpmTowers("overlap"); + } + } + + if (m_cpmHitsPrint) { + + // Find CPM hits + + const CpmHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cpmHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CPM Hits found" << endreq; + } else { + + // Order by crate, module + + setupCpmHitsMap(hitCollection); + + // Print the CPM hits + + printCpmHits(); + } + } + + if (m_cmmCpHitsPrint) { + + // Find CMM-CP hits + + const CmmCpHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmmCpHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMM-CP Hits found" << endreq; + } else { + + // Order by crate, dataID + + setupCmmCpHitsMap(hitCollection); + + // Print the CMM-CP hits + + printCmmCpHits(); + } + } + + if (m_cpmRoiPrint) { + + // Find CPM RoIs + + const CpmRoiCollection* roiCollection = 0; + StatusCode sc = evtStore()->retrieve(roiCollection, m_cpmRoiLocation); + if (sc.isFailure() || !roiCollection || roiCollection->empty()) { + msg() << "No CPM RoIs found" << endreq; + } else { + + // Order by RoI word + + setupCpmRoiMap(roiCollection); + + // Print the CPM RoIs + + printCpmRois("DAQ"); + } + } + + if (m_cpmRoiPrintRoib) { + + // Find CPM RoIs from RoIB + + const CpmRoiCollection* roiCollection = 0; + StatusCode sc = evtStore()->retrieve(roiCollection, m_cpmRoiLocationRoib); + if (sc.isFailure() || !roiCollection || roiCollection->empty()) { + msg() << "No CPM RoIs from RoIB found" << endreq; + } else { + + // Order by RoI word + + setupCpmRoiMap(roiCollection); + + // Print the CPM RoIs from RoIB + + printCpmRois("RoIB"); + } + } + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpmTester::finalize() +{ + delete m_towerKey; + + return StatusCode::SUCCESS; +} + +// Print the CPM towers + +void CpmTester::printCpmTowers(const std::string& source) const +{ + msg() << "Number of " << source << " CPM towers = " + << m_ttMap.size() << endreq; + CpmTowerMap::const_iterator mapIter = m_ttMap.begin(); + CpmTowerMap::const_iterator mapEnd = m_ttMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMTower* const tt = mapIter->second; + int peak = tt->peak(); + int slices = (tt->emEnergyVec()).size(); + if (m_forceSlicesCpm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCpm); + slices = m_forceSlicesCpm; + } + msg() << "key/eta/phi/peak/em/had/emErr/hadErr: " + << mapIter->first << "/" << tt->eta() << "/" << tt->phi() << "/" + << peak << "/"; + + std::vector<int> emEnergy; + std::vector<int> hadEnergy; + std::vector<int> emError; + std::vector<int> hadError; + ModifySlices::data(tt->emEnergyVec(), emEnergy, slices); + ModifySlices::data(tt->hadEnergyVec(), hadEnergy, slices); + ModifySlices::data(tt->emErrorVec(), emError, slices); + ModifySlices::data(tt->hadErrorVec(), hadError, slices); + printVec(emEnergy); + printVec(hadEnergy); + msg() << MSG::hex; + printVec(emError); + printVec(hadError); + msg() << MSG::dec << endreq; + } +} + +// Print the CPM hits + +void CpmTester::printCpmHits() const +{ + msg() << "Number of CPM Hits = " << m_hitsMap.size() << endreq; + CpmHitsMap::const_iterator mapIter = m_hitsMap.begin(); + CpmHitsMap::const_iterator mapEnd = m_hitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMHits* const ch = mapIter->second; + int peak = ch->peak(); + int slices = (ch->HitsVec0()).size(); + if (m_forceSlicesCpm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCpm); + slices = m_forceSlicesCpm; + } + msg() << "crate/module/peak/hits0/hits1: " + << ch->crate() << "/" << ch->module() << "/" << peak << "/"; + + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + ModifySlices::data(ch->HitsVec0(), hits0, slices); + ModifySlices::data(ch->HitsVec1(), hits1, slices); + printVecH(hits0); + printVecH(hits1); + msg() << endreq; + } +} + +// Print the CMM-CP hits + +void CpmTester::printCmmCpHits() const +{ + msg() << "Number of CMM-CP Hits = " << m_cmmHitsMap.size() << endreq; + CmmCpHitsMap::const_iterator mapIter = m_cmmHitsMap.begin(); + CmmCpHitsMap::const_iterator mapEnd = m_cmmHitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMMCPHits* const ch = mapIter->second; + int peak = ch->peak(); + int slices = (ch->HitsVec0()).size(); + if (m_forceSlicesCmm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmm); + slices = m_forceSlicesCmm; + } + msg() << "crate/dataID/peak/hits0/hits1/err0/err1: " + << ch->crate() << "/" << ch->dataID() << "/" << peak << "/"; + + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + std::vector<int> err0; + std::vector<int> err1; + ModifySlices::data(ch->HitsVec0(), hits0, slices); + ModifySlices::data(ch->HitsVec1(), hits1, slices); + ModifySlices::data(ch->ErrorVec0(), err0, slices); + ModifySlices::data(ch->ErrorVec1(), err1, slices); + printVecH(hits0); + printVecH(hits1); + msg() << MSG::hex; + printVec(err0); + printVec(err1); + msg() << MSG::dec << endreq; + } +} + +// Print the CPM RoIs + +void CpmTester::printCpmRois(const std::string& source) const +{ + msg() << "Number of CPM RoIs (" << source << ") = " << m_roiMap.size() + << endreq; + CpmRoiMap::const_iterator mapIter = m_roiMap.begin(); + CpmRoiMap::const_iterator mapEnd = m_roiMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMRoI* const roi = mapIter->second; + msg() << "crate/cpm/chip/loc/hits/error: " + << roi->crate() << "/" << roi->cpm() << "/" << roi->chip() << "/" + << roi->location() << "/"; + int hits = roi->hits(); + for (int i = 0; i < 16; ++i) { + if (i == 8) msg() << ";"; + else if (i > 0) msg() << ":"; + msg() << ((hits >> i) & 0x1); + } + msg() << "/" << roi->error() << "/" << endreq; + } +} + +// Print a vector + +void CpmTester::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Print a vector of hits + +void CpmTester::printVecH(const std::vector<unsigned int>& vec) const +{ + const int words = 8; + const int bits = 3; + const unsigned int mask = 0x7; + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = vec.begin(); + std::vector<unsigned int>::const_iterator pose = vec.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> (bits*i)) & mask; + msg() << thr; + } + } + msg() << "/"; +} + +// Set up CPM tower map + +void CpmTester::setupCpmTowerMap(const CpmTowerCollection* const ttCollection) +{ + m_ttMap.clear(); + if (ttCollection) { + CpmTowerCollection::const_iterator pos = ttCollection->begin(); + CpmTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMTower* const tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + m_ttMap.insert(std::make_pair(key, tt)); + } + } +} + +// Set up CPM hits map + +void CpmTester::setupCpmHitsMap(const CpmHitsCollection* const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + CpmHitsCollection::const_iterator pos = hitCollection->begin(); + CpmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMHits* const hits = *pos; + const int key = hits->crate()*100 + hits->module() - 1; + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM-CP hits map + +void CpmTester::setupCmmCpHitsMap(const CmmCpHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmCpHitsCollection::const_iterator pos = hitCollection->begin(); + CmmCpHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMCPHits* const hits = *pos; + const int key = hits->crate()*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CPM RoI map + +void CpmTester::setupCpmRoiMap(const CpmRoiCollection* const roiCollection) +{ + m_roiMap.clear(); + if (roiCollection) { + CpmRoiCollection::const_iterator pos = roiCollection->begin(); + CpmRoiCollection::const_iterator pose = roiCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTester.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTester.h new file mode 100755 index 0000000000000000000000000000000000000000..0dd651e6e4420442564062df75549e250848d59d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTester.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMTESTER_H +#define TRIGT1CALOBYTESTREAM_CPMTESTER_H + +#include <map> +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CMMCPHits; + class CPMHits; + class CPMTower; + class CPMRoI; + class TriggerTowerKey; +} + +namespace LVL1BS { + +/** Algorithm to test CPM component bytestream conversions. + * + * Just prints out the contents of the CPMTower objects + * and CPMHits objects. + * Also includes CMMCPHits and CPMRoIs. + * + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class CpmTester : public AthAlgorithm { + + public: + CpmTester(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~CpmTester(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef DataVector<LVL1::CPMTower> CpmTowerCollection; + typedef DataVector<LVL1::CPMHits> CpmHitsCollection; + typedef DataVector<LVL1::CMMCPHits> CmmCpHitsCollection; + typedef DataVector<LVL1::CPMRoI> CpmRoiCollection; + typedef std::map<unsigned int, const LVL1::CPMTower*> CpmTowerMap; + typedef std::map<int, const LVL1::CPMHits*> CpmHitsMap; + typedef std::map<int, const LVL1::CMMCPHits*> CmmCpHitsMap; + typedef std::map<uint32_t, const LVL1::CPMRoI*> CpmRoiMap; + + /// Print the CPM towers + void printCpmTowers(const std::string& source) const; + /// Print the CPM hits + void printCpmHits() const; + /// Print the CMM-CP hits + void printCmmCpHits() const; + /// Print the CPM RoIs + void printCpmRois(const std::string& source) const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + /// Print a vector of hits + void printVecH(const std::vector<unsigned int>& vec) const; + + /// Set up CPM tower map + void setupCpmTowerMap(const CpmTowerCollection* ttCollection); + /// Set up CPM hits map + void setupCpmHitsMap(const CpmHitsCollection* hitCollection); + /// Set up CMM-CP hits map + void setupCmmCpHitsMap(const CmmCpHitsCollection* hitCollection); + /// Set up CPM RoI map + void setupCpmRoiMap(const CpmRoiCollection* roiCollection); + + /// CPM tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// CPM tower container StoreGate key + std::string m_cpmTowerLocation; + /// CPM hits container StoreGate key + std::string m_cpmHitsLocation; + /// CMM-CP hits container StoreGate key + std::string m_cmmCpHitsLocation; + /// CPM RoI container StoreGate key + std::string m_cpmRoiLocation; + /// CPM RoI from RoIB container StoreGate key + std::string m_cpmRoiLocationRoib; + /// CPM tower overlap container StoreGate key + std::string m_cpmTowerLocationOverlap; + /// Force number of CPM slices + int m_forceSlicesCpm; + /// Force number of CMM slices + int m_forceSlicesCmm; + /// CPM tower print flag + int m_cpmTowerPrint; + /// CPM hits print flag + int m_cpmHitsPrint; + /// CMM-CP hits print flag + int m_cmmCpHitsPrint; + /// CPM RoI print flag + int m_cpmRoiPrint; + /// CPM RoI from RoIB print flag + int m_cpmRoiPrintRoib; + /// CPM tower overlap print flag + int m_cpmTowerPrintOverlap; + + /// CPM tower map + CpmTowerMap m_ttMap; + /// CPM hits map + CpmHitsMap m_hitsMap; + /// CMM-CP hits map + CmmCpHitsMap m_cmmHitsMap; + /// CPM RoI map + CpmRoiMap m_roiMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV1.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV1.cxx new file mode 100755 index 0000000000000000000000000000000000000000..be1142fe5a370a31b2f178a972e3c66ee735e5cc --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV1.cxx @@ -0,0 +1,437 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <utility> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/CMMCPHits.h" +#include "TrigT1CaloEvent/CPMHits.h" +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/CPMRoI.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "CpmTesterV1.h" +#include "../src/ModifySlices.h" + +namespace LVL1BS { + +CpmTesterV1::CpmTesterV1(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_towerKey(0) +{ + declareProperty("CPMTowerLocation", + m_cpmTowerLocation = LVL1::TrigT1CaloDefs::CPMTowerLocation); + declareProperty("CPMHitsLocation", + m_cpmHitsLocation = LVL1::TrigT1CaloDefs::CPMHitsLocation); + declareProperty("CMMCPHitsLocation", + m_cmmCpHitsLocation = LVL1::TrigT1CaloDefs::CMMCPHitsLocation); + declareProperty("CPMRoILocation", + m_cpmRoiLocation = LVL1::TrigT1CaloDefs::CPMRoILocation); + declareProperty("CPMRoILocationRoIB", + m_cpmRoiLocationRoib = + LVL1::TrigT1CaloDefs::CPMRoILocation + "RoIB"); + declareProperty("CPMTowerLocationOverlap", + m_cpmTowerLocationOverlap = + LVL1::TrigT1CaloDefs::CPMTowerLocation + "Overlap"); + + declareProperty("ForceSlicesCPM", m_forceSlicesCpm = 0); + declareProperty("ForceSlicesCMM", m_forceSlicesCmm = 0); + + // By default print everything except RoIB RoIs and Tower overlap + declareProperty("CPMTowerPrint", m_cpmTowerPrint = 1); + declareProperty("CPMHitsPrint", m_cpmHitsPrint = 1); + declareProperty("CMMCPHitsPrint", m_cmmCpHitsPrint = 1); + declareProperty("CPMRoIPrint", m_cpmRoiPrint = 1); + declareProperty("CPMRoIPrintRoIB", m_cpmRoiPrintRoib = 0); + declareProperty("CPMTowerPrintOverlap", m_cpmTowerPrintOverlap = 0); +} + +CpmTesterV1::~CpmTesterV1() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmTesterV1::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + m_towerKey = new LVL1::TriggerTowerKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode CpmTesterV1::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + if (m_cpmTowerPrint) { + + // Find CPM towers + + const CpmTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_cpmTowerLocation); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No core CPM towers found" << endreq; + } else { + + // Order by eta, phi + + setupCpmTowerMap(ttCollection); + + // Print the CPM towers + + printCpmTowers("core"); + } + } + + if (m_cpmTowerPrintOverlap) { + + // Find overlap CPM towers + + const CpmTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_cpmTowerLocationOverlap); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No overlap CPM towers found" << endreq; + } else { + + // Order by eta, phi + + setupCpmTowerMap(ttCollection); + + // Print the overlap CPM towers + + printCpmTowers("overlap"); + } + } + + if (m_cpmHitsPrint) { + + // Find CPM hits + + const CpmHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cpmHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CPM Hits found" << endreq; + } else { + + // Order by crate, module + + setupCpmHitsMap(hitCollection); + + // Print the CPM hits + + printCpmHits(); + } + } + + if (m_cmmCpHitsPrint) { + + // Find CMM-CP hits + + const CmmCpHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmmCpHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMM-CP Hits found" << endreq; + } else { + + // Order by crate, dataID + + setupCmmCpHitsMap(hitCollection); + + // Print the CMM-CP hits + + printCmmCpHits(); + } + } + + if (m_cpmRoiPrint) { + + // Find CPM RoIs + + const CpmRoiCollection* roiCollection = 0; + StatusCode sc = evtStore()->retrieve(roiCollection, m_cpmRoiLocation); + if (sc.isFailure() || !roiCollection || roiCollection->empty()) { + msg() << "No CPM RoIs found" << endreq; + } else { + + // Order by RoI word + + setupCpmRoiMap(roiCollection); + + // Print the CPM RoIs + + printCpmRois("DAQ"); + } + } + + if (m_cpmRoiPrintRoib) { + + // Find CPM RoIs from RoIB + + const CpmRoiCollection* roiCollection = 0; + StatusCode sc = evtStore()->retrieve(roiCollection, m_cpmRoiLocationRoib); + if (sc.isFailure() || !roiCollection || roiCollection->empty()) { + msg() << "No CPM RoIs from RoIB found" << endreq; + } else { + + // Order by RoI word + + setupCpmRoiMap(roiCollection); + + // Print the CPM RoIs from RoIB + + printCpmRois("RoIB"); + } + } + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpmTesterV1::finalize() +{ + delete m_towerKey; + + return StatusCode::SUCCESS; +} + +// Print the CPM towers + +void CpmTesterV1::printCpmTowers(const std::string& source) const +{ + msg() << "Number of " << source << " CPM towers = " + << m_ttMap.size() << endreq; + CpmTowerMap::const_iterator mapIter = m_ttMap.begin(); + CpmTowerMap::const_iterator mapEnd = m_ttMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMTower* const tt = mapIter->second; + int peak = tt->peak(); + int slices = (tt->emEnergyVec()).size(); + if (m_forceSlicesCpm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCpm); + slices = m_forceSlicesCpm; + } + msg() << "key/eta/phi/peak/em/had/emErr/hadErr: " + << mapIter->first << "/" << tt->eta() << "/" << tt->phi() << "/" + << peak << "/"; + + std::vector<int> emEnergy; + std::vector<int> hadEnergy; + std::vector<int> emError; + std::vector<int> hadError; + ModifySlices::data(tt->emEnergyVec(), emEnergy, slices); + ModifySlices::data(tt->hadEnergyVec(), hadEnergy, slices); + ModifySlices::data(tt->emErrorVec(), emError, slices); + ModifySlices::data(tt->hadErrorVec(), hadError, slices); + printVec(emEnergy); + printVec(hadEnergy); + msg() << MSG::hex; + printVec(emError); + printVec(hadError); + msg() << MSG::dec << endreq; + } +} + +// Print the CPM hits + +void CpmTesterV1::printCpmHits() const +{ + msg() << "Number of CPM Hits = " << m_hitsMap.size() << endreq; + CpmHitsMap::const_iterator mapIter = m_hitsMap.begin(); + CpmHitsMap::const_iterator mapEnd = m_hitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMHits* const ch = mapIter->second; + int peak = ch->peak(); + int slices = (ch->HitsVec0()).size(); + if (m_forceSlicesCpm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCpm); + slices = m_forceSlicesCpm; + } + msg() << "crate/module/peak/hits0/hits1: " + << ch->crate() << "/" << ch->module() << "/" << peak << "/"; + + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + ModifySlices::data(ch->HitsVec0(), hits0, slices); + ModifySlices::data(ch->HitsVec1(), hits1, slices); + printVecH(hits0); + printVecH(hits1); + msg() << endreq; + } +} + +// Print the CMM-CP hits + +void CpmTesterV1::printCmmCpHits() const +{ + msg() << "Number of CMM-CP Hits = " << m_cmmHitsMap.size() << endreq; + CmmCpHitsMap::const_iterator mapIter = m_cmmHitsMap.begin(); + CmmCpHitsMap::const_iterator mapEnd = m_cmmHitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMMCPHits* const ch = mapIter->second; + int peak = ch->peak(); + int slices = (ch->HitsVec0()).size(); + if (m_forceSlicesCmm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmm); + slices = m_forceSlicesCmm; + } + msg() << "crate/dataID/peak/hits0/hits1/err0/err1: " + << ch->crate() << "/" << ch->dataID() << "/" << peak << "/"; + + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + std::vector<int> err0; + std::vector<int> err1; + ModifySlices::data(ch->HitsVec0(), hits0, slices); + ModifySlices::data(ch->HitsVec1(), hits1, slices); + ModifySlices::data(ch->ErrorVec0(), err0, slices); + ModifySlices::data(ch->ErrorVec1(), err1, slices); + printVecH(hits0); + printVecH(hits1); + msg() << MSG::hex; + printVec(err0); + printVec(err1); + msg() << MSG::dec << endreq; + } +} + +// Print the CPM RoIs + +void CpmTesterV1::printCpmRois(const std::string& source) const +{ + msg() << "Number of CPM RoIs (" << source << ") = " << m_roiMap.size() + << endreq; + CpmRoiMap::const_iterator mapIter = m_roiMap.begin(); + CpmRoiMap::const_iterator mapEnd = m_roiMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMRoI* const roi = mapIter->second; + msg() << "crate/cpm/chip/loc/hits/error: " + << roi->crate() << "/" << roi->cpm() << "/" << roi->chip() << "/" + << roi->location() << "/"; + int hits = roi->hits(); + for (int i = 0; i < 16; ++i) { + if (i == 8) msg() << ";"; + else if (i > 0) msg() << ":"; + msg() << ((hits >> i) & 0x1); + } + msg() << "/" << roi->error() << "/" << endreq; + } +} + +// Print a vector + +void CpmTesterV1::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Print a vector of hits + +void CpmTesterV1::printVecH(const std::vector<unsigned int>& vec) const +{ + const int words = 8; + const int bits = 3; + const unsigned int mask = 0x7; + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = vec.begin(); + std::vector<unsigned int>::const_iterator pose = vec.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> (bits*i)) & mask; + msg() << thr; + } + } + msg() << "/"; +} + +// Set up CPM tower map + +void CpmTesterV1::setupCpmTowerMap(const CpmTowerCollection* const ttCollection) +{ + m_ttMap.clear(); + if (ttCollection) { + CpmTowerCollection::const_iterator pos = ttCollection->begin(); + CpmTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMTower* const tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + m_ttMap.insert(std::make_pair(key, tt)); + } + } +} + +// Set up CPM hits map + +void CpmTesterV1::setupCpmHitsMap(const CpmHitsCollection* const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + CpmHitsCollection::const_iterator pos = hitCollection->begin(); + CpmHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMHits* const hits = *pos; + const int key = hits->crate()*100 + hits->module() - 1; + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM-CP hits map + +void CpmTesterV1::setupCmmCpHitsMap(const CmmCpHitsCollection* + const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmCpHitsCollection::const_iterator pos = hitCollection->begin(); + CmmCpHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMCPHits* const hits = *pos; + const int key = hits->crate()*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CPM RoI map + +void CpmTesterV1::setupCpmRoiMap(const CpmRoiCollection* const roiCollection) +{ + m_roiMap.clear(); + if (roiCollection) { + CpmRoiCollection::const_iterator pos = roiCollection->begin(); + CpmRoiCollection::const_iterator pose = roiCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV1.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV1.h new file mode 100755 index 0000000000000000000000000000000000000000..a08d05f35ebcf084eab350c55ccb550d53403b7d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV1.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMTESTERV1_H +#define TRIGT1CALOBYTESTREAM_CPMTESTERV1_H + +#include <map> +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CMMCPHits; + class CPMHits; + class CPMTower; + class CPMRoI; + class TriggerTowerKey; +} + +namespace LVL1BS { + +/** Algorithm to test CPM component bytestream conversions. + * + * Just prints out the contents of the CPMTower objects + * and CPMHits objects. + * Also includes CMMCPHits and CPMRoIs. + * + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class CpmTesterV1 : public AthAlgorithm { + + public: + CpmTesterV1(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~CpmTesterV1(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef DataVector<LVL1::CPMTower> CpmTowerCollection; + typedef DataVector<LVL1::CPMHits> CpmHitsCollection; + typedef DataVector<LVL1::CMMCPHits> CmmCpHitsCollection; + typedef DataVector<LVL1::CPMRoI> CpmRoiCollection; + typedef std::map<unsigned int, const LVL1::CPMTower*> CpmTowerMap; + typedef std::map<int, const LVL1::CPMHits*> CpmHitsMap; + typedef std::map<int, const LVL1::CMMCPHits*> CmmCpHitsMap; + typedef std::map<uint32_t, const LVL1::CPMRoI*> CpmRoiMap; + + /// Print the CPM towers + void printCpmTowers(const std::string& source) const; + /// Print the CPM hits + void printCpmHits() const; + /// Print the CMM-CP hits + void printCmmCpHits() const; + /// Print the CPM RoIs + void printCpmRois(const std::string& source) const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + /// Print a vector of hits + void printVecH(const std::vector<unsigned int>& vec) const; + + /// Set up CPM tower map + void setupCpmTowerMap(const CpmTowerCollection* ttCollection); + /// Set up CPM hits map + void setupCpmHitsMap(const CpmHitsCollection* hitCollection); + /// Set up CMM-CP hits map + void setupCmmCpHitsMap(const CmmCpHitsCollection* hitCollection); + /// Set up CPM RoI map + void setupCpmRoiMap(const CpmRoiCollection* roiCollection); + + /// CPM tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// CPM tower container StoreGate key + std::string m_cpmTowerLocation; + /// CPM hits container StoreGate key + std::string m_cpmHitsLocation; + /// CMM-CP hits container StoreGate key + std::string m_cmmCpHitsLocation; + /// CPM RoI container StoreGate key + std::string m_cpmRoiLocation; + /// CPM RoI from RoIB container StoreGate key + std::string m_cpmRoiLocationRoib; + /// CPM tower overlap container StoreGate key + std::string m_cpmTowerLocationOverlap; + /// Force number of CPM slices + int m_forceSlicesCpm; + /// Force number of CMM slices + int m_forceSlicesCmm; + /// CPM tower print flag + int m_cpmTowerPrint; + /// CPM hits print flag + int m_cpmHitsPrint; + /// CMM-CP hits print flag + int m_cmmCpHitsPrint; + /// CPM RoI print flag + int m_cpmRoiPrint; + /// CPM RoI from RoIB print flag + int m_cpmRoiPrintRoib; + /// CPM tower overlap print flag + int m_cpmTowerPrintOverlap; + + /// CPM tower map + CpmTowerMap m_ttMap; + /// CPM hits map + CpmHitsMap m_hitsMap; + /// CMM-CP hits map + CmmCpHitsMap m_cmmHitsMap; + /// CPM RoI map + CpmRoiMap m_roiMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV2.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV2.cxx new file mode 100755 index 0000000000000000000000000000000000000000..cc65885467bad8c6115a6ceeb9d87b5c25a7fb3a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV2.cxx @@ -0,0 +1,474 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <utility> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/CMXCPHits.h" +#include "TrigT1CaloEvent/CMXCPTob.h" +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/CPMTobRoI.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "CpmTesterV2.h" +#include "../src/ModifySlices.h" + +namespace LVL1BS { + +CpmTesterV2::CpmTesterV2(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_towerKey(0) +{ + declareProperty("CPMTowerLocation", + m_cpmTowerLocation = LVL1::TrigT1CaloDefs::CPMTowerLocation); + declareProperty("CMXCPTobLocation", + m_cmxCpTobLocation = LVL1::TrigT1CaloDefs::CMXCPTobLocation); + declareProperty("CMXCPHitsLocation", + m_cmxCpHitsLocation = LVL1::TrigT1CaloDefs::CMXCPHitsLocation); + declareProperty("CPMTobRoILocation", + m_cpmRoiLocation = LVL1::TrigT1CaloDefs::CPMTobRoILocation); + declareProperty("CPMTobRoILocationRoIB", + m_cpmRoiLocationRoib = LVL1::TrigT1CaloDefs::CPMTobRoILocation + "RoIB"); + declareProperty("CPMTowerLocationOverlap", + m_cpmTowerLocationOverlap = + LVL1::TrigT1CaloDefs::CPMTowerLocation + "Overlap"); + + declareProperty("ForceSlicesCPM", m_forceSlicesCpm = 0); + declareProperty("ForceSlicesCMX", m_forceSlicesCmx = 0); + + // By default print everything except RoIB RoIs and Tower overlap + declareProperty("CPMTowerPrint", m_cpmTowerPrint = 1); + declareProperty("CMXCPTobPrint", m_cmxCpTobPrint = 1, + "Set to 2 to print presence maps (Neutral format only)"); + declareProperty("CMXCPHitsPrint", m_cmxCpHitsPrint = 1, + "Set to 2 to print overflow bit (Neutral format only)"); + declareProperty("CPMTobRoIPrint", m_cpmRoiPrint = 1); + declareProperty("CPMTobRoIPrintRoIB", m_cpmRoiPrintRoib = 0); + declareProperty("CPMTowerPrintOverlap", m_cpmTowerPrintOverlap = 0); +} + +CpmTesterV2::~CpmTesterV2() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode CpmTesterV2::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + m_towerKey = new LVL1::TriggerTowerKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode CpmTesterV2::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + if (m_cpmTowerPrint) { + + // Find CPM towers + + const CpmTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_cpmTowerLocation); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No core CPM towers found" << endreq; + } else { + + // Order by eta, phi + + setupCpmTowerMap(ttCollection); + + // Print the CPM towers + + printCpmTowers("core"); + } + } + + if (m_cpmTowerPrintOverlap) { + + // Find overlap CPM towers + + const CpmTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_cpmTowerLocationOverlap); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No overlap CPM towers found" << endreq; + } else { + + // Order by eta, phi + + setupCpmTowerMap(ttCollection); + + // Print the overlap CPM towers + + printCpmTowers("overlap"); + } + } + + if (m_cmxCpTobPrint) { + + // Find CMX-CP TOBs + + const CmxCpTobCollection* tobCollection = 0; + StatusCode sc = evtStore()->retrieve(tobCollection, m_cmxCpTobLocation); + if (sc.isFailure() || !tobCollection || tobCollection->empty()) { + msg() << "No CMX-CP TOBs found" << endreq; + } else { + + // Order by crate, cmx, cpm, chip + + setupCmxCpTobMap(tobCollection); + + // Print the CMX-CP TOBs + + printCmxCpTobs(); + } + } + + if (m_cmxCpHitsPrint) { + + // Find CMX-CP hits + + const CmxCpHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmxCpHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMX-CP Hits found" << endreq; + } else { + + // Order by crate, cmx, source + + setupCmxCpHitsMap(hitCollection); + + // Print the CMX-CP hits + + printCmxCpHits(); + } + } + + if (m_cpmRoiPrint) { + + // Find CPM RoIs + + const CpmRoiCollection* roiCollection = 0; + StatusCode sc = evtStore()->retrieve(roiCollection, m_cpmRoiLocation); + if (sc.isFailure() || !roiCollection || roiCollection->empty()) { + msg() << "No CPM RoIs found" << endreq; + } else { + + // Order by RoI word + + setupCpmRoiMap(roiCollection); + + // Print the CPM RoIs + + printCpmRois("DAQ"); + } + } + + if (m_cpmRoiPrintRoib) { + + // Find CPM RoIs from RoIB + + const CpmRoiCollection* roiCollection = 0; + StatusCode sc = evtStore()->retrieve(roiCollection, m_cpmRoiLocationRoib); + if (sc.isFailure() || !roiCollection || roiCollection->empty()) { + msg() << "No CPM RoIs from RoIB found" << endreq; + } else { + + // Order by RoI word + + setupCpmRoiMap(roiCollection); + + // Print the CPM RoIs from RoIB + + printCpmRois("RoIB"); + } + } + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode CpmTesterV2::finalize() +{ + delete m_towerKey; + + return StatusCode::SUCCESS; +} + +// Print the CPM towers + +void CpmTesterV2::printCpmTowers(const std::string& source) const +{ + msg() << "Number of " << source << " CPM towers = " + << m_ttMap.size() << endreq; + CpmTowerMap::const_iterator mapIter = m_ttMap.begin(); + CpmTowerMap::const_iterator mapEnd = m_ttMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMTower* const tt = mapIter->second; + int peak = tt->peak(); + int slices = (tt->emEnergyVec()).size(); + if (m_forceSlicesCpm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCpm); + slices = m_forceSlicesCpm; + } + msg() << "key/eta/phi/peak/em/had/emErr/hadErr: " + << mapIter->first << "/" << tt->eta() << "/" << tt->phi() << "/" + << peak << "/"; + + std::vector<int> emEnergy; + std::vector<int> hadEnergy; + std::vector<int> emError; + std::vector<int> hadError; + ModifySlices::data(tt->emEnergyVec(), emEnergy, slices); + ModifySlices::data(tt->hadEnergyVec(), hadEnergy, slices); + ModifySlices::data(tt->emErrorVec(), emError, slices); + ModifySlices::data(tt->hadErrorVec(), hadError, slices); + printVec(emEnergy); + printVec(hadEnergy); + msg() << MSG::hex; + printVec(emError); + printVec(hadError); + msg() << MSG::dec << endreq; + } +} + +// Print the CMX-CP TOBs + +void CpmTesterV2::printCmxCpTobs() const +{ + msg() << "Number of CMX-CP TOBs = " << m_tobMap.size() << endreq; + CmxCpTobMap::const_iterator mapIter = m_tobMap.begin(); + CmxCpTobMap::const_iterator mapEnd = m_tobMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMXCPTob* const tb = mapIter->second; + int peak = tb->peak(); + int slices = (tb->energyVec()).size(); + if (m_forceSlicesCmx) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmx); + slices = m_forceSlicesCmx; + } + if (m_cmxCpTobPrint == 2) { + msg() << "crate/cmx/cpm/chip/loc/peak/energy/isolation/error/presenceMap: "; + } else { + msg() << "crate/cmx/cpm/chip/loc/peak/energy/isolation/error: "; + } + msg() << tb->crate() << "/" << tb->cmx() << "/" << tb->cpm() << "/" + << tb->chip() << "/" << tb->location() << "/" << peak << "/"; + + std::vector<int> energy; + std::vector<int> isolation; + std::vector<int> error; + ModifySlices::data(tb->energyVec(), energy, slices); + ModifySlices::data(tb->isolationVec(), isolation, slices); + ModifySlices::data(tb->errorVec(), error, slices); + printVec(energy); + msg() << MSG::hex; + printVec(isolation); + printVec(error); + if (m_cmxCpTobPrint == 2) { + std::vector<unsigned int> presence; + ModifySlices::data(tb->presenceMapVec(), presence, slices); + printVecH(presence, 1, 16); + } + msg() << MSG::dec << endreq; + } +} + +// Print the CMX-CP hits + +void CpmTesterV2::printCmxCpHits() const +{ + msg() << "Number of CMX-CP Hits = " << m_hitsMap.size() << endreq; + CmxCpHitsMap::const_iterator mapIter = m_hitsMap.begin(); + CmxCpHitsMap::const_iterator mapEnd = m_hitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMXCPHits* const ch = mapIter->second; + int peak = ch->peak(); + int slices = (ch->hitsVec0()).size(); + if (m_forceSlicesCmx) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmx); + slices = m_forceSlicesCmx; + } + msg() << "crate/cmx/source/peak/hits0/hits1/err0/err1: " + << ch->crate() << "/" << ch->cmx() << "/" << ch->source() << "/" + << peak << "/"; + + std::vector<unsigned int> hits0; + std::vector<unsigned int> hits1; + std::vector<int> err0; + std::vector<int> err1; + ModifySlices::data(ch->hitsVec0(), hits0, slices); + ModifySlices::data(ch->hitsVec1(), hits1, slices); + ModifySlices::data(ch->errorVec0(), err0, slices); + ModifySlices::data(ch->errorVec1(), err1, slices); + int bits = 3; + int words = 8; + if (ch->source() == LVL1::CMXCPHits::TOPO_CHECKSUM) { + bits = 16; + words = 1; + } else if (ch->source() == LVL1::CMXCPHits::TOPO_OCCUPANCY_MAP) { + bits = 1; + words = 14; + } else if (ch->source() == LVL1::CMXCPHits::TOPO_OCCUPANCY_COUNTS) { + words = 7; + } + printVecH(hits0, bits, words); + printVecH(hits1, bits, words); + msg() << MSG::hex; + if (m_cmxCpHitsPrint != 2) { // Suppress overflow bit + for (int sl = 0; sl < slices; ++sl) { + LVL1::DataError d0(err0[sl]); + d0.set(LVL1::DataError::Overflow, 0); + err0[sl] = d0.error(); + LVL1::DataError d1(err1[sl]); + d1.set(LVL1::DataError::Overflow, 0); + err1[sl] = d1.error(); + } + } + printVec(err0); + printVec(err1); + msg() << MSG::dec << endreq; + } +} + +// Print the CPM RoIs + +void CpmTesterV2::printCpmRois(const std::string& source) const +{ + msg() << "Number of CPM RoIs (" << source << ") = " << m_roiMap.size() + << endreq; + CpmRoiMap::const_iterator mapIter = m_roiMap.begin(); + CpmRoiMap::const_iterator mapEnd = m_roiMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CPMTobRoI* const roi = mapIter->second; + msg() << "crate/cpm/chip/loc/type/energy/isolation: " + << roi->crate() << "/" << roi->cpm() << "/" << roi->chip() << "/" + << roi->location() << "/" << roi->type() << "/" + << roi->energy() << "/" << MSG::hex << roi->isolation() << MSG::dec + << endreq; + } +} + +// Print a vector + +void CpmTesterV2::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Print a vector of hits + +void CpmTesterV2::printVecH(const std::vector<unsigned int>& vec, + const int bits, const int words) const +{ + const unsigned int mask = (1<<bits)-1; + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = vec.begin(); + std::vector<unsigned int>::const_iterator pose = vec.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> (bits*i)) & mask; + msg() << thr; + } + } + msg() << "/"; +} + +// Set up CPM tower map + +void CpmTesterV2::setupCpmTowerMap(const CpmTowerCollection* const ttCollection) +{ + m_ttMap.clear(); + if (ttCollection) { + CpmTowerCollection::const_iterator pos = ttCollection->begin(); + CpmTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMTower* const tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + m_ttMap.insert(std::make_pair(key, tt)); + } + } +} + +// Set up CMX-CP TOB map + +void CpmTesterV2::setupCmxCpTobMap(const CmxCpTobCollection* const tobCollection) +{ + m_tobMap.clear(); + if (tobCollection) { + CmxCpTobCollection::const_iterator pos = tobCollection->begin(); + CmxCpTobCollection::const_iterator pose = tobCollection->end(); + for (; pos != pose; ++pos) { + LVL1::CMXCPTob* const tob = *pos; + const int crate = tob->crate(); + const int cmx = tob->cmx(); + const int cpm = tob->cpm(); + const int chip = tob->chip(); + const int loc = tob->location(); + const int key = (((((((crate<<1)|cmx)<<4)|cpm)<<4)|chip)<<2)|loc; + m_tobMap.insert(std::make_pair(key, tob)); + } + } +} + +// Set up CMX-CP hits map + +void CpmTesterV2::setupCmxCpHitsMap(const CmxCpHitsCollection* + const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + CmxCpHitsCollection::const_iterator pos = hitCollection->begin(); + CmxCpHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMXCPHits* const hits = *pos; + const int key = (((hits->crate()<<1)|hits->cmx())<<3)|hits->source(); + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CPM RoI map + +void CpmTesterV2::setupCpmRoiMap(const CpmRoiCollection* const roiCollection) +{ + m_roiMap.clear(); + if (roiCollection) { + CpmRoiCollection::const_iterator pos = roiCollection->begin(); + CpmRoiCollection::const_iterator pose = roiCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CPMTobRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV2.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV2.h new file mode 100755 index 0000000000000000000000000000000000000000..dd479fd56d61b7c659734402869c6ce645a3094e --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/CpmTesterV2.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_CPMTESTERV2_H +#define TRIGT1CALOBYTESTREAM_CPMTESTERV2_H + +#include <map> +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CMXCPHits; + class CMXCPTob; + class CPMTower; + class CPMTobRoI; + class TriggerTowerKey; +} + +namespace LVL1BS { + +/** Algorithm to test CPM component bytestream conversions. + * + * Just prints out the contents of the CPMTower objects + * Also includes CMXCPTob, CMXCPHits and CPMTobRoIs. + * + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class CpmTesterV2 : public AthAlgorithm { + + public: + CpmTesterV2(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~CpmTesterV2(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef DataVector<LVL1::CPMTower> CpmTowerCollection; + typedef DataVector<LVL1::CMXCPTob> CmxCpTobCollection; + typedef DataVector<LVL1::CMXCPHits> CmxCpHitsCollection; + typedef DataVector<LVL1::CPMTobRoI> CpmRoiCollection; + typedef std::map<unsigned int, const LVL1::CPMTower*> CpmTowerMap; + typedef std::map<int, const LVL1::CMXCPTob*> CmxCpTobMap; + typedef std::map<int, const LVL1::CMXCPHits*> CmxCpHitsMap; + typedef std::map<uint32_t, const LVL1::CPMTobRoI*> CpmRoiMap; + + /// Print the CPM towers + void printCpmTowers(const std::string& source) const; + /// Print the CMX-CP TOBs + void printCmxCpTobs() const; + /// Print the CMX-CP hits + void printCmxCpHits() const; + /// Print the CPM RoIs + void printCpmRois(const std::string& source) const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + /// Print a vector of hits + void printVecH(const std::vector<unsigned int>& vec, int bits, + int words) const; + + /// Set up CPM tower map + void setupCpmTowerMap(const CpmTowerCollection* ttCollection); + /// Set up CMX-CP TOB map + void setupCmxCpTobMap(const CmxCpTobCollection* tobCollection); + /// Set up CMX-CP hits map + void setupCmxCpHitsMap(const CmxCpHitsCollection* hitCollection); + /// Set up CPM RoI map + void setupCpmRoiMap(const CpmRoiCollection* roiCollection); + + /// CPM tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// CPM tower container StoreGate key + std::string m_cpmTowerLocation; + /// CMX-CP TOB container StoreGate key + std::string m_cmxCpTobLocation; + /// CMX-CP hits container StoreGate key + std::string m_cmxCpHitsLocation; + /// CPM RoI container StoreGate key + std::string m_cpmRoiLocation; + /// CPM RoI from RoIB container StoreGate key + std::string m_cpmRoiLocationRoib; + /// CPM tower overlap container StoreGate key + std::string m_cpmTowerLocationOverlap; + /// Force number of CPM slices + int m_forceSlicesCpm; + /// Force number of CMX slices + int m_forceSlicesCmx; + /// CPM tower print flag + int m_cpmTowerPrint; + /// CMX-CP TOB print flag + int m_cmxCpTobPrint; + /// CMX-CP hits print flag + int m_cmxCpHitsPrint; + /// CPM RoI print flag + int m_cpmRoiPrint; + /// CPM RoI from RoIB print flag + int m_cpmRoiPrintRoib; + /// CPM tower overlap print flag + int m_cpmTowerPrintOverlap; + + /// CPM tower map + CpmTowerMap m_ttMap; + /// CMX-CP TOB map + CmxCpTobMap m_tobMap; + /// CMX-CP hits map + CmxCpHitsMap m_hitsMap; + /// CPM RoI map + CpmRoiMap m_roiMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/ErrorTester.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/ErrorTester.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7f3119c7bd9db16c84d0e0edd27b76fb57d982a5 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/ErrorTester.cxx @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/StoreGateSvc.h" +#include "SGTools/StlVectorClids.h" + +#include "ErrorTester.h" + +namespace LVL1BS { + +ErrorTester::ErrorTester(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator) +{ + declareProperty("L1CaloErrorLocation", + m_errorVectorLocation = "L1CaloUnpackingErrors"); +} + +ErrorTester::~ErrorTester() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode ErrorTester::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode ErrorTester::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + const ErrorCollection* errVec = 0; + StatusCode sc = evtStore()->retrieve(errVec, m_errorVectorLocation); + if (sc.isFailure() || !errVec) { + msg() << "No error vector found for " << m_errorVectorLocation << endreq; + } else { + if (errVec->empty()) { + msg() << "Error vector empty" << endreq; + } else { + ErrorCollection::const_iterator iter = errVec->begin(); + ErrorCollection::const_iterator iterE = errVec->end(); + unsigned int size1 = *iter; + ++iter; + msg() << "Number of ROB status errors: " << size1 << endreq; + while (iter != iterE) { + msg() << "ROB ID: " << MSG::hex << *iter << MSG::dec; + ++iter; + if (iter != iterE) { + if (size1 > 0) { + msg() << " status error: " << MSG::hex << *iter << MSG::dec + << endreq; + size1--; + } else msg() << " unpacking error: " << *iter << endreq; + ++iter; + } else { + msg() << " vector truncated, no error value" << endreq; + } + } + } + } + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode ErrorTester::finalize() +{ + + return StatusCode::SUCCESS; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/ErrorTester.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/ErrorTester.h new file mode 100644 index 0000000000000000000000000000000000000000..674da867a2a080c5a32f984401af3b9be141db28 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/ErrorTester.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_ERRORTESTER_H +#define TRIGT1CALOBYTESTREAM_ERRORTESTER_H + +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgorithm.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1BS { + +/** Algorithm to test unpacking error bytestream conversions. + * + * Just prints out the contents of the Error vector + * + * @author Peter Faulkner + */ + +class ErrorTester : public AthAlgorithm { + + public: + ErrorTester(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~ErrorTester(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef std::vector<unsigned int> ErrorCollection; + + /// Error vector StoreGate key + std::string m_errorVectorLocation; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemErrors.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemErrors.cxx new file mode 100755 index 0000000000000000000000000000000000000000..d9be8df272766248a09270b17d185756a3da534f --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemErrors.cxx @@ -0,0 +1,649 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ISvcLocator.h" +#include "StoreGate/StoreGateSvc.h" +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventID.h" + +#include "TrigT1CaloEvent/CMXEtSums.h" +#include "TrigT1CaloEvent/CMXJetTob.h" +#include "TrigT1CaloEvent/CMXJetHits.h" +#include "TrigT1CaloEvent/CMXRoI.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JEMTobRoI.h" +#include "TrigT1CaloEvent/JetElement.h" +#include "TrigT1CaloUtils/CoordToHardware.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1Interfaces/Coordinate.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "JemErrors.h" + +namespace LVL1BS { + +JemErrors::JemErrors(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_doneThisEvent(false), + m_doneEmParity(false), + m_doneHadParity(false), + m_doneEmLinkDown(false), + m_doneHadLinkDown(false), + m_doneEmReadoutA(false), + m_doneEmReadoutB(false), + m_doneEmReadoutC(false), + m_doneHadReadoutA(false), + m_doneHadReadoutB(false), + m_doneHadReadoutC(false), + m_doneJeSubStatus(false), + m_doneJemEtReadoutA(false), + m_doneJemEtReadoutB(false), + m_doneJemEtReadoutC(false), + m_doneJemExReadoutA(false), + m_doneJemExReadoutB(false), + m_doneJemExReadoutC(false), + m_doneJemEyReadoutA(false), + m_doneJemEyReadoutB(false), + m_doneJemEyReadoutC(false), + m_doneCmxTobParity(false), + m_doneTobLgReadoutA(false), + m_doneTobLgReadoutB(false), + m_doneTobLgReadoutC(false), + m_doneTobSmReadoutA(false), + m_doneTobSmReadoutB(false), + m_doneTobSmReadoutC(false), + m_doneCmxHitsParity0(false), + m_doneCmxHitsParity1(false), + m_doneCmxHitsParity2(false), + m_doneCmxHitsParity3(false) + +{ + declareProperty("JetElementLocation", + m_jetElementLocation = LVL1::TrigT1CaloDefs::JetElementLocation); + declareProperty("JEMEtSumsLocation", + m_jemEtSumsLocation = LVL1::TrigT1CaloDefs::JEMEtSumsLocation); + declareProperty("CMXJetTobLocation", + m_cmxJetTobLocation = LVL1::TrigT1CaloDefs::CMXJetTobLocation); + declareProperty("CMXJetHitsLocation", + m_cmxJetHitsLocation = LVL1::TrigT1CaloDefs::CMXJetHitsLocation); + declareProperty("CMXEtSumsLocation", + m_cmxEnergyLocation = LVL1::TrigT1CaloDefs::CMXEtSumsLocation); + declareProperty("JEMTobRoILocation", + m_jemRoiLocation = LVL1::TrigT1CaloDefs::JEMTobRoILocation); + declareProperty("CMXRoILocation", + m_cmxRoiLocation = LVL1::TrigT1CaloDefs::CMXRoILocation); + declareProperty("JetElementLocationOut", + m_jetElementLocationOut = LVL1::TrigT1CaloDefs::JetElementLocation+"Errors"); + declareProperty("JEMEtSumsLocationOut", + m_jemEtSumsLocationOut = LVL1::TrigT1CaloDefs::JEMEtSumsLocation+"Errors"); + declareProperty("CMXJetTobLocationOut", + m_cmxJetTobLocationOut = LVL1::TrigT1CaloDefs::CMXJetTobLocation+"Errors"); + declareProperty("CMXJetHitsLocationOut", + m_cmxJetHitsLocationOut = LVL1::TrigT1CaloDefs::CMXJetHitsLocation+"Errors"); + declareProperty("CMXEtSumsLocationOut", + m_cmxEnergyLocationOut = LVL1::TrigT1CaloDefs::CMXEtSumsLocation+"Errors"); + declareProperty("JEMTobRoILocationOut", + m_jemRoiLocationOut = LVL1::TrigT1CaloDefs::JEMTobRoILocation+"Errors"); + declareProperty("CMXRoILocationOut", + m_cmxRoiLocationOut = LVL1::TrigT1CaloDefs::CMXRoILocation+"Errors"); + + declareProperty("JetElementErrors", m_jetElementErrors = 0xffff); + declareProperty("JEMEtSumsErrors", m_jemEtSumsErrors = 0xffff); + declareProperty("CMXJetTobErrors", m_cmxTobErrors = 0xffff); + declareProperty("CMXJetHitsErrors", m_cmxHitsErrors = 0xffff); + declareProperty("CMXEtSumsErrors", m_cmxEtSumsErrors = 0xffff); + declareProperty("JEMTobRoIErrors", m_jemRoiErrors = 0xffff); + declareProperty("CMXRoIErrors", m_cmxRoiErrors = 0xffff); +} + +JemErrors::~JemErrors() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JemErrors::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + // Initialise individual error flags + + m_doneEmParity = ((m_jetElementErrors&Error1) == 0); + m_doneHadParity = ((m_jetElementErrors&Error2) == 0); + m_doneEmLinkDown = ((m_jetElementErrors&Error3) == 0); + m_doneHadLinkDown = ((m_jetElementErrors&Error4) == 0); + m_doneEmReadoutA = ((m_jetElementErrors&Error5) == 0); + m_doneEmReadoutB = ((m_jetElementErrors&Error6) == 0); + m_doneEmReadoutC = ((m_jetElementErrors&Error7) == 0); + m_doneHadReadoutA = ((m_jetElementErrors&Error8) == 0); + m_doneHadReadoutB = ((m_jetElementErrors&Error9) == 0); + m_doneHadReadoutC = ((m_jetElementErrors&Error10) == 0); + m_doneJeSubStatus = ((m_jetElementErrors&Error11) == 0); + + m_doneJemEtReadoutA = ((m_jemEtSumsErrors&Error1) == 0); + m_doneJemEtReadoutB = ((m_jemEtSumsErrors&Error2) == 0); + m_doneJemEtReadoutC = ((m_jemEtSumsErrors&Error3) == 0); + m_doneJemExReadoutA = ((m_jemEtSumsErrors&Error4) == 0); + m_doneJemExReadoutB = ((m_jemEtSumsErrors&Error5) == 0); + m_doneJemExReadoutC = ((m_jemEtSumsErrors&Error6) == 0); + m_doneJemEyReadoutA = ((m_jemEtSumsErrors&Error7) == 0); + m_doneJemEyReadoutB = ((m_jemEtSumsErrors&Error8) == 0); + m_doneJemEyReadoutC = ((m_jemEtSumsErrors&Error9) == 0); + + m_doneCmxTobParity = ((m_cmxTobErrors&Error1) == 0); + m_doneTobLgReadoutA = ((m_cmxTobErrors&Error2) == 0); + m_doneTobLgReadoutB = ((m_cmxTobErrors&Error3) == 0); + m_doneTobLgReadoutC = ((m_cmxTobErrors&Error4) == 0); + m_doneTobSmReadoutA = ((m_cmxTobErrors&Error5) == 0); + m_doneTobSmReadoutB = ((m_cmxTobErrors&Error6) == 0); + m_doneTobSmReadoutC = ((m_cmxTobErrors&Error7) == 0); + + m_doneCmxHitsParity0 = ((m_cmxHitsErrors&Error1) == 0); + m_doneCmxHitsParity1 = ((m_cmxHitsErrors&Error2) == 0); + m_doneCmxHitsParity2 = ((m_cmxHitsErrors&Error3) == 0); + m_doneCmxHitsParity3 = ((m_cmxHitsErrors&Error4) == 0); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode JemErrors::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + m_doneThisEvent = false; + + if (m_jetElementErrors) { + + // Find jet elements + + const JetElementCollection* jeCollection = 0; + StatusCode sc = evtStore()->retrieve(jeCollection, m_jetElementLocation); + if (sc.isFailure() || !jeCollection || jeCollection->empty()) { + msg() << "No Jet Elements found" << endreq; + jeCollection = 0; + } + + // Generate jet element errors + + JetElementCollection* errCollection = new JetElementCollection; + if (jeCollection) { + jetElementErrors(jeCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_jetElementLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording JetElement container in TDS " << endreq; + return sc; + } + } + + if (m_jemEtSumsErrors) { + + // Find energy sums + + const EnergySumsCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_jemEtSumsLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No Energy Sums found" << endreq; + etCollection = 0; + } + + // Generate energy sum errors + + EnergySumsCollection* errCollection = new EnergySumsCollection; + if (etCollection) { + jemEtSumsErrors(etCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_jemEtSumsLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording JEMEtSums container in TDS " << endreq; + return sc; + } + } + + if (m_cmxTobErrors) { + + // Find CMX TOBs + + const CmxJetTobCollection* tobCollection = 0; + StatusCode sc = evtStore()->retrieve(tobCollection, m_cmxJetTobLocation); + if (sc.isFailure() || !tobCollection || tobCollection->empty()) { + msg() << "No CMX TOBs found" << endreq; + tobCollection = 0; + } + + // Generate CMX TOB errors + + CmxJetTobCollection* errCollection = new CmxJetTobCollection; + if (tobCollection) { + cmxTobErrors(tobCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_cmxJetTobLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CMXJetTob container in TDS " << endreq; + return sc; + } + } + + if (m_cmxHitsErrors) { + + // Find CMX hits + + const CmxJetHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmxJetHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMX Hits found" << endreq; + hitCollection = 0; + } + + // Generate CMX Hits errors + + CmxJetHitsCollection* errCollection = new CmxJetHitsCollection; + if (hitCollection) { + cmxHitsErrors(hitCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_cmxJetHitsLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CMXJetHits container in TDS " << endreq; + return sc; + } + } +/* + if (m_cmxEtSumsErrors) { + + // Find CMX energy sums + + const CmxEnergyCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_cmxEnergyLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No CMX Energy Sums found" << endreq; + etCollection = 0; + } + + // Generate CMX energy sums errors + + CmxEnergyCollection* errCollection = new CmxEnergyCollection; + if (etCollection) { + cmxEtSumsErrors(etCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_cmxEnergyLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CMXEtSums container in TDS " << endreq; + return sc; + } + } + + if (m_jemRoiErrors) { + + // Find JEM RoIs + + const JemRoiCollection* jrCollection = 0; + StatusCode sc = evtStore()->retrieve(jrCollection, m_jemRoiLocation); + if (sc.isFailure() || !jrCollection || jrCollection->empty()) { + msg() << "No JEM RoIs found" << endreq; + jrCollection = 0; + } + + // Generate JEM RoI errors + + JemRoiCollection* errCollection = new JemRoiCollection; + if (jrCollection) { + jemRoiErrors(jrCollection, errCollection); + } + + // Save error collection + + sc = evtStore()->record(errCollection, m_jemRoiLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording JEMTobRoI container in TDS " << endreq; + return sc; + } + } + + if (m_cmxRoiErrors) { + + // Find CMX RoIs + + const LVL1::CMXRoI* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cmxRoiLocation); + if (sc.isFailure() || !crCollection || (!crCollection->roiWord(0) && + !crCollection->roiWord(1) && + !crCollection->roiWord(2) && + !crCollection->roiWord(3) && + !crCollection->roiWord(4) && + !crCollection->roiWord(5))) { + msg() << "No CMX RoIs found" << endreq; + crCollection = 0; + } + + // Generate CMX RoI errors + + CMXRoI* errCollection = 0; + if (crCollection) { + cmxRoiErrors(crCollection, errCollection); + } else errCollection = new CMXRoI(); + + // Save error collection + + sc = evtStore()->record(errCollection, m_cmxRoiLocationOut); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error recording CMXRoI container in TDS " << endreq; + return sc; + } + } +*/ + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JemErrors::finalize() +{ + return StatusCode::SUCCESS; +} + +// Generate JetElement errors + +void JemErrors::jetElementErrors(const JetElementCollection* jeCollection, + JetElementCollection* errCollection) +{ + LVL1::CoordToHardware converter; + JetElementCollection::const_iterator iter = jeCollection->begin(); + JetElementCollection::const_iterator iterEnd = jeCollection->end(); + for (; iter != iterEnd; ++iter) { + const LVL1::JetElement* const je = *iter; + const double eta = je->eta(); + const double phi = je->phi(); + const LVL1::Coordinate coord(phi, eta); + const bool overlap = (converter.jepCrateOverlap(coord) <= 1); + unsigned int key = je->key(); + const int peak = je->peak(); + std::vector<int> emEnergy(je->emEnergyVec()); + std::vector<int> hadEnergy(je->hadEnergyVec()); + std::vector<int> emError(je->emErrorVec()); + std::vector<int> hadError(je->hadErrorVec()); + std::vector<int> linkError(je->linkErrorVec()); + if (!m_doneThisEvent && !overlap) { + std::string errorType = ""; + if (!m_doneEmParity) { + emError[peak] |= (1 << LVL1::DataError::Parity); + errorType = "EM Parity"; + m_doneEmParity = true; + } else if (!m_doneHadParity) { + hadError[peak] |= (1 << LVL1::DataError::Parity); + errorType = "Had Parity"; + m_doneHadParity = true; + } else if (!m_doneEmLinkDown) { + emError[peak] |= (1 << LVL1::DataError::LinkDown); + linkError[peak] |= 0x1; + errorType = "EM Link Down"; + m_doneEmLinkDown = true; + } else if (!m_doneHadLinkDown) { + hadError[peak] |= (1 << LVL1::DataError::LinkDown); + linkError[peak] |= 0x2; + errorType = "Had Link Down"; + m_doneHadLinkDown = true; + } else if (!m_doneEmReadoutA && emEnergy[peak] != 0 && + !je->isEmSaturated()) { + emEnergy[peak] += 1; + errorType = "EM readout non-zero mismatch"; + m_doneEmReadoutA = true; + } else if (!m_doneEmReadoutB && emEnergy[peak] == 0) { + emEnergy[peak] = 1; + errorType = "EM readout sim zero mismatch"; + m_doneEmReadoutB = true; + } else if (!m_doneEmReadoutC && emEnergy[peak] != 0 && + hadEnergy[peak] != 0) { + emEnergy[peak] = 0; + errorType = "EM readout data zero mismatch"; + m_doneEmReadoutC = true; + } else if (!m_doneHadReadoutA && hadEnergy[peak] != 0 && + !je->isHadSaturated()) { + hadEnergy[peak] += 1; + errorType = "Had readout non-zero mismatch"; + m_doneHadReadoutA = true; + } else if (!m_doneHadReadoutB && hadEnergy[peak] == 0) { + hadEnergy[peak] = 1; + errorType = "Had readout sim zero mismatch"; + m_doneHadReadoutB = true; + } else if (!m_doneHadReadoutC && hadEnergy[peak] != 0 && + emEnergy[peak] != 0) { + hadEnergy[peak] = 0; + errorType = "Had readout data zero mismatch"; + m_doneHadReadoutC = true; + } else if (!m_doneJeSubStatus) { + emError[peak] |= (1 << LVL1::DataError::BCNMismatch); + hadError[peak] |= (1 << LVL1::DataError::BCNMismatch); + errorType = "SubStatus"; + m_doneJeSubStatus = true; + } + if (errorType != "") { + errorMessage("JetElements " + errorType); + m_doneThisEvent = true; + } + } + LVL1::JetElement* err = new LVL1::JetElement(phi, eta, emEnergy, hadEnergy, + key, emError, hadError, linkError, peak); + errCollection->push_back(err); + } +} + +// Generate JEMEtSums errors + +void JemErrors::jemEtSumsErrors(const EnergySumsCollection* etCollection, + EnergySumsCollection* errCollection) +{ + EnergySumsCollection::const_iterator iter = etCollection->begin(); + EnergySumsCollection::const_iterator iterEnd = etCollection->end(); + for (; iter != iterEnd; ++iter) { + const LVL1::JEMEtSums* const es = *iter; + const int crate = es->crate(); + const int module = es->module(); + const int peak = es->peak(); + std::vector<unsigned int> et(es->EtVec()); + std::vector<unsigned int> ex(es->ExVec()); + std::vector<unsigned int> ey(es->EyVec()); + if (!m_doneThisEvent) { + std::string errorType = ""; + if (!m_doneJemEtReadoutA && et[peak] != 0) { + et[peak] += 1; + errorType = "Et readout non-zero mismatch"; + m_doneJemEtReadoutA = true; + } else if (!m_doneJemEtReadoutB && et[peak] == 0) { + et[peak] = 1; + errorType = "Et readout sim zero mismatch"; + m_doneJemEtReadoutB = true; + } else if (!m_doneJemEtReadoutC && et[peak] != 0) { + et[peak] = 0; + errorType = "Et readout data zero mismatch"; + m_doneJemEtReadoutC = true; + } else if (!m_doneJemExReadoutA && ex[peak] != 0) { + ex[peak] += 1; + errorType = "Ex readout non-zero mismatch"; + m_doneJemExReadoutA = true; + } else if (!m_doneJemExReadoutB && ex[peak] == 0) { + ex[peak] = 1; + errorType = "Ex readout sim zero mismatch"; + m_doneJemExReadoutB = true; + } else if (!m_doneJemExReadoutC && ex[peak] != 0) { + ex[peak] = 0; + errorType = "Ex readout data zero mismatch"; + m_doneJemExReadoutC = true; + } else if (!m_doneJemEyReadoutA && ey[peak] != 0) { + ey[peak] += 1; + errorType = "Ey readout non-zero mismatch"; + m_doneJemEyReadoutA = true; + } else if (!m_doneJemEyReadoutB && ey[peak] == 0) { + ey[peak] = 1; + errorType = "Ey readout sim zero mismatch"; + m_doneJemEyReadoutB = true; + } else if (!m_doneJemEyReadoutC && ey[peak] != 0) { + ey[peak] = 0; + errorType = "Ey readout data zero mismatch"; + m_doneJemEyReadoutC = true; + } + if (errorType != "") { + errorMessage("JEMEtSums " + errorType); + m_doneThisEvent = true; + } + } + LVL1::JEMEtSums* err = new LVL1::JEMEtSums(crate, module, + et, ex, ey, peak); + errCollection->push_back(err); + } +} + +// Generate CMXJetTob errors + +void JemErrors::cmxTobErrors(const CmxJetTobCollection* tobCollection, + CmxJetTobCollection* errCollection) +{ + CmxJetTobCollection::const_iterator iter = tobCollection->begin(); + CmxJetTobCollection::const_iterator iterEnd = tobCollection->end(); + for (; iter != iterEnd; ++iter) { + const LVL1::CMXJetTob* const tob = *iter; + const int crate = tob->crate(); + const int jem = tob->jem(); + const int frame = tob->frame(); + const int loc = tob->location(); + const int peak = tob->peak(); + std::vector<int> energyLg(tob->energyLgVec()); + std::vector<int> energySm(tob->energySmVec()); + std::vector<int> error(tob->errorVec()); + std::vector<unsigned int> presence(tob->presenceMapVec()); + if (!m_doneThisEvent) { + std::string errorType = ""; + if (!m_doneCmxTobParity) { + error[peak] |= (1 << LVL1::DataError::Parity); + error[peak] |= (1 << LVL1::DataError::ParityPhase1); + errorType = "CMX-Jet TOB Parity"; + m_doneCmxTobParity = true; + } else if (!m_doneTobLgReadoutA && energyLg[peak] != 0) { + energyLg[peak] += 1; + errorType = "CMX-Jet TOB Energy Large readout non-zero mismatch"; + m_doneTobLgReadoutA = true; + } else if (!m_doneTobLgReadoutB && energyLg[peak] == 0) { // never happen? + energyLg[peak] = 1; + errorType = "CMX-Jet TOB Energy Large readout sim zero mismatch"; + m_doneTobLgReadoutB = true; + } else if (!m_doneTobLgReadoutC && energyLg[peak] != 0) { + energyLg[peak] = 0; + errorType = "CMX-Jet TOB Energy Large readout data zero mismatch"; + m_doneTobLgReadoutC = true; + } else if (!m_doneTobSmReadoutA && energySm[peak] != 0) { + energySm[peak] += 1; + errorType = "CMX-Jet TOB Energy Small readout non-zero mismatch"; + m_doneTobSmReadoutA = true; + } else if (!m_doneTobSmReadoutB && energySm[peak] == 0) { + energySm[peak] = 1; + errorType = "CMX-Jet TOB Energy Small readout sim zero mismatch"; + m_doneTobSmReadoutB = true; + } else if (!m_doneTobSmReadoutC && energySm[peak] != 0) { + energySm[peak] = 0; + errorType = "CMX-Jet TOB Energy Small readout data zero mismatch"; + m_doneTobSmReadoutC = true; + } + if (errorType != "") { + errorMessage("CMXJetTob " + errorType); + m_doneThisEvent = true; + } + } + LVL1::CMXJetTob* err = new LVL1::CMXJetTob(crate, jem, frame, loc, + energyLg, energySm, error, + presence, peak); + errCollection->push_back(err); + } +} + +// Generate CMXJetHits errors + +void JemErrors::cmxHitsErrors(const CmxJetHitsCollection* hitCollection, + CmxJetHitsCollection* errCollection) +{ + CmxJetHitsCollection::const_iterator iter = hitCollection->begin(); + CmxJetHitsCollection::const_iterator iterEnd = hitCollection->end(); + for (; iter != iterEnd; ++iter) { + const LVL1::CMXJetHits* const hits = *iter; + const int crate = hits->crate(); + const int source = hits->source(); + const int peak = hits->peak(); + std::vector<unsigned int> hits0(hits->hitsVec0()); + std::vector<unsigned int> hits1(hits->hitsVec1()); + std::vector<int> error0(hits->errorVec0()); + std::vector<int> error1(hits->errorVec1()); + if (!m_doneThisEvent) { + std::string errorType = ""; + if (!m_doneCmxHitsParity0 && source == LVL1::CMXJetHits::REMOTE_MAIN) { + error0[peak] |= (1 << LVL1::DataError::Parity); + errorType = "CMX-Jet Hits Parity Cable 0 Phase 0"; + m_doneCmxHitsParity0 = true; + } else if (!m_doneCmxHitsParity1 && source == LVL1::CMXJetHits::REMOTE_MAIN) { + error1[peak] |= (1 << LVL1::DataError::Parity); + errorType = "CMX-Jet Hits Parity Cable 0 Phase 1"; + m_doneCmxHitsParity1 = true; + } else if (!m_doneCmxHitsParity2 && source == LVL1::CMXJetHits::REMOTE_FORWARD) { + error0[peak] |= (1 << LVL1::DataError::Parity); + errorType = "CMX-Jet Hits Parity Cable 1 Phase 0"; + m_doneCmxHitsParity2 = true; + } else if (!m_doneCmxHitsParity3 && source == LVL1::CMXJetHits::REMOTE_FORWARD) { + error1[peak] |= (1 << LVL1::DataError::Parity); + errorType = "CMX-Jet Hits Parity Cable 1 Phase 1"; + m_doneCmxHitsParity3 = true; + /* + * To be continued? + */ + } + if (errorType != "") { + errorMessage("CMXJetHits " + errorType); + m_doneThisEvent = true; + } + } + LVL1::CMXJetHits* err = new LVL1::CMXJetHits(crate, source, hits0, hits1, + error0, error1, peak); + errCollection->push_back(err); + } +} + +// Print a message when error generated + +void JemErrors::errorMessage(const std::string& errmsg) +{ + int eventNumber = 0; + const EventInfo* evInfo = 0; + StatusCode sc = evtStore()->retrieve(evInfo); + if (sc.isFailure()) { + msg(MSG::ERROR) << "No EventInfo found" << endreq; + } else { + const EventID* evID = evInfo->event_ID(); + if (evID) eventNumber = evID->event_number(); + } + msg(MSG::INFO) << "Event " << eventNumber + << " has error " << errmsg << endreq; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemErrors.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemErrors.h new file mode 100755 index 0000000000000000000000000000000000000000..1a2a6686d09fe63c5d8bf6ec80fc7261f41c9dec --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemErrors.h @@ -0,0 +1,161 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMERRORS_H +#define TRIGT1CALOBYTESTREAM_JEMERRORS_H + +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CMXEtSums; + class CMXJetTob; + class CMXJetHits; + class CMXRoI; + class JEMEtSums; + class JEMTobRoI; + class JetElement; +} + +namespace LVL1BS { + +/** Algorithm to add errors to JEM data for testing bytestream converters + * and monitoring. + * + * + * @author Peter Faulkner + */ + +class JemErrors : public AthAlgorithm { + + public: + JemErrors(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~JemErrors(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + enum ErrorBits { Error1 = 0x1, Error2 = 0x2, Error3 = 0x4, Error4 = 0x8, + Error5 = 0x10, Error6 = 0x20, Error7 = 0x40, Error8 = 0x80, + Error9 = 0x100, Error10 = 0x200, Error11 = 0x400, + Error12 = 0x800, Error13 = 0x1000, Error14 = 0x2000, + Error15 = 0x4000, Error16 = 0x8000 }; + + typedef DataVector<LVL1::JetElement> JetElementCollection; + typedef DataVector<LVL1::JEMEtSums> EnergySumsCollection; + typedef DataVector<LVL1::CMXJetTob> CmxJetTobCollection; + typedef DataVector<LVL1::CMXJetHits> CmxJetHitsCollection; + typedef DataVector<LVL1::CMXEtSums> CmxEnergyCollection; + typedef DataVector<LVL1::JEMTobRoI> JemRoiCollection; + + /// Generate JetElement errors + void jetElementErrors(const JetElementCollection* jeCollection, + JetElementCollection* errCollection); + /// Generate JEMEtSums errors + void jemEtSumsErrors(const EnergySumsCollection* etCollection, + EnergySumsCollection* errCollection); + /// Generate CMXJetTob errors + void cmxTobErrors(const CmxJetTobCollection* tobCollection, + CmxJetTobCollection* errCollection); + /// Generate CMXJetHits errors + void cmxHitsErrors(const CmxJetHitsCollection* hitCollection, + CmxJetHitsCollection* errCollection); + + /// Print a message when error generated + void errorMessage(const std::string& msg); + + /// Jet element container input StoreGate key + std::string m_jetElementLocation; + /// Energy sums container input StoreGate key + std::string m_jemEtSumsLocation; + /// CMX TOB container input StoreGate key + std::string m_cmxJetTobLocation; + /// CMX hits container input StoreGate key + std::string m_cmxJetHitsLocation; + /// CMX energy sums container input StoreGate key + std::string m_cmxEnergyLocation; + /// JEM RoI container input StoreGate key + std::string m_jemRoiLocation; + /// CMX RoI container input StoreGate key + std::string m_cmxRoiLocation; + /// Jet element container output StoreGate key + std::string m_jetElementLocationOut; + /// Energy sums container output StoreGate key + std::string m_jemEtSumsLocationOut; + /// CMX TOB container output StoreGate key + std::string m_cmxJetTobLocationOut; + /// CMX hits container output StoreGate key + std::string m_cmxJetHitsLocationOut; + /// CMX energy sums container output StoreGate key + std::string m_cmxEnergyLocationOut; + /// JEM RoI container output StoreGate key + std::string m_jemRoiLocationOut; + /// CMX RoI container output StoreGate key + std::string m_cmxRoiLocationOut; + /// Jet element errors flag + int m_jetElementErrors; + /// Energy sums errors flag + int m_jemEtSumsErrors; + /// CMX TOB errors flag + int m_cmxTobErrors; + /// CMX hits errors flag + int m_cmxHitsErrors; + /// CMX energy sums errors flag + int m_cmxEtSumsErrors; + /// JEM RoI errors flag + int m_jemRoiErrors; + /// CMX RoI errors flag + int m_cmxRoiErrors; + + /// Individual error done flags + bool m_doneThisEvent; + /// JetElement + bool m_doneEmParity; + bool m_doneHadParity; + bool m_doneEmLinkDown; + bool m_doneHadLinkDown; + bool m_doneEmReadoutA; + bool m_doneEmReadoutB; + bool m_doneEmReadoutC; + bool m_doneHadReadoutA; + bool m_doneHadReadoutB; + bool m_doneHadReadoutC; + bool m_doneJeSubStatus; + /// JEMEtSums + bool m_doneJemEtReadoutA; + bool m_doneJemEtReadoutB; + bool m_doneJemEtReadoutC; + bool m_doneJemExReadoutA; + bool m_doneJemExReadoutB; + bool m_doneJemExReadoutC; + bool m_doneJemEyReadoutA; + bool m_doneJemEyReadoutB; + bool m_doneJemEyReadoutC; + /// CMXJetTob + bool m_doneCmxTobParity; + bool m_doneTobLgReadoutA; + bool m_doneTobLgReadoutB; + bool m_doneTobLgReadoutC; + bool m_doneTobSmReadoutA; + bool m_doneTobSmReadoutB; + bool m_doneTobSmReadoutC; + /// CMXJetHits + bool m_doneCmxHitsParity0; + bool m_doneCmxHitsParity1; + bool m_doneCmxHitsParity2; + bool m_doneCmxHitsParity3; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTester.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTester.cxx new file mode 100755 index 0000000000000000000000000000000000000000..026aa89a9d4e42921e336c71849d125a671f0a9a --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTester.cxx @@ -0,0 +1,694 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <utility> + +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ISvcLocator.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMRoI.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JEMHits.h" +#include "TrigT1CaloEvent/JEMRoI.h" +#include "TrigT1CaloEvent/JetElement.h" +#include "TrigT1CaloUtils/JetElementKey.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "JemTester.h" +#include "../src/ModifySlices.h" + +namespace LVL1BS { + +JemTester::JemTester(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_elementKey(0) +{ + declareProperty("JetElementLocation", + m_jetElementLocation = LVL1::TrigT1CaloDefs::JetElementLocation); + declareProperty("JEMHitsLocation", + m_jemHitsLocation = LVL1::TrigT1CaloDefs::JEMHitsLocation); + declareProperty("JEMEtSumsLocation", + m_jemEtSumsLocation = LVL1::TrigT1CaloDefs::JEMEtSumsLocation); + declareProperty("CMMJetHitsLocation", + m_cmmJetLocation = LVL1::TrigT1CaloDefs::CMMJetHitsLocation); + declareProperty("CMMEtSumsLocation", + m_cmmEnergyLocation = LVL1::TrigT1CaloDefs::CMMEtSumsLocation); + declareProperty("JEMRoILocation", + m_jemRoiLocation = LVL1::TrigT1CaloDefs::JEMRoILocation); + declareProperty("CMMRoILocation", + m_cmmRoiLocation = LVL1::TrigT1CaloDefs::CMMRoILocation); + declareProperty("JEMRoILocationRoIB", + m_jemRoiLocationRoib = + LVL1::TrigT1CaloDefs::JEMRoILocation + "RoIB"); + declareProperty("CMMRoILocationRoIB", + m_cmmRoiLocationRoib = + LVL1::TrigT1CaloDefs::CMMRoILocation + "RoIB"); + declareProperty("JetElementLocationOverlap", + m_jetElementLocationOverlap = + LVL1::TrigT1CaloDefs::JetElementLocation + "Overlap"); + + declareProperty("ForceSlicesJEM", m_forceSlicesJem = 0); + declareProperty("ForceSlicesCMM", m_forceSlicesCmm = 0); + + // By default print everything except RoIB RoIs and jet element overlap + declareProperty("JetElementPrint", m_jetElementPrint = 1); + declareProperty("JEMHitsPrint", m_jemHitsPrint = 1); + declareProperty("JEMEtSumsPrint", m_jemEtSumsPrint = 1); + declareProperty("CMMJetHitsPrint", m_cmmHitsPrint = 1); + declareProperty("CMMEtSumsPrint", m_cmmEtSumsPrint = 1); + declareProperty("JEMRoIPrint", m_jemRoiPrint = 1); + declareProperty("CMMRoIPrint", m_cmmRoiPrint = 1); + declareProperty("JEMRoIPrintRoIB", m_jemRoiPrintRoib = 0); + declareProperty("CMMRoIPrintRoIB", m_cmmRoiPrintRoib = 0); + declareProperty("JetElementPrintOverlap", m_jetElementPrintOverlap = 0); +} + +JemTester::~JemTester() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JemTester::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + m_elementKey = new LVL1::JetElementKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode JemTester::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + if (m_jetElementPrint) { + + // Find core jet elements + + const JetElementCollection* jeCollection = 0; + StatusCode sc = evtStore()->retrieve(jeCollection, m_jetElementLocation); + if (sc.isFailure() || !jeCollection || jeCollection->empty()) { + msg() << "No core Jet Elements found" << endreq; + } else { + + // Order by eta, phi + + setupJeMap(jeCollection); + + // Print the jet elements + + printJetElements("core"); + } + } + + if (m_jetElementPrintOverlap) { + + // Find overlap jet elements + + const JetElementCollection* jeCollection = 0; + StatusCode sc = evtStore()->retrieve(jeCollection, + m_jetElementLocationOverlap); + if (sc.isFailure() || !jeCollection || jeCollection->empty()) { + msg() << "No overlap Jet Elements found" << endreq; + } else { + + // Order by eta, phi + + setupJeMap(jeCollection); + + // Print the jet elements + + printJetElements("overlap"); + } + } + + if (m_jemHitsPrint) { + + // Find jet hits + + const JetHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_jemHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No Jet Hits found" << endreq; + } else { + + // Order by crate, module + + setupHitsMap(hitCollection); + + // Print the jet hits + + printJetHits(); + } + } + + if (m_jemEtSumsPrint) { + + // Find energy sums + + const EnergySumsCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_jemEtSumsLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No Energy Sums found" << endreq; + } else { + + // Order by crate, module + + setupEtMap(etCollection); + + // Print the energy sums + + printEnergySums(); + } + } + + if (m_cmmHitsPrint) { + + // Find CMM hits + + const CmmJetCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmmJetLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMM Hits found" << endreq; + } else { + + // Order by crate, dataID + + setupCmmHitsMap(hitCollection); + + // Print the CMM hits + + printCmmHits(); + } + } + + if (m_cmmEtSumsPrint) { + + // Find CMM energy sums + + const CmmEnergyCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_cmmEnergyLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No CMM Energy Sums found" << endreq; + } else { + + // Order by crate, dataID + + setupCmmEtMap(etCollection); + + // Print the CMM energy sums + + printCmmSums(); + } + } + + if (m_jemRoiPrint) { + + // Find JEM RoIs + + const JemRoiCollection* jrCollection = 0; + StatusCode sc = evtStore()->retrieve(jrCollection, m_jemRoiLocation); + if (sc.isFailure() || !jrCollection || jrCollection->empty()) { + msg() << "No JEM RoIs found" << endreq; + } else { + + // Order by RoI word + + setupJemRoiMap(jrCollection); + + // Print the JEM RoIs + + printJemRois("DAQ"); + } + } + + if (m_jemRoiPrintRoib) { + + // Find JEM RoIs from RoIB + + const JemRoiCollection* jrCollection = 0; + StatusCode sc = evtStore()->retrieve(jrCollection, m_jemRoiLocationRoib); + if (sc.isFailure() || !jrCollection || jrCollection->empty()) { + msg() << "No JEM RoIs from RoIB found" << endreq; + } else { + + // Order by RoI word + + setupJemRoiMap(jrCollection); + + // Print the JEM RoIs from RoIB + + printJemRois("RoIB"); + } + } + + if (m_cmmRoiPrint) { + + // Find CMM RoIs + + const LVL1::CMMRoI* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cmmRoiLocation); + if (sc.isFailure() || !crCollection || (!crCollection->jetEtRoiWord() && + !crCollection->energyRoiWord0() && + !crCollection->energyRoiWord1() && + !crCollection->energyRoiWord2())) { + msg() << "No CMM RoIs found" << endreq; + } else { + + // Print the CMM RoIs + + printCmmRois("DAQ", crCollection); + } + } + + if (m_cmmRoiPrintRoib) { + + // Find CMM RoIs from RoIB + + const LVL1::CMMRoI* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cmmRoiLocationRoib); + if (sc.isFailure() || !crCollection || (!crCollection->jetEtRoiWord() && + !crCollection->energyRoiWord0() && + !crCollection->energyRoiWord1() && + !crCollection->energyRoiWord2())) { + msg() << "No CMM RoIs from RoIB found" << endreq; + } else { + + // Print the CMM RoIs from RoIB + + printCmmRois("RoIB", crCollection); + } + } + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JemTester::finalize() +{ + delete m_elementKey; + + return StatusCode::SUCCESS; +} + +// Print the jet elements + +void JemTester::printJetElements(const std::string& source) const +{ + msg() << "Number of " << source << " Jet Elements = " + << m_jeMap.size() << endreq; + JetElementMap::const_iterator mapIter = m_jeMap.begin(); + JetElementMap::const_iterator mapEnd = m_jeMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JetElement* const je = mapIter->second; + int peak = je->peak(); + int slices = (je->emEnergyVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + msg() << "key/eta/phi/peak/em/had/emErr/hadErr/linkErr: " + << mapIter->first << "/" << je->eta() << "/" << je->phi() << "/" + << peak << "/"; + + std::vector<int> emEnergy; + std::vector<int> hadEnergy; + std::vector<int> emError; + std::vector<int> hadError; + std::vector<int> linkError; + ModifySlices::data(je->emEnergyVec(), emEnergy, slices); + ModifySlices::data(je->hadEnergyVec(), hadEnergy, slices); + ModifySlices::data(je->emErrorVec(), emError, slices); + ModifySlices::data(je->hadErrorVec(), hadError, slices); + ModifySlices::data(je->linkErrorVec(), linkError, slices); + printVec(emEnergy); + printVec(hadEnergy); + msg() << MSG::hex; + printVec(emError); + printVec(hadError); + printVec(linkError); + msg() << MSG::dec << endreq; + } +} + +// Print the jet hits + +void JemTester::printJetHits() const +{ + msg() << "Number of Jet Hits = " << m_hitsMap.size() << endreq; + JetHitsMap::const_iterator mapIter = m_hitsMap.begin(); + JetHitsMap::const_iterator mapEnd = m_hitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMHits* const jh = mapIter->second; + int peak = jh->peak(); + int slices = (jh->JetHitsVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + msg() << "crate/module/peak/hits: " + << jh->crate() << "/" << jh->module() << "/" << peak << "/"; + int words = 8; + int bits = 3; + unsigned int mask = 0x7; + if (jh->forward()) { + words = 12; + bits = 2; + mask = 0x3; + } + std::vector<unsigned int> jetHits; + ModifySlices::data(jh->JetHitsVec(), jetHits, slices); + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = jetHits.begin(); + std::vector<unsigned int>::const_iterator pose = jetHits.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> bits*i) & mask; + msg() << thr; + } + } + msg() << "/" << endreq; + } +} + +// Print energy sums + +void JemTester::printEnergySums() const +{ + msg() << "Number of Energy Sums = " << m_etMap.size() << endreq; + EnergySumsMap::const_iterator mapIter = m_etMap.begin(); + EnergySumsMap::const_iterator mapEnd = m_etMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMEtSums* const et = mapIter->second; + int peak = et->peak(); + int slices = (et->ExVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + msg() << "crate/module/peak/Ex/Ey/Et: " + << et->crate() << "/" << et->module() << "/" << peak << "/"; + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + ModifySlices::data(et->ExVec(), exVec, slices); + ModifySlices::data(et->EyVec(), eyVec, slices); + ModifySlices::data(et->EtVec(), etVec, slices); + printVecU(exVec); + printVecU(eyVec); + printVecU(etVec); + msg() << endreq; + } +} + +// Print the CMM hits + +void JemTester::printCmmHits() const +{ + msg() << "Number of CMM Hits = " << m_cmmHitsMap.size() << endreq; + CmmHitsMap::const_iterator mapIter = m_cmmHitsMap.begin(); + CmmHitsMap::const_iterator mapEnd = m_cmmHitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMMJetHits* const jh = mapIter->second; + const int dataID = jh->dataID(); + int peak = jh->peak(); + int slices = (jh->HitsVec()).size(); + if (m_forceSlicesCmm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmm); + slices = m_forceSlicesCmm; + } + msg() << "crate/dataID/peak/hits/error: " + << jh->crate() << "/" << dataID << "/" << peak << "/"; + int words = 8; + int bits = 3; + unsigned int mask = 0x7; + if (dataID == 0 || dataID == 7 || dataID == 8 || dataID == 15) { + words = 12; + bits = 2; + mask = 0x3; + } else if (dataID == LVL1::CMMJetHits::REMOTE_FORWARD || + dataID == LVL1::CMMJetHits::LOCAL_FORWARD || + dataID == LVL1::CMMJetHits::TOTAL_FORWARD) { + bits = 2; + mask = 0x3; + } else if (dataID == LVL1::CMMJetHits::ET_MAP) { + words = 1; + bits = 4; + mask = 0xf; + } + std::vector<unsigned int> hitsVec; + ModifySlices::data(jh->HitsVec(), hitsVec, slices); + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = hitsVec.begin(); + std::vector<unsigned int>::const_iterator pose = hitsVec.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> bits*i) & mask; + msg() << thr; + } + } + msg() << "/" << MSG::hex; + std::vector<int> errorVec; + ModifySlices::data(jh->ErrorVec(), errorVec, slices); + printVec(errorVec); + msg() << MSG::dec << endreq; + } +} + +// Print CMM energy sums + +void JemTester::printCmmSums() const +{ + msg() << "Number of CMM Energy Sums = " << m_cmmEtMap.size() << endreq; + CmmSumsMap::const_iterator mapIter = m_cmmEtMap.begin(); + CmmSumsMap::const_iterator mapEnd = m_cmmEtMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMMEtSums* const et = mapIter->second; + int peak = et->peak(); + int slices = (et->ExVec()).size(); + if (m_forceSlicesCmm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmm); + slices = m_forceSlicesCmm; + } + msg() << "crate/dataID/peak/Ex/Ey/Et/ExErr/EyErr/EtErr: " + << et->crate() << "/" << et->dataID() << "/" << peak << "/"; + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + std::vector<int> exError; + std::vector<int> eyError; + std::vector<int> etError; + ModifySlices::data(et->ExVec(), exVec, slices); + ModifySlices::data(et->EyVec(), eyVec, slices); + ModifySlices::data(et->EtVec(), etVec, slices); + ModifySlices::data(et->ExErrorVec(), exError, slices); + ModifySlices::data(et->EyErrorVec(), eyError, slices); + ModifySlices::data(et->EtErrorVec(), etError, slices); + printVecU(exVec); + printVecU(eyVec); + printVecU(etVec); + msg() << MSG::hex; + printVec(exError); + printVec(eyError); + printVec(etError); + msg() << MSG::dec << endreq; + } +} + +// Print the JEM RoIs + +void JemTester::printJemRois(const std::string& source) const +{ + msg() << "Number of JEM RoIs (" << source << ") = " << m_roiMap.size() + << endreq; + JemRoiMap::const_iterator mapIter = m_roiMap.begin(); + JemRoiMap::const_iterator mapEnd = m_roiMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMRoI* const roi = mapIter->second; + msg() << "crate/jem/frame/loc/fwd/hits/error: " + << roi->crate() << "/" << roi->jem() << "/" << roi->frame() << "/" + << roi->location() << "/" << roi->forward() << "/"; + const int hits = roi->hits(); + const int numHits = (roi->forward()) ? 4 : 8; + for (int i = 0; i < numHits; ++i) { + if (i > 0) msg() << ":"; + msg() << ((hits >> i) & 0x1); + } + msg() << "/" << roi->error() << "/" << endreq; + } +} + +// Print the CMM RoIs + +void JemTester::printCmmRois(const std::string& source, + const LVL1::CMMRoI* const roi) const +{ + msg() << "CMMRoI(" << source + << "):jetEtHits/sumEtHits/missingEtHits/missingEtSigHits/Ex/Ey/Et;error: " + << MSG::hex << roi->jetEtHits() << ";" << roi->jetEtError() << "/" + << roi->sumEtHits() << ";" << roi->sumEtError() << "/" + << roi->missingEtHits() << ";" << roi->missingEtError() << "/" + << roi->missingEtSigHits() << ";" << roi->missingEtSigError() << "/" + << MSG::dec << roi->ex() << ";" << roi->exError() << "/" + << roi->ey() << ";" << roi->eyError() << "/" + << roi->et() << ";" << roi->etError() << "/" << endreq; +} + +// Print a vector + +void JemTester::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Print a vector (unsigned) + +void JemTester::printVecU(const std::vector<unsigned int>& vec) const +{ + std::vector<unsigned int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Set up jet element map + +void JemTester::setupJeMap(const JetElementCollection* const jeCollection) +{ + m_jeMap.clear(); + if (jeCollection) { + JetElementCollection::const_iterator pos = jeCollection->begin(); + JetElementCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JetElement* const je = *pos; + const unsigned int key = m_elementKey->jeKey(je->phi(), je->eta()); + m_jeMap.insert(std::make_pair(key, je)); + } + } +} + +// Set up jet hits map + +void JemTester::setupHitsMap(const JetHitsCollection* const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + JetHitsCollection::const_iterator pos = hitCollection->begin(); + JetHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMHits* const hits = *pos; + const int key = hits->crate()*100 + hits->module(); + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up energy sums map + +void JemTester::setupEtMap(const EnergySumsCollection* const etCollection) +{ + m_etMap.clear(); + if (etCollection) { + EnergySumsCollection::const_iterator pos = etCollection->begin(); + EnergySumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMEtSums* const sums = *pos; + // Sim doesn't zero suppress properly, do it here + if (std::accumulate((sums->ExVec()).begin(), (sums->ExVec()).end(), 0) || + std::accumulate((sums->EyVec()).begin(), (sums->EyVec()).end(), 0) || + std::accumulate((sums->EtVec()).begin(), (sums->EtVec()).end(), 0)) { + const int key = sums->crate()*100 + sums->module(); + m_etMap.insert(std::make_pair(key, sums)); + } + } + } +} + +// Set up CMM hits map + +void JemTester::setupCmmHitsMap(const CmmJetCollection* const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmJetCollection::const_iterator pos = hitCollection->begin(); + CmmJetCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMJetHits* const hits = *pos; + const int key = hits->crate()*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM energy sums map + +void JemTester::setupCmmEtMap(const CmmEnergyCollection* const etCollection) +{ + m_cmmEtMap.clear(); + if (etCollection) { + CmmEnergyCollection::const_iterator pos = etCollection->begin(); + CmmEnergyCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMEtSums* const sums = *pos; + if (std::accumulate((sums->ExVec()).begin(), (sums->ExVec()).end(), 0) || + std::accumulate((sums->EyVec()).begin(), (sums->EyVec()).end(), 0) || + std::accumulate((sums->EtVec()).begin(), (sums->EtVec()).end(), 0) || + std::accumulate((sums->ExErrorVec()).begin(), + (sums->ExErrorVec()).end(), 0) || + std::accumulate((sums->EyErrorVec()).begin(), + (sums->EyErrorVec()).end(), 0) || + std::accumulate((sums->EtErrorVec()).begin(), + (sums->EtErrorVec()).end(), 0)) { + const int key = sums->crate()*100 + sums->dataID(); + m_cmmEtMap.insert(std::make_pair(key, sums)); + } + } + } +} + +// Set up JEM RoI map + +void JemTester::setupJemRoiMap(const JemRoiCollection* const jrCollection) +{ + m_roiMap.clear(); + if (jrCollection) { + JemRoiCollection::const_iterator pos = jrCollection->begin(); + JemRoiCollection::const_iterator pose = jrCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTester.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTester.h new file mode 100755 index 0000000000000000000000000000000000000000..5fe76c76733057cfa1678cc9b287bc23d6bf2171 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTester.h @@ -0,0 +1,164 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMTESTER_H +#define TRIGT1CALOBYTESTREAM_JEMTESTER_H + +#include <map> +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CMMEtSums; + class CMMJetHits; + class CMMRoI; + class JEMEtSums; + class JEMHits; + class JEMRoI; + class JetElement; + class JetElementKey; +} + +namespace LVL1BS { + +/** Algorithm to test JEM component bytestream conversions. + * + * Just prints out the contents of the JetElement objects, + * JEMHits objects and JEMEtSums objects. + * Now also includes CMMJetHits, CMMEtSums, JEMRoI and CMMRoI. + * + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class JemTester : public AthAlgorithm { + + public: + JemTester(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~JemTester(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef DataVector<LVL1::JetElement> JetElementCollection; + typedef DataVector<LVL1::JEMHits> JetHitsCollection; + typedef DataVector<LVL1::JEMEtSums> EnergySumsCollection; + typedef DataVector<LVL1::CMMJetHits> CmmJetCollection; + typedef DataVector<LVL1::CMMEtSums> CmmEnergyCollection; + typedef DataVector<LVL1::JEMRoI> JemRoiCollection; + typedef std::map<unsigned int, const LVL1::JetElement*> JetElementMap; + typedef std::map<int, const LVL1::JEMHits*> JetHitsMap; + typedef std::map<int, const LVL1::JEMEtSums*> EnergySumsMap; + typedef std::map<int, const LVL1::CMMJetHits*> CmmHitsMap; + typedef std::map<int, const LVL1::CMMEtSums*> CmmSumsMap; + typedef std::map<uint32_t, const LVL1::JEMRoI*> JemRoiMap; + + /// Print the jet elements + void printJetElements(const std::string& source) const; + /// Print the jet hits + void printJetHits() const; + /// Print the energy sums + void printEnergySums() const; + /// Print the CMM hits + void printCmmHits() const; + /// Print the CMM energy sums + void printCmmSums() const; + /// Print the JEM RoIs + void printJemRois(const std::string& source) const; + /// Print the CMM RoIs + void printCmmRois(const std::string& source, + const LVL1::CMMRoI* roi) const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + /// Print a vector (unsigned) + void printVecU(const std::vector<unsigned int>& vec) const; + + /// Set up jet element map + void setupJeMap(const JetElementCollection* jeCollection); + /// Set up jet hits map + void setupHitsMap(const JetHitsCollection* hitCollection); + /// Set up energy sums map + void setupEtMap(const EnergySumsCollection* etCollection); + /// Set up CMM hits map + void setupCmmHitsMap(const CmmJetCollection* hitCollection); + /// Set up CMM energy sums map + void setupCmmEtMap(const CmmEnergyCollection* etCollection); + /// Set up JEM RoI map + void setupJemRoiMap(const JemRoiCollection* jrCollection); + + /// Jet element key provider + LVL1::JetElementKey* m_elementKey; + /// Jet element container StoreGate key + std::string m_jetElementLocation; + /// Jet hits container StoreGate key + std::string m_jemHitsLocation; + /// Energy sums container StoreGate key + std::string m_jemEtSumsLocation; + /// CMM hits container StoreGate key + std::string m_cmmJetLocation; + /// CMM energy sums container StoreGate key + std::string m_cmmEnergyLocation; + /// JEM RoI container StoreGate key + std::string m_jemRoiLocation; + /// CMM RoI container StoreGate key + std::string m_cmmRoiLocation; + /// JEM RoI from RoIB container StoreGate key + std::string m_jemRoiLocationRoib; + /// CMM RoI from RoIB container StoreGate key + std::string m_cmmRoiLocationRoib; + /// Jet element overlap container StoreGate key + std::string m_jetElementLocationOverlap; + /// Force number of JEM slices + int m_forceSlicesJem; + /// Force number of CMM slices + int m_forceSlicesCmm; + /// Jet element print flag + int m_jetElementPrint; + /// Jet hits print flag + int m_jemHitsPrint; + /// Energy sums print flag + int m_jemEtSumsPrint; + /// CMM hits print flag + int m_cmmHitsPrint; + /// CMM energy sums print flag + int m_cmmEtSumsPrint; + /// JEM RoI print flag + int m_jemRoiPrint; + /// CMM RoI print flag + int m_cmmRoiPrint; + /// JEM RoI from RoIB print flag + int m_jemRoiPrintRoib; + /// CMM RoI from RoIB print flag + int m_cmmRoiPrintRoib; + /// Jet element overlap print flag + int m_jetElementPrintOverlap; + + /// Jet element map + JetElementMap m_jeMap; + /// Jet hits map + JetHitsMap m_hitsMap; + /// Energy sums map + EnergySumsMap m_etMap; + /// CMM hits map + CmmHitsMap m_cmmHitsMap; + /// CMM energy sums map + CmmSumsMap m_cmmEtMap; + /// JEM RoI map + JemRoiMap m_roiMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV1.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV1.cxx new file mode 100755 index 0000000000000000000000000000000000000000..62a58e175f35b12004659b920ef2fbf070686aea --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV1.cxx @@ -0,0 +1,694 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <utility> + +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ISvcLocator.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMRoI.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JEMHits.h" +#include "TrigT1CaloEvent/JEMRoI.h" +#include "TrigT1CaloEvent/JetElement.h" +#include "TrigT1CaloUtils/JetElementKey.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "JemTesterV1.h" +#include "../src/ModifySlices.h" + +namespace LVL1BS { + +JemTesterV1::JemTesterV1(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_elementKey(0) +{ + declareProperty("JetElementLocation", + m_jetElementLocation = LVL1::TrigT1CaloDefs::JetElementLocation); + declareProperty("JEMHitsLocation", + m_jemHitsLocation = LVL1::TrigT1CaloDefs::JEMHitsLocation); + declareProperty("JEMEtSumsLocation", + m_jemEtSumsLocation = LVL1::TrigT1CaloDefs::JEMEtSumsLocation); + declareProperty("CMMJetHitsLocation", + m_cmmJetLocation = LVL1::TrigT1CaloDefs::CMMJetHitsLocation); + declareProperty("CMMEtSumsLocation", + m_cmmEnergyLocation = LVL1::TrigT1CaloDefs::CMMEtSumsLocation); + declareProperty("JEMRoILocation", + m_jemRoiLocation = LVL1::TrigT1CaloDefs::JEMRoILocation); + declareProperty("CMMRoILocation", + m_cmmRoiLocation = LVL1::TrigT1CaloDefs::CMMRoILocation); + declareProperty("JEMRoILocationRoIB", + m_jemRoiLocationRoib = + LVL1::TrigT1CaloDefs::JEMRoILocation + "RoIB"); + declareProperty("CMMRoILocationRoIB", + m_cmmRoiLocationRoib = + LVL1::TrigT1CaloDefs::CMMRoILocation + "RoIB"); + declareProperty("JetElementLocationOverlap", + m_jetElementLocationOverlap = + LVL1::TrigT1CaloDefs::JetElementLocation + "Overlap"); + + declareProperty("ForceSlicesJEM", m_forceSlicesJem = 0); + declareProperty("ForceSlicesCMM", m_forceSlicesCmm = 0); + + // By default print everything except RoIB RoIs and jet element overlap + declareProperty("JetElementPrint", m_jetElementPrint = 1); + declareProperty("JEMHitsPrint", m_jemHitsPrint = 1); + declareProperty("JEMEtSumsPrint", m_jemEtSumsPrint = 1); + declareProperty("CMMJetHitsPrint", m_cmmHitsPrint = 1); + declareProperty("CMMEtSumsPrint", m_cmmEtSumsPrint = 1); + declareProperty("JEMRoIPrint", m_jemRoiPrint = 1); + declareProperty("CMMRoIPrint", m_cmmRoiPrint = 1); + declareProperty("JEMRoIPrintRoIB", m_jemRoiPrintRoib = 0); + declareProperty("CMMRoIPrintRoIB", m_cmmRoiPrintRoib = 0); + declareProperty("JetElementPrintOverlap", m_jetElementPrintOverlap = 0); +} + +JemTesterV1::~JemTesterV1() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JemTesterV1::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + m_elementKey = new LVL1::JetElementKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode JemTesterV1::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + if (m_jetElementPrint) { + + // Find core jet elements + + const JetElementCollection* jeCollection = 0; + StatusCode sc = evtStore()->retrieve(jeCollection, m_jetElementLocation); + if (sc.isFailure() || !jeCollection || jeCollection->empty()) { + msg() << "No core Jet Elements found" << endreq; + } else { + + // Order by eta, phi + + setupJeMap(jeCollection); + + // Print the jet elements + + printJetElements("core"); + } + } + + if (m_jetElementPrintOverlap) { + + // Find overlap jet elements + + const JetElementCollection* jeCollection = 0; + StatusCode sc = evtStore()->retrieve(jeCollection, + m_jetElementLocationOverlap); + if (sc.isFailure() || !jeCollection || jeCollection->empty()) { + msg() << "No overlap Jet Elements found" << endreq; + } else { + + // Order by eta, phi + + setupJeMap(jeCollection); + + // Print the jet elements + + printJetElements("overlap"); + } + } + + if (m_jemHitsPrint) { + + // Find jet hits + + const JetHitsCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_jemHitsLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No Jet Hits found" << endreq; + } else { + + // Order by crate, module + + setupHitsMap(hitCollection); + + // Print the jet hits + + printJetHits(); + } + } + + if (m_jemEtSumsPrint) { + + // Find energy sums + + const EnergySumsCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_jemEtSumsLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No Energy Sums found" << endreq; + } else { + + // Order by crate, module + + setupEtMap(etCollection); + + // Print the energy sums + + printEnergySums(); + } + } + + if (m_cmmHitsPrint) { + + // Find CMM hits + + const CmmJetCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmmJetLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMM Hits found" << endreq; + } else { + + // Order by crate, dataID + + setupCmmHitsMap(hitCollection); + + // Print the CMM hits + + printCmmHits(); + } + } + + if (m_cmmEtSumsPrint) { + + // Find CMM energy sums + + const CmmEnergyCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_cmmEnergyLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No CMM Energy Sums found" << endreq; + } else { + + // Order by crate, dataID + + setupCmmEtMap(etCollection); + + // Print the CMM energy sums + + printCmmSums(); + } + } + + if (m_jemRoiPrint) { + + // Find JEM RoIs + + const JemRoiCollection* jrCollection = 0; + StatusCode sc = evtStore()->retrieve(jrCollection, m_jemRoiLocation); + if (sc.isFailure() || !jrCollection || jrCollection->empty()) { + msg() << "No JEM RoIs found" << endreq; + } else { + + // Order by RoI word + + setupJemRoiMap(jrCollection); + + // Print the JEM RoIs + + printJemRois("DAQ"); + } + } + + if (m_jemRoiPrintRoib) { + + // Find JEM RoIs from RoIB + + const JemRoiCollection* jrCollection = 0; + StatusCode sc = evtStore()->retrieve(jrCollection, m_jemRoiLocationRoib); + if (sc.isFailure() || !jrCollection || jrCollection->empty()) { + msg() << "No JEM RoIs from RoIB found" << endreq; + } else { + + // Order by RoI word + + setupJemRoiMap(jrCollection); + + // Print the JEM RoIs from RoIB + + printJemRois("RoIB"); + } + } + + if (m_cmmRoiPrint) { + + // Find CMM RoIs + + const LVL1::CMMRoI* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cmmRoiLocation); + if (sc.isFailure() || !crCollection || (!crCollection->jetEtRoiWord() && + !crCollection->energyRoiWord0() && + !crCollection->energyRoiWord1() && + !crCollection->energyRoiWord2())) { + msg() << "No CMM RoIs found" << endreq; + } else { + + // Print the CMM RoIs + + printCmmRois("DAQ", crCollection); + } + } + + if (m_cmmRoiPrintRoib) { + + // Find CMM RoIs from RoIB + + const LVL1::CMMRoI* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cmmRoiLocationRoib); + if (sc.isFailure() || !crCollection || (!crCollection->jetEtRoiWord() && + !crCollection->energyRoiWord0() && + !crCollection->energyRoiWord1() && + !crCollection->energyRoiWord2())) { + msg() << "No CMM RoIs from RoIB found" << endreq; + } else { + + // Print the CMM RoIs from RoIB + + printCmmRois("RoIB", crCollection); + } + } + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JemTesterV1::finalize() +{ + delete m_elementKey; + + return StatusCode::SUCCESS; +} + +// Print the jet elements + +void JemTesterV1::printJetElements(const std::string& source) const +{ + msg() << "Number of " << source << " Jet Elements = " + << m_jeMap.size() << endreq; + JetElementMap::const_iterator mapIter = m_jeMap.begin(); + JetElementMap::const_iterator mapEnd = m_jeMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JetElement* const je = mapIter->second; + int peak = je->peak(); + int slices = (je->emEnergyVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + msg() << "key/eta/phi/peak/em/had/emErr/hadErr/linkErr: " + << mapIter->first << "/" << je->eta() << "/" << je->phi() << "/" + << peak << "/"; + + std::vector<int> emEnergy; + std::vector<int> hadEnergy; + std::vector<int> emError; + std::vector<int> hadError; + std::vector<int> linkError; + ModifySlices::data(je->emEnergyVec(), emEnergy, slices); + ModifySlices::data(je->hadEnergyVec(), hadEnergy, slices); + ModifySlices::data(je->emErrorVec(), emError, slices); + ModifySlices::data(je->hadErrorVec(), hadError, slices); + ModifySlices::data(je->linkErrorVec(), linkError, slices); + printVec(emEnergy); + printVec(hadEnergy); + msg() << MSG::hex; + printVec(emError); + printVec(hadError); + printVec(linkError); + msg() << MSG::dec << endreq; + } +} + +// Print the jet hits + +void JemTesterV1::printJetHits() const +{ + msg() << "Number of Jet Hits = " << m_hitsMap.size() << endreq; + JetHitsMap::const_iterator mapIter = m_hitsMap.begin(); + JetHitsMap::const_iterator mapEnd = m_hitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMHits* const jh = mapIter->second; + int peak = jh->peak(); + int slices = (jh->JetHitsVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + msg() << "crate/module/peak/hits: " + << jh->crate() << "/" << jh->module() << "/" << peak << "/"; + int words = 8; + int bits = 3; + unsigned int mask = 0x7; + if (jh->forward()) { + words = 12; + bits = 2; + mask = 0x3; + } + std::vector<unsigned int> jetHits; + ModifySlices::data(jh->JetHitsVec(), jetHits, slices); + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = jetHits.begin(); + std::vector<unsigned int>::const_iterator pose = jetHits.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> bits*i) & mask; + msg() << thr; + } + } + msg() << "/" << endreq; + } +} + +// Print energy sums + +void JemTesterV1::printEnergySums() const +{ + msg() << "Number of Energy Sums = " << m_etMap.size() << endreq; + EnergySumsMap::const_iterator mapIter = m_etMap.begin(); + EnergySumsMap::const_iterator mapEnd = m_etMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMEtSums* const et = mapIter->second; + int peak = et->peak(); + int slices = (et->ExVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + msg() << "crate/module/peak/Ex/Ey/Et: " + << et->crate() << "/" << et->module() << "/" << peak << "/"; + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + ModifySlices::data(et->ExVec(), exVec, slices); + ModifySlices::data(et->EyVec(), eyVec, slices); + ModifySlices::data(et->EtVec(), etVec, slices); + printVecU(exVec); + printVecU(eyVec); + printVecU(etVec); + msg() << endreq; + } +} + +// Print the CMM hits + +void JemTesterV1::printCmmHits() const +{ + msg() << "Number of CMM Hits = " << m_cmmHitsMap.size() << endreq; + CmmHitsMap::const_iterator mapIter = m_cmmHitsMap.begin(); + CmmHitsMap::const_iterator mapEnd = m_cmmHitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMMJetHits* const jh = mapIter->second; + const int dataID = jh->dataID(); + int peak = jh->peak(); + int slices = (jh->HitsVec()).size(); + if (m_forceSlicesCmm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmm); + slices = m_forceSlicesCmm; + } + msg() << "crate/dataID/peak/hits/error: " + << jh->crate() << "/" << dataID << "/" << peak << "/"; + int words = 8; + int bits = 3; + unsigned int mask = 0x7; + if (dataID == 0 || dataID == 7 || dataID == 8 || dataID == 15) { + words = 12; + bits = 2; + mask = 0x3; + } else if (dataID == LVL1::CMMJetHits::REMOTE_FORWARD || + dataID == LVL1::CMMJetHits::LOCAL_FORWARD || + dataID == LVL1::CMMJetHits::TOTAL_FORWARD) { + bits = 2; + mask = 0x3; + } else if (dataID == LVL1::CMMJetHits::ET_MAP) { + words = 1; + bits = 4; + mask = 0xf; + } + std::vector<unsigned int> hitsVec; + ModifySlices::data(jh->HitsVec(), hitsVec, slices); + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = hitsVec.begin(); + std::vector<unsigned int>::const_iterator pose = hitsVec.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> bits*i) & mask; + msg() << thr; + } + } + msg() << "/" << MSG::hex; + std::vector<int> errorVec; + ModifySlices::data(jh->ErrorVec(), errorVec, slices); + printVec(errorVec); + msg() << MSG::dec << endreq; + } +} + +// Print CMM energy sums + +void JemTesterV1::printCmmSums() const +{ + msg() << "Number of CMM Energy Sums = " << m_cmmEtMap.size() << endreq; + CmmSumsMap::const_iterator mapIter = m_cmmEtMap.begin(); + CmmSumsMap::const_iterator mapEnd = m_cmmEtMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMMEtSums* const et = mapIter->second; + int peak = et->peak(); + int slices = (et->ExVec()).size(); + if (m_forceSlicesCmm) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmm); + slices = m_forceSlicesCmm; + } + msg() << "crate/dataID/peak/Ex/Ey/Et/ExErr/EyErr/EtErr: " + << et->crate() << "/" << et->dataID() << "/" << peak << "/"; + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + std::vector<int> exError; + std::vector<int> eyError; + std::vector<int> etError; + ModifySlices::data(et->ExVec(), exVec, slices); + ModifySlices::data(et->EyVec(), eyVec, slices); + ModifySlices::data(et->EtVec(), etVec, slices); + ModifySlices::data(et->ExErrorVec(), exError, slices); + ModifySlices::data(et->EyErrorVec(), eyError, slices); + ModifySlices::data(et->EtErrorVec(), etError, slices); + printVecU(exVec); + printVecU(eyVec); + printVecU(etVec); + msg() << MSG::hex; + printVec(exError); + printVec(eyError); + printVec(etError); + msg() << MSG::dec << endreq; + } +} + +// Print the JEM RoIs + +void JemTesterV1::printJemRois(const std::string& source) const +{ + msg() << "Number of JEM RoIs (" << source << ") = " << m_roiMap.size() + << endreq; + JemRoiMap::const_iterator mapIter = m_roiMap.begin(); + JemRoiMap::const_iterator mapEnd = m_roiMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMRoI* const roi = mapIter->second; + msg() << "crate/jem/frame/loc/fwd/hits/error: " + << roi->crate() << "/" << roi->jem() << "/" << roi->frame() << "/" + << roi->location() << "/" << roi->forward() << "/"; + const int hits = roi->hits(); + const int numHits = (roi->forward()) ? 4 : 8; + for (int i = 0; i < numHits; ++i) { + if (i > 0) msg() << ":"; + msg() << ((hits >> i) & 0x1); + } + msg() << "/" << roi->error() << "/" << endreq; + } +} + +// Print the CMM RoIs + +void JemTesterV1::printCmmRois(const std::string& source, + const LVL1::CMMRoI* const roi) const +{ + msg() << "CMMRoI(" << source + << "):jetEtHits/sumEtHits/missingEtHits/missingEtSigHits/Ex/Ey/Et;error: " + << MSG::hex << roi->jetEtHits() << ";" << roi->jetEtError() << "/" + << roi->sumEtHits() << ";" << roi->sumEtError() << "/" + << roi->missingEtHits() << ";" << roi->missingEtError() << "/" + << roi->missingEtSigHits() << ";" << roi->missingEtSigError() << "/" + << MSG::dec << roi->ex() << ";" << roi->exError() << "/" + << roi->ey() << ";" << roi->eyError() << "/" + << roi->et() << ";" << roi->etError() << "/" << endreq; +} + +// Print a vector + +void JemTesterV1::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Print a vector (unsigned) + +void JemTesterV1::printVecU(const std::vector<unsigned int>& vec) const +{ + std::vector<unsigned int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Set up jet element map + +void JemTesterV1::setupJeMap(const JetElementCollection* const jeCollection) +{ + m_jeMap.clear(); + if (jeCollection) { + JetElementCollection::const_iterator pos = jeCollection->begin(); + JetElementCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JetElement* const je = *pos; + const unsigned int key = m_elementKey->jeKey(je->phi(), je->eta()); + m_jeMap.insert(std::make_pair(key, je)); + } + } +} + +// Set up jet hits map + +void JemTesterV1::setupHitsMap(const JetHitsCollection* const hitCollection) +{ + m_hitsMap.clear(); + if (hitCollection) { + JetHitsCollection::const_iterator pos = hitCollection->begin(); + JetHitsCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMHits* const hits = *pos; + const int key = hits->crate()*100 + hits->module(); + m_hitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up energy sums map + +void JemTesterV1::setupEtMap(const EnergySumsCollection* const etCollection) +{ + m_etMap.clear(); + if (etCollection) { + EnergySumsCollection::const_iterator pos = etCollection->begin(); + EnergySumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMEtSums* const sums = *pos; + // Sim doesn't zero suppress properly, do it here + if (std::accumulate((sums->ExVec()).begin(), (sums->ExVec()).end(), 0) || + std::accumulate((sums->EyVec()).begin(), (sums->EyVec()).end(), 0) || + std::accumulate((sums->EtVec()).begin(), (sums->EtVec()).end(), 0)) { + const int key = sums->crate()*100 + sums->module(); + m_etMap.insert(std::make_pair(key, sums)); + } + } + } +} + +// Set up CMM hits map + +void JemTesterV1::setupCmmHitsMap(const CmmJetCollection* const hitCollection) +{ + m_cmmHitsMap.clear(); + if (hitCollection) { + CmmJetCollection::const_iterator pos = hitCollection->begin(); + CmmJetCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMJetHits* const hits = *pos; + const int key = hits->crate()*100 + hits->dataID(); + m_cmmHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMM energy sums map + +void JemTesterV1::setupCmmEtMap(const CmmEnergyCollection* const etCollection) +{ + m_cmmEtMap.clear(); + if (etCollection) { + CmmEnergyCollection::const_iterator pos = etCollection->begin(); + CmmEnergyCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMMEtSums* const sums = *pos; + if (std::accumulate((sums->ExVec()).begin(), (sums->ExVec()).end(), 0) || + std::accumulate((sums->EyVec()).begin(), (sums->EyVec()).end(), 0) || + std::accumulate((sums->EtVec()).begin(), (sums->EtVec()).end(), 0) || + std::accumulate((sums->ExErrorVec()).begin(), + (sums->ExErrorVec()).end(), 0) || + std::accumulate((sums->EyErrorVec()).begin(), + (sums->EyErrorVec()).end(), 0) || + std::accumulate((sums->EtErrorVec()).begin(), + (sums->EtErrorVec()).end(), 0)) { + const int key = sums->crate()*100 + sums->dataID(); + m_cmmEtMap.insert(std::make_pair(key, sums)); + } + } + } +} + +// Set up JEM RoI map + +void JemTesterV1::setupJemRoiMap(const JemRoiCollection* const jrCollection) +{ + m_roiMap.clear(); + if (jrCollection) { + JemRoiCollection::const_iterator pos = jrCollection->begin(); + JemRoiCollection::const_iterator pose = jrCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV1.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV1.h new file mode 100755 index 0000000000000000000000000000000000000000..3ab152fc80aad8ebd194f550c66df0810e9b136b --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV1.h @@ -0,0 +1,164 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMTESTERV1_H +#define TRIGT1CALOBYTESTREAM_JEMTESTERV1_H + +#include <map> +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CMMEtSums; + class CMMJetHits; + class CMMRoI; + class JEMEtSums; + class JEMHits; + class JEMRoI; + class JetElement; + class JetElementKey; +} + +namespace LVL1BS { + +/** Algorithm to test JEM component bytestream conversions. + * + * Just prints out the contents of the JetElement objects, + * JEMHits objects and JEMEtSums objects. + * Now also includes CMMJetHits, CMMEtSums, JEMRoI and CMMRoI. + * + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class JemTesterV1 : public AthAlgorithm { + + public: + JemTesterV1(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~JemTesterV1(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef DataVector<LVL1::JetElement> JetElementCollection; + typedef DataVector<LVL1::JEMHits> JetHitsCollection; + typedef DataVector<LVL1::JEMEtSums> EnergySumsCollection; + typedef DataVector<LVL1::CMMJetHits> CmmJetCollection; + typedef DataVector<LVL1::CMMEtSums> CmmEnergyCollection; + typedef DataVector<LVL1::JEMRoI> JemRoiCollection; + typedef std::map<unsigned int, const LVL1::JetElement*> JetElementMap; + typedef std::map<int, const LVL1::JEMHits*> JetHitsMap; + typedef std::map<int, const LVL1::JEMEtSums*> EnergySumsMap; + typedef std::map<int, const LVL1::CMMJetHits*> CmmHitsMap; + typedef std::map<int, const LVL1::CMMEtSums*> CmmSumsMap; + typedef std::map<uint32_t, const LVL1::JEMRoI*> JemRoiMap; + + /// Print the jet elements + void printJetElements(const std::string& source) const; + /// Print the jet hits + void printJetHits() const; + /// Print the energy sums + void printEnergySums() const; + /// Print the CMM hits + void printCmmHits() const; + /// Print the CMM energy sums + void printCmmSums() const; + /// Print the JEM RoIs + void printJemRois(const std::string& source) const; + /// Print the CMM RoIs + void printCmmRois(const std::string& source, + const LVL1::CMMRoI* roi) const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + /// Print a vector (unsigned) + void printVecU(const std::vector<unsigned int>& vec) const; + + /// Set up jet element map + void setupJeMap(const JetElementCollection* jeCollection); + /// Set up jet hits map + void setupHitsMap(const JetHitsCollection* hitCollection); + /// Set up energy sums map + void setupEtMap(const EnergySumsCollection* etCollection); + /// Set up CMM hits map + void setupCmmHitsMap(const CmmJetCollection* hitCollection); + /// Set up CMM energy sums map + void setupCmmEtMap(const CmmEnergyCollection* etCollection); + /// Set up JEM RoI map + void setupJemRoiMap(const JemRoiCollection* jrCollection); + + /// Jet element key provider + LVL1::JetElementKey* m_elementKey; + /// Jet element container StoreGate key + std::string m_jetElementLocation; + /// Jet hits container StoreGate key + std::string m_jemHitsLocation; + /// Energy sums container StoreGate key + std::string m_jemEtSumsLocation; + /// CMM hits container StoreGate key + std::string m_cmmJetLocation; + /// CMM energy sums container StoreGate key + std::string m_cmmEnergyLocation; + /// JEM RoI container StoreGate key + std::string m_jemRoiLocation; + /// CMM RoI container StoreGate key + std::string m_cmmRoiLocation; + /// JEM RoI from RoIB container StoreGate key + std::string m_jemRoiLocationRoib; + /// CMM RoI from RoIB container StoreGate key + std::string m_cmmRoiLocationRoib; + /// Jet element overlap container StoreGate key + std::string m_jetElementLocationOverlap; + /// Force number of JEM slices + int m_forceSlicesJem; + /// Force number of CMM slices + int m_forceSlicesCmm; + /// Jet element print flag + int m_jetElementPrint; + /// Jet hits print flag + int m_jemHitsPrint; + /// Energy sums print flag + int m_jemEtSumsPrint; + /// CMM hits print flag + int m_cmmHitsPrint; + /// CMM energy sums print flag + int m_cmmEtSumsPrint; + /// JEM RoI print flag + int m_jemRoiPrint; + /// CMM RoI print flag + int m_cmmRoiPrint; + /// JEM RoI from RoIB print flag + int m_jemRoiPrintRoib; + /// CMM RoI from RoIB print flag + int m_cmmRoiPrintRoib; + /// Jet element overlap print flag + int m_jetElementPrintOverlap; + + /// Jet element map + JetElementMap m_jeMap; + /// Jet hits map + JetHitsMap m_hitsMap; + /// Energy sums map + EnergySumsMap m_etMap; + /// CMM hits map + CmmHitsMap m_cmmHitsMap; + /// CMM energy sums map + CmmSumsMap m_cmmEtMap; + /// JEM RoI map + JemRoiMap m_roiMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV2.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV2.cxx new file mode 100755 index 0000000000000000000000000000000000000000..8ad28a0e8c0747a6efd66ee3e99ee0133bf99123 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV2.cxx @@ -0,0 +1,752 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <numeric> +#include <utility> + +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ISvcLocator.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/CMXEtSums.h" +#include "TrigT1CaloEvent/CMXJetTob.h" +#include "TrigT1CaloEvent/CMXJetHits.h" +#include "TrigT1CaloEvent/CMXRoI.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JEMTobRoI.h" +#include "TrigT1CaloEvent/JetElement.h" +#include "TrigT1CaloUtils/JetElementKey.h" +#include "TrigT1CaloUtils/DataError.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "JemTesterV2.h" +#include "../src/ModifySlices.h" + +namespace LVL1BS { + +JemTesterV2::JemTesterV2(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_elementKey(0) +{ + declareProperty("JetElementLocation", + m_jetElementLocation = LVL1::TrigT1CaloDefs::JetElementLocation); + declareProperty("JEMEtSumsLocation", + m_jemEtSumsLocation = LVL1::TrigT1CaloDefs::JEMEtSumsLocation); + declareProperty("CMXJetTobLocation", + m_cmxTobLocation = LVL1::TrigT1CaloDefs::CMXJetTobLocation); + declareProperty("CMXJetHitsLocation", + m_cmxJetLocation = LVL1::TrigT1CaloDefs::CMXJetHitsLocation); + declareProperty("CMXEtSumsLocation", + m_cmxEnergyLocation = LVL1::TrigT1CaloDefs::CMXEtSumsLocation); + declareProperty("JEMTobRoILocation", + m_jemRoiLocation = LVL1::TrigT1CaloDefs::JEMTobRoILocation); + declareProperty("CMXRoILocation", + m_cmxRoiLocation = LVL1::TrigT1CaloDefs::CMXRoILocation); + declareProperty("JEMTobRoILocationRoIB", + m_jemRoiLocationRoib = + LVL1::TrigT1CaloDefs::JEMTobRoILocation + "RoIB"); + declareProperty("CMXRoILocationRoIB", + m_cmxRoiLocationRoib = + LVL1::TrigT1CaloDefs::CMXRoILocation + "RoIB"); + declareProperty("JetElementLocationOverlap", + m_jetElementLocationOverlap = + LVL1::TrigT1CaloDefs::JetElementLocation + "Overlap"); + + declareProperty("ForceSlicesJEM", m_forceSlicesJem = 0); + declareProperty("ForceSlicesCMX", m_forceSlicesCmx = 0); + + // By default print everything except RoIB RoIs and jet element overlap + declareProperty("JetElementPrint", m_jetElementPrint = 1); + declareProperty("JEMEtSumsPrint", m_jemEtSumsPrint = 1); + declareProperty("CMXJetTobPrint", m_cmxTobPrint = 1, + "Set to 2 to print presence maps (Neutral format only)"); + declareProperty("CMXJetHitsPrint", m_cmxHitsPrint = 1); + declareProperty("CMXEtSumsPrint", m_cmxEtSumsPrint = 1); + declareProperty("JEMRoIPrint", m_jemRoiPrint = 1); + declareProperty("CMXRoIPrint", m_cmxRoiPrint = 1); + declareProperty("JEMRoIPrintRoIB", m_jemRoiPrintRoib = 0); + declareProperty("CMXRoIPrintRoIB", m_cmxRoiPrintRoib = 0); + declareProperty("JetElementPrintOverlap", m_jetElementPrintOverlap = 0); +} + +JemTesterV2::~JemTesterV2() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode JemTesterV2::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + m_elementKey = new LVL1::JetElementKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode JemTesterV2::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + if (m_jetElementPrint) { + + // Find core jet elements + + const JetElementCollection* jeCollection = 0; + StatusCode sc = evtStore()->retrieve(jeCollection, m_jetElementLocation); + if (sc.isFailure() || !jeCollection || jeCollection->empty()) { + msg() << "No core Jet Elements found" << endreq; + } else { + + // Order by eta, phi + + setupJeMap(jeCollection); + + // Print the jet elements + + printJetElements("core"); + } + } + + if (m_jetElementPrintOverlap) { + + // Find overlap jet elements + + const JetElementCollection* jeCollection = 0; + StatusCode sc = evtStore()->retrieve(jeCollection, + m_jetElementLocationOverlap); + if (sc.isFailure() || !jeCollection || jeCollection->empty()) { + msg() << "No overlap Jet Elements found" << endreq; + } else { + + // Order by eta, phi + + setupJeMap(jeCollection); + + // Print the jet elements + + printJetElements("overlap"); + } + } + + if (m_jemEtSumsPrint) { + + // Find energy sums + + const EnergySumsCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_jemEtSumsLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No Energy Sums found" << endreq; + } else { + + // Order by crate, module + + setupEtMap(etCollection); + + // Print the energy sums + + printEnergySums(); + } + } + + if (m_cmxTobPrint) { + + // Find CMX TOBs + + const CmxTobCollection* tobCollection = 0; + StatusCode sc = evtStore()->retrieve(tobCollection, m_cmxTobLocation); + if (sc.isFailure() || !tobCollection || tobCollection->empty()) { + msg() << "No CMX TOBs found" << endreq; + } else { + + // Order by crate, jem, frame, loc + + setupCmxTobMap(tobCollection); + + // Print the CMX TOBs + + printCmxTobs(); + } + } + + if (m_cmxHitsPrint) { + + // Find CMX hits + + const CmxJetCollection* hitCollection = 0; + StatusCode sc = evtStore()->retrieve(hitCollection, m_cmxJetLocation); + if (sc.isFailure() || !hitCollection || hitCollection->empty()) { + msg() << "No CMX Hits found" << endreq; + } else { + + // Order by crate, source + + setupCmxHitsMap(hitCollection); + + // Print the CMX hits + + printCmxHits(); + } + } + + if (m_cmxEtSumsPrint) { + + // Find CMX energy sums + + const CmxEnergyCollection* etCollection = 0; + StatusCode sc = evtStore()->retrieve(etCollection, m_cmxEnergyLocation); + if (sc.isFailure() || !etCollection || etCollection->empty()) { + msg() << "No CMX Energy Sums found" << endreq; + } else { + + // Order by crate, source + + setupCmxEtMap(etCollection); + + // Print the CMX energy sums + + printCmxSums(); + } + } + + if (m_jemRoiPrint) { + + // Find JEM RoIs + + const JemRoiCollection* jrCollection = 0; + StatusCode sc = evtStore()->retrieve(jrCollection, m_jemRoiLocation); + if (sc.isFailure() || !jrCollection || jrCollection->empty()) { + msg() << "No JEM RoIs found" << endreq; + } else { + + // Order by RoI word + + setupJemRoiMap(jrCollection); + + // Print the JEM RoIs + + printJemRois("DAQ"); + } + } + + if (m_jemRoiPrintRoib) { + + // Find JEM RoIs from RoIB + + const JemRoiCollection* jrCollection = 0; + StatusCode sc = evtStore()->retrieve(jrCollection, m_jemRoiLocationRoib); + if (sc.isFailure() || !jrCollection || jrCollection->empty()) { + msg() << "No JEM RoIs from RoIB found" << endreq; + } else { + + // Order by RoI word + + setupJemRoiMap(jrCollection); + + // Print the JEM RoIs from RoIB + + printJemRois("RoIB"); + } + } + + if (m_cmxRoiPrint) { + + // Find CMX RoIs + + const LVL1::CMXRoI* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cmxRoiLocation); + if (sc.isFailure() || !crCollection || (!crCollection->roiWord(0) && + !crCollection->roiWord(1) && + !crCollection->roiWord(2) && + !crCollection->roiWord(3) && + !crCollection->roiWord(4) && + !crCollection->roiWord(5))) { + msg() << "No CMX RoIs found" << endreq; + } else { + + // Print the CMX RoIs + + printCmxRois("DAQ", crCollection); + } + } + + if (m_cmxRoiPrintRoib) { + + // Find CMX RoIs from RoIB + + const LVL1::CMXRoI* crCollection = 0; + StatusCode sc = evtStore()->retrieve(crCollection, m_cmxRoiLocationRoib); + if (sc.isFailure() || !crCollection || (!crCollection->roiWord(0) && + !crCollection->roiWord(1) && + !crCollection->roiWord(2) && + !crCollection->roiWord(3) && + !crCollection->roiWord(4) && + !crCollection->roiWord(5))) { + msg() << "No CMX RoIs from RoIB found" << endreq; + } else { + + // Print the CMX RoIs from RoIB + + printCmxRois("RoIB", crCollection); + } + } + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode JemTesterV2::finalize() +{ + delete m_elementKey; + + return StatusCode::SUCCESS; +} + +// Print the jet elements + +void JemTesterV2::printJetElements(const std::string& source) const +{ + msg() << "Number of " << source << " Jet Elements = " + << m_jeMap.size() << endreq; + JetElementMap::const_iterator mapIter = m_jeMap.begin(); + JetElementMap::const_iterator mapEnd = m_jeMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JetElement* const je = mapIter->second; + int peak = je->peak(); + int slices = (je->emEnergyVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + std::vector<int> emEnergy; + std::vector<int> hadEnergy; + std::vector<int> emError; + std::vector<int> hadError; + std::vector<int> linkError; + ModifySlices::data(je->emEnergyVec(), emEnergy, slices); + ModifySlices::data(je->hadEnergyVec(), hadEnergy, slices); + ModifySlices::data(je->emErrorVec(), emError, slices); + ModifySlices::data(je->hadErrorVec(), hadError, slices); + ModifySlices::data(je->linkErrorVec(), linkError, slices); + msg() << "key/eta/phi/peak/em/had/emErr/hadErr/linkErr: " + << mapIter->first << "/" << je->eta() << "/" << je->phi() << "/" + << peak << "/"; + printVec(emEnergy); + printVec(hadEnergy); + msg() << MSG::hex; + printVec(emError); + printVec(hadError); + printVec(linkError); + msg() << MSG::dec << endreq; + } +} + +// Print energy sums + +void JemTesterV2::printEnergySums() const +{ + msg() << "Number of Energy Sums = " << m_etMap.size() << endreq; + EnergySumsMap::const_iterator mapIter = m_etMap.begin(); + EnergySumsMap::const_iterator mapEnd = m_etMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMEtSums* const et = mapIter->second; + int peak = et->peak(); + int slices = (et->ExVec()).size(); + if (m_forceSlicesJem) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesJem); + slices = m_forceSlicesJem; + } + msg() << "crate/module/peak/Ex/Ey/Et: " + << et->crate() << "/" << et->module() << "/" << peak << "/"; + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + ModifySlices::data(et->ExVec(), exVec, slices); + ModifySlices::data(et->EyVec(), eyVec, slices); + ModifySlices::data(et->EtVec(), etVec, slices); + printVecU(exVec); + printVecU(eyVec); + printVecU(etVec); + msg() << endreq; + } +} + +// Print the CMX-Jet TOBs + +void JemTesterV2::printCmxTobs() const +{ + msg() << "Number of CMX-Jet TOBs = " << m_cmxTobMap.size() << endreq; + CmxTobMap::const_iterator mapIter = m_cmxTobMap.begin(); + CmxTobMap::const_iterator mapEnd = m_cmxTobMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMXJetTob* const tb = mapIter->second; + int peak = tb->peak(); + int slices = (tb->energyLgVec()).size(); + if (m_forceSlicesCmx) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmx); + slices = m_forceSlicesCmx; + } + if (m_cmxTobPrint == 2) { + msg() << "crate/jem/frame/loc/peak/energyLg/energySm/error/presenceMap: "; + } else { + msg() << "crate/jem/frame/loc/peak/energyLg/energySm/error: "; + } + msg() << tb->crate() << "/" << tb->jem() << "/" << tb->frame() << "/" + << tb->location() << "/" << peak << "/"; + + std::vector<int> energyLg; + std::vector<int> energySm; + std::vector<int> error; + ModifySlices::data(tb->energyLgVec(), energyLg, slices); + ModifySlices::data(tb->energySmVec(), energySm, slices); + ModifySlices::data(tb->errorVec(), error, slices); + printVec(energyLg); + printVec(energySm); + msg() << MSG::hex; + printVec(error); + if (m_cmxTobPrint == 2) { + std::vector<unsigned int> presence; + ModifySlices::data(tb->presenceMapVec(), presence, slices); + printVecH(presence, 1, 16); + } + msg() << MSG::dec << endreq; + } +} + +// Print the CMX hits + +void JemTesterV2::printCmxHits() const +{ + msg() << "Number of CMX Hits = " << m_cmxHitsMap.size() << endreq; + CmxHitsMap::const_iterator mapIter = m_cmxHitsMap.begin(); + CmxHitsMap::const_iterator mapEnd = m_cmxHitsMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMXJetHits* const jh = mapIter->second; + const int source = jh->source(); + int peak = jh->peak(); + int slices = (jh->hitsVec0()).size(); + if (m_forceSlicesCmx) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmx); + slices = m_forceSlicesCmx; + } + msg() << "crate/source/peak/hits0/hits1/error0/error1: " + << jh->crate() << "/" << source << "/" << peak << "/"; + int words1 = 5; + int words2 = 5; + int bits = 3; + unsigned int mask = 0x7; + if (source == LVL1::CMXJetHits::REMOTE_FORWARD || + source == LVL1::CMXJetHits::LOCAL_FORWARD || + source == LVL1::CMXJetHits::TOTAL_FORWARD) { + words1 = 8; + words2 = 7; + bits = 2; + mask = 0x3; + } else if (source == LVL1::CMXJetHits::TOPO_CHECKSUM) { + words1 = 1; + words2 = 0; + bits = 16; + mask = 0xffff; + } else if (source == LVL1::CMXJetHits::TOPO_OCCUPANCY_MAP) { + words1 = 16; + words2 = 0; + bits = 1; + mask = 0x1; + } else if (source == LVL1::CMXJetHits::TOPO_OCCUPANCY_COUNTS) { + words1 = 8; + words2 = 8; + } + std::vector<unsigned int> hitsVec0; + std::vector<unsigned int> hitsVec1; + ModifySlices::data(jh->hitsVec0(), hitsVec0, slices); + ModifySlices::data(jh->hitsVec1(), hitsVec1, slices); + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = hitsVec0.begin(); + std::vector<unsigned int>::const_iterator pose = hitsVec0.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words1; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> bits*i) & mask; + msg() << thr; + } + } + msg() << "/"; + posb = hitsVec1.begin(); + pose = hitsVec1.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words2; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> bits*i) & mask; + msg() << thr; + } + } + msg() << "/" << MSG::hex; + std::vector<int> errorVec0; + std::vector<int> errorVec1; + ModifySlices::data(jh->errorVec0(), errorVec0, slices); + ModifySlices::data(jh->errorVec1(), errorVec1, slices); + printVec(errorVec0); + printVec(errorVec1); + msg() << MSG::dec << endreq; + } +} + +// Print CMX energy sums + +void JemTesterV2::printCmxSums() const +{ + msg() << "Number of CMX Energy Sums = " << m_cmxEtMap.size() << endreq; + CmxSumsMap::const_iterator mapIter = m_cmxEtMap.begin(); + CmxSumsMap::const_iterator mapEnd = m_cmxEtMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::CMXEtSums* const et = mapIter->second; + int peak = et->peak(); + int slices = (et->ExVec()).size(); + if (m_forceSlicesCmx) { + peak = ModifySlices::peak(peak, slices, m_forceSlicesCmx); + slices = m_forceSlicesCmx; + } + msg() << "crate/source/peak/Ex/Ey/Et/ExErr/EyErr/EtErr: " + << et->crate() << "/" << et->source() << "/" << peak << "/"; + std::vector<unsigned int> exVec; + std::vector<unsigned int> eyVec; + std::vector<unsigned int> etVec; + std::vector<int> exError; + std::vector<int> eyError; + std::vector<int> etError; + ModifySlices::data(et->ExVec(), exVec, slices); + ModifySlices::data(et->EyVec(), eyVec, slices); + ModifySlices::data(et->EtVec(), etVec, slices); + ModifySlices::data(et->ExErrorVec(), exError, slices); + ModifySlices::data(et->EyErrorVec(), eyError, slices); + ModifySlices::data(et->EtErrorVec(), etError, slices); + printVecU(exVec); + printVecU(eyVec); + printVecU(etVec); + msg() << MSG::hex; + printVec(exError); + printVec(eyError); + printVec(etError); + msg() << MSG::dec << endreq; + } +} + +// Print the JEM RoIs + +void JemTesterV2::printJemRois(const std::string& source) const +{ + msg() << "Number of JEM RoIs (" << source << ") = " << m_roiMap.size() + << endreq; + JemRoiMap::const_iterator mapIter = m_roiMap.begin(); + JemRoiMap::const_iterator mapEnd = m_roiMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::JEMTobRoI* const roi = mapIter->second; + msg() << "crate/jem/frame/loc/energyLg/energySm: " + << roi->crate() << "/" << roi->jem() << "/" << roi->frame() << "/" + << roi->location() << "/" << roi->energyLarge() << "/" + << roi->energySmall() << "/" << endreq; + } +} + +// Print the CMX RoIs + +void JemTesterV2::printCmxRois(const std::string& source, + const LVL1::CMXRoI* const roi) const +{ + msg() << "CMXRoI(" << source + << "):Normal:sumEtHits/missingEtHits/missingEtSigHits/Ex/Ey/Et;error: " + << MSG::hex + << roi->sumEtHits() << "/" + << roi->missingEtHits() << "/" + << roi->missingEtSigHits() << "/" + << MSG::dec + << roi->ex() << ";" << roi->exError() << "/" + << roi->ey() << ";" << roi->eyError() << "/" + << roi->et() << ";" << roi->etError() << "/" << endreq; + msg() << "CMXRoI(" << source + << "):Masked:sumEtHits/missingEtHits/Ex/Ey/Et;error: " + << MSG::hex + << roi->sumEtHits(LVL1::CMXRoI::MASKED) << "/" + << roi->missingEtHits(LVL1::CMXRoI::MASKED) << "/" + << MSG::dec + << roi->ex(LVL1::CMXRoI::MASKED) << ";" + << roi->exError(LVL1::CMXRoI::MASKED) << "/" + << roi->ey(LVL1::CMXRoI::MASKED) << ";" + << roi->eyError(LVL1::CMXRoI::MASKED) << "/" + << roi->et(LVL1::CMXRoI::MASKED) << ";" + << roi->etError(LVL1::CMXRoI::MASKED) << "/" << endreq; +} + +// Print a vector + +void JemTesterV2::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Print a vector (unsigned) + +void JemTesterV2::printVecU(const std::vector<unsigned int>& vec) const +{ + std::vector<unsigned int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Print a vector of hits + +void JemTesterV2::printVecH(const std::vector<unsigned int>& vec, + const int bits, const int words) const +{ + const unsigned int mask = (1<<bits)-1; + std::vector<unsigned int>::const_iterator pos; + std::vector<unsigned int>::const_iterator posb = vec.begin(); + std::vector<unsigned int>::const_iterator pose = vec.end(); + for (pos = posb; pos != pose; ++pos) { + if (pos != posb) msg() << ","; + const unsigned int hits = *pos; + for (int i = 0; i < words; ++i) { + if (i != 0) msg() << ":"; + const unsigned int thr = (hits >> (bits*i)) & mask; + msg() << thr; + } + } + msg() << "/"; +} + +// Set up jet element map + +void JemTesterV2::setupJeMap(const JetElementCollection* const jeCollection) +{ + m_jeMap.clear(); + if (jeCollection) { + JetElementCollection::const_iterator pos = jeCollection->begin(); + JetElementCollection::const_iterator pose = jeCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JetElement* const je = *pos; + const unsigned int key = m_elementKey->jeKey(je->phi(), je->eta()); + m_jeMap.insert(std::make_pair(key, je)); + } + } +} + +// Set up energy sums map + +void JemTesterV2::setupEtMap(const EnergySumsCollection* const etCollection) +{ + m_etMap.clear(); + if (etCollection) { + EnergySumsCollection::const_iterator pos = etCollection->begin(); + EnergySumsCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMEtSums* const sums = *pos; + // Sim doesn't zero suppress properly, do it here + if (std::accumulate((sums->ExVec()).begin(), (sums->ExVec()).end(), 0) || + std::accumulate((sums->EyVec()).begin(), (sums->EyVec()).end(), 0) || + std::accumulate((sums->EtVec()).begin(), (sums->EtVec()).end(), 0)) { + const int key = sums->crate()*100 + sums->module(); + m_etMap.insert(std::make_pair(key, sums)); + } + } + } +} + +// Set up CMX TOBs map + +void JemTesterV2::setupCmxTobMap(const CmxTobCollection* const tobCollection) +{ + m_cmxTobMap.clear(); + if (tobCollection) { + CmxTobCollection::const_iterator pos = tobCollection->begin(); + CmxTobCollection::const_iterator pose = tobCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMXJetTob* const tob = *pos; + const int key = ((((((tob->crate()<<4)+tob->jem())<<3)+tob->frame())<<2) + +tob->location()); + m_cmxTobMap.insert(std::make_pair(key, tob)); + } + } +} + +// Set up CMX hits map + +void JemTesterV2::setupCmxHitsMap(const CmxJetCollection* const hitCollection) +{ + m_cmxHitsMap.clear(); + if (hitCollection) { + CmxJetCollection::const_iterator pos = hitCollection->begin(); + CmxJetCollection::const_iterator pose = hitCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMXJetHits* const hits = *pos; + const int key = hits->crate()*100 + hits->source(); + m_cmxHitsMap.insert(std::make_pair(key, hits)); + } + } +} + +// Set up CMX energy sums map + +void JemTesterV2::setupCmxEtMap(const CmxEnergyCollection* const etCollection) +{ + m_cmxEtMap.clear(); + if (etCollection) { + CmxEnergyCollection::const_iterator pos = etCollection->begin(); + CmxEnergyCollection::const_iterator pose = etCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::CMXEtSums* const sums = *pos; + if (std::accumulate((sums->ExVec()).begin(), (sums->ExVec()).end(), 0) || + std::accumulate((sums->EyVec()).begin(), (sums->EyVec()).end(), 0) || + std::accumulate((sums->EtVec()).begin(), (sums->EtVec()).end(), 0) || + std::accumulate((sums->ExErrorVec()).begin(), + (sums->ExErrorVec()).end(), 0) || + std::accumulate((sums->EyErrorVec()).begin(), + (sums->EyErrorVec()).end(), 0) || + std::accumulate((sums->EtErrorVec()).begin(), + (sums->EtErrorVec()).end(), 0)) { + const int key = sums->crate()*100 + sums->source(); + m_cmxEtMap.insert(std::make_pair(key, sums)); + } + } + } +} + +// Set up JEM RoI map + +void JemTesterV2::setupJemRoiMap(const JemRoiCollection* const jrCollection) +{ + m_roiMap.clear(); + if (jrCollection) { + JemRoiCollection::const_iterator pos = jrCollection->begin(); + JemRoiCollection::const_iterator pose = jrCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::JEMTobRoI* const roi = *pos; + const uint32_t key = roi->roiWord(); + m_roiMap.insert(std::make_pair(key, roi)); + } + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV2.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV2.h new file mode 100755 index 0000000000000000000000000000000000000000..ea12e247880a533b9bf1431e1c32459bd89480a7 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/JemTesterV2.h @@ -0,0 +1,166 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_JEMTESTERV2_H +#define TRIGT1CALOBYTESTREAM_JEMTESTERV2_H + +#include <map> +#include <string> +#include <stdint.h> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class CMXEtSums; + class CMXJetTob; + class CMXJetHits; + class CMXRoI; + class JEMEtSums; + class JEMTobRoI; + class JetElement; + class JetElementKey; +} + +namespace LVL1BS { + +/** Algorithm to test JEM component bytestream conversions. + * + * Just prints out the contents of the JetElement objects, + * JEMEtSums, CMXJetTob, CMXJetHits, CMXEtSums, JEMTobRoI and CMXRoI. + * + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class JemTesterV2 : public AthAlgorithm { + + public: + JemTesterV2(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~JemTesterV2(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef DataVector<LVL1::JetElement> JetElementCollection; + typedef DataVector<LVL1::JEMEtSums> EnergySumsCollection; + typedef DataVector<LVL1::CMXJetTob> CmxTobCollection; + typedef DataVector<LVL1::CMXJetHits> CmxJetCollection; + typedef DataVector<LVL1::CMXEtSums> CmxEnergyCollection; + typedef DataVector<LVL1::JEMTobRoI> JemRoiCollection; + typedef std::map<unsigned int, const LVL1::JetElement*> JetElementMap; + typedef std::map<int, const LVL1::JEMEtSums*> EnergySumsMap; + typedef std::map<int, const LVL1::CMXJetTob*> CmxTobMap; + typedef std::map<int, const LVL1::CMXJetHits*> CmxHitsMap; + typedef std::map<int, const LVL1::CMXEtSums*> CmxSumsMap; + typedef std::map<uint32_t, const LVL1::JEMTobRoI*> JemRoiMap; + + /// Print the jet elements + void printJetElements(const std::string& source) const; + /// Print the energy sums + void printEnergySums() const; + /// Print the CMX TOBs + void printCmxTobs() const; + /// Print the CMX hits + void printCmxHits() const; + /// Print the CMX energy sums + void printCmxSums() const; + /// Print the JEM RoIs + void printJemRois(const std::string& source) const; + /// Print the CMX RoIs + void printCmxRois(const std::string& source, + const LVL1::CMXRoI* roi) const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + /// Print a vector (unsigned) + void printVecU(const std::vector<unsigned int>& vec) const; + /// Print a vector of hits + void printVecH(const std::vector<unsigned int>& vec, int bits, + int words) const; + + /// Set up jet element map + void setupJeMap(const JetElementCollection* jeCollection); + /// Set up energy sums map + void setupEtMap(const EnergySumsCollection* etCollection); + /// Set up CMX TOB map + void setupCmxTobMap(const CmxTobCollection* tobCollection); + /// Set up CMX hits map + void setupCmxHitsMap(const CmxJetCollection* hitCollection); + /// Set up CMX energy sums map + void setupCmxEtMap(const CmxEnergyCollection* etCollection); + /// Set up JEM RoI map + void setupJemRoiMap(const JemRoiCollection* jrCollection); + + /// Jet element key provider + LVL1::JetElementKey* m_elementKey; + /// Jet element container StoreGate key + std::string m_jetElementLocation; + /// Energy sums container StoreGate key + std::string m_jemEtSumsLocation; + /// CMX TOB container StoreGate key + std::string m_cmxTobLocation; + /// CMX hits container StoreGate key + std::string m_cmxJetLocation; + /// CMX energy sums container StoreGate key + std::string m_cmxEnergyLocation; + /// JEM RoI container StoreGate key + std::string m_jemRoiLocation; + /// CMX RoI container StoreGate key + std::string m_cmxRoiLocation; + /// JEM RoI from RoIB container StoreGate key + std::string m_jemRoiLocationRoib; + /// CMX RoI from RoIB container StoreGate key + std::string m_cmxRoiLocationRoib; + /// Jet element overlap container StoreGate key + std::string m_jetElementLocationOverlap; + /// Force number of JEM slices + int m_forceSlicesJem; + /// Force number of CMX slices + int m_forceSlicesCmx; + /// Jet element print flag + int m_jetElementPrint; + /// Energy sums print flag + int m_jemEtSumsPrint; + /// CMX TOB print flag + int m_cmxTobPrint; + /// CMX hits print flag + int m_cmxHitsPrint; + /// CMX energy sums print flag + int m_cmxEtSumsPrint; + /// JEM RoI print flag + int m_jemRoiPrint; + /// CMX RoI print flag + int m_cmxRoiPrint; + /// JEM RoI from RoIB print flag + int m_jemRoiPrintRoib; + /// CMX RoI from RoIB print flag + int m_cmxRoiPrintRoib; + /// Jet element overlap print flag + int m_jetElementPrintOverlap; + + /// Jet element map + JetElementMap m_jeMap; + /// Energy sums map + EnergySumsMap m_etMap; + /// CMX TOB map + CmxTobMap m_cmxTobMap; + /// CMX hits map + CmxHitsMap m_cmxHitsMap; + /// CMX energy sums map + CmxSumsMap m_cmxEtMap; + /// JEM RoI map + JemRoiMap m_roiMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmMappingTester.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmMappingTester.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1280c454e68d18824bcf6a07fc815090fcb2b31d --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmMappingTester.cxx @@ -0,0 +1,225 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <cmath> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" + +#include "TrigT1CaloMappingToolInterfaces/IL1CaloMappingTool.h" + +#include "PpmMappingTester.h" + +namespace LVL1BS { + +PpmMappingTester::PpmMappingTester(const std::string& name, + ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_tool1("LVL1::PpmMappingTool/PpmMappingTool"), + m_tool2("LVL1::PpmCoolMappingTool/PpmCoolMappingTool") +{ + + declareProperty("PpmMappingTool1", m_tool1); + declareProperty("PpmMappingTool2", m_tool2); + + declareProperty("Timing", m_timing = -1); + + // Initialise m_etaBins + double base = -4.9; + const double width = 0.425; + const double offset1 = width/2.; + for (int i = 0; i < 4; ++i) { + m_etaBins.push_back(base + double(i)*width + offset1); + } + m_etaBins.push_back(-3.15); + m_etaBins.push_back(-3.0); + m_etaBins.push_back(-2.8); + m_etaBins.push_back(-2.6); + const double offset2 = 0.05; + for (int i = -25; i < 25; ++i) { + m_etaBins.push_back(double(i)/10. + offset2); + } + m_etaBins.push_back(2.6); + m_etaBins.push_back(2.8); + m_etaBins.push_back(3.0); + m_etaBins.push_back(3.15); + base = 3.2; + for (int i = 0; i < 4; ++i) { + m_etaBins.push_back(base + double(i)*width + offset1); + } +} + +PpmMappingTester::~PpmMappingTester() +{ +} + +// Initialisation + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode PpmMappingTester::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + // Retrieve mapping tools + + StatusCode sc = m_tool1.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_tool1 << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_tool1 << endreq; + + sc = m_tool2.retrieve(); + if ( sc.isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_tool2 << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_tool2 << endreq; + + return StatusCode::SUCCESS; +} + +StatusCode PpmMappingTester::finalize() +{ + + return StatusCode::SUCCESS; +} + +StatusCode PpmMappingTester::execute() +{ + // Timing tests + + std::vector<unsigned int> chanIds; + std::vector<double> etas; + std::vector<double> phis; + std::vector<int> layers; + if (m_timing == 0) etaPhiToChannel(m_tool1, chanIds); + else if (m_timing == 1) etaPhiToChannel(m_tool1, chanIds); + else if (m_timing == 2) etaPhiToChannel(m_tool2, chanIds); + else if (m_timing == 3) channelToEtaPhi(m_tool1, etas, phis, layers); + else if (m_timing == 4) channelToEtaPhi(m_tool2, etas, phis, layers); + else { + + // Comparison tests + + etaPhiToChannel(m_tool1, chanIds); + std::vector<unsigned int> chanIds2; + etaPhiToChannel(m_tool2, chanIds2); + unsigned int size1 = chanIds.size(); + unsigned int size2 = chanIds2.size(); + msg(MSG::INFO) << "Vector sizes: " << size1 << ", " << size2 << endreq; + if (size1 == size2) { + for (unsigned int i = 0; i < size1; ++i) { + if (chanIds[i] != chanIds2[i]) { + msg(MSG::INFO) << "ChanID mismatch: " << chanIds[i] << ", " + << chanIds2[i] << endreq; + } + } + } + channelToEtaPhi(m_tool1, etas, phis, layers); + std::vector<double> etas2; + std::vector<double> phis2; + std::vector<int> layers2; + channelToEtaPhi(m_tool2, etas2, phis2, layers2); + size1 = etas.size(); + size2 = etas2.size(); + msg(MSG::INFO) << "Vector sizes: " << size1 << ", " << size2 << endreq; + if (size1 == size2) { + for (unsigned int i = 0; i < size1; ++i) { + if (notEqual(etas[i], etas2[i]) || + notEqual(phis[i], phis2[i]) || + notEqual(layers[i], layers2[i])) { + msg(MSG::INFO) << "ChanID mismatch: eta/phi/layer " + << etas[i] << "/" << phis[i] << "/" + << layers[i] << "/" + << etas2[i] << "/" << phis2[i] << "/" + << layers2[i] << endreq; + } + } + } + } + + return StatusCode::SUCCESS; +} + +// Return a list of TT channel IDs for all possible eta/phi/layers + +void PpmMappingTester::etaPhiToChannel( + ToolHandle<LVL1::IL1CaloMappingTool>& tool, + std::vector<unsigned int>& chanIds) +{ + const double etaMin = -4.9; + const double etaMax = 4.9; + const double phiMin = 0.; + const double phiMax = 2.*M_PI; + std::vector<double>::const_iterator etaPos = m_etaBins.begin(); + std::vector<double>::const_iterator etaPosE = m_etaBins.end(); + for (; etaPos != etaPosE; ++etaPos) { + const double eta = *etaPos; + if (eta < etaMin) continue; + if (eta > etaMax) break; + const double absEta = (eta < 0.) ? -eta : eta; + const int phiBins = (absEta > 3.2) ? 16 : (absEta > 2.5) ? 32 : 64; + const double phiGran = 2.*M_PI/phiBins; + for (int bin = 0; bin < phiBins; ++bin) { + const double phi = phiGran*(double(bin) + 0.5); + if (phi < phiMin) continue; + if (phi > phiMax) break; + int crate, module, channel; + if (m_timing) { + if (tool->mapping(eta, phi, 0, crate, module, channel)) { + const unsigned int id = (crate * 16 + module) * 64 + channel; + chanIds.push_back(id); + } + } else chanIds.push_back(0); + if (m_timing) { + if (tool->mapping(eta, phi, 1, crate, module, channel)) { + const unsigned int id = (crate * 16 + module) * 64 + channel; + chanIds.push_back(id); + } + } else chanIds.push_back(0); + } + } +} + +void PpmMappingTester::channelToEtaPhi( + ToolHandle<LVL1::IL1CaloMappingTool>& tool, + std::vector<double>& etas, std::vector<double>& phis, + std::vector<int>& layers) +{ + const int ncrates = 8; + const int nmodules = 16; + const int nchannels = 64; + for (int crate = 0; crate < ncrates; ++crate) { + for (int module = 0; module < nmodules; ++module) { + for (int channel = 0; channel < nchannels; ++channel) { + double eta = 0.; + double phi = 0.; + int layer = 0; + if (m_timing) { + if (tool->mapping(crate, module, channel, eta, phi, layer)) { + etas.push_back(eta); + phis.push_back(phi); + layers.push_back(layer); + } + } else { + etas.push_back(0); + phis.push_back(0); + layers.push_back(0); + } + } + } + } +} + +bool PpmMappingTester::notEqual(double item1, double item2) +{ + const double tolerance = 0.00001; + return std::abs(item1 - item2) > tolerance; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmMappingTester.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmMappingTester.h new file mode 100644 index 0000000000000000000000000000000000000000..cb5777f34d971fca51547ae572555a12c99abbc8 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmMappingTester.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMMAPPINGTESTER_H +#define TRIGT1CALOBYTESTREAM_PPMMAPPINGTESTER_H + +#include <string> +#include <vector> + +#include "GaudiKernel/ToolHandle.h" + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class IL1CaloMappingTool; +} + +namespace LVL1BS { + +/** Algorithm to compare Trigger tower mapping tools. + * + * @author Peter Faulkner + */ + +class PpmMappingTester : public AthAlgorithm { + + public: + PpmMappingTester(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~PpmMappingTester(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + void etaPhiToChannel(ToolHandle<LVL1::IL1CaloMappingTool>& tool, + std::vector<unsigned int>& chanIds); + void channelToEtaPhi(ToolHandle<LVL1::IL1CaloMappingTool>& tool, + std::vector<double>& etas, std::vector<double>& phis, + std::vector<int>& layers); + bool notEqual(double item1, double item2); + + /// Mapping tool 1 + ToolHandle<LVL1::IL1CaloMappingTool> m_tool1; + /// Mapping tool 2 + ToolHandle<LVL1::IL1CaloMappingTool> m_tool2; + + int m_timing; + std::vector<double> m_etaBins; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmSubsetTester.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmSubsetTester.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8b921a33f63f482fbaabdfc02b79f7a9b4a73844 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmSubsetTester.cxx @@ -0,0 +1,236 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <cmath> +#include <utility> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/TriggerTower.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "TrigT1CaloByteStream/ITrigT1CaloDataAccess.h" + +#include "../src/ModifySlices.h" + +#include "PpmSubsetTester.h" + +namespace LVL1BS { + +PpmSubsetTester::PpmSubsetTester(const std::string& name, + ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_dataAccess("LVL1BS::TrigT1CaloDataAccess/TrigT1CaloDataAccess"), + m_towerKey(0) +{ + declareProperty("TrigT1CaloDataAccess", m_dataAccess, + "TriggerTower access tool"); + declareProperty("TriggerTowerLocation", + m_triggerTowerLocation = LVL1::TrigT1CaloDefs::TriggerTowerLocation); + + declareProperty("ForceSlicesLUT", m_forceSlicesLut = 0); + declareProperty("ForceSlicesFADC", m_forceSlicesFadc = 0); +} + +PpmSubsetTester::~PpmSubsetTester() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode PpmSubsetTester::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + StatusCode sc = m_dataAccess.retrieve(); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_dataAccess << endreq; + return sc; + } else msg(MSG::INFO) << "Retrieved tool " << m_dataAccess << endreq; + + m_towerKey = new LVL1::TriggerTowerKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode PpmSubsetTester::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + const double etaMin = -4.9; + const double etaMax = 4.9; + const double phiMin = 0.; + const double phiMax = M_PI*2.; + + // Find trigger towers + + const TriggerTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_triggerTowerLocation); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No Trigger Towers found" << endreq; + return StatusCode::SUCCESS; + } + + // Order by key + + setupTTMap(ttCollection, etaMin, etaMax, phiMin, phiMax); + + // Print the trigger towers + + printTriggerTowers(); + + // Now use subset tool + + TriggerTowerCollection::const_iterator beg; + TriggerTowerCollection::const_iterator end; + sc = m_dataAccess->loadCollection(beg, end, etaMin, etaMax, phiMin, phiMax, false); + if (sc.isFailure()) { + msg(MSG::ERROR) << "Error accessing data" << endreq; + return sc; + } + + // Order by key + + setupTTMap(beg, end); + + // Print the trigger towers + + printTriggerTowers(); + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode PpmSubsetTester::finalize() +{ + delete m_towerKey; + + return StatusCode::SUCCESS; +} + +// Print the trigger towers + +void PpmSubsetTester::printTriggerTowers() const +{ + msg() << "Number of Trigger Towers = " << m_ttMap.size() << endreq; + TriggerTowerMap::const_iterator mapIter = m_ttMap.begin(); + TriggerTowerMap::const_iterator mapEnd = m_ttMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::TriggerTower* const tt = mapIter->second; + int emPeak = tt->emPeak(); + int hadPeak = tt->hadPeak(); + int emADCPeak = tt->emADCPeak(); + int hadADCPeak = tt->hadADCPeak(); + int emLUTSlices = (tt->emLUT()).size(); + int emADCSlices = (tt->emADC()).size(); + int hadLUTSlices = (tt->hadLUT()).size(); + int hadADCSlices = (tt->hadADC()).size(); + if (m_forceSlicesLut) { + emPeak = ModifySlices::peak(emPeak, emLUTSlices, m_forceSlicesLut); + hadPeak = ModifySlices::peak(hadPeak, hadLUTSlices, m_forceSlicesLut); + emLUTSlices = m_forceSlicesLut; + hadLUTSlices = m_forceSlicesLut; + } + if (m_forceSlicesFadc) { + emADCPeak = ModifySlices::peak(emADCPeak, emADCSlices, + m_forceSlicesFadc); + hadADCPeak = ModifySlices::peak(hadADCPeak, hadADCSlices, + m_forceSlicesFadc); + emADCSlices = m_forceSlicesFadc; + hadADCSlices = m_forceSlicesFadc; + } + msg() << " EM:key/eta/phi/LUTpeak/FADCpeak/LUT/FADC/bcidLUT/bcidFADC/error: " + << mapIter->first << "/" << tt->eta() << "/" << tt->phi() << "/" + << emPeak << "/" << emADCPeak << "/"; + std::vector<int> lut; + std::vector<int> fadc; + std::vector<int> bcidLut; + std::vector<int> bcidFadc; + ModifySlices::data(tt->emLUT(), lut, emLUTSlices); + ModifySlices::data(tt->emADC(), fadc, emADCSlices); + ModifySlices::data(tt->emBCIDvec(), bcidLut, emLUTSlices); + ModifySlices::data(tt->emBCIDext(), bcidFadc, emADCSlices); + printVec(lut); + printVec(fadc); + printVec(bcidLut); + printVec(bcidFadc); + msg() << MSG::hex << tt->emError() << MSG::dec << "/" << endreq + << "HAD:key/eta/phi/LUTpeak/FADCpeak/LUT/FADC/bcidLUT/bcidFADC/error: " + << mapIter->first << "/" << tt->eta() << "/" << tt->phi() << "/" + << hadPeak << "/" << hadADCPeak << "/"; + ModifySlices::data(tt->hadLUT(), lut, hadLUTSlices); + ModifySlices::data(tt->hadADC(), fadc, hadADCSlices); + ModifySlices::data(tt->hadBCIDvec(), bcidLut, hadLUTSlices); + ModifySlices::data(tt->hadBCIDext(), bcidFadc, hadADCSlices); + printVec(lut); + printVec(fadc); + printVec(bcidLut); + printVec(bcidFadc); + msg() << MSG::hex << tt->hadError() << MSG::dec << "/" << endreq; + } +} + +// Print a vector + +void PpmSubsetTester::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Set up trigger tower map + +void PpmSubsetTester::setupTTMap(const TriggerTowerCollection* + const ttCollection, + const double etaMin, const double etaMax, + const double phiMin, const double phiMax) +{ + m_ttMap.clear(); + TriggerTowerCollection::const_iterator pos = ttCollection->begin(); + TriggerTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::TriggerTower* const tt = *pos; + const double eta = tt->eta(); + if (eta < etaMin || eta > etaMax) continue; + const double phi = tt->phi(); + if (phi < phiMin || phi > phiMax) continue; + const unsigned int key = m_towerKey->ttKey(phi, eta); + m_ttMap.insert(std::make_pair(key, tt)); + } +} + +// Set up trigger tower map + +void PpmSubsetTester::setupTTMap(TriggerTowerCollection::const_iterator& beg, + TriggerTowerCollection::const_iterator& end) +{ + m_ttMap.clear(); + TriggerTowerCollection::const_iterator pos = beg; + TriggerTowerCollection::const_iterator pose = end; + for (; pos != pose; ++pos) { + const LVL1::TriggerTower* const tt = *pos; + const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + m_ttMap.insert(std::make_pair(key, tt)); + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmSubsetTester.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmSubsetTester.h new file mode 100644 index 0000000000000000000000000000000000000000..9122e48e5910b8da55a0fb1262736037037231d4 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmSubsetTester.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMSUBSETTESTER_H +#define TRIGT1CALOBYTESTREAM_PPMSUBSETTESTER_H + +#include <map> +#include <string> + +#include "GaudiKernel/ToolHandle.h" + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class TriggerTower; + class TriggerTowerKey; +} + +namespace LVL1BS { + +class ITrigT1CaloDataAccess; + +/** Algorithm to test Trigger tower bytestream conversions. + * + * Just prints out the contents of the TriggerTower objects. + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class PpmSubsetTester : public AthAlgorithm { + + public: + PpmSubsetTester(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~PpmSubsetTester(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + /// Trigger tower container + typedef DataVector<LVL1::TriggerTower> TriggerTowerCollection; + /// Trigger tower map + typedef std::map<unsigned int, const LVL1::TriggerTower*> TriggerTowerMap; + + /// Print the trigger towers + void printTriggerTowers() const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + + /// Set up trigger tower map + void setupTTMap(const TriggerTowerCollection* ttCollection, + double etaMin, double etaMax, double phiMin, double phiMax); + /// Set up trigger tower map + void setupTTMap(TriggerTowerCollection::const_iterator& beg, + TriggerTowerCollection::const_iterator& end); + + /// TT subset access tool + ToolHandle<LVL1BS::ITrigT1CaloDataAccess> m_dataAccess; + /// Trigger tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// Trigger tower container StoreGate key + std::string m_triggerTowerLocation; + /// Force number of LUT slices + int m_forceSlicesLut; + /// Force number of FADC slices + int m_forceSlicesFadc; + + /// Trigger tower map + TriggerTowerMap m_ttMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmTester.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmTester.cxx new file mode 100755 index 0000000000000000000000000000000000000000..e062118d45b40f31be15ba9dbe905d46916812a7 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmTester.cxx @@ -0,0 +1,180 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <utility> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1CaloEvent/TriggerTower.h" +#include "TrigT1CaloUtils/TriggerTowerKey.h" +#include "TrigT1Interfaces/TrigT1CaloDefs.h" + +#include "../src/ModifySlices.h" + +#include "PpmTester.h" + +namespace LVL1BS { + +PpmTester::PpmTester(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator), + m_towerKey(0) +{ + declareProperty("TriggerTowerLocation", + m_triggerTowerLocation = LVL1::TrigT1CaloDefs::TriggerTowerLocation); + + declareProperty("ForceSlicesLUT", m_forceSlicesLut = 0); + declareProperty("ForceSlicesFADC", m_forceSlicesFadc = 0); +} + +PpmTester::~PpmTester() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode PpmTester::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + m_towerKey = new LVL1::TriggerTowerKey(); + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode PpmTester::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + // Find trigger towers + + const TriggerTowerCollection* ttCollection = 0; + StatusCode sc = evtStore()->retrieve(ttCollection, m_triggerTowerLocation); + if (sc.isFailure() || !ttCollection || ttCollection->empty()) { + msg() << "No Trigger Towers found" << endreq; + return StatusCode::SUCCESS; + } + + // Order by key + + setupTTMap(ttCollection); + + // Print the trigger towers + + printTriggerTowers(); + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode PpmTester::finalize() +{ + delete m_towerKey; + + return StatusCode::SUCCESS; +} + +// Print the trigger towers + +void PpmTester::printTriggerTowers() const +{ + msg() << "Number of Trigger Towers = " << m_ttMap.size() << endreq; + TriggerTowerMap::const_iterator mapIter = m_ttMap.begin(); + TriggerTowerMap::const_iterator mapEnd = m_ttMap.end(); + for (; mapIter != mapEnd; ++mapIter) { + const LVL1::TriggerTower* const tt = mapIter->second; + int emPeak = tt->emPeak(); + int hadPeak = tt->hadPeak(); + int emADCPeak = tt->emADCPeak(); + int hadADCPeak = tt->hadADCPeak(); + int emLUTSlices = (tt->emLUT()).size(); + int emADCSlices = (tt->emADC()).size(); + int hadLUTSlices = (tt->hadLUT()).size(); + int hadADCSlices = (tt->hadADC()).size(); + if (m_forceSlicesLut) { + emPeak = ModifySlices::peak(emPeak, emLUTSlices, m_forceSlicesLut); + hadPeak = ModifySlices::peak(hadPeak, hadLUTSlices, m_forceSlicesLut); + emLUTSlices = m_forceSlicesLut; + hadLUTSlices = m_forceSlicesLut; + } + if (m_forceSlicesFadc) { + emADCPeak = ModifySlices::peak(emADCPeak, emADCSlices, + m_forceSlicesFadc); + hadADCPeak = ModifySlices::peak(hadADCPeak, hadADCSlices, + m_forceSlicesFadc); + emADCSlices = m_forceSlicesFadc; + hadADCSlices = m_forceSlicesFadc; + } + msg() << " EM:key/eta/phi/LUTpeak/FADCpeak/LUT/FADC/bcidLUT/bcidFADC/error: " + << mapIter->first << "/" << tt->eta() << "/" << tt->phi() << "/" + << emPeak << "/" << emADCPeak << "/"; + std::vector<int> lut; + std::vector<int> fadc; + std::vector<int> bcidLut; + std::vector<int> bcidFadc; + ModifySlices::data(tt->emLUT(), lut, emLUTSlices); + ModifySlices::data(tt->emADC(), fadc, emADCSlices); + ModifySlices::data(tt->emBCIDvec(), bcidLut, emLUTSlices); + ModifySlices::data(tt->emBCIDext(), bcidFadc, emADCSlices); + printVec(lut); + printVec(fadc); + printVec(bcidLut); + printVec(bcidFadc); + msg() << MSG::hex << tt->emError() << MSG::dec << "/" << endreq; + msg() << "HAD:key/eta/phi/LUTpeak/FADCpeak/LUT/FADC/bcidLUT/bcidFADC/error: " + << mapIter->first << "/" << tt->eta() << "/" << tt->phi() << "/" + << hadPeak << "/" << hadADCPeak << "/"; + ModifySlices::data(tt->hadLUT(), lut, hadLUTSlices); + ModifySlices::data(tt->hadADC(), fadc, hadADCSlices); + ModifySlices::data(tt->hadBCIDvec(), bcidLut, hadLUTSlices); + ModifySlices::data(tt->hadBCIDext(), bcidFadc, hadADCSlices); + printVec(lut); + printVec(fadc); + printVec(bcidLut); + printVec(bcidFadc); + msg() << MSG::hex << tt->hadError() << MSG::dec << "/" << endreq; + } +} + +// Print a vector + +void PpmTester::printVec(const std::vector<int>& vec) const +{ + std::vector<int>::const_iterator pos; + for (pos = vec.begin(); pos != vec.end(); ++pos) { + if (pos != vec.begin()) msg() << ","; + msg() << *pos; + } + msg() << "/"; +} + +// Set up trigger tower map + +void PpmTester::setupTTMap(const TriggerTowerCollection* const ttCollection) +{ + m_ttMap.clear(); + TriggerTowerCollection::const_iterator pos = ttCollection->begin(); + TriggerTowerCollection::const_iterator pose = ttCollection->end(); + for (; pos != pose; ++pos) { + const LVL1::TriggerTower* const tt = *pos; + // doesn't work for spare channels (unphysical eta/phi): + //const unsigned int key = m_towerKey->ttKey(tt->phi(), tt->eta()); + const unsigned int key = tt->key(); + m_ttMap.insert(std::make_pair(key, tt)); + } +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmTester.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmTester.h new file mode 100755 index 0000000000000000000000000000000000000000..abe56cf03dd8833a5c2372961743f2420a0de4ae --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/PpmTester.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_PPMTESTER_H +#define TRIGT1CALOBYTESTREAM_PPMTESTER_H + +#include <map> +#include <string> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class TriggerTower; + class TriggerTowerKey; +} + +namespace LVL1BS { + +/** Algorithm to test Trigger tower bytestream conversions. + * + * Just prints out the contents of the TriggerTower objects. + * Run before writing bytestream and after reading it and compare. + * + * @author Peter Faulkner + */ + +class PpmTester : public AthAlgorithm { + + public: + PpmTester(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~PpmTester(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + /// Trigger tower container + typedef DataVector<LVL1::TriggerTower> TriggerTowerCollection; + /// Trigger tower map + typedef std::map<unsigned int, const LVL1::TriggerTower*> TriggerTowerMap; + + /// Print the trigger towers + void printTriggerTowers() const; + + /// Print a vector + void printVec(const std::vector<int>& vec) const; + + /// Set up trigger tower map + void setupTTMap(const TriggerTowerCollection* jeCollection); + + /// Trigger tower key provider + LVL1::TriggerTowerKey* m_towerKey; + /// Trigger tower container StoreGate key + std::string m_triggerTowerLocation; + /// Force number of LUT slices + int m_forceSlicesLut; + /// Force number of FADC slices + int m_forceSlicesFadc; + + /// Trigger tower map + TriggerTowerMap m_ttMap; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/RodTester.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/RodTester.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dd6a6abb9fd476c748e4ccf8daa2ff3aeacafca9 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/RodTester.cxx @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include <stdint.h> + +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/StoreGateSvc.h" + +#include "TrigT1Interfaces/TrigT1CaloDefs.h" +#include "TrigT1CaloEvent/RODHeader.h" + +#include "RodTester.h" + +namespace LVL1BS { + +RodTester::RodTester(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator) +{ + declareProperty("RodHeaderLocation", m_rodHeaderLocation = + LVL1::TrigT1CaloDefs::RODHeaderLocation); + + m_flags.push_back(""); + m_flags.push_back("PP"); + m_flags.push_back("CP"); + m_flags.push_back("CPRoI"); + m_flags.push_back("JEP"); + m_flags.push_back("JEPRoI"); + m_flags.push_back("CPRoIB"); + m_flags.push_back("JEPRoIB"); +} + +RodTester::~RodTester() +{ +} + +// Initialize + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +StatusCode RodTester::initialize() +{ + msg(MSG::INFO) << "Initializing " << name() << " - package version " + << /* version() */ PACKAGE_VERSION << endreq; + + return StatusCode::SUCCESS; +} + +// Execute + +StatusCode RodTester::execute() +{ + if ( !msgLvl(MSG::INFO) ) return StatusCode::SUCCESS; + msg(MSG::INFO); + + // Loop over all possible collections + + std::vector<std::string>::const_iterator flagIter = m_flags.begin(); + std::vector<std::string>::const_iterator flagEnd = m_flags.end(); + for (; flagIter != flagEnd; ++flagIter) { + msg() << "=================================================" + << endreq; + const std::string location(m_rodHeaderLocation + *flagIter); + const RodHeaderCollection* rods = 0; + StatusCode sc = evtStore()->retrieve(rods, location); + if (sc.isFailure() || !rods || rods->empty()) { + msg() << "No ROD headers found for " << location << endreq; + } else { + + // Print the ROD headers + + msg() << "Number of ROD headers in collection " + << location << " is " << rods->size() << MSG::hex << endreq; + RodHeaderCollection::const_iterator rodIter = rods->begin(); + RodHeaderCollection::const_iterator rodEnd = rods->end(); + for (; rodIter != rodEnd; ++rodIter) { + const LVL1::RODHeader* const header = *rodIter; + msg() << "-------------------------------------------------" + << endreq + << "version/majorVersion/minorVersion: " + << header->version() << "/" << header->majorVersion() << "/" + << header->minorVersion() << endreq + << "sourceID/subDetectorID/moduleID/crate/sLink/dataType: " + << header->sourceID() << "/" << header->subDetectorID() << "/" + << header->moduleID() << "/" << header->crate() << "/" + << header->sLink() << "/" << header->dataType() << endreq + << "run/runType/runNumber: " + << header->run() << "/" << header->runType() << "/" + << header->runNumber() << endreq + << "extendedL1ID/ecrID/l1ID: " + << header->extendedL1ID() << "/" << header->ecrID() << "/" + << header->l1ID() << endreq + << "bunchCrossing/l1TriggerType: " + << header->bunchCrossing() << "/" << header->l1TriggerType() << "/" + << endreq + << "detEventType/orbitCount/stepNumber/stepType: " + << header->detEventType() << "/" << header->orbitCount() << "/" + << header->stepNumber() << "/" << header->stepType() << endreq + << "payloadSize: " << header->payloadSize() << endreq; + const std::vector<uint32_t>& words(header->statusWords()); + msg() << "statusWords(" << words.size() << "): "; + std::vector<uint32_t>::const_iterator wordIter = words.begin(); + std::vector<uint32_t>::const_iterator wordEnd = words.end(); + for (; wordIter != wordEnd; ++wordIter) { + msg() << *wordIter << " "; + } + msg() << endreq + << "bcnMismatch/gLinkTimeout/dataTransportError/rodFifoOverflow: " + << header->bcnMismatch() << "/" << header->gLinkTimeout() << "/" + << header->dataTransportError() << "/" << header->rodFifoOverflow() + << endreq + << "lvdsLinkError/cmmParityError/gLinkError: " + << header->lvdsLinkError() << "/" << header->cmmParityError() << "/" + << header->gLinkError() << endreq + << "limitedRoISet/triggerTypeTimeout: " + << header->limitedRoISet() << "/" << header->triggerTypeTimeout() + << endreq; + } + msg() << MSG::dec; + } + } + + return StatusCode::SUCCESS; +} + +// Finalize + +StatusCode RodTester::finalize() +{ + + return StatusCode::SUCCESS; +} + +} // end namespace diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/RodTester.h b/Trigger/TrigT1/TrigT1CaloByteStream/test/RodTester.h new file mode 100644 index 0000000000000000000000000000000000000000..41f03ac3001e1918a9f2fd5577d6984b08236928 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/RodTester.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1CALOBYTESTREAM_RODTESTER_H +#define TRIGT1CALOBYTESTREAM_RODTESTER_H + +#include <string> +#include <vector> + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "DataModel/DataVector.h" + +class ISvcLocator; +class StatusCode; + +namespace LVL1 { + class RODHeader; +} + +namespace LVL1BS { + +/** Algorithm to test ROD header bytestream conversions. + * + * Just prints out the contents of the RODHeader objects + * + * @author Peter Faulkner + */ + +class RodTester : public AthAlgorithm { + + public: + RodTester(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~RodTester(); + + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + typedef DataVector<LVL1::RODHeader> RodHeaderCollection; + + /// RODHeader container StoreGate key + std::string m_rodHeaderLocation; + /// Variant collection flags + std::vector<std::string> m_flags; + +}; + +} // end namespace + +#endif diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/TrigT1CaloByteStream_entries.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/TrigT1CaloByteStream_entries.cxx new file mode 100755 index 0000000000000000000000000000000000000000..b202aaedede40602bfac87d378b7dc5a68b781fb --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/TrigT1CaloByteStream_entries.cxx @@ -0,0 +1,264 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "DataModel/DataVector.h" +#include "GaudiKernel/DeclareFactoryEntries.h" + +// Post-LS1 +#include "TrigT1CaloEvent/CMXCPTob.h" +#include "TrigT1CaloEvent/CMXCPHits.h" +#include "TrigT1CaloEvent/CMXEtSums.h" +#include "TrigT1CaloEvent/CMXJetTob.h" +#include "TrigT1CaloEvent/CMXJetHits.h" +#include "TrigT1CaloEvent/CMXRoI.h" +#include "TrigT1CaloEvent/JEMTobRoI.h" +// Pre-LS1 +#include "TrigT1CaloEvent/CPMHits.h" +#include "TrigT1CaloEvent/CMMCPHits.h" +#include "TrigT1CaloEvent/CMMEtSums.h" +#include "TrigT1CaloEvent/CMMJetHits.h" +#include "TrigT1CaloEvent/CMMRoI.h" +#include "TrigT1CaloEvent/JEMHits.h" +#include "TrigT1CaloEvent/JEMRoI.h" +// Both +#include "TrigT1CaloEvent/CPMTower.h" +#include "TrigT1CaloEvent/JEMEtSums.h" +#include "TrigT1CaloEvent/JetElement.h" + +// Post-LS1 +#include "../src/CpByteStreamV2Cnv.h" +#include "../src/CpmRoiByteStreamV2Cnv.h" +#include "../src/CpReadByteStreamV2Cnv.h" +#include "../src/JepByteStreamV2Cnv.h" +#include "../src/JepReadByteStreamV2Cnv.h" +#include "../src/JepRoiByteStreamV2Cnv.h" +#include "../src/JepRoiReadByteStreamV2Cnv.h" +// Pre-LS1 +#include "../src/CpByteStreamV1Cnv.h" +#include "../src/CpmRoiByteStreamV1Cnv.h" +#include "../src/CpReadByteStreamV1Cnv.h" +#include "../src/JepByteStreamV1Cnv.h" +#include "../src/JepReadByteStreamV1Cnv.h" +#include "../src/JepRoiByteStreamV1Cnv.h" +#include "../src/JepRoiReadByteStreamV1Cnv.h" +// Both +#include "../src/CpReadByteStreamV1V2Cnv.h" +#include "../src/JepReadByteStreamV1V2Cnv.h" +#include "../src/PpmByteStreamCnv.h" +#include "../src/RodHeaderByteStreamCnv.h" +#include "../src/L1CaloErrorByteStreamCnv.h" + +// Post-LS1 +#include "../src/CpByteStreamV2Tool.h" +#include "../src/CpmRoiByteStreamV2Tool.h" +#include "../src/JepByteStreamV2Tool.h" +#include "../src/JepRoiByteStreamV2Tool.h" +// Pre-LS1 +#include "../src/CpByteStreamV1Tool.h" +#include "../src/CpmRoiByteStreamV1Tool.h" +#include "../src/JepByteStreamV1Tool.h" +#include "../src/JepRoiByteStreamV1Tool.h" +// Both +#include "../src/PpmByteStreamTool.h" +#include "../src/RodHeaderByteStreamTool.h" +#include "../src/L1CaloErrorByteStreamTool.h" + +#include "../src/PpmByteStreamSubsetTool.h" +#include "../src/TriggerTowerSelectionTool.h" +#include "../src/TrigT1CaloDataAccess.h" + +// Post-LS1 +#include "CpmTesterV2.h" +#include "JemTesterV2.h" +#include "CpmErrors.h" +#include "JemErrors.h" +// Pre-LS1 +#include "CpmTesterV1.h" +#include "JemTesterV1.h" +// Both +#include "PpmMappingTester.h" +#include "PpmSubsetTester.h" +#include "PpmTester.h" +#include "RodTester.h" +#include "ErrorTester.h" + +namespace LVL1BS { + +// Post-LS1 +typedef DataVector<LVL1::CMXCPTob> CMXCPTobCollection; +typedef DataVector<LVL1::CMXCPHits> CMXCPHitsCollection; +typedef DataVector<LVL1::CMXJetTob> CMXJetTobCollection; +typedef DataVector<LVL1::CMXJetHits> CMXJetHitsCollection; +typedef DataVector<LVL1::CMXEtSums> CMXEtSumsCollection; +typedef DataVector<LVL1::JEMTobRoI> JEMTobRoICollection; +// Pre-LS1 +typedef DataVector<LVL1::CPMHits> CPMHitsCollection; +typedef DataVector<LVL1::CMMCPHits> CMMCPHitsCollection; +typedef DataVector<LVL1::CMMJetHits> CMMJetHitsCollection; +typedef DataVector<LVL1::CMMEtSums> CMMEtSumsCollection; +typedef DataVector<LVL1::JEMHits> JEMHitsCollection; +typedef DataVector<LVL1::JEMRoI> JEMRoICollection; +// Both +typedef DataVector<LVL1::CPMTower> CPMTowerCollection; +typedef DataVector<LVL1::JetElement> JetElementCollection; +typedef DataVector<LVL1::JEMEtSums> JEMEtSumsCollection; + +// Post-LS1 +typedef CpReadByteStreamV2Cnv<CMXCPTobCollection> CpReadCRByteStreamV2CnvT; +typedef CpReadByteStreamV2Cnv<CMXCPHitsCollection> CpReadCCByteStreamV2CnvT; +typedef JepReadByteStreamV2Cnv<CMXJetTobCollection> JepReadCTByteStreamV2CnvT; +typedef JepReadByteStreamV2Cnv<CMXJetHitsCollection> JepReadCJByteStreamV2CnvT; +typedef JepReadByteStreamV2Cnv<CMXEtSumsCollection> JepReadCEByteStreamV2CnvT; +typedef JepRoiReadByteStreamV2Cnv<JEMTobRoICollection> JepRoiReadJRByteStreamV2CnvT; +typedef JepRoiReadByteStreamV2Cnv<LVL1::CMXRoI> JepRoiReadCRByteStreamV2CnvT; +// Pre-LS1 +typedef CpReadByteStreamV1Cnv<CPMHitsCollection> CpReadCHByteStreamV1CnvT; +typedef CpReadByteStreamV1Cnv<CMMCPHitsCollection> CpReadCCByteStreamV1CnvT; +typedef JepReadByteStreamV1Cnv<CMMJetHitsCollection> JepReadCJByteStreamV1CnvT; +typedef JepReadByteStreamV1Cnv<CMMEtSumsCollection> JepReadCEByteStreamV1CnvT; +typedef JepReadByteStreamV1Cnv<JEMHitsCollection> JepReadJHByteStreamV1CnvT; +typedef JepRoiReadByteStreamV1Cnv<JEMRoICollection> JepRoiReadJRByteStreamV1CnvT; +typedef JepRoiReadByteStreamV1Cnv<LVL1::CMMRoI> JepRoiReadCRByteStreamV1CnvT; +// Both +typedef JepReadByteStreamV1V2Cnv<JetElementCollection> JepReadJEByteStreamV1V2CnvT; +typedef JepReadByteStreamV1V2Cnv<JEMEtSumsCollection> JepReadESByteStreamV1V2CnvT; +} + +// declare +// Post-LS1 +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpmRoiByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCRByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCCByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiByteStreamV2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCTByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCJByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCEByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadJRByteStreamV2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadCRByteStreamV2CnvT ) +// Pre-LS1 +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpmRoiByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCHByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadCCByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiByteStreamV1Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCJByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadCEByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadJHByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadJRByteStreamV1CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepRoiReadCRByteStreamV1CnvT ) +// Both +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, CpReadByteStreamV1V2Cnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadJEByteStreamV1V2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, JepReadESByteStreamV1V2CnvT ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, PpmByteStreamCnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, RodHeaderByteStreamCnv ) +DECLARE_NAMESPACE_CONVERTER_FACTORY( LVL1BS, L1CaloErrorByteStreamCnv ) + +// Post-LS1 +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpByteStreamV2Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpmRoiByteStreamV2Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepByteStreamV2Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepRoiByteStreamV2Tool ) +// Pre-LS1 +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpByteStreamV1Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, CpmRoiByteStreamV1Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepByteStreamV1Tool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, JepRoiByteStreamV1Tool ) +// Both +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, PpmByteStreamTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, RodHeaderByteStreamTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, L1CaloErrorByteStreamTool ) + +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, PpmByteStreamSubsetTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, TriggerTowerSelectionTool ) +DECLARE_NAMESPACE_TOOL_FACTORY( LVL1BS, TrigT1CaloDataAccess ) + +// Post-LS1 +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, CpmTesterV2 ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, JemTesterV2 ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, CpmErrors ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, JemErrors ) +// Pre-LS1 +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, CpmTesterV1 ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, JemTesterV1 ) +// Both +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, PpmTester ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, RodTester ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, ErrorTester ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, PpmSubsetTester ) +DECLARE_NAMESPACE_ALGORITHM_FACTORY( LVL1BS, PpmMappingTester ) + +DECLARE_FACTORY_ENTRIES( TrigT1CaloByteStream ) +{ + // Post-LS1 + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpmRoiByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCRByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCCByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiByteStreamV2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCTByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCJByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCEByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadJRByteStreamV2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadCRByteStreamV2CnvT ) + // Pre-LS1 + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpmRoiByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCHByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadCCByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiByteStreamV1Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCJByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadCEByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadJHByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadJRByteStreamV1CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepRoiReadCRByteStreamV1CnvT ) + // Both + DECLARE_NAMESPACE_CONVERTER( LVL1BS, CpReadByteStreamV1V2Cnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadJEByteStreamV1V2CnvT ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, JepReadESByteStreamV1V2CnvT ) + // Both + DECLARE_NAMESPACE_CONVERTER( LVL1BS, PpmByteStreamCnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, RodHeaderByteStreamCnv ) + DECLARE_NAMESPACE_CONVERTER( LVL1BS, L1CaloErrorByteStreamCnv ) + + // Post-LS1 + DECLARE_NAMESPACE_TOOL( LVL1BS, CpByteStreamV2Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, CpmRoiByteStreamV2Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepByteStreamV2Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepRoiByteStreamV2Tool ) + // Pre-LS1 + DECLARE_NAMESPACE_TOOL( LVL1BS, CpByteStreamV1Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, CpmRoiByteStreamV1Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepByteStreamV1Tool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, JepRoiByteStreamV1Tool ) + // Both + DECLARE_NAMESPACE_TOOL( LVL1BS, PpmByteStreamTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, RodHeaderByteStreamTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, L1CaloErrorByteStreamTool ) + + DECLARE_NAMESPACE_TOOL( LVL1BS, PpmByteStreamSubsetTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, TriggerTowerSelectionTool ) + DECLARE_NAMESPACE_TOOL( LVL1BS, TrigT1CaloDataAccess ) + + // Post-LS1 + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, CpmTesterV2 ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, JemTesterV2 ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, CpmErrors ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, JemErrors ) + // Pre-LS1 + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, CpmTesterV1 ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, JemTesterV1 ) + // Both + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, PpmTester ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, RodTester ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, ErrorTester ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, PpmSubsetTester ) + DECLARE_NAMESPACE_ALGORITHM( LVL1BS, PpmMappingTester ) +} diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/test/TrigT1CaloByteStream_load.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/test/TrigT1CaloByteStream_load.cxx new file mode 100755 index 0000000000000000000000000000000000000000..caf9bbc06f9f48f587d01be9020adc2cda56aca0 --- /dev/null +++ b/Trigger/TrigT1/TrigT1CaloByteStream/test/TrigT1CaloByteStream_load.cxx @@ -0,0 +1,9 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(TrigT1CaloByteStream) +