ATLAS Offline Software
Loading...
Searching...
No Matches
L1Muon::L1MM::MMTriggerTool Class Reference

Run 4 emulation of the MM trigger processor. More...

#include <MMTriggerTool.h>

Inheritance diagram for L1Muon::L1MM::MMTriggerTool:
Collaboration diagram for L1Muon::L1MM::MMTriggerTool:

Public Member Functions

virtual ~MMTriggerTool ()=default
virtual StatusCode initialize () override
virtual StatusCode runTrigger (const EventContext &ctx, std::vector< MMCandidate > &candidates, MMDebugInfo *debug) const override

Private Attributes

SG::ReadHandleKey< MmDigitContainer > m_keyMmDigit
ActsTrk::GeoContextReadKey_t m_geoCtxKey
 Phase-II geometry context, carrying the alignment (same key as L1MuonMDT and L1MuonS1RPC).
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Gaudi::Property< int > m_diamRoadSize {this, "DiamondRoadSize", 8, "Number of strips to create a road"}
Gaudi::Property< bool > m_uv {this, "DiamondUV", true, "Include Stereo planes for tracking"}
Gaudi::Property< int > m_diamXthreshold
Gaudi::Property< int > m_diamUVthreshold
Gaudi::Property< int > m_diamOverlapEtaUp
Gaudi::Property< int > m_diamOverlapEtaDown
Gaudi::Property< int > m_diamOverlapStereoUp
Gaudi::Property< int > m_diamOverlapStereoDown
const MuonGMR4::MuonDetectorManager * m_detMgr {nullptr}
std::unique_ptr< MMT_Diamond > m_diamond

Detailed Description

Run 4 emulation of the MM trigger processor.

Ported from the Run 3 NSWL1::MMTriggerTool (Trigger/TrigT1/TrigT1NSWSimTools), which is left untouched: hits are built with the Phase-II geometry (MMT_Hit), roads and coincidences with the unchanged Diamond Road algorithm (MMT_Road, MMT_Diamond). The output is a list of MMCandidate (physics values). The Run 3 RDO encoding is not ported, the Run 4 encoding is done by the caller.

Definition at line 33 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

Constructor & Destructor Documentation

◆ ~MMTriggerTool()

virtual L1Muon::L1MM::MMTriggerTool::~MMTriggerTool ( )
virtualdefault

Member Function Documentation

◆ initialize()

StatusCode L1Muon::L1MM::MMTriggerTool::initialize ( )
overridevirtual

Definition at line 27 of file Muon/L1MuonNSW/src/MMTriggerTool.cxx.

