ATLAS Offline Software
HnlSkimmingTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // HnlSkimmingTool.cxx, (c) ATLAS Detector software
8 // Author: Avishek Chatterjee (avishek.chatterjee@cern.ch)
9 // Heavily borrowed from DerivationFramework/DerivationFrameworkExamples/src/SkimmingToolExample.cxx
10 // and DerivationFramework/DerivationFrameworkMuons/src/dimuonTaggingTool.cxx
11 
13 
14 // Constructor
16  const std::string& n,
17  const IInterface* p):
18  AthAlgTool(t, n, p),
19  m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool")
20 {
21  declareInterface<DerivationFramework::ISkimmingTool>(this);
22 
23  // Lepton types
24  declareProperty("IsPromptMuon", m_isPromptMuon=true);
25  declareProperty("IsDisplacedMuon", m_isDisplacedMuon=true);
26 
27  // Triggers
28  declareProperty("TrigDecisionTool", m_trigDecisionTool, "Tool to access the trigger decision");
29  declareProperty("Triggers", m_triggers=std::vector<std::string>());
30 
31  // Prompt muons
32  declareProperty("Mu1PtMin", m_mu1PtMin=-1.);
33  declareProperty("Mu1AbsEtaMax", m_mu1AbsEtaMax=2.5);
34  declareProperty("Mu1Types", m_mu1Types=std::vector<int>());
36  declareProperty("Mu1IsoCutIsRel", m_mu1IsoCutIsRel=true, "Cut is on relative isolation");
37  declareProperty("Mu1IsoCut", m_mu1IsoCut=0.05);
38  // Displaced muons
39  declareProperty("Mu2PtMin", m_mu2PtMin=-1.);
40  declareProperty("Mu2AbsEtaMax", m_mu2AbsEtaMax=2.5);
41  declareProperty("Mu2Types", m_mu2Types=std::vector<int>());
43  declareProperty("Mu2IsoCutIsRel", m_mu2IsoCutIsRel=true, "Cut is on relative isolation");
44  declareProperty("Mu2IsoCut", m_mu2IsoCut=1.);
45  declareProperty("Mu2d0Min", m_mu2d0Min=0.1, "Unit is mm");
46 
47  // Prompt electrons
48  declareProperty("El1PtMin", m_el1PtMin=-1.);
49  declareProperty("El1AbsEtaMax", m_el1AbsEtaMax=2.5);
50  declareProperty("El1ID", m_el1IDKey="LHLoose");
52  declareProperty("El1IsoCutIsRel", m_el1IsoCutIsRel=true, "Cut is on relative isolation");
53  declareProperty("El1IsoCut", m_el1IsoCut=0.05);
54  // Displaced electrons
55  declareProperty("El2PtMin", m_el2PtMin=-1.);
56  declareProperty("El2AbsEtaMax", m_el2AbsEtaMax=2.5);
58  declareProperty("El2IsoCutIsRel", m_el2IsoCutIsRel=true, "Cut is on relative isolation");
59  declareProperty("El2IsoCut", m_el2IsoCut=1.);
60  declareProperty("El2d0Min", m_el2d0Min=1.0, "Unit is mm");
61 
62  declareProperty("dPhiMin", m_dPhiMin=0.0, "Unit is radian");
63 }
64 
65 // Athena initialize and finalize
67 {
68  ATH_MSG_VERBOSE("HnlSkimmingTool initialize() ...");
69 
70  ATH_CHECK(m_trigDecisionTool.retrieve());
71  ATH_MSG_INFO("Retrieved tool: " << m_trigDecisionTool);
72  ATH_CHECK(m_muonSGKey.initialize());
73  ATH_CHECK(m_electronSGKey.initialize());
74  ATH_CHECK(m_muonIsoDecorKey.initialize());
75  ATH_CHECK(m_electronIsoDecorKey.initialize());
76 
77  return StatusCode::SUCCESS;
78 }
79 
81 {
82  ATH_MSG_VERBOSE("HnlSkimmingTool finalize() ...");
83 
84  return StatusCode::SUCCESS;
85 }
86 
87 // The filter itself
88 
89 // Check for the chi2 cut
91 {
92  if (mu.muonType() != xAOD::Muon::Combined) return false;
93 
94  float chi2 = 0.;
95  if (not mu.parameter(chi2, xAOD::Muon::msInnerMatchChi2)) return false;
96 
97  int dof = 1;
98  if (not mu.parameter(dof, xAOD::Muon::msInnerMatchDOF)) return false;
99  if (dof == 0) dof = 1;
100 
101  return ((chi2 / static_cast<float>(dof)) < 5.);
102 }
104 
106 {
107  bool acceptEvent = false;
108 
109  // Trigger check
110  bool passedTrigger = true;
111  if (m_triggers.size() > 0) {
112  passedTrigger = false;
113  for (const std::string& trigger : m_triggers) {
114  bool decision = m_trigDecisionTool->isPassed(trigger);
115  if (decision) {
116  passedTrigger = true;
117  break;
118  }
119  }
120  }
121  if (not passedTrigger) return acceptEvent;
122 
123  // Retrieve muon container
124  SG::ReadHandle<xAOD::MuonContainer> muons(m_muonSGKey);
125  if (m_isPromptMuon or m_isDisplacedMuon) {
126  if( !muons.isValid() ) {
127  ATH_MSG_FATAL("No muon collection with name " << m_muonSGKey << " found in StoreGate!");
128  return acceptEvent;
129  }
130  }
131 
132  // Retrieve electron container
134  if ((not m_isPromptMuon) or (not m_isDisplacedMuon)) {
135  if( !electrons.isValid() ) {
136  ATH_MSG_FATAL("No electron collection with name " << m_electronSGKey << " found in StoreGate!");
137  return acceptEvent;
138  }
139  }
140 
141  // Prompt leptons
142  std::vector<const xAOD::Muon*> promptMuonCandidates;
143  std::vector<const xAOD::Electron*> promptElectronCandidates;
144  if (m_isPromptMuon) {
145  getPromptMuonCandidates(muons, promptMuonCandidates);
146  if (promptMuonCandidates.empty()) return acceptEvent;
147  } else {
148  getPromptElectronCandidates(electrons, promptElectronCandidates);
149  if (promptElectronCandidates.empty()) return acceptEvent;
150  }
151 
152  // Displaced leptons
153  std::vector<const xAOD::Muon*> displacedMuonCandidates;
154  std::vector<const xAOD::Electron*> displacedElectronCandidates;
155  if (m_isDisplacedMuon) {
156  getDisplacedMuonCandidates(muons, displacedMuonCandidates);
157  if (displacedMuonCandidates.empty()) return acceptEvent;
158  } else {
159  getDisplacedElectronCandidates(electrons, displacedElectronCandidates);
160  if (displacedElectronCandidates.empty()) return acceptEvent;
161  }
162 
163  // Final check: at least one pair of a prompt lepton candidate and
164  // a displaced lepton candidate, which is different from the prompt lepton candidate
165  if (m_isPromptMuon and m_isDisplacedMuon) {
166  // mu-mu
167  for (const xAOD::Muon* promptMuonCandidate : promptMuonCandidates) {
168  for (const xAOD::Muon* displacedMuonCandidate : displacedMuonCandidates) {
169  if (promptMuonCandidate!=displacedMuonCandidate) {
170  double dPhi = promptMuonCandidate->phi() - displacedMuonCandidate->phi();
171  while (dPhi>=+M_PI) dPhi -= 2.*M_PI;
172  while (dPhi<=-M_PI) dPhi += 2.*M_PI;
173  dPhi = std::abs(dPhi);
174  if (dPhi>=m_dPhiMin) {
175  acceptEvent = true;
176  break;
177  }
178  }
179  }
180  }
181  } else if (m_isPromptMuon and (not m_isDisplacedMuon)) {
182  // mu-e
183  for (const xAOD::Muon* promptMuonCandidate : promptMuonCandidates) {
184  for (const xAOD::Electron* displacedElectronCandidate : displacedElectronCandidates) {
185  double dPhi = promptMuonCandidate->phi() - displacedElectronCandidate->phi();
186  while (dPhi>=+M_PI) dPhi -= 2.*M_PI;
187  while (dPhi<=-M_PI) dPhi += 2.*M_PI;
188  dPhi = std::abs(dPhi);
189  if (dPhi>=m_dPhiMin) {
190  acceptEvent = true;
191  break;
192  }
193  }
194  }
195  } else if ((not m_isPromptMuon) and m_isDisplacedMuon) {
196  // e-mu
197  for (const xAOD::Electron* promptElectronCandidate : promptElectronCandidates) {
198  for (const xAOD::Muon* displacedMuonCandidate : displacedMuonCandidates) {
199  double dPhi = promptElectronCandidate->phi() - displacedMuonCandidate->phi();
200  while (dPhi>=+M_PI) dPhi -= 2.*M_PI;
201  while (dPhi<=-M_PI) dPhi += 2.*M_PI;
202  dPhi = std::abs(dPhi);
203  if (dPhi>=m_dPhiMin) {
204  acceptEvent = true;
205  break;
206  }
207  }
208  }
209  } else if ((not m_isPromptMuon) and (not m_isDisplacedMuon)) {
210  // e-e
211  for (const xAOD::Electron* promptElectronCandidate : promptElectronCandidates) {
212  for (const xAOD::Electron* displacedElectronCandidate : displacedElectronCandidates) {
213  if (promptElectronCandidate!=displacedElectronCandidate) {
214  double dPhi = promptElectronCandidate->phi() - displacedElectronCandidate->phi();
215  while (dPhi>=+M_PI) dPhi -= 2.*M_PI;
216  while (dPhi<=-M_PI) dPhi += 2.*M_PI;
217  dPhi = std::abs(dPhi);
218  if (dPhi>=m_dPhiMin) {
219  acceptEvent = true;
220  break;
221  }
222  }
223  }
224  }
225  }
226 
227  return acceptEvent;
228 }
229 
231  std::vector<const xAOD::Muon*>& promptMuonCandidates) const
232 {
233  for (const xAOD::Muon* muon : *muons) {
234  // pT cut
235  if (not (muon->pt() > m_mu1PtMin)) continue;
236 
237  // eta cut
238  if (not (std::abs(muon->eta()) < m_mu1AbsEtaMax)) continue;
239 
240  // type cut
241  bool passTypeCut = true;
242  if (m_mu1Types.size() > 0) {
243  passTypeCut = false;
244  int type = muon->muonType();
245  for (const int& allowedType : m_mu1Types) {
246  if (allowedType==type) {
247  passTypeCut = true;
248  break;
249  }
250  }
251  }
252  if (not passTypeCut) continue;
253 
254  // isolation cut
255  bool isIso = false;
256  float isoValue = 0.;
257  const xAOD::Iso::IsolationType isoType = static_cast<xAOD::Iso::IsolationType>(m_mu1IsoType);
258  if (not m_mu1IsoCutIsRel) {
259  if (muon->isolation(isoValue, isoType) and (isoValue < m_mu1IsoCut)) isIso = true;
260  } else {
261  if (muon->isolation(isoValue, isoType) and (isoValue/muon->pt() < m_mu1IsoCut)) isIso = true;
262  }
263  if (not isIso) continue;
264 
265  promptMuonCandidates.push_back(muon);
266  }
267 }
268 
270  std::vector<const xAOD::Muon*>& displacedMuonCandidates) const
271 {
272  for (const xAOD::Muon* muon : *muons) {
273  // pT cut
274  if (not (muon->pt() > m_mu2PtMin)) continue;
275 
276  // eta cut
277  if (not (std::abs(muon->eta()) < m_mu2AbsEtaMax)) continue;
278 
279  // type cut
280  bool passTypeCut = true;
281  int type = muon->muonType();
282  if (m_mu2Types.size() > 0) {
283  passTypeCut = false;
284  for (const int& allowedType : m_mu2Types) {
285  if (type==allowedType) {
286  passTypeCut = true;
287  break;
288  }
289  }
290  }
291  if (not passTypeCut) continue;
292 
293  // isolation cut
294  bool isIso = false;
295  float isoValue = 0.;
296  const xAOD::Iso::IsolationType isoType = static_cast<xAOD::Iso::IsolationType>(m_mu2IsoType);
297  if (not m_mu2IsoCutIsRel) {
298  if (muon->isolation(isoValue, isoType) and (isoValue < m_mu2IsoCut)) isIso = true;
299  } else {
300  if (muon->isolation(isoValue, isoType) and isoValue/muon->pt() < m_mu2IsoCut) isIso = true;
301  }
302  if (not isIso) continue;
303 
304  // d0 cut
305  bool passD0cut = true;
306  if (type==xAOD::Muon::Combined) { // d0 cut is for combined muons only
307  passD0cut = false;
308  if (isGood(*muon)) { // if muon has a good chi2/dof
309  if (std::abs(muon->primaryTrackParticle()->d0()) > m_mu2d0Min) passD0cut = true;
310  } else {
311  passD0cut = true;
312  }
313  }
314  if (not passD0cut) continue;
315 
316  displacedMuonCandidates.push_back(muon);
317  }
318 }
319 
321  std::vector<const xAOD::Electron*>& promptElectronCandidates) const
322 {
323  for (const xAOD::Electron* electron : *electrons) {
324  // pT cut
325  if (not (electron->pt() > m_el1PtMin)) continue;
326 
327  // eta cut
328  if (not (std::abs(electron->eta()) < m_el1AbsEtaMax)) continue;
329 
330  // eID cut
331  bool passEID = false;
332  if (not electron->passSelection(passEID, m_el1IDKey)) continue;
333  if (not passEID) continue;
334 
335  // isolation cut
336  bool isIso = false;
337  float isoValue = 0.;
338  const xAOD::Iso::IsolationType isoType = static_cast<xAOD::Iso::IsolationType>(m_el1IsoType);
339  if (not m_el1IsoCutIsRel) {
340  if (electron->isolation(isoValue, isoType) and (isoValue < m_el1IsoCut)) isIso = true;
341  } else {
342  if (electron->isolation(isoValue, isoType) and (isoValue/electron->pt() < m_el1IsoCut)) isIso = true;
343  }
344  if (not isIso) continue;
345 
346  promptElectronCandidates.push_back(electron);
347  }
348 }
349 
351  std::vector<const xAOD::Electron*>& displacedElectronCandidates) const
352 {
353  for (const xAOD::Electron* electron : *electrons) {
354  // pT cut
355  if (not (electron->pt() > m_el2PtMin)) continue;
356 
357  // eta cut
358  if (not (std::abs(electron->eta()) < m_el2AbsEtaMax)) continue;
359 
360  // isolation cut
361  bool isIso = false;
362  float isoValue = 0.;
363  const xAOD::Iso::IsolationType isoType = static_cast<xAOD::Iso::IsolationType>(m_el2IsoType);
364  if (not m_el2IsoCutIsRel) {
365  if (electron->isolation(isoValue, isoType) and (isoValue < m_el2IsoCut)) isIso = true;
366  } else {
367  if (electron->isolation(isoValue, isoType) and isoValue/electron->pt() < m_el2IsoCut) isIso = true;
368  }
369  if (not isIso) continue;
370 
371  // d0 cut
372  bool passD0cut = false;
373  if (std::abs(electron->trackParticle()->d0()) > m_el2d0Min) passD0cut = true;
374  if (not passD0cut) continue;
375 
376  displacedElectronCandidates.push_back(electron);
377  }
378 }
xAOD::muon
@ muon
Definition: TrackingPrimitives.h:195
DerivationFramework::HnlSkimmingTool::m_mu2AbsEtaMax
float m_mu2AbsEtaMax
Definition: HnlSkimmingTool.h:65
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
DerivationFramework::HnlSkimmingTool::m_el1IsoCutIsRel
bool m_el1IsoCutIsRel
Definition: HnlSkimmingTool.h:80
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
DerivationFramework::HnlSkimmingTool::m_dPhiMin
float m_dPhiMin
Definition: HnlSkimmingTool.h:90
DerivationFramework::HnlSkimmingTool::m_el2AbsEtaMax
float m_el2AbsEtaMax
Definition: HnlSkimmingTool.h:84
DerivationFramework::HnlSkimmingTool::m_el1PtMin
float m_el1PtMin
Definition: HnlSkimmingTool.h:76
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
DerivationFramework::HnlSkimmingTool::m_el2d0Min
float m_el2d0Min
Definition: HnlSkimmingTool.h:88
DerivationFramework::HnlSkimmingTool::m_el2IsoCut
float m_el2IsoCut
Definition: HnlSkimmingTool.h:87
DerivationFramework::HnlSkimmingTool::m_el1AbsEtaMax
float m_el1AbsEtaMax
Definition: HnlSkimmingTool.h:77
DerivationFramework::HnlSkimmingTool::m_mu1Types
std::vector< int > m_mu1Types
Definition: HnlSkimmingTool.h:59
DerivationFramework::HnlSkimmingTool::m_trigDecisionTool
ToolHandle< Trig::TrigDecisionTool > m_trigDecisionTool
Definition: HnlSkimmingTool.h:50
DerivationFramework::HnlSkimmingTool::getPromptMuonCandidates
void getPromptMuonCandidates(SG::ReadHandle< DataVector< xAOD::Muon_v1 >> &muons, std::vector< const xAOD::Muon * > &promptMuonCandidates) const
Definition: HnlSkimmingTool.cxx:230
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
DerivationFramework::HnlSkimmingTool::m_mu2Types
std::vector< int > m_mu2Types
Definition: HnlSkimmingTool.h:66
DerivationFramework::HnlSkimmingTool::eventPassesFilter
virtual bool eventPassesFilter() const override
Check that the current event passes this filter.
Definition: HnlSkimmingTool.cxx:105
xAOD::Iso::ptcone30
@ ptcone30
Definition: IsolationType.h:41
M_PI
#define M_PI
Definition: ActiveFraction.h:11
DerivationFramework::HnlSkimmingTool::m_mu2IsoCut
float m_mu2IsoCut
Definition: HnlSkimmingTool.h:69
DerivationFramework::HnlSkimmingTool::getDisplacedElectronCandidates
void getDisplacedElectronCandidates(SG::ReadHandle< DataVector< xAOD::Electron_v1 >> &electrons, std::vector< const xAOD::Electron * > &displacedElectronCandidates) const
Definition: HnlSkimmingTool.cxx:350
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::Muon_v1
Class describing a Muon.
Definition: Muon_v1.h:38
DerivationFramework::HnlSkimmingTool::m_mu2IsoType
int m_mu2IsoType
Definition: HnlSkimmingTool.h:67
DerivationFramework::HnlSkimmingTool::m_el2PtMin
float m_el2PtMin
Definition: HnlSkimmingTool.h:83
DerivationFramework::HnlSkimmingTool::m_isDisplacedMuon
bool m_isDisplacedMuon
Definition: HnlSkimmingTool.h:47
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
DerivationFramework::HnlSkimmingTool::isGood
bool isGood(const xAOD::Muon &mu) const
Definition: HnlSkimmingTool.cxx:90
xAOD::Iso::IsolationType
IsolationType
Overall enumeration for isolation types in xAOD files.
Definition: IsolationType.h:26
TauGNNUtils::Variables::Track::dPhi
bool dPhi(const xAOD::TauJet &tau, const xAOD::TauTrack &track, double &out)
Definition: TauGNNUtils.cxx:530
chi2
double chi2(TH1 *h0, TH1 *h1)
Definition: comparitor.cxx:522
DerivationFramework::HnlSkimmingTool::m_el1IDKey
std::string m_el1IDKey
Definition: HnlSkimmingTool.h:78
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
HnlSkimmingTool.h
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
DerivationFramework::HnlSkimmingTool::m_isPromptMuon
bool m_isPromptMuon
Definition: HnlSkimmingTool.h:46
DerivationFramework::HnlSkimmingTool::m_el2IsoCutIsRel
bool m_el2IsoCutIsRel
Definition: HnlSkimmingTool.h:86
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
DerivationFramework::HnlSkimmingTool::m_el1IsoCut
float m_el1IsoCut
Definition: HnlSkimmingTool.h:81
Trk::Combined
@ Combined
Definition: TrackSummaryTool.h:32
DerivationFramework::HnlSkimmingTool::getDisplacedMuonCandidates
void getDisplacedMuonCandidates(SG::ReadHandle< DataVector< xAOD::Muon_v1 >> &muons, std::vector< const xAOD::Muon * > &displacedMuonCandidates) const
Definition: HnlSkimmingTool.cxx:269
DerivationFramework::HnlSkimmingTool::m_mu2IsoCutIsRel
bool m_mu2IsoCutIsRel
Definition: HnlSkimmingTool.h:68
DerivationFramework::HnlSkimmingTool::m_mu2PtMin
float m_mu2PtMin
Definition: HnlSkimmingTool.h:64
xAOD::Electron_v1
Definition: Electron_v1.h:34
DerivationFramework::HnlSkimmingTool::m_mu1PtMin
float m_mu1PtMin
Definition: HnlSkimmingTool.h:57
DerivationFramework::HnlSkimmingTool::finalize
virtual StatusCode finalize() override
Definition: HnlSkimmingTool.cxx:80
DerivationFramework::HnlSkimmingTool::m_el2IsoType
int m_el2IsoType
Definition: HnlSkimmingTool.h:85
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
DerivationFramework::HnlSkimmingTool::m_mu1AbsEtaMax
float m_mu1AbsEtaMax
Definition: HnlSkimmingTool.h:58
DerivationFramework::HnlSkimmingTool::m_triggers
std::vector< std::string > m_triggers
Definition: HnlSkimmingTool.h:51
DerivationFramework::HnlSkimmingTool::m_el1IsoType
int m_el1IsoType
Definition: HnlSkimmingTool.h:79
xAOD::EgammaParameters::electron
@ electron
Definition: EgammaEnums.h:18
DerivationFramework::HnlSkimmingTool::getPromptElectronCandidates
void getPromptElectronCandidates(SG::ReadHandle< DataVector< xAOD::Electron_v1 >> &electrons, std::vector< const xAOD::Electron * > &promptElectronCandidates) const
Definition: HnlSkimmingTool.cxx:320
DerivationFramework::HnlSkimmingTool::m_mu1IsoCut
float m_mu1IsoCut
Definition: HnlSkimmingTool.h:62
AthAlgTool
Definition: AthAlgTool.h:26
DerivationFramework::HnlSkimmingTool::HnlSkimmingTool
HnlSkimmingTool(const std::string &t, const std::string &n, const IInterface *p)
Constructor with parameters.
Definition: HnlSkimmingTool.cxx:15
CaloNoise_fillDB.mu
mu
Definition: CaloNoise_fillDB.py:53
DerivationFramework::HnlSkimmingTool::m_mu1IsoType
int m_mu1IsoType
Definition: HnlSkimmingTool.h:60
DerivationFramework::HnlSkimmingTool::m_mu1IsoCutIsRel
bool m_mu1IsoCutIsRel
Definition: HnlSkimmingTool.h:61
DerivationFramework::HnlSkimmingTool::m_mu2d0Min
float m_mu2d0Min
Definition: HnlSkimmingTool.h:70
DerivationFramework::HnlSkimmingTool::initialize
virtual StatusCode initialize() override
Definition: HnlSkimmingTool.cxx:66
InDetDD::electrons
@ electrons
Definition: InDetDD_Defs.h:17
PhysDESDM_Quirks.trigger
trigger
Definition: PhysDESDM_Quirks.py:27