ATLAS Offline Software
Loading...
Searching...
No Matches
MuonCalibTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Framework include(s):
9
10// Local include(s):
11#include <cmath>
12#include "TRandom3.h"
13
15
17
18namespace CP
19{
20
22
24 m_MuonSelectionTool.declarePropertyFor(this,"MuonSelectionTool", "Instance of the MuonSelectionTool needed for the HighPt categorization");
25 m_MuonIntSagittaTool.declarePropertyFor(this, "SagittaTool", "Instance of the Sagitta bias corrections sub tool");
26 m_MuonIntScaleSmearTool.declarePropertyFor(this, "ScaleAndSmearTool", "Instance of the tool that applies the smearing & scale corrections");
27 m_MuonIntHighTSmearTool.declarePropertyFor(this, "HighPtSmearingTool", "Extra smearing of the high pt working point");
28 }
29
31 {
32 // Greet the user:
33 ATH_MSG_INFO("Initialising...");
34
35 // Get the m_eventinfo container
36 ATH_CHECK(m_eventInfo.initialize());
37
38 // Set the options
39 if (m_calibMode == MuonCalibTool::correctData_CB) {
40 ATH_MSG_INFO("Data will be corrected for sagitta bias and Montecarlo will be corrected using CB calibration");
42 } else if (m_calibMode == MuonCalibTool::correctData_IDMS) {
43 ATH_MSG_INFO("Data will be corrected for sagitta bias and Montecarlo will be corrected using ID+MS calibration");
45 } else if (m_calibMode == MuonCalibTool::notCorrectData_IDMS) {
46 ATH_MSG_INFO("Data will be untouched (no sagitta bias corrections) and Montecarlo will be corrected using ID+MS calibration");
48 } else if (m_calibMode == MuonCalibTool::notCorrectData_CB) {
49 ATH_MSG_INFO("Data will be untouched (no sagitta bias corrections) and Montecarlo will be corrected using CB calibration");
51 } else if (m_calibMode == MuonCalibTool::correctData_IDonly) {
52 ATH_MSG_INFO("Data will be corrected for sagitta bias and Montecarlo will be corrected using ID calibration only");
54 } else if (m_calibMode == MuonCalibTool::correctData_MSonly) {
55 ATH_MSG_INFO("Data will be corrected for sagitta bias and Montecarlo will be corrected using MS calibration only");
57 } else if (m_calibMode == MuonCalibTool::userDefined) {
58 ATH_MSG_INFO("Using options as provided by the user");
59 }
60 else {
61 ATH_MSG_FATAL("Invalid calibration mode: " << m_calibMode << " Allowed modes are correctData_CB("
62 << MuonCalibTool::correctData_CB << ") correctData_IDMS ("
63 << MuonCalibTool::correctData_IDMS << ") or notCorrectData_IDMS ("
64 << MuonCalibTool::notCorrectData_IDMS << ") or notCorrectData_CB ("
65 << MuonCalibTool::notCorrectData_CB << ") or correctData_IDonly ("
66 << MuonCalibTool::correctData_IDonly << ") or correctData_MSonly ("
67 << MuonCalibTool::correctData_MSonly << ")");
68 return StatusCode::FAILURE;
69 }
70
71 if (!m_skipResolutionCategory.value())
72 {
73 // Get the muon selection tool
74 if (m_MuonSelectionTool.empty()) {
75 m_MuonSelectionTool.setTypeAndName("CP::MuonSelectionTool/MCaST_Own_MST");
76 ATH_CHECK(m_MuonSelectionTool.setProperty("MaxEta", 2.7));
77 ATH_CHECK(m_MuonSelectionTool.setProperty("MuQuality", 1));
78 ATH_CHECK(m_MuonSelectionTool.setProperty("TurnOffMomCorr", true));
79 ATH_CHECK(m_MuonSelectionTool.setProperty("IsRun3Geo", m_isRun3.value()));
80 ATH_CHECK(m_MuonSelectionTool.setProperty("OutputLevel", msg().level()));
81 ATH_CHECK(m_MuonSelectionTool.setProperty("ExcludeNSWFromPrecisionLayers", m_excludeNSWFromPrecisionLayers.value()));
82 }
84 if (auto *selectionTool = dynamic_cast<columnar::ColumnarTool<>*>(m_MuonSelectionTool.get()))
85 addSubtool (*selectionTool);
86 }
87
88 // Create the Sagitta tool
89 if (m_MuonIntSagittaTool.empty()) {
90 m_MuonIntSagittaTool.setTypeAndName("CP::MuonCalibIntSagittaTool/MCaST_Sagitta");
91 ATH_CHECK(m_MuonIntSagittaTool.setProperty("release", m_release.value()));
92 ATH_CHECK(m_MuonIntSagittaTool.setProperty("systematicScheme", m_sysScheme.value()));
93 ATH_CHECK(m_MuonIntSagittaTool.setProperty("calibMode", m_calibMode));
94 ATH_CHECK(m_MuonIntSagittaTool.setProperty("doEtaSagittaSys", m_doEtaSagittaSys.value()));
95 ATH_CHECK(m_MuonIntSagittaTool.setProperty("OutputLevel", msg().level()));
96 }
98
99 // Create the scale smear tool
100 if (m_MuonIntScaleSmearTool.empty()) {
101 m_MuonIntScaleSmearTool.setTypeAndName("CP::MuonCalibIntScaleSmearTool/MCaST_ScaleSmear");
102 ATH_CHECK(m_MuonIntScaleSmearTool.setProperty("release", m_release.value()));
103 ATH_CHECK(m_MuonIntScaleSmearTool.setProperty("systematicScheme", m_sysScheme.value()));
104 ATH_CHECK(m_MuonIntScaleSmearTool.setProperty("calibMode", m_calibMode));
105 ATH_CHECK(m_MuonIntScaleSmearTool.setProperty("OutputLevel", msg().level()));
107 }
110 if (m_MuonIntHighTSmearTool.empty()) {
111 m_MuonIntHighTSmearTool.setTypeAndName("CP::MuonCalibIntHighpTSmearTool/MCaST_highPtScaleSmear");
112 ATH_CHECK(m_MuonIntHighTSmearTool.setProperty("release", m_release.value()));
113 ATH_CHECK(m_MuonIntHighTSmearTool.setProperty("OutputLevel", msg().level()));
114 }
117 }
119 {
120 ATH_MSG_ERROR("Unable to run with no systematic");
121 return StatusCode::FAILURE;
122 }
124 if (registry.registerSystematics(*this) != StatusCode::SUCCESS)
125 {
126 ATH_MSG_ERROR("Unkown systematic list");
127 return StatusCode::FAILURE;
128 }
129 ATH_CHECK (initializeColumns());
130 // Return gracefully:
131 return StatusCode::SUCCESS;
132 }
133
135 {
136 // Retrieve the event information:
139 }
140
142 {
143 auto& acc = *m_acc;
144 ATH_MSG_VERBOSE("Muon Type = " << mu(acc.muonTypeAcc) << " ( 0: Combined, 1: StandAlone, 2: SegmentTagged, 3: CaloTagged, 4: SiliconAssociatedForwardMuon)");
145 ATH_MSG_VERBOSE("Muon Author = " << mu(acc.authorAcc));
146
147 // Convert to the internal object
148 MCP::MuonObj muonObj = convertToMuonObj(mu, evtInfo);
149
150 ATH_MSG_VERBOSE("input ID pT "<<muonObj.ID.calib_pt);
151 ATH_MSG_VERBOSE("input ME pT "<<muonObj.ME.calib_pt);
152 ATH_MSG_VERBOSE("input CB pT "<<muonObj.CB.calib_pt);
153 ATH_MSG_VERBOSE("input eta "<<muonObj.CB.eta);
154 ATH_MSG_VERBOSE("input phi "<<muonObj.CB.phi);
155
156 if (muonObj.CB.isData)
157 {
158 ATH_MSG_VERBOSE("Doing data corrections");
159
160 // Sagitta Correction specifics
162 {
163 CorrectionCode sgCode = m_MuonIntSagittaTool->applyCorrection(muonObj);
164 if (sgCode != CorrectionCode::Ok) return sgCode;
165 }
166
167 // Override combined momentum for special cases
168 if (std::abs(muonObj.ME.calib_pt) == 0) muonObj.CB.calib_pt = muonObj.ID.calib_pt;
169 if (std::abs(muonObj.ID.calib_pt) == 0) muonObj.CB.calib_pt = muonObj.ME.calib_pt;
170
171 // Only for combined set it
172 if (mu(acc.muonTypeAcc) == xAOD::Muon::MuonType::Combined)
173 {
174 acc.ptOutDec (mu) = muonObj.CB.calib_pt * GeVtoMeV;
175 }
176
177
178 acc.dec_idPt(mu) = muonObj.ID.calib_pt * GeVtoMeV;
179 acc.dec_mePt(mu) = muonObj.ME.calib_pt * GeVtoMeV;
180 acc.dec_idCharge(mu) = muonObj.ID.calib_charge;
181 acc.dec_meCharge(mu) = muonObj.ME.calib_charge;
182
183 ATH_MSG_DEBUG("Checking Output Muon Info for data - Pt_ID: " << acc.dec_idPt(mu));
184 ATH_MSG_DEBUG("Checking Output Muon Info for data - Pt_MS: " << acc.dec_mePt(mu));
185 ATH_MSG_DEBUG("Checking Output Muon Info for data - Pt_CB: " << mu(acc.ptAcc));
186
187 return CorrectionCode::Ok;
188 }
189
190 // Do Scale and Smearing corrections
191 CorrectionCode sgCode = m_MuonIntScaleSmearTool->applyCorrection(muonObj);
192 if (sgCode != CorrectionCode::Ok) return sgCode;
193
194 // Systematics for sagitta correction
195 if ((mu(acc.muonTypeAcc) != xAOD::Muon::MuonType::SiliconAssociatedForwardMuon))
196 {
197 ATH_MSG_VERBOSE("Systematic uncertainties for sagitta bias ");
198 // TODO:: something specific for calo tags
199 CorrectionCode sgCode = m_MuonIntSagittaTool->applyCorrection(muonObj);
200 if (sgCode != CorrectionCode::Ok) return sgCode;
201 }
202
203 // Override combined momentum for special cases
204 if (std::abs(muonObj.ME.calib_pt) == 0) muonObj.CB.calib_pt = muonObj.ID.calib_pt;
205 if (std::abs(muonObj.ID.calib_pt) == 0) muonObj.CB.calib_pt = muonObj.ME.calib_pt;
206
207 // Setting the output object properties right now, so the resolution category get the corrected info
208 acc.ptOutDec(mu) = muonObj.CB.calib_pt * GeVtoMeV;
209 acc.chargeOutDec(mu) = muonObj.CB.calib_charge;
210 acc.dec_idPt(mu) = muonObj.ID.calib_pt * GeVtoMeV;
211 acc.dec_mePt(mu) = muonObj.ME.calib_pt * GeVtoMeV;
212 acc.dec_idCharge(mu) = muonObj.ID.calib_charge;
213 acc.dec_meCharge(mu) = muonObj.ME.calib_charge;
214
216 {
217 muonObj.raw_mst_category = (CP::IMuonSelectionTool::ResolutionCategory) m_MuonSelectionTool->getResolutionCategory(mu.getXAODObject());
218 }
219
220 // Special case: if the proper flags are selected (m_extra_highpt_smearing or m_2stations_highpt_smearing)
221 // an ad-hoc smearing of the combined momentum has to be applied
222 bool extra_smearing = (m_extra_highpt_smearing && (muonObj.raw_mst_category.value() >= 0) && !( muonObj.raw_mst_category.value() & IMuonSelectionTool::CategoryFour)); // Extra smearing, if selected, gets anyway only applied to non-3-station muons!
223 bool highpt_smearing = (m_2stations_highpt_smearing && (muonObj.raw_mst_category.value() >= 0) && ( muonObj.raw_mst_category.value() & IMuonSelectionTool::CategoryThree)); // Special highpt smearing, if selected, gets anyway only applied to missing-inner, 2-station muons only!
224
225 if (((extra_smearing || highpt_smearing)) && (mu(acc.ptAcc) > m_HighPtSystThreshold * GeVtoMeV))
226 {
227 sgCode = m_MuonIntHighTSmearTool->applyCorrection(muonObj);
228 if (sgCode != CorrectionCode::Ok) return sgCode;
229 }
230
231 // Final info to be written to the muon object
232 acc.ptOutDec(mu) = muonObj.CB.calib_pt * GeVtoMeV;
233 acc.dec_idPt(mu) = muonObj.ID.calib_pt * GeVtoMeV;
234 acc.dec_mePt(mu) = muonObj.ME.calib_pt * GeVtoMeV;
235
236
237 ATH_MSG_DEBUG("Checking Output Muon Info - Pt_ID: " << acc.dec_idPt(mu));
238 ATH_MSG_DEBUG("Checking Output Muon Info - Pt_MS: " << acc.dec_mePt(mu));
239 ATH_MSG_DEBUG("Checking Output Muon Info - Pt_CB: " << acc.ptOutDec(mu));
240
241 // If saggita was out of validity, return it here
242 if (sgCode == CorrectionCode::OutOfValidityRange) return sgCode;
243
244 // Return gracefully:
245 return CorrectionCode::Ok;
246 }
247
249 {
250 // Convert to the internal object
251 MCP::MuonObj muonObj = convertToMuonObj(inTrk, DetType);
252
253 // Do Scale and Smearing corrections
254 CorrectionCode sgCode = m_MuonIntScaleSmearTool->applyCorrection(muonObj);
255 if (sgCode != CorrectionCode::Ok) return sgCode;
256
257 double res_pt = (DetType == MCP::DetectorType::MS) ? muonObj.ME.calib_pt*GeVtoMeV : muonObj.ID.calib_pt*GeVtoMeV;
258
259 inTrk.setDefiningParameters(inTrk.d0(), inTrk.z0(), inTrk.phi0(), inTrk.theta(),
260 inTrk.charge() / (res_pt * std::cosh(inTrk.eta())));
261
262 // Return gracefully:
263 return CorrectionCode::Ok;
264 }
265
267 {
268 // A sanity check:
269 if (output)
271 "Non-null pointer received. "
272 "There's a possible memory leak!");
273
274 // Create a new object:
275 ATH_MSG_VERBOSE("Going to create new xAOD::Muon...");
276 output = new xAOD::Muon();
277 ATH_MSG_VERBOSE("Calling makePrivateStore...");
278 output->makePrivateStore(input);
279
280 // Use the other function to modify this object:
281 ATH_MSG_VERBOSE("Calling applyCorrection...");
282
283 CP::CorrectionCode retCode = applyCorrection(*output);
284
285 return retCode;
286 }
287
289 {
291 return sys.find(systematic) != sys.end();
292 }
293
295 {
296 SystematicSet result = m_MuonIntSagittaTool->affectingSystematics();
297 result.insert(m_MuonIntScaleSmearTool->affectingSystematics());
298 if (m_MuonIntHighTSmearToolInitialized) result.insert(m_MuonIntHighTSmearTool->affectingSystematics());
299 return result;
300 }
301
303
305 {
306 // Apply to the underlying tool
307 StatusCode code = m_MuonIntSagittaTool->applySystematicVariation(systConfig);
308 if(code != StatusCode::SUCCESS) return code;
309
310 code = m_MuonIntScaleSmearTool->applySystematicVariation(systConfig);
311 if(code != StatusCode::SUCCESS) return code;
312
314 code = m_MuonIntHighTSmearTool->applySystematicVariation(systConfig);
315 if(code != StatusCode::SUCCESS) return code;
316 }
317 return code;
318 }
319
320 double MuonCalibTool::expectedResolution(const std::string &DetType, const xAOD::Muon &mu, const bool addMCCorrectionSmearing) const
321 {
322 // Expected resolution in data (or unsmeared MC if second argument is true)
323 if (DetType == "MS") {
324 return expectedResolution(MCP::DetectorType::MS, mu, addMCCorrectionSmearing);
325 } else if (DetType == "ID") {
326 return expectedResolution(MCP::DetectorType::ID, mu, addMCCorrectionSmearing);
327 } else if (DetType == "CB") {
328 return expectedResolution(MCP::DetectorType::CB, mu, addMCCorrectionSmearing);
329 } else {
330 ATH_MSG_ERROR("The DetType that you entered is not allows - DetType = " << DetType);
331 return 0.;
332 }
333 }
334
335 double MuonCalibTool::expectedResolution(const int &DetType, const xAOD::Muon &mu, const bool addMCCorrectionSmearing) const
336 {
338 return expectedResolution(DetType, columnar::MuonId(mu), columnar::EventInfoId(*evtInfo), addMCCorrectionSmearing);
339 }
340
341 double MuonCalibTool::expectedResolution(const int &DetType, columnar::MuonId mu, columnar::EventInfoId evtInfo, const bool addMCCorrectionSmearing) const
342 {
343 auto& acc = *m_acc;
344 // Get information about data
345 bool isData = false;
347 else
348 {
349 // Retrieve the event information:
350 isData = !evtInfo(acc.eventTypeAcc, xAOD::EventInfo::IS_SIMULATION);
351 }
352
353 // Get information about which year it is here
354 MCP::DataYear dataYear = MuonCalibTool::getPeriod(isData, evtInfo);
355
356 // get the pt measurements from the xAOD::Muon object
357 double loc_ptid = 0;
358 double loc_ptms = 0;
359 double loc_ptcb = 0;
360
361 double Primary_eta = mu(acc.etaAcc);
362 double Primary_phi = mu(acc.phiAcc);
363
364 if (m_validationMode)
365 {
366 static const SG::AuxElement::Accessor<float> id_pt("expert_ptid");
367 static const SG::AuxElement::Accessor<float> ms_pt("expert_ptms");
368 static const SG::AuxElement::Accessor<float> cb_pt("expert_ptcb");
369
370 loc_ptid = id_pt(mu.getXAODObject()) * MeVtoGeV;
371 loc_ptms = ms_pt(mu.getXAODObject()) * MeVtoGeV;
372 loc_ptcb = cb_pt(mu.getXAODObject()) * MeVtoGeV;
373
374 } else {
375
376 // Retrieve all the trans
377 auto CB_track = mu(acc.combinedTrackParticleLinkAcc);
378 auto ID_track = mu(acc.inDetTrackParticleLinkAcc).opt_value();
379 auto ME_track = mu(acc.extrapolatedMuonSpectrometerTrackParticleLinkAcc);
380
381 if(CB_track) loc_ptcb = acc.trkMomentumAcc.pt(CB_track.value(), ParticleConstants::muonMassInMeV) * MeVtoGeV;
382 if(ID_track) loc_ptid = acc.trkMomentumAcc.pt(ID_track.value(), ParticleConstants::muonMassInMeV) * MeVtoGeV;
383 if(ME_track) loc_ptms = acc.trkMomentumAcc.pt(ME_track.value(), ParticleConstants::muonMassInMeV) * MeVtoGeV;
384 }
385
387 {
388 return m_MuonIntScaleSmearTool->getExpectedResolution(DetType, loc_ptms, Primary_eta, Primary_phi, dataYear, addMCCorrectionSmearing);
389 }
390 else if (DetType == MCP::DetectorType::ID)
391 {
392 return m_MuonIntScaleSmearTool->getExpectedResolution(DetType, loc_ptid, Primary_eta, Primary_phi, dataYear, addMCCorrectionSmearing);
393 }
394 else if (DetType == MCP::DetectorType::CB)
395 {
396 // Due to complicated maths, the expected combined resolution
397 // is given by this equation (note: all sigmas are fractional uncertainties):
398 // sigma_CB = std::sqrt(2) * sigma_ID * sigma_MS * pTMS * pTID / {pTCB * std::sqrt({sigma_ID*pTID}^2 + {sigma_MS*pTMS}^2)}
399 // Do a little recursive calling to make things easier to read
400 // Turn these into *absolute* uncertainties to make life easier
401 double sigmaID = expectedResolution(MCP::DetectorType::ID, mu, evtInfo, addMCCorrectionSmearing) * loc_ptid;
402 double sigmaMS = expectedResolution(MCP::DetectorType::MS, mu, evtInfo, addMCCorrectionSmearing) * loc_ptms;
403 double denominator = (loc_ptcb)*std::sqrt(sigmaID * sigmaID + sigmaMS * sigmaMS);
404 return denominator ? sigmaID * sigmaMS / denominator : 0.;
405 }
406 else
407 {
408 ATH_MSG_ERROR("wrong DetType in input " << DetType);
409 }
410 return 0.;
411
412 }
413
414 // Internal tool function
416 {
417 auto& acc = *m_acc;
418 // Get information about data
419 bool isData = false;
421 else
422 {
423 // Retrieve the event information:
424 isData = !evtInfo(acc.eventTypeAcc, xAOD::EventInfo::IS_SIMULATION);
425 }
426 ATH_MSG_VERBOSE("Checking Simulation flag: " << !isData);
427
428 // Get information about which year it is here
429 auto year = MuonCalibTool::getPeriod(isData, evtInfo);
430
431
432 double Primary_eta = mu(acc.etaAcc);
433 double Primary_phi = mu(acc.phiAcc);
434 int charge = mu(acc.chargeAcc);
436
438 {
439 static const SG::AuxElement::Accessor<float> cb_pt("expert_ptcb");
440 static const SG::AuxElement::Accessor<float> id_pt("expert_ptid");
441 static const SG::AuxElement::Accessor<float> ms_pt("expert_ptms");
442 static const SG::AuxElement::Accessor<AmgVector(5)> CBParam("CBParam");
443 static const SG::AuxElement::Accessor<AmgSymMatrix(5)> CBCov("CBCov");
444 static const SG::AuxElement::Accessor<AmgVector(5)> IDParam("IDParam");
445 static const SG::AuxElement::Accessor<AmgSymMatrix(5)> IDCov("IDCov");
446 static const SG::AuxElement::Accessor<AmgVector(5)> MEParam("MEParam");
447 static const SG::AuxElement::Accessor<AmgSymMatrix(5)> MECov("MECov");
448
449 // Use the constructor where the eta/phi are overwritten to keep it inma line with current recommendations. To be changed in the future
450 auto CB = MCP::TrackCalibObj(MCP::TrackType::CB, charge, cb_pt(mu.getXAODObject()), Primary_eta, Primary_phi, mass, CBParam(mu.getXAODObject()), CBCov(mu.getXAODObject()), year, isData);
451 auto ID = MCP::TrackCalibObj(MCP::TrackType::ID, charge, id_pt(mu.getXAODObject()), Primary_eta, Primary_phi, mass, IDParam(mu.getXAODObject()), IDCov(mu.getXAODObject()), year, isData);
452 auto ME = MCP::TrackCalibObj(MCP::TrackType::ME, charge, ms_pt(mu.getXAODObject()), Primary_eta, Primary_phi, mass, MEParam(mu.getXAODObject()), MECov(mu.getXAODObject()), year, isData);
453
454 MCP::MuonObj muonObj{CB,ID,ME};
455 initializeRandNumbers(muonObj, evtInfo);
456
459 muonObj.expectedResID = expectedResolution(MCP::DetectorType::ID, mu, evtInfo, true) * muonObj.CB.calib_pt;
460 muonObj.expectedResME = expectedResolution(MCP::DetectorType::MS, mu, evtInfo, true) * muonObj.CB.calib_pt;
461
462 return muonObj;
463 }
464
465
466 // Retrieve all the trans
467 auto CB_track = mu(acc.combinedTrackParticleLinkAcc);
468 auto ID_track = mu(acc.inDetTrackParticleLinkAcc).opt_value();
469 auto ME_track = mu(acc.extrapolatedMuonSpectrometerTrackParticleLinkAcc);
470
471 // For SI muons, overwrite the charge from the CB track
472 if (mu(acc.muonTypeAcc) == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon)
473 {
474 if (CB_track) charge = CB_track.value()(acc.trkChargeAcc);
475 }
476
477 // Use the constructor where the eta/phi are overwritten to keep it inma line with current recommendations. To be changed in the future
478 auto CB = MCP::TrackCalibObj(acc, columnar::OptObjectId<columnar::MuonTrackDef>(CB_track), MCP::TrackType::CB, charge, Primary_eta, Primary_phi, year, isData);
479 auto ID = MCP::TrackCalibObj(acc, columnar::OptObjectId<columnar::MuonTrackDef>(ID_track), MCP::TrackType::ID, charge, Primary_eta, Primary_phi, year, isData);
480 auto ME = MCP::TrackCalibObj(acc, columnar::OptObjectId<columnar::MuonTrackDef>(ME_track), MCP::TrackType::ME, charge, Primary_eta, Primary_phi, year, isData);
481
482 MCP::MuonObj muonObj{CB,ID,ME};
483 initializeRandNumbers(muonObj, evtInfo);
486
487 muonObj.expectedResID = expectedResolution(MCP::DetectorType::ID, mu, evtInfo, true) * muonObj.CB.calib_pt;
488 muonObj.expectedResME = expectedResolution(MCP::DetectorType::MS, mu, evtInfo, true) * muonObj.CB.calib_pt;
489 return muonObj;
490 }
492 {
493 auto& acc = *m_acc;
494 // Get information about data
495 bool isData = false;
496
497 // Retrieve the event information:
499 isData = !evtInfo->eventType(xAOD::EventInfo::IS_SIMULATION);
500
501 ATH_MSG_VERBOSE("Checking Simulation flag: " << !isData);
502
503 // Get information about which year it is here
504 auto year = MuonCalibTool::getPeriod(isData, *evtInfo);
505 int charge = inTrk.charge();
507 {
508 auto CB = MCP::TrackCalibObj(acc, &inTrk, MCP::TrackType::CB, charge, year, isData);
509 auto ID = MCP::TrackCalibObj(acc, &inTrk, MCP::TrackType::ID, charge, year, isData);
510 auto ME = MCP::TrackCalibObj(acc, &inTrk, MCP::TrackType::ME, charge, year, isData);
511
512 MCP::MuonObj muonObj{CB,ID,ME};
513 return muonObj;
514 }
515
516 auto CB = MCP::TrackCalibObj(acc, &inTrk, MCP::TrackType::CB, charge, year, isData);
517 auto ID = MCP::TrackCalibObj(acc, nullptr, MCP::TrackType::ID, charge, year, isData);
518 auto ME = MCP::TrackCalibObj(acc, &inTrk, MCP::TrackType::ME, charge, year, isData);
519
520 MCP::MuonObj muonObj{CB,ID,ME};
521 return muonObj;
522 }
523
524
526 {
527 auto& acc = *m_acc;
528 // Random number generation for smearing
529 TRandom3 loc_random3;
530 // Get Event Number, Retrieve the event information:
531 unsigned long long eventNumber = 0;
533 else eventNumber = evtInfo(acc.eventNumberAcc);
534 // Construct a seed for the random number generator:
535 const UInt_t seed = 1 + std::abs(muonObj.CB.phi) * 1E6 + std::abs(muonObj.CB.eta) * 1E3 + eventNumber;
536 loc_random3.SetSeed(seed);
537
538 muonObj.rnd_g0 = loc_random3.Gaus(0, 1);
539 muonObj.rnd_g1 = loc_random3.Gaus(0, 1);
540 muonObj.rnd_g2 = loc_random3.Gaus(0, 1);
541 muonObj.rnd_g3 = loc_random3.Gaus(0, 1);
542 muonObj.rnd_g4 = loc_random3.Gaus(0, 1);
543 muonObj.rnd_g_highPt = loc_random3.Gaus(0, 1);
544
545
546 }
547
549 {
550 // I've copied the run number ranges from SUSYTools (Run2) - Haider
551 // https://gitlab.cern.ch/atlas/athena/blob/21.2/PhysicsAnalysis/SUSYPhys/SUSYTools/Root/SUSYObjDef_xAOD.cxx#L2438
552 // Range for Run3 taken from COMA - Luca
553 // https://atlas-tagservices.cern.ch/tagservices/RunBrowser/runBrowserReport/rBR_Period_Report.php?fnt=data22_13p6TeV
554 // https://atlas-tagservices.cern.ch/tagservices/RunBrowser/runBrowserReport/rBR_Period_Report.php?fnt=data23_13p6TeV
555 // https://atlas-tagservices.cern.ch/tagservices/RunBrowser/runBrowserReport/rBR_Period_Report.php?fnt=data24_13p6TeV
556 constexpr unsigned int last_run_16 = 320000;
557 constexpr unsigned int last_run_17 = 342000;
558 constexpr unsigned int last_run_18 = 370000;
559 constexpr unsigned int last_run_22 = 440614;
560 constexpr unsigned int last_run_23 = 456750;
561 constexpr unsigned int last_run_24 = 999999;
562
563 static const std::set<int> MCperiods1516{284500};
564 static const std::set<int> MCperiods17{300000, 304000, 305000};
565 static const std::set<int> MCperiods18{310000};
566 static const std::set<int> MCperiods22{330000, 410000};
567 static const std::set<int> MCperiods23{450000};
568 static const std::set<int> MCperiods24{470000};
569
570 static const std::set<int> MCperiodsRun4{350000, 350060, 350140, 350200};
571
572 auto& acc = *m_acc;
573 unsigned int run = 0;
575 else run = evtInfo(acc.runNumberAcc);
576 // retrieve the random run number
577 if (!isData && m_useRndRun) {
578 if (acc.acc_rnd.isAvailable(evtInfo))
579 run = acc.acc_rnd(evtInfo);
580 else {
582 "No random runnumber could be found although the tool is configured to assign the years based on it. Please make sure "
583 "to apply the prwTool before-hand or consider to set the property 'useRandomRunNumber' to false.");
585 }
586 }
587 // Check the Monte carlo
588 if (!isData && (!m_useRndRun || !acc.acc_rnd.isAvailable(evtInfo))) {
589 if (MCperiods1516.count(run)) {
590 ATH_MSG_DEBUG("The current run " << run << " corresponds to data mc20a / data15-16");
592 } else if (MCperiods17.count(run)) {
593 ATH_MSG_DEBUG("The current run " << run << " corresponds to data mc20d / data17");
595 } else if (MCperiods18.count(run)) {
596 ATH_MSG_DEBUG("The current run " << run << " corresponds to data mc20e / data18");
598 } else if (MCperiods22.count(run)) {
599 ATH_MSG_DEBUG("The current run " << run << " corresponds to data mc21 / mc23a / data22");
601 } else if (MCperiods23.count(run)) {
602 ATH_MSG_DEBUG("The current run " << run << " corresponds to data mc23c / mc23d / data23");
604 } else if (MCperiods24.count(run)) {
605 ATH_MSG_DEBUG("The current run " << run << " corresponds to data mc23e / data24");
607 } else if (MCperiodsRun4.count(run)) {
608 ATH_MSG_DEBUG("The current run " << run << " corresponds to data Run4");
609 return MCP::DataYear::Run4;
610 }
611
612 }
613 // Check data itself or the random run number is used
614 else if (isData || m_useRndRun) {
615 if (run < last_run_16) {
616 ATH_MSG_DEBUG("The current run " << run << " is taken in data 15-16");
618 } else if (run <= last_run_17) {
619 ATH_MSG_DEBUG("The current run " << run << " is taken in data 17");
621 } else if (run <= last_run_18) {
622 ATH_MSG_DEBUG("The current run " << run << " is taken in data 18");
624 } else if (run <= last_run_22) {
625 ATH_MSG_DEBUG("The current run " << run << " is taken in data 22");
627 } else if (run < last_run_23) {
628 ATH_MSG_DEBUG("The current run " << run << " is taken in data 23");
630 } else if (run < last_run_24) {
631 ATH_MSG_DEBUG("The current run " << run << " is taken in data 24");
633 }
634 }
635 static std::atomic<bool> warningPrinted {false};
636 if (!warningPrinted) {
637 ATH_MSG_WARNING("Could not assign run-number " << run << " to a specific year of data-taking, using default year 24");
638 warningPrinted = true;
639 }
641 }
642
643
645 {
646 for (columnar::MuonId muon : muons)
647 {
648 switch (applyCorrection(muon, event).code())
649 {
651 break;
653 throw std::runtime_error("OutOfValidityRange in applyCorrection");
654 break;
656 throw std::runtime_error("Error in applyCorrection");
657 }
658 }
659 }
660
662 auto& acc = *m_acc;
663 for (columnar::EventContextId event : events)
664 {
665 auto eventInfo = acc.m_eventInfoCol(event);
666 callSingleEvent (acc.m_muons(event), eventInfo);
667 }
668 }
669
670} // namespace CP
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Handle class for reading from StoreGate.
#define AmgSymMatrix(dim)
#define AmgVector(rows)
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ OutOfValidityRange
Input object is out of validity range.
@ Ok
The correction was done successfully.
ResolutionCategory
Declare the interface that the class provides.
Gaudi::Property< std::string > m_sysScheme
asg::AnaToolHandle< CP::IMuonCalibIntScaleSmearTool > m_MuonIntScaleSmearTool
Gaudi::Property< unsigned long long > m_expertMode_EvtNumber
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
Gaudi::Property< std::string > m_release
Gaudi::Property< bool > m_validationMode
Gaudi::Property< bool > m_excludeNSWFromPrecisionLayers
virtual ASG_TOOL_CLASS3(MuonCalibTool, CP::IMuonCalibrationAndSmearingTool, CP::ISystematicsTool, CP::IReentrantSystematicsTool) public CorrectionCode applyCorrection(xAOD::Muon &mu) const override
Declare the interface that the class provides.
MuonCalibTool(const std::string &name)
Gaudi::Property< bool > m_useRndRun
void initializeRandNumbers(MCP::MuonObj &obj, columnar::EventInfoId evtInfo) const
Decorate all information that's needed to ensure reproducibility of the smearing.
Gaudi::Property< bool > m_extra_highpt_smearing
virtual CorrectionCode applyCorrectionTrkOnly(xAOD::TrackParticle &inTrk, const int DetType) const override
Gaudi::Property< bool > m_skipResolutionCategory
MCP::DataYear getPeriod(bool isData, columnar::EventInfoId evtInfo) const
virtual CorrectionCode correctedCopy(const xAOD::Muon &input, xAOD::Muon *&output) const override
Create a corrected copy from a constant muon.
bool m_MuonIntHighTSmearToolInitialized
asg::AnaToolHandle< CP::IMuonCalibIntTool > m_MuonIntHighTSmearTool
Gaudi::Property< bool > m_doEtaSagittaSys
void callEvents(columnar::EventContextRange events) const override
Gaudi::Property< bool > m_applyCorrectionOnData
Gaudi::Property< float > m_HighPtSystThreshold
void callSingleEvent(columnar::MuonRange muons, columnar::EventInfoId event) const
asg::AnaToolHandle< CP::IMuonSelectionTool > m_MuonSelectionTool
MCP::MuonObj convertToMuonObj(columnar::MuonId mu, columnar::EventInfoId evtInfo) const
Gaudi::Property< bool > m_isRun3
virtual double expectedResolution(const std::string &DetType, const xAOD::Muon &mu, const bool addMCCorrectionSmearing) const override
Get the expected pT resolution.
asg::AnaToolHandle< CP::IMuonCalibIntTool > m_MuonIntSagittaTool
Gaudi::Property< bool > m_2stations_highpt_smearing
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo
virtual StatusCode applySystematicVariation(const SystematicSet &systConfig) override
effects: configure this tool for the given list of systematic variations.
Gaudi::Property< int > m_expertMode_RunNumber
virtual bool isAffectedBySystematic(const SystematicVariation &systematic) const override
Declare the interface that this class provides.
virtual SystematicSet affectingSystematics() const override
the list of all systematics this tool can be affected by
Gaudi::Property< int > m_calibMode
std::unique_ptr< MCP::MuonCalibToolAccessors > m_acc
virtual SystematicSet recommendedSystematics() const override
the list of all systematics this tool recommends to use
Gaudi::Property< bool > m_expertMode_isData
This module implements the central registry for handling systematic uncertainties with CP tools.
static SystematicRegistry & getInstance()
Get the singleton instance of the registry for the curren thread.
StatusCode registerSystematics(const IReentrantSystematicsTool &tool)
effects: register all the systematics from the tool
Class to wrap a set of SystematicVariations.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
a class representing a single optional object (electron, muons, etc.)
@ IS_SIMULATION
true: simulation, false: data
float z0() const
Returns the parameter.
float theta() const
Returns the parameter, which has range 0 to .
float d0() const
Returns the parameter.
void setDefiningParameters(float d0, float z0, float phi0, float theta, float qOverP)
Set the defining parameters.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
float charge() const
Returns the charge.
float phi0() const
Returns the parameter, which has range to .
Select isolated Photons, Electrons and Muons.
constexpr float MeVtoGeV
DataYear
Definition EnumDef.h:28
constexpr double muonMassInMeV
the mass of the muon (in MeV)
ObjectId< MuonDef > MuonId
Definition MuonDef.h:22
ObjectRange< EventContextDef > EventContextRange
ObjectId< EventContextDef > EventContextId
ObjectRange< MuonDef > MuonRange
Definition MuonDef.h:21
ObjectId< EventInfoDef > EventInfoId
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Muon_v1 Muon
Reference the current persistent version:
static const SG::AuxElement::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.
double rnd_g1
Definition MuonObj.h:188
double rnd_g3
Definition MuonObj.h:190
double expectedResID
Definition MuonObj.h:201
double expectedPercentResME
Definition MuonObj.h:205
double rnd_g0
Random numbers helping for the calibration.
Definition MuonObj.h:187
double expectedResME
Definition MuonObj.h:202
double rnd_g2
Definition MuonObj.h:189
TrackCalibObj ID
Definition MuonObj.h:182
std::optional< ResolutionCategory > raw_mst_category
Definition MuonObj.h:198
double rnd_g_highPt
Definition MuonObj.h:192
double expectedPercentResID
Definition MuonObj.h:204
TrackCalibObj CB
Definition MuonObj.h:184
TrackCalibObj ME
Definition MuonObj.h:183
double rnd_g4
Definition MuonObj.h:191
Basic object to cache all relevant information from the track.
Definition MuonObj.h:74
int calib_charge
Value of the track-charge (after calibration).
Definition MuonObj.h:165
const double eta
Value of the track-eta.
Definition MuonObj.h:157
const double phi
Value of the track-phi.
Definition MuonObj.h:159
const bool isData
Definition MuonObj.h:169
double calib_pt
Smeared track pt.
Definition MuonObj.h:155
MsgStream & msg
Definition testRead.cxx:32
int run(int argc, char *argv[])