27 {
28 ATH_MSG_DEBUG("Initializing " << name() << "...");
29 ATH_CHECK(m_keyMmDigit.initialize());
30 ATH_CHECK(m_geoCtxKey.initialize());
31 ATH_CHECK(m_idHelperSvc.retrieve());
32 ATH_CHECK(detStore()->retrieve(m_detMgr));
33
34 m_diamond = std::make_unique<MMT_Diamond>(m_diamXthreshold, m_uv, m_diamUVthreshold, m_diamRoadSize,
37 return StatusCode::SUCCESS;
38 }
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
ActsTrk::GeoContextReadKey_t m_geoCtxKey
Phase-II geometry context, carrying the alignment (same key as L1MuonMDT and L1MuonS1RPC).
const MuonGMR4::MuonDetectorManager * m_detMgr
SG::ReadHandleKey< MmDigitContainer > m_keyMmDigit
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
std::unique_ptr< MMT_Diamond > m_diamond

◆ runTrigger()

StatusCode L1Muon::L1MM::MMTriggerTool::runTrigger ( const EventContext & ctx,
std::vector< MMCandidate > & candidates,
MMDebugInfo * debug ) const
overridevirtual

Definition at line 40 of file Muon/L1MuonNSW/src/MMTriggerTool.cxx.

41 {
42 candidates.clear();
43 if (debug) {
44 debug->hits.clear();
45 debug->nTrig.clear();
46 }
47
48 const MmDigitContainer* mmDigits{nullptr};
49 ATH_CHECK(SG::get(mmDigits, m_keyMmDigit, ctx));
50 const ActsTrk::GeometryContext* gctx{nullptr};
51 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
52
53 const MmIdHelper& idHelper = m_idHelperSvc->mmIdHelper();
54
55 unsigned int nCollections{0}, nHitsTotal{0};
56 for (const MmDigitCollection* digitCollection : *mmDigits) {
57
58 std::vector<MMT_Hit> ev_hits;
59 double tanStereoAngle{0.}; // tan of the U/V stereo angle, from the geometry of the stereo layers
60 unsigned int nOutOfRange{0}, nNegTime{0}, nInfSlope{0};
61 Identifier firstHitId{}; // any accepted hit of the collection, to get the sector centre from the geometry
62
63 for (const MmDigit* digit : *digitCollection) {
64 const Identifier id = digit->identify();
65 if (!m_idHelperSvc->isMM(id)) continue;
66
67 // The Run 3 DCS / data-quality selection for real data is not ported: MC only for now.
68
69 const int channel = idHelper.channel(id);
70
71 // Strip-range check. Run 3: 1 <= channel <= totalStrips. Phase II: the active
72 // strips of the layer, [firstStrip, firstStrip + numStrips). Mandatory here, since
73 // the Phase-II strip position of an out-of-range strip is undefined.
74 const MuonGMR4::MmReadoutElement* readout = m_detMgr->getMmReadoutElement(id);
75 const IdentifierHash layHash = readout->layerHash(id);
76 const int firstStrip = readout->firstStrip(layHash);
77 const int numStrips = readout->numStrips(layHash);
78 const MuonGMR4::StripDesign& design = readout->stripLayer(layHash).design();
79 // X layers have no stereo angle (0): keep the value of the stereo layers of the collection
80 tanStereoAngle = std::max(tanStereoAngle, std::tan(std::abs(design.stereoAngle())));
81 if (channel < firstStrip || channel >= firstStrip + numStrips) {
82 ++nOutOfRange;
83 ATH_MSG_DEBUG("Strip out of active range: " << m_idHelperSvc->toString(id)
84 << " allowed [" << firstStrip << ", " << firstStrip + numStrips - 1 << "]");
85 continue;
86 }
87
88 const float stripTime = digit->stripResponseTime();
89 // Checking positive digitization time
90 if (stripTime < 0.) {
91 ++nNegTime;
92 continue;
93 }
94 const int BC = static_cast<int>(std::ceil(stripTime / kBunchSpacing));
95 ev_hits.emplace_back(id, stripTime, BC, m_detMgr, *gctx);
96
97 if (ev_hits.back().infSlope()) {
98 ATH_MSG_WARNING("Infinite slope, removing hit");
99 ++nInfSlope;
100 ev_hits.pop_back();
101 continue;
102 }
103 if (!firstHitId.is_valid()) firstHitId = id;
104
105 // Every accepted hit, also in collections without coincidence (as the Run 3 ntuple)
106 if (debug) {
107 const MMT_Hit& h = ev_hits.back();
108 MMHitInfo& info = debug->hits.emplace_back();
109 info.stationEta = h.getStationEta();
110 info.stationPhi = h.getStationPhi();
111 info.sectorPhi = h.getSectorPhi();
112 info.sector = h.getSector();
113 info.plane = h.getPlane();
114 info.strip = h.getChannel();
115 info.VMM = h.getVMM();
116 info.ART = h.getART();
117 info.BC = h.getBC();
118 info.time = h.getTime();
119 info.R = h.getR();
120 info.Z = h.getZ();
121 info.RZslope = h.getRZSlope();
122 info.shift = h.getShift();
123 }
124 }
125
126 if (ev_hits.empty() && nOutOfRange == 0) continue;
127 ++nCollections;
128 nHitsTotal += ev_hits.size();
129
130 ATH_MSG_DEBUG("MM station " << m_idHelperSvc->toStringChamber((*digitCollection->begin())->identify())
131 << ": " << ev_hits.size() << " hits"
132 << " (dropped: out-of-range " << nOutOfRange << ", negative time " << nNegTime
133 << ", inf slope " << nInfSlope << ")");
134
135 // Go ahead when hits are more than X+UV thresholds (as in Run 3)
136 if (ev_hits.size() < (m_diamond->getXthreshold() + m_diamond->getUVthreshold())) {
137 ATH_MSG_DEBUG("Available hits are " << ev_hits.size()
138 << ", less than X+UV threshold, skipping digit collection");
139 continue;
140 }
141
142 const bool isLarge = std::ranges::all_of(ev_hits, [](const auto& hit) { return hit.getSector() == 'L'; });
143 const SideType side = std::ranges::all_of(ev_hits, [](const auto& hit) { return hit.getStationEta() < 0; })
145 const int sectorPhi = ev_hits[0].getSectorPhi();
146 const bool allSectorPhi = std::ranges::all_of(ev_hits,
147 [&](const auto& hit) { return hit.getSectorPhi() == sectorPhi; });
148 if (!allSectorPhi) {
149 ATH_MSG_ERROR("Available digits belongs to different sectors IDs, unable to assign an unique ID");
150 return StatusCode::FAILURE;
151 }
152 const bool isEta1 = std::ranges::all_of(ev_hits,
153 [](const auto& hit) { return std::abs(hit.getStationEta()) == 1; });
154
155 // Setup roads
156 std::vector<MMT_Road> ev_roads;
157 m_diamond->createRoads(ev_roads, isLarge, isEta1);
158
159 // Evaluate coincidences
160 std::vector<slope_t> diamondSlopes;
161 m_diamond->findDiamonds(ev_hits, ev_roads, diamondSlopes, sectorPhi, tanStereoAngle);
162 ATH_MSG_DEBUG(" -> " << diamondSlopes.size() << " coincidence(s) in sector " << sectorPhi << side);
163 if (diamondSlopes.empty()) continue;
164 if (debug) debug->nTrig.push_back(diamondSlopes.size());
165
166 // Sector centre phi from the Phase-II geometry: the readout element is a trapezoid centred on
167 // the sector axis. It is used for the global phi instead of MMT_Diamond::phiShift(sectorPhi, ...),
168 // which places sector n at n*pi/8 while the Athena sectors (1-16) are centred at (n-1)*pi/8.
169 // The Run 3 output carries the local phi, so there the offset only affects MM_diamond_phiShf.
170 const MuonGMR4::MmReadoutElement* stationEl = m_detMgr->getMmReadoutElement(firstHitId);
171 const double sectorCentrePhi = stationEl->center(*gctx).phi();
172
173 for (const slope_t& slope : diamondSlopes) {
174 MMCandidate& cand = candidates.emplace_back();
175 cand.sectorPhi = sectorPhi;
176 cand.side = side;
177 cand.BC = slope.BC;
178 cand.eta = slope.eta;
179 cand.phi = slope.phi;
180 cand.phiShf = slope.phiShf;
181 // Same local-phi sign convention as Run 3 phiShift: flipped on side A
182 cand.phiGlobal = NSWEncoding::wrapTwoPi(sectorCentrePhi - Acts::copySign(slope.phi, slope.side));
183 cand.dtheta = slope.dtheta;
184 cand.lowRes = slope.lowRes;
185 cand.iX = slope.iRoad;
186 cand.iU = slope.iRoadu;
187 cand.iV = slope.iRoadv;
188 cand.nHits = slope.totalCount;
189 // Rest of the Run 3 slope_t, for the validation ntuple
190 cand.sector = isLarge ? 'L' : 'S';
191 cand.xCount = slope.xCount;
192 cand.uCount = slope.uCount;
193 cand.age = slope.age;
194 cand.mx = slope.mx;
195 cand.my = slope.my;
196 cand.mxl = slope.mxl;
197 cand.uavg = slope.uavg;
198 cand.vavg = slope.vavg;
199 cand.theta = slope.theta;
200 cand.secCentrePhi = sectorCentrePhi;
201 }
202 }
203
204 ATH_MSG_DEBUG("MM trigger: " << nHitsTotal << " hits in " << nCollections
205 << " digit collections -> " << candidates.size() << " candidates");
206 return StatusCode::SUCCESS;
207 }
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
bool hit(const Container &ids, int pdgId)
const bool debug
bool is_valid() const
Check if id is in a valid state.
int channel(const Identifier &id) const override
const StripLayer & stripLayer(const Identifier &measId) const
unsigned int numStrips(const IdentifierHash &layerHash) const
Returns the number of total active strips.
IdentifierHash layerHash(const Identifier &measId) const override final
The layer hash removes the bits from the IdentifierHash corresponding to the measurement's channel nu...
unsigned int firstStrip(const IdentifierHash &layerHash) const
Returns the first active strip.
Amg::Vector3D center(const ActsTrk::GeometryContext &ctx) const
Returns the geometrical center point of the readout element.
double stereoAngle() const
Returns the value of the stereo angle.
const StripDesign & design(bool phiView=false) const
Returns the underlying strip design.
SideType
Detector side. The value is the sign of z, so that it can be used as a sign (e.g. Acts::copySign).
double wrapTwoPi(double phi)
Map any angle to [0, 2pi).
Definition NSWEncoding.h:29
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.

Member Data Documentation

◆ m_detMgr

const MuonGMR4::MuonDetectorManager* L1Muon::L1MM::MMTriggerTool::m_detMgr {nullptr}
private

Definition at line 67 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

67{nullptr};

◆ m_diamond

std::unique_ptr<MMT_Diamond> L1Muon::L1MM::MMTriggerTool::m_diamond
private

Definition at line 68 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

◆ m_diamOverlapEtaDown

Gaudi::Property<int> L1Muon::L1MM::MMTriggerTool::m_diamOverlapEtaDown
private
Initial value:
{this, "DiamondEtaDownOverlap", 0,
"Number of Eta strips for lower road overlap"}

Definition at line 60 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

60 {this, "DiamondEtaDownOverlap", 0,
61 "Number of Eta strips for lower road overlap"};

◆ m_diamOverlapEtaUp

Gaudi::Property<int> L1Muon::L1MM::MMTriggerTool::m_diamOverlapEtaUp
private
Initial value:
{this, "DiamondEtaUpOverlap", 4,
"Number of Eta strips for upper road overlap"}

Definition at line 58 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

58 {this, "DiamondEtaUpOverlap", 4,
59 "Number of Eta strips for upper road overlap"};

◆ m_diamOverlapStereoDown

Gaudi::Property<int> L1Muon::L1MM::MMTriggerTool::m_diamOverlapStereoDown
private
Initial value:
{this, "DiamondStereoDownOverlap", 0,
"Number of Stereo strips for lower road overlap"}

Definition at line 64 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

64 {this, "DiamondStereoDownOverlap", 0,
65 "Number of Stereo strips for lower road overlap"};

◆ m_diamOverlapStereoUp

Gaudi::Property<int> L1Muon::L1MM::MMTriggerTool::m_diamOverlapStereoUp
private
Initial value:
{this, "DiamondStereoUpOverlap", 4,
"Number of Stereo strips for upper road overlap"}

Definition at line 62 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

62 {this, "DiamondStereoUpOverlap", 4,
63 "Number of Stereo strips for upper road overlap"};

◆ m_diamRoadSize

Gaudi::Property<int> L1Muon::L1MM::MMTriggerTool::m_diamRoadSize {this, "DiamondRoadSize", 8, "Number of strips to create a road"}
private

Definition at line 52 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

52{this, "DiamondRoadSize", 8, "Number of strips to create a road"};

◆ m_diamUVthreshold

Gaudi::Property<int> L1Muon::L1MM::MMTriggerTool::m_diamUVthreshold
private
Initial value:
{this, "DiamondStereoThreshold", 3,
"Number of Stereo planes for coincidences"}

Definition at line 56 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

56 {this, "DiamondStereoThreshold", 3,
57 "Number of Stereo planes for coincidences"};

◆ m_diamXthreshold

Gaudi::Property<int> L1Muon::L1MM::MMTriggerTool::m_diamXthreshold
private
Initial value:
{this, "DiamondEtaThreshold", 3,
"Number of Eta planes for coincidences"}

Definition at line 54 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

54 {this, "DiamondEtaThreshold", 3,
55 "Number of Eta planes for coincidences"};

◆ m_geoCtxKey

ActsTrk::GeoContextReadKey_t L1Muon::L1MM::MMTriggerTool::m_geoCtxKey
private
Initial value:
{this, "AlignmentKey", "ActsAlignment",
"Geometry context with the alignment"}

Phase-II geometry context, carrying the alignment (same key as L1MuonMDT and L1MuonS1RPC).

Definition at line 46 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

46 {this, "AlignmentKey", "ActsAlignment",
47 "Geometry context with the alignment"};

◆ m_idHelperSvc

ServiceHandle<Muon::IMuonIdHelperSvc> L1Muon::L1MM::MMTriggerTool::m_idHelperSvc
private
Initial value:
{this, "MuonIdHelperSvc",
"Muon::MuonIdHelperSvc/MuonIdHelperSvc"}

Definition at line 48 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

48 {this, "MuonIdHelperSvc",
49 "Muon::MuonIdHelperSvc/MuonIdHelperSvc"};

◆ m_keyMmDigit

SG::ReadHandleKey<MmDigitContainer> L1Muon::L1MM::MMTriggerTool::m_keyMmDigit
private
Initial value:
{this, "MMDigits", "MM_DIGITS",
"Input MM digit container"}

Definition at line 43 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

43 {this, "MMDigits", "MM_DIGITS",
44 "Input MM digit container"};

◆ m_uv

Gaudi::Property<bool> L1Muon::L1MM::MMTriggerTool::m_uv {this, "DiamondUV", true, "Include Stereo planes for tracking"}
private

Definition at line 53 of file Muon/L1MuonNSW/src/MMTriggerTool.h.

53{this, "DiamondUV", true, "Include Stereo planes for tracking"};

The documentation for this class was generated from the following files: