ATLAS Offline Software
Loading...
Searching...
No Matches
METMaker.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5*/
6
7// METMaker.cxx
8// Implementation file for class METMaker
9// Author: T.J.Khoo<khoo@cern.ch>
11
12// METUtilities includes
15
16// MET EDM
22
23// Jet EDM
25
26// Tracking EDM
29
30// Shallow copy
32
33// Muon EDM
35
36// Electron EDM
39
40// framework includes
46
47#include <memory>
48
49namespace met {
50
51 using xAOD::MissingET;
57 using xAOD::IParticle;
62
63 using iplink_t = ElementLink<xAOD::IParticleContainer>;
64 static const SG::ConstAccessor< iplink_t > acc_originalObject("originalObjectLink");
65 static const SG::ConstAccessor< iplink_t > acc_nominalObject("nominalObjectLink");
68
69 static const SG::ConstAccessor< std::vector<int> > acc_trkN("NumTrkPt500");
70 static const SG::ConstAccessor< std::vector<float> > acc_trksumpt("SumPtTrkPt500");
71 static const SG::ConstAccessor< std::vector<float> > acc_sampleE("EnergyPerSampling");
72
73 static const SG::ConstAccessor<float> acc_emf("EMFrac");
74 static const SG::ConstAccessor<float> acc_psf("PSFrac");
75 static const SG::ConstAccessor<float> acc_width("Width");
76 static const SG::ConstAccessor<float> acc_Eloss("EnergyLoss");
77
78 static const SG::Accessor< std::vector<iplink_t> > dec_constitObjLinks("ConstitObjectLinks");
79 static const SG::Accessor< std::vector<float> > dec_constitObjWeights("ConstitObjectWeights");
80
81
83 // Public methods:
85
86 // Constructors
88 METMaker::METMaker(const std::string& name) :
90 m_PVkey("PrimaryVertices"),
91 m_acc_jetRejectionDec(nullptr),
92 m_trkseltool(""),
93 m_JvtTool("", this)
94 {
95 //
96 // Property declaration
97 //
98 declareProperty("JetRejectionDec", m_jetRejectionDec = "" );
99 declareProperty("JetMinEFrac", m_jetMinEfrac = 0.0 );
100 declareProperty("JetMinWeightedPt", m_jetMinWeightedPt = 20.0e3 );
101 declareProperty("JetConstitScaleMom", m_jetConstitScaleMom = "JetConstitScaleMomentum");
102 declareProperty("CorrectJetPhi", m_jetCorrectPhi = false );
103 declareProperty("DoPFlow", m_doPFlow = false );
104 declareProperty("DoSoftTruth", m_doSoftTruth = false );
105 declareProperty("DoJetTruth", m_doConstJet = false );
106
107 declareProperty("JetSelection", m_jetSelection = "Tight" );
108 declareProperty("JetEtaMax", m_JetEtaMax = 4.5 );
109 declareProperty("JetEtaForw", m_JetEtaForw = 2.5 );
110 declareProperty("CustomCentralJetPt", m_customCenJetPtCut = 20e3 );
111 declareProperty("CustomForwardJetPt", m_customFwdJetPtCut = 20e3 );
112 declareProperty("CustomJetJvtPtMax", m_customJvtPtMax = 60e3 );
113 declareProperty("CustomJetJvtWP", m_customJvtWP = "FixedEffPt" );
114
115 declareProperty("DoMuonEloss", m_muEloss = false );
116 declareProperty("ORCaloTaggedMuons", m_orCaloTaggedMuon = true );
117 declareProperty("GreedyPhotons", m_greedyPhotons = false );
118 declareProperty("VeryGreedyPhotons", m_veryGreedyPhotons = false );
119
120 declareProperty("UseGhostMuons", m_useGhostMuons = false );
121 declareProperty("DoRemoveMuonJets", m_doRemoveMuonJets = true );
122 declareProperty("DoSetMuonJetEMScale", m_doSetMuonJetEMScale = true );
123
124 declareProperty("DoRemoveElecTrks", m_doRemoveElecTrks = true );
125 declareProperty("DoRemoveElecTrksEM", m_doRemoveElecTrksEM = false );
126
127 declareProperty("skipSystematicJetSelection", m_skipSystematicJetSelection = false,
128 "EXPERIMENTAL: whether to use simplified OR based on nominal jets "
129 "and for jet-related systematics only. "
130 "WARNING: this property is strictly for doing physics studies of the feasibility "
131 "of this OR scheme, it should not be used in a regular analysis");
132
133 // muon overlap variables (expert use only)
134 declareProperty("JetTrkNMuOlap", m_jetTrkNMuOlap = 5 );
135 declareProperty("JetWidthMuOlap", m_jetWidthMuOlap = 0.1 );
136 declareProperty("JetPsEMuOlap", m_jetPsEMuOlap = 2.5e3 );
137 declareProperty("JetEmfMuOlap", m_jetEmfMuOlap = 0.9 );
138 declareProperty("JetTrkPtMuPt", m_jetTrkPtMuPt = 0.8 );
139 declareProperty("muIDPTJetPtRatioMuOlap", m_muIDPTJetPtRatioMuOlap = 2.0 );
140
141 declareProperty("MissingObjWarnThreshold", m_missObjWarningPtThreshold = 7.0e3 );
142
143 declareProperty("TrackSelectorTool", m_trkseltool );
144 declareProperty("JvtSelTool", m_JvtTool );
145 }
146
147 // Destructor
150 = default;
151
152 // Athena algtool's Hooks
155 {
156 ATH_MSG_INFO ("Initializing " << name() << "...");
157
158 ATH_MSG_INFO("Use jet selection criterion: " << m_jetSelection << " PFlow: " << m_doPFlow);
159 if (m_jetSelection == "Loose") { m_CenJetPtCut = 20e3; m_FwdJetPtCut = 20e3; m_JvtWP = "FixedEffPt"; m_JvtPtMax = 60e3; }
160 else if (m_jetSelection == "Tight") { m_CenJetPtCut = 20e3; m_FwdJetPtCut = 30e3; m_JvtWP = "FixedEffPt"; m_JvtPtMax = 60e3; }
161 else if (m_jetSelection == "Tighter"){ m_CenJetPtCut = 20e3; m_FwdJetPtCut = 35e3; m_JvtWP = "FixedEffPt"; m_JvtPtMax = 60e3; }
162 else if (m_jetSelection == "Tenacious"){ m_CenJetPtCut = 20e3; m_FwdJetPtCut = 40e3; m_JvtWP = "FixedEffPt"; m_JvtPtMax = 60e3; }
163 else if (m_jetSelection == "Tier0") { m_CenJetPtCut = 0; m_FwdJetPtCut = 0; m_JvtWP = "None"; }
164 else if (m_jetSelection == "Expert") {
165 ATH_MSG_INFO("Custom jet selection configured. *** FOR EXPERT USE ONLY ***");
170 }
171 else if (m_jetSelection == "HRecoil") {
172 ATH_MSG_INFO("Jet selection for hadronic recoil calculation is configured.");
173 m_CenJetPtCut = 9999e3;
174 m_FwdJetPtCut = 9999e3;
175 m_JetEtaMax = 5;
176 m_JvtWP = "None";
177 }
178 else {
179 if (m_jetSelection == "Default") ATH_MSG_WARNING( "WARNING: Default is now deprecated" );
180 ATH_MSG_ERROR( "Error: No available jet selection found! Please update JetSelection in METMaker. Choose one: Loose, Tight (recommended), Tighter, Tenacious" );
181 return StatusCode::FAILURE;
182 }
183
184 if (!m_trkseltool.empty()) ATH_CHECK( m_trkseltool.retrieve() );
185
186 ATH_CHECK( m_jetContainer.initialize(m_JvtWP != "None" && m_JvtTool.empty()) );
187
188 if (m_JvtWP != "None"){
189 if (m_JvtTool.empty()) {
190 asg::AsgToolConfig config_jvt ("CP::NNJvtSelectionTool/JvtSelTool_METMaker_" + m_jetSelection);
191 ATH_CHECK(config_jvt.setProperty("JetContainer", m_jetContainer.key()));
192 ATH_CHECK(config_jvt.setProperty("WorkingPoint", m_JvtWP));
193 ATH_CHECK(config_jvt.setProperty("JvtMomentName", "NNJvt"));
194 ATH_CHECK(config_jvt.setProperty("MaxPtForJvt", m_JvtPtMax));
196 }
197 ATH_CHECK(m_JvtTool.retrieve());
198 }
199
200 // ReadHandleKey(s)
201 ATH_CHECK( m_PVkey.initialize() );
202
203 // configurable accessors
204 if (!m_jetRejectionDec.empty()) {
205 m_acc_jetRejectionDec = std::make_unique<SG::ConstAccessor<char>>(m_jetRejectionDec);
206 ATH_MSG_INFO("Applying additional jet rejection criterium in MET calculation: " << m_jetRejectionDec);
207 }
208
209 ATH_MSG_INFO("Suppressing warnings of objects missing in METAssociationMap for objects with pT < " << m_missObjWarningPtThreshold/1e3 << " GeV.");
210
211 // overlap removal simplification?
213 ATH_MSG_INFO("Requesting simplified overlap removal procedure in MET calculation");
214 }
215
216 return StatusCode::SUCCESS;
217 }
218
219
220 // **** Rebuild generic MET term ****
221
222 StatusCode METMaker::rebuildMET(const std::string& metKey,
225 const xAOD::IParticleContainer* collection,
228 {
230 switch(metType) {
233 break;
235 metSource = MissingETBase::Source::photon();
236 break;
237 case xAOD::Type::Tau:
238 metSource = MissingETBase::Source::tau();
239 break;
240 case xAOD::Type::Muon:
241 metSource = MissingETBase::Source::muon();
242 break;
243 case xAOD::Type::Jet:
244 ATH_MSG_WARNING("Incorrect use of rebuildMET -- use rebuildJetMET for RefJet term");
245 return StatusCode::FAILURE;
246 default:
247 ATH_MSG_WARNING("Invalid object type provided: " << metType);
248 return StatusCode::FAILURE;
249 }
250
251 MissingET* met = nullptr;
252 if( fillMET(met,metCont, metKey , metSource) != StatusCode::SUCCESS) {
253 ATH_MSG_ERROR("failed to fill MET term \"" << metKey << "\"");
254 return StatusCode::FAILURE;
255 }
256
257 // If muon eloss corrections are required, create a new term to hold these if it doesn't already exist
258 if(metType==xAOD::Type::Muon && (m_muEloss || m_doSetMuonJetEMScale) && !(*metCont)["MuonEloss"]) {
259 MissingET* met_muEloss = nullptr;
260 if( fillMET(met_muEloss,metCont,"MuonEloss",
261 MissingETBase::Source::Type::Muon | MissingETBase::Source::Category::Calo) != StatusCode::SUCCESS) {
262 ATH_MSG_ERROR("failed to create Muon Eloss MET term");
263 return StatusCode::FAILURE;
264 }
265 }
266
267 return rebuildMET(met,collection,helper,objScale);
268 }
269
271 const xAOD::IParticleContainer* collection,
274 {
276 bool removeOverlap = true;
277 if(!collection->empty()) {
278 const IParticle* obj = collection->front();
279 if(obj->type()==xAOD::Type::Muon) {
281 removeOverlap = false;
282 }
283 }
286 return rebuildMET(met,collection,helper,p,removeOverlap,objScale);
287 }
288
290 const xAOD::IParticleContainer* collection,
293 bool removeOverlap,
295 if(!met || !collection) {
296 ATH_MSG_ERROR("Invalid pointer supplied for "
297 << "MET (" << met << ") or "
298 << "collection (" << collection << ").");
299 return StatusCode::FAILURE;
300 }
301 const xAOD::MissingETAssociationMap* map = helper.map();
302 if(!map){
303 ATH_MSG_ERROR("MET Association Helper isn't associated with a MissingETAssociationMap!");
304 return StatusCode::FAILURE;
305 }
306 if(map->empty()) {
307 ATH_MSG_WARNING("Incomplete association map received. Cannot rebuild MET.");
308 ATH_MSG_WARNING("Note: METMaker should only be run on events containing at least one PV");
309 return StatusCode::SUCCESS;
310 }
311 ATH_MSG_VERBOSE("Building MET term " << met->name());
312 dec_constitObjLinks(*met) = std::vector<iplink_t>(0);
313 dec_constitObjWeights(*met) = std::vector<float>(0);
314 std::vector<iplink_t>& uniqueLinks = dec_constitObjLinks(*met);
315 std::vector<float>& uniqueWeights = dec_constitObjWeights(*met);
316 uniqueLinks.reserve(collection->size());
317 uniqueWeights.reserve(collection->size());
318
319 // Get the hashed key of this collection, if we can. Though his only works
320 // if
321 // 1. the container is an owning container, and not just a view;
322 // 2. the container is in the event store already.
323 // Since we will be creating ElementLink-s to these objects later on in the
324 // code, and it should work in AnalysisBase, only the first one of these
325 // is checked. Since the code can not work otherwise.
326 SG::sgkey_t collectionSgKey = 0;
327 if(collection->ownPolicy() == SG::OWN_ELEMENTS) {
328 collectionSgKey = getKey(collection);
329 if(collectionSgKey == 0) {
330 ATH_MSG_ERROR("Could not find the collection with pointer: "
331 << collection);
332 return StatusCode::FAILURE;
333 }
334 }
335
336 if(collection->empty()) return StatusCode::SUCCESS;
337
338 bool originalInputs = !acc_originalObject.isAvailable(*collection->front());
339 bool isShallowCopy = dynamic_cast<const xAOD::ShallowAuxContainer*>(collection->front()->container()->getConstStore());
340 ATH_MSG_VERBOSE("const store = " << collection->front()->container()->getConstStore());
341 if(isShallowCopy && originalInputs) {
342 ATH_MSG_WARNING("Shallow copy provided without \"originalObjectLinks\" decoration! "
343 << "Overlap removal cannot be done. "
344 << "Will not compute this term.");
345 ATH_MSG_WARNING("Please apply xAOD::setOriginalObjectLink() from xAODBase/IParticleHelpers.h");
346 return StatusCode::SUCCESS;
347 }
348 ATH_MSG_VERBOSE("Original inputs? " << originalInputs);
349 for(const auto *const obj : *collection) {
350 const IParticle* orig = obj;
351 bool selected = false;
352 if(!originalInputs) { orig = *acc_originalObject(*obj); }
353 std::vector<const xAOD::MissingETAssociation*> assocs = xAOD::MissingETComposition::getAssociations(map,orig);
354 if(assocs.empty()) {
355 std::string message = "Object is not in association map. Did you make a deep copy but fail to set the \"originalObjectLinks\" decoration? "
356 "If not, Please apply xAOD::setOriginalObjectLink() from xAODBase/IParticleHelpers.h";
357 // Avoid warnings for leptons with pT below threshold for association map
358 if (orig->pt()>m_missObjWarningPtThreshold) {
359 ATH_MSG_WARNING(message);
360 } else {
361 ATH_MSG_DEBUG(message);
362 }
363 // if this is an uncalibrated electron below the threshold, then we put it into the soft term
364 if(orig->type()==xAOD::Type::Electron){
365 iplink_t objLink;
366 if(collectionSgKey == 0) {
367 const xAOD::IParticleContainer* ipc = static_cast<const xAOD::IParticleContainer*>(obj->container());
368 objLink = iplink_t(*ipc, obj->index());
369 } else {
370 objLink = iplink_t(collectionSgKey, obj->index());
371 }
372 uniqueLinks.emplace_back( objLink );
373 uniqueWeights.emplace_back( 0. );
374 message = "Missing an electron from the MET map. Included as a track in the soft term. pT: " + std::to_string(obj->pt()/1e3) + " GeV";
375 if (orig->pt()>m_missObjWarningPtThreshold) {
376 ATH_MSG_WARNING(message);
377 } else {
378 ATH_MSG_DEBUG(message);
379 }
380 continue;
381 } else {
382 ATH_MSG_ERROR("Missing an object: " << orig->type() << " pT: " << obj->pt()/1e3 << " GeV, may be duplicated in the soft term.");
383 }
384 }
385
386 // If the object has already been selected and processed, ignore it.
387 if(MissingETComposition::objSelected(helper,orig)) continue;
388 selected = MissingETComposition::selectIfNoOverlaps(helper,orig,p) || !removeOverlap;
389 ATH_MSG_VERBOSE(obj->type() << " (" << orig <<") with pt " << obj->pt()
390 << " is " << ( selected ? "non-" : "") << "overlapping");
391
392 // Greedy photon options: set selection flags
393 if ((m_greedyPhotons || m_veryGreedyPhotons) && selected && obj->type() == xAOD::Type::Photon){
394 for(const xAOD::MissingETAssociation* assoc : assocs){
395 std::vector<size_t> indices = assoc->overlapIndices(orig);
396 std::vector<const xAOD::IParticle*> allObjects = assoc->objects();
397 for (size_t index : indices){
398 const xAOD::IParticle* thisObj = allObjects[index];
399 if(!thisObj) continue;
400 if ((thisObj->type() == xAOD::Type::Jet && m_veryGreedyPhotons) ||
401 thisObj->type() == xAOD::Type::Electron)
402 helper.setObjSelectionFlag(assoc, thisObj, true);
403 }
404 }
405 }
406
407 //Do special overlap removal for calo tagged muons
408 if(m_orCaloTaggedMuon && !removeOverlap &&
409 orig->type()==xAOD::Type::Muon && static_cast<const xAOD::Muon*>(orig)->muonType()==xAOD::Muon::MuonType::CaloTagged) {
410 for (size_t i = 0; i < assocs.size(); i++) {
411 std::vector<size_t> ind = assocs[i]->overlapIndices(orig);
412 std::vector<const xAOD::IParticle*> allObjects = assocs[i]->objects();
413 for (size_t indi = 0; indi < ind.size(); indi++) if (allObjects[ind[indi]]) {
414 if (allObjects[ind[indi]]->type()==xAOD::Type::Electron
415 && helper.objSelected(assocs[i], ind[indi])) {
416 selected = false;
417 break;
418 }
419 }
420 }
421 }
422 // Don't overlap remove muons, but flag the non-overlapping muons to take out their tracks from jets
423 // Removed eloss from here -- clusters already flagged.
424 // To be handled in rebuildJetMET
425 if(selected) {
427 ATH_MSG_VERBOSE("Add object with pt " << obj->pt());
428 *met += obj;
429 } else {
431 ATH_MSG_VERBOSE("Add truth object with pt " << constvec.cpt());
432 met->add(constvec.cpx(),constvec.cpy(),constvec.cpt());
433 }
434 iplink_t objLink;
435 if(collectionSgKey == 0) {
436 const xAOD::IParticleContainer* ipc =
437 static_cast<const xAOD::IParticleContainer*>(obj->container());
438 objLink = iplink_t(*ipc, obj->index());
439 } else {
440 objLink = iplink_t(collectionSgKey, obj->index());
441 }
442 uniqueLinks.push_back( objLink );
443 uniqueWeights.push_back( 1. );
444 }
445 }
446 ATH_MSG_DEBUG("Built met term " << met->name() << ", with magnitude " << met->met());
447 return StatusCode::SUCCESS;
448 }
449
450 StatusCode METMaker::rebuildJetMET(const std::string& metJetKey,
451 const std::string& softKey,
453 const xAOD::JetContainer* jets,
454 const xAOD::MissingETContainer* metCoreCont,
456 bool doJetJVT) const
457 {
458 ATH_MSG_VERBOSE("Rebuild jet term: " << metJetKey << " and soft term: " << softKey);
459
460 MissingET* metJet = nullptr;
461 if( fillMET(metJet,metCont, metJetKey, MissingETBase::Source::jet()) != StatusCode::SUCCESS) {
462 ATH_MSG_ERROR("failed to fill MET term \"" << metJetKey << "\"");
463 return StatusCode::FAILURE;
464 }
465
466 const MissingET *coreSoftClus(nullptr), *coreSoftTrk(nullptr);
467 MissingET *metSoftClus(nullptr), *metSoftTrk(nullptr);
468
469 const MissingET* coreSoft = (*metCoreCont)[softKey+"Core"];
470 if(!coreSoft) {
471 ATH_MSG_WARNING("Invalid soft term key supplied: " << softKey);
472 return StatusCode::FAILURE;
473 }
475 coreSoftTrk = coreSoft;
476
477 metSoftTrk = nullptr;
478 if( fillMET(metSoftTrk,metCont, softKey , coreSoftTrk->source() ) != StatusCode::SUCCESS) {
479 ATH_MSG_ERROR("failed to fill MET term \"" << softKey << "\"");
480 return StatusCode::FAILURE;
481 }
482 } else {
483 coreSoftClus = coreSoft;
484
485 metSoftClus = nullptr;
486 if( fillMET(metSoftClus, metCont, softKey , coreSoftClus->source() ) != StatusCode::SUCCESS) {
487 ATH_MSG_ERROR("failed to fill MET term \"" << softKey << "\"");
488 return StatusCode::FAILURE;
489 }
490 }
491
492 return rebuildJetMET(metJet, jets, helper,
493 metSoftClus, coreSoftClus,
494 metSoftTrk, coreSoftTrk,
495 doJetJVT);
496 }
497
498 StatusCode METMaker::rebuildTrackMET(const std::string& metJetKey,
499 const std::string& softKey,
501 const xAOD::JetContainer* jets,
502 const xAOD::MissingETContainer* metCoreCont,
504 bool doJetJVT) const
505 {
506 ATH_MSG_VERBOSE("Rebuild jet term: " << metJetKey << " and soft term: " << softKey);
507
508 MissingET* metJet = nullptr;
509 if( fillMET(metJet , metCont, metJetKey , MissingETBase::Source::jet() | MissingETBase::Source::track() ) != StatusCode::SUCCESS) {
510 ATH_MSG_ERROR("failed to fill MET term \"" << metJetKey << "\"");
511 return StatusCode::FAILURE;
512 }
513
514 const MissingET *coreSoftTrk(nullptr);
515 MissingET *metSoftTrk(nullptr);
516
517 const MissingET* coreSoft = (*metCoreCont)[softKey+"Core"];
518 if(!coreSoft) {
519 ATH_MSG_WARNING("Invalid soft term key supplied: " << softKey);
520 return StatusCode::FAILURE;
521 }
522 coreSoftTrk = coreSoft;
523
524 metSoftTrk = nullptr;
525 if( fillMET(metSoftTrk , metCont, softKey , coreSoftTrk->source()) != StatusCode::SUCCESS) {
526 ATH_MSG_ERROR("failed to fill MET term \"" << softKey << "\"");
527 return StatusCode::FAILURE;
528 }
529
530 return rebuildTrackMET(metJet, jets, helper,
531 metSoftTrk, coreSoftTrk,
532 doJetJVT);
533 }
534
535 StatusCode METMaker::rebuildJetMET(const std::string& metJetKey,
536 const std::string& softClusKey,
537 const std::string& softTrkKey,
539 const xAOD::JetContainer* jets,
540 const xAOD::MissingETContainer* metCoreCont,
542 bool doJetJVT) const
543 {
544
545 ATH_MSG_VERBOSE("Create Jet MET " << metJetKey);
546 MissingET* metJet = nullptr;
547 if( fillMET(metJet , metCont ,metJetKey , MissingETBase::Source::jet()) != StatusCode::SUCCESS) {
548 ATH_MSG_ERROR("failed to fill MET term \"" << metJetKey << "\"");
549 return StatusCode::FAILURE;
550 }
551 ATH_MSG_VERBOSE("Create SoftClus MET " << softClusKey);
552 const MissingET* coreSoftClus = (*metCoreCont)[softClusKey+"Core"];
553 ATH_MSG_VERBOSE("Create SoftTrk MET " << softTrkKey);
554 const MissingET* coreSoftTrk = (*metCoreCont)[softTrkKey+"Core"];
555 if(!coreSoftClus) {
556 ATH_MSG_WARNING("Invalid cluster soft term key supplied: " << softClusKey);
557 return StatusCode::FAILURE;
558 }
559 if(!coreSoftTrk) {
560 ATH_MSG_WARNING("Invalid track soft term key supplied: " << softTrkKey);
561 return StatusCode::FAILURE;
562 }
563 MissingET* metSoftClus = nullptr;
564 if( fillMET(metSoftClus, metCont, softClusKey, coreSoftClus->source()) != StatusCode::SUCCESS) {
565 ATH_MSG_ERROR("failed to fill MET term \"" << softClusKey << "\"");
566 return StatusCode::FAILURE;
567 }
568
569 MissingET* metSoftTrk = nullptr;
570 if( fillMET(metSoftTrk, metCont, softTrkKey, coreSoftTrk->source()) != StatusCode::SUCCESS) {
571 ATH_MSG_ERROR("failed to fill MET term \"" << softTrkKey << "\"");
572 return StatusCode::FAILURE;
573 }
574
575 return rebuildJetMET(metJet, jets, helper,
576 metSoftClus, coreSoftClus,
577 metSoftTrk, coreSoftTrk,
578 doJetJVT);
579 }
580
582 const xAOD::JetContainer* jets,
584 xAOD::MissingET* metSoftClus,
585 const xAOD::MissingET* coreSoftClus,
586 xAOD::MissingET* metSoftTrk,
587 const xAOD::MissingET* coreSoftTrk,
588 bool doJetJVT,
589 bool tracksForHardJets,
590 std::vector<const xAOD::IParticle*>* softConst) const {
591 if(!metJet || !jets) {
592 ATH_MSG_ERROR("Invalid pointer supplied for "
593 << "MET (" << metJet << ") or "
594 << "jet collection (" << jets << ").");
595 return StatusCode::FAILURE;
596 }
597 const xAOD::MissingETAssociationMap* map = helper.map();
598 if(!map){
599 ATH_MSG_ERROR("MET Association Helper isn't associated with a MissingETAssociationMap!");
600 return StatusCode::FAILURE;
601 }
602 if(softConst && m_trkseltool.empty() && !m_doPFlow && !m_doSoftTruth) {
603 ATH_MSG_WARNING( "Requested soft track element links, but no track selection tool supplied.");
604 }
605 const xAOD::Vertex *pv = softConst?getPV():nullptr;
606
607 if(map->empty()) {
608 ATH_MSG_WARNING("Incomplete association map received. Cannot rebuild MET.");
609 ATH_MSG_WARNING("Note: METMaker should only be run on events containing at least one PV");
610 return StatusCode::SUCCESS;
611 }
612
613 if(doJetJVT && m_JvtWP == "None"){
614 ATH_MSG_WARNING("rebuildJetMET requested JVT, which is inconsistent with jet selection " << m_jetSelection << ". Ignoring JVT.");
615 doJetJVT = false;
616 }
617
618 ATH_MSG_VERBOSE("Building MET jet term " << metJet->name());
619 if(!metSoftClus && !metSoftTrk) {
620 ATH_MSG_WARNING("Neither soft cluster nor soft track term has been supplied!");
621 return StatusCode::SUCCESS;
622 }
623 static const SG::ConstAccessor<std::vector<ElementLink<IParticleContainer> > > acc_softConst("softConstituents");
624 if(metSoftClus) {
625 dec_constitObjLinks(*metSoftClus) = std::vector<iplink_t>(0);
626 if(!coreSoftClus) {
627 ATH_MSG_ERROR("Soft cluster term provided without a core term!");
628 return StatusCode::FAILURE;
629 }
630 ATH_MSG_VERBOSE("Building MET soft cluster term " << metSoftClus->name());
631 ATH_MSG_VERBOSE("Core soft cluster mpx " << coreSoftClus->mpx()
632 << ", mpy " << coreSoftClus->mpy()
633 << " sumet " << coreSoftClus->sumet());
634 *metSoftClus += *coreSoftClus;
635 // Fill a vector with the soft constituents, if one was provided.
636 // For now, only setting up to work with those corresponding to the jet constituents.
637 // Can expand if needed.
638 if(softConst && acc_softConst.isAvailable(*coreSoftClus)) {
639 for(const auto& constit : acc_softConst(*coreSoftClus)) {
640 softConst->push_back(*constit);
641 }
642 ATH_MSG_DEBUG(softConst->size() << " soft constituents from core term");
643 }
644 }
645 if(metSoftTrk) {
646 dec_constitObjLinks(*metSoftTrk) = std::vector<iplink_t>(0);
647 if(!coreSoftTrk) {
648 ATH_MSG_ERROR("Soft track term provided without a core term!");
649 return StatusCode::FAILURE;
650 }
651 ATH_MSG_VERBOSE("Building MET soft track term " << metSoftTrk->name());
652 ATH_MSG_VERBOSE("Core soft track mpx " << coreSoftTrk->mpx()
653 << ", mpy " << coreSoftTrk->mpy()
654 << " sumet " << coreSoftTrk->sumet());
655 *metSoftTrk += *coreSoftTrk;
656 if(softConst && acc_softConst.isAvailable(*coreSoftTrk) && !m_doPFlow && !m_doSoftTruth) {
657 for(const auto& constit : acc_softConst(*coreSoftTrk)) {
658 softConst->push_back(*constit);
659 }
660 ATH_MSG_DEBUG(softConst->size() << " soft constituents from trk core term");
661 }
662 }
663
664 dec_constitObjLinks(*metJet) = std::vector<iplink_t>(0);
665 dec_constitObjWeights(*metJet) = std::vector<float>(0);
666 std::vector<iplink_t>& uniqueLinks = dec_constitObjLinks(*metJet);
667 std::vector<float>& uniqueWeights = dec_constitObjWeights(*metJet);
668 uniqueLinks.reserve(jets->size());
669 uniqueWeights.reserve(jets->size());
670 std::vector<iplink_t> softJetLinks;
671 std::vector<float> softJetWeights;
672 bool originalInputs = jets->empty() ? false : !acc_originalObject.isAvailable(*jets->front());
673
674 // Get the hashed key of this jet, if we can. Though his only works if
675 // 1. the container is an owning container, and not just a view;
676 // 2. the container is in the event store already.
677 // Since we will be creating ElementLink-s to these jets later on in the
678 // code, and it should work in AnalysisBase, only the first one of these
679 // is checked. Since the code can not work otherwise.
680 SG::sgkey_t jetsSgKey = 0;
681 if(jets->ownPolicy() == SG::OWN_ELEMENTS) {
682 jetsSgKey = getKey(jets);
683 if(jetsSgKey == 0) {
684 ATH_MSG_ERROR("Could not find the jets with pointer: " << jets);
685 return StatusCode::FAILURE;
686 }
687 }
688
689 for(const xAOD::Jet* jet : *jets) {
690 const MissingETAssociation* assoc = nullptr;
691 if(originalInputs) {
693 } else {
694 const IParticle* orig = *acc_originalObject(*jet);
695 assoc = MissingETComposition::getAssociation(map,static_cast<const xAOD::Jet*>(orig));
696 }
697 if(!assoc || assoc->isMisc()){
698 ATH_MSG_WARNING( "Jet without association found!" );
699 continue;
700 }
701
703 // retrieve nominal calibrated jet
704 if (acc_nominalObject.isAvailable(*jet)){
705 ATH_MSG_VERBOSE( "Jet pt before nominal replacement = " << jet->pt());
706 jet = static_cast<const xAOD::Jet*>(*acc_nominalObject(*jet));
707
708 }
709 else
710 ATH_MSG_ERROR("No nominal calibrated jet available for jet " << jet->index() << ". Cannot simplify overlap removal!");
711 }
712 ATH_MSG_VERBOSE( "Jet pt = " << jet->pt());
713
714 bool selected = (std::abs(jet->eta())<m_JetEtaForw && jet->pt()>m_CenJetPtCut) || (std::abs(jet->eta())>=m_JetEtaForw && jet->pt()>m_FwdJetPtCut );
715 bool JVT_reject(false);
716 bool isMuFSRJet(false);
717
718 // Apply a cut on the maximum jet eta. This restricts jets to those with calibration. Excluding more forward jets was found to have a minimal impact on the MET in Zee events
719 if (m_JetEtaMax > 0.0 && std::abs(jet->eta()) > m_JetEtaMax)
720 JVT_reject = true;
721
722 if(doJetJVT) {
723 // intrinsically checks that is within range to apply Jvt requirement
724 JVT_reject = !bool(m_JvtTool->accept(jet));
725 ATH_MSG_VERBOSE("Jet " << (JVT_reject ? "fails" : "passes") <<" JVT selection");
726 }
727
728 // if defined apply additional jet criterium
729 if (m_acc_jetRejectionDec && (*m_acc_jetRejectionDec)(*jet)==0) JVT_reject = true;
730 bool hardJet(false);
731 MissingETBase::Types::constvec_t calvec = assoc->overlapCalVec(helper);
732 bool caloverlap = false;
733 caloverlap = calvec.ce()>0;
734 ATH_MSG_DEBUG("Jet " << jet->index() << " is " << ( caloverlap ? "" : "non-") << "overlapping");
735
736 if(m_veryGreedyPhotons && caloverlap) {
737 for(const auto& object : assoc->objects()) {
738 // Correctly handle this jet if we're using very greedy photons
739 if (object && object->type() == xAOD::Type::Photon) hardJet = true;
740 }
741 }
742
743 xAOD::JetFourMom_t constjet;
744 double constSF(1);
745 if(m_jetConstitScaleMom.empty() && assoc->hasAlternateConstVec()){
746 constjet = assoc->getAlternateConstVec();
747 } else {
748 constjet = jet->jetP4(m_jetConstitScaleMom);//grab a constituent scale added by the JetMomentTool/JetConstitFourMomTool.cxx
749 double denom = (assoc->hasAlternateConstVec() ? assoc->getAlternateConstVec() : jet->jetP4("JetConstitScaleMomentum")).E();
750 constSF = denom>1e-9 ? constjet.E()/denom : 0.;
751 ATH_MSG_VERBOSE("Scale const jet by factor " << constSF);
752 calvec *= constSF;
753 }
754 double jpx = constjet.Px();
755 double jpy = constjet.Py();
756 double jpt = constjet.Pt();
757 double opx = jpx - calvec.cpx();
758 double opy = jpy - calvec.cpy();
759
760 MissingET* met_muonEloss(nullptr);
762 // Get a term to hold the Eloss corrections
763 MissingETContainer* metCont = static_cast<MissingETContainer*>(metJet->container());
764 met_muonEloss = (*metCont)["MuonEloss"];
765 if(!met_muonEloss) {
766 ATH_MSG_WARNING("Attempted to apply muon Eloss correction, but corresponding MET term does not exist!");
767 return StatusCode::FAILURE;
768 }
769 }
770
771 float total_eloss(0);
772 MissingETBase::Types::bitmask_t muons_selflags(0);
773 std::vector<const xAOD::Muon*> muons_in_jet;
774 std::vector<const xAOD::Electron*> electrons_in_jet;
775 bool passJetForEl=false;
776 if(m_useGhostMuons) { // for backwards-compatibility
777 if(!acc_ghostMuons.isAvailable(*jet)){
778 ATH_MSG_ERROR("Ghost muons requested but not found!");
779 return StatusCode::FAILURE;
780 }
781 for(const auto& el : acc_ghostMuons(*jet)) {
782 if(!el.isValid()){
783 ATH_MSG_ERROR("Invalid element link to ghost muon! Quitting.");
784 return StatusCode::FAILURE;
785 }
786 muons_in_jet.push_back(static_cast<const xAOD::Muon*>(*el));
787 }
788 }
789 for(const auto& obj : assoc->objects()) {
790 if(!obj) continue;
791 if(obj->type()==xAOD::Type::Muon && !m_useGhostMuons) {
792 const xAOD::Muon* mu_test(static_cast<const xAOD::Muon*>(obj));
793 ATH_MSG_VERBOSE("Muon " << mu_test->index() << " found in jet " << jet->index());
795 if(acc_originalObject.isAvailable(*mu_test)) mu_test = static_cast<const xAOD::Muon*>(*acc_originalObject(*mu_test));
796 if(MissingETComposition::objSelected(helper,mu_test)) { //
797 muons_in_jet.push_back(mu_test);
798 ATH_MSG_VERBOSE("Muon is selected by MET.");
799 }
800 }
801 } else if(obj->type()==xAOD::Type::Electron && m_doRemoveElecTrks) {
802 const xAOD::Electron* el_test(static_cast<const xAOD::Electron*>(obj));
803 ATH_MSG_VERBOSE("Electron " << el_test->index() << " found in jet " << jet->index());
804 if(acc_originalObject.isAvailable(*el_test)) el_test = static_cast<const xAOD::Electron*>(*acc_originalObject(*el_test));
805 if(helper.objSelected(assoc,el_test)){
806 if(el_test->pt()>90.0e3) { // only worry about high-pt electrons?
807 electrons_in_jet.push_back(el_test);
808 ATH_MSG_VERBOSE("High-pt electron is selected by MET.");
809 }
810 }
811 }
812 }
814 MissingETBase::Types::constvec_t initialTrkMom = assoc->jetTrkVec();
815 float jet_ORtrk_sumpt = assoc->overlapTrkVec(helper).sumpt();
816 float jet_all_trk_pt = initialTrkMom.sumpt();
817 float jet_unique_trk_pt = jet_all_trk_pt - jet_ORtrk_sumpt;
820 for(const auto& elec : electrons_in_jet) {
821 el_calvec += assoc->calVec(elec);
822 el_trkvec += assoc->trkVec(elec);
823 }
824 float el_cal_pt = el_calvec.cpt();
825 float el_trk_pt = el_trkvec.cpt();
826 ATH_MSG_VERBOSE("Elec trk: " << el_trk_pt
827 << " jetalltrk: " << jet_all_trk_pt
828 << " jetORtrk: " << jet_ORtrk_sumpt
829 << " electrk-jetORtrk: " << (el_trk_pt-jet_ORtrk_sumpt)
830 << " elec cal: " << el_cal_pt
831 << " jetalltrk-electrk: " << (jet_all_trk_pt-el_trk_pt)
832 << " jetalltrk-jetORtrk: " << (jet_all_trk_pt-jet_ORtrk_sumpt) );
833 // Want to use the jet calo measurement if we had at least one electron
834 // and the jet has a lot of residual track pt
835 // Is the cut appropriate?
836 if(el_trk_pt>1e-9 && jet_unique_trk_pt>10.0e3) passJetForEl=true;
837 } // end ele-track removal
838
839 for(const xAOD::Muon* mu_in_jet : muons_in_jet) {
840 if (!mu_in_jet) continue;
841 float mu_Eloss = acc_Eloss(*mu_in_jet);
842
843 if(!JVT_reject) {
844 if (m_doRemoveMuonJets) {
845 // need to investigate how this is affected by the recording of muon clusters in the map
846 float mu_id_pt = mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) ? mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle)->pt() : 0.;
847 float jet_trk_sumpt = acc_trksumpt.isAvailable(*jet) && this->getPV() ? acc_trksumpt(*jet)[this->getPV()->index()] : 0.;
848
849 // missed the muon, so we should add it back
850 if(0.9999*mu_id_pt>jet_trk_sumpt)
851 jet_trk_sumpt+=mu_id_pt;
852 float jet_trk_N = acc_trkN.isAvailable(*jet) && this->getPV() ? acc_trkN(*jet)[this->getPV()->index()] : 0.;
853 ATH_MSG_VERBOSE("Muon has ID pt " << mu_id_pt);
854 ATH_MSG_VERBOSE("Jet has pt " << jet->pt() << ", trk sumpt " << jet_trk_sumpt << ", trk N " << jet_trk_N);
855 bool jet_from_muon = mu_id_pt>1e-9 && jet_trk_sumpt>1e-9 && (jet->pt()/mu_id_pt < m_muIDPTJetPtRatioMuOlap && mu_id_pt/jet_trk_sumpt>m_jetTrkPtMuPt) && jet_trk_N<m_jetTrkNMuOlap;
856 if(jet_from_muon) {
857 ATH_MSG_VERBOSE("Jet is from muon -- remove.");
858 JVT_reject = true;
859 }
860 }
861
863 // need to investigate how this is affected by the recording of muon clusters in the map
864 float mu_id_pt = mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) ? mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle)->pt() : 0.;
865 float jet_trk_sumpt = acc_trksumpt.isAvailable(*jet) && this->getPV() ? acc_trksumpt(*jet)[this->getPV()->index()] : 0.;
866 // missed the muon, so we should add it back
867 if(0.9999*mu_id_pt>jet_trk_sumpt)
868 jet_trk_sumpt+=mu_id_pt;
869 float jet_trk_N = acc_trkN.isAvailable(*jet) && this->getPV() ? acc_trkN(*jet)[this->getPV()->index()] : 0.;
870
871 float jet_psE = 0.;
872 if (acc_psf.isAvailable(*jet)){
873 jet_psE = acc_psf(*jet);
874 } else if (acc_sampleE.isAvailable(*jet)){
875 jet_psE = acc_sampleE(*jet)[0] + acc_sampleE(*jet)[4];
876 } else {
877 ATH_MSG_ERROR("Jet PS fraction or sampling energy must be available to calculate MET with doSetMuonJetEMScale");
878 return StatusCode::FAILURE;
879 }
880
881 bool jet_from_muon = jet_trk_sumpt>1e-9 && jet_trk_N<3 && mu_id_pt / jet_trk_sumpt > m_jetTrkPtMuPt && acc_emf(*jet)>m_jetEmfMuOlap && acc_width(*jet)<m_jetWidthMuOlap && jet_psE>m_jetPsEMuOlap;
882 ATH_MSG_VERBOSE("Muon has ID pt " << mu_id_pt);
883 ATH_MSG_VERBOSE("Jet has trk sumpt " << jet_trk_sumpt << ", trk N " << jet_trk_N << ", PS E " << jet_psE << ", width " << acc_width(*jet) << ", emfrac " << acc_emf(*jet));
884
885 if(jet_from_muon) {
886 ATH_MSG_VERBOSE("Jet is from muon -- set to EM scale and subtract Eloss.");
887 // Using constjet now because we focus on AntiKt4EMTopo.
888 // Probably not a massive difference to LC, but PF needs some consideration
889 ATH_MSG_VERBOSE("Jet e: " << constjet.E() << ", mu Eloss: " << mu_Eloss);
890 float elosscorr = mu_Eloss >= constjet.e() ? 0. : 1.-mu_Eloss/constjet.e();
891 // Effectively, take the unique fraction of the jet times the eloss-corrected fraction
892 // This might in some cases oversubtract, but should err on the side of undercounting the jet contribution
893 opx *= elosscorr;
894 opy *= elosscorr;
895 ATH_MSG_VERBOSE(" Jet eloss factor " << elosscorr << ", final pt: " << sqrt(opx*opx+opy*opy));
896 // Don't treat this jet normally. Instead, just add to the Eloss term
897 isMuFSRJet = true;
898 }
899 }
900 } // end muon-jet overlap-removal
901
902 switch(mu_in_jet->energyLossType()) {
903 using enum xAOD::Muon::EnergyLossType;
904 case Parametrized:
905 case MOP:
906 case Tail:
907 case FSRcandidate:
908 case NotIsolated:
909 // For now don't differentiate the behaviour
910 // Remove the Eloss assuming the parameterised value
911 // The correction is limited to the selected clusters
912 total_eloss += mu_Eloss;
913 muons_selflags |= (1<<assoc->findIndex(mu_in_jet));
914 }
915 }
916 ATH_MSG_VERBOSE("Muon selection flags: " << muons_selflags);
917 ATH_MSG_VERBOSE("Muon total eloss: " << total_eloss);
918
920 // borrowed from overlapCalVec
921 for(size_t iKey = 0; iKey < assoc->sizeCal(); iKey++) {
922 bool selector = (muons_selflags & assoc->calkey()[iKey]);
923 if(selector) mu_calovec += assoc->calVec(iKey);
924 ATH_MSG_VERBOSE("This key: " << assoc->calkey()[iKey] << ", selector: " << selector);
925 }
926 ATH_MSG_VERBOSE("Mu calovec pt, no Eloss: " << mu_calovec.cpt());
927 if(m_muEloss) mu_calovec *= std::max<float>(0.,1-(total_eloss/mu_calovec.ce()));
928 ATH_MSG_VERBOSE("Mu calovec pt, with Eloss: " << mu_calovec.cpt());
929
930 // re-add calo components of muons beyond Eloss correction
931 ATH_MSG_VERBOSE("Jet " << jet->index() << " const pT before OR " << jpt);
932 ATH_MSG_VERBOSE("Jet " << jet->index() << " const pT after OR " << sqrt(opx*opx+opy*opy));
933 opx += mu_calovec.cpx();
934 opy += mu_calovec.cpy();
935 double opt = sqrt( opx*opx+opy*opy );
936 ATH_MSG_VERBOSE("Jet " << jet->index() << " const pT diff after OR readding muon clusters " << opt-jpt);
937 double uniquefrac = 1. - (calvec.ce() - mu_calovec.ce()) / constjet.E();
938 ATH_MSG_VERBOSE( "Jet constscale px, py, pt, E = " << jpx << ", " << jpy << ", " << jpt << ", " << constjet.E() );
939 ATH_MSG_VERBOSE( "Jet overlap E = " << calvec.ce() - mu_calovec.ce() );
940 ATH_MSG_VERBOSE( "Jet OR px, py, pt, E = " << opx << ", " << opy << ", " << opt << ", " << constjet.E() - calvec.ce() );
941
942 if(isMuFSRJet) {
943 if(!met_muonEloss){
944 ATH_MSG_ERROR("Attempted to apply muon Eloss correction, but corresponding MET term does not exist!");
945 return StatusCode::FAILURE;
946 }
947 met_muonEloss->add(opx,opy,opt);
948 continue;
949 }
950
951 if(selected && !JVT_reject) {
952 if(!caloverlap) {
953 // add jet full four-vector
954 hardJet = true;
955 if (!tracksForHardJets) {
956 if(m_doConstJet)
957 metJet->add(jpx,jpy,jpt);
958 else
959 *metJet += jet;
960 }
961 }
962 else if((uniquefrac>m_jetMinEfrac || passJetForEl) && opt>m_jetMinWeightedPt){
963 // add jet corrected for overlaps if sufficient unique fraction
964 hardJet = true;
965 if(!tracksForHardJets) {
966 if(m_jetCorrectPhi) {
967 if (m_doConstJet)
968 metJet->add(opx,opy,opt);
969 else {
970 double jesF = jet->pt() / jpt;
971 metJet->add(opx*jesF,opy*jesF,opt*jesF);
972 }
973 } else {
974 if (m_doConstJet)
975 metJet->add(uniquefrac*jpx,uniquefrac*jpy,uniquefrac*jpt);
976 else{
977 if(passJetForEl && m_doRemoveElecTrksEM)
978 metJet->add(opx,opy,opt);
979 else
980 metJet->add(uniquefrac*jet->px(),uniquefrac*jet->py(),uniquefrac*jet->pt());
981 }
982 }
983 }
984 }
985 } // hard jet selection
986
987 // Create the appropriate ElementLink for this jet just the once.
988 iplink_t jetLink;
989 if(jetsSgKey == 0) {
990 const xAOD::IParticleContainer* ipc =
991 static_cast<const xAOD::IParticleContainer*>(jet->container());
992 jetLink = iplink_t(*ipc, jet->index());
993 } else {
994 jetLink = iplink_t(jetsSgKey, jet->index());
995 }
996
997 if(hardJet){
998 ATH_MSG_VERBOSE("Jet added at full scale");
999 uniqueLinks.push_back( jetLink );
1000 uniqueWeights.push_back( uniquefrac );
1001 } else {
1002 if(metSoftClus && !JVT_reject) {
1003 // add fractional contribution
1004 ATH_MSG_VERBOSE("Jet added at const scale");
1005 if (std::abs(jet->eta())<2.5 || !(coreSoftClus->source()&MissingETBase::Source::Region::Central)) {
1006 softJetLinks.push_back( jetLink );
1007 softJetWeights.push_back( uniquefrac );
1008 metSoftClus->add(opx,opy,opt);
1009 }
1010
1011 // Fill a vector with the soft constituents, if one was provided.
1012 // For now, only setting up to work with those corresponding to the jet constituents.
1013 // Can expand if needed.
1014 // This ignores overlap removal.
1015 //
1016 if(softConst) {
1017 for(size_t iConst=0; iConst<jet->numConstituents(); ++iConst) {
1018 const IParticle* constit = jet->rawConstituent(iConst);
1019 softConst->push_back(constit);
1020 }
1021 }
1022 }
1023 } // hard jet or CST
1024
1025 if(!metSoftTrk || (hardJet && !tracksForHardJets)) continue;
1026
1027 // use jet tracks
1028 // remove any tracks already used by other objects
1029 MissingETBase::Types::constvec_t trkvec = assoc->overlapTrkVec(helper);
1030 MissingETBase::Types::constvec_t jettrkvec = assoc->jetTrkVec();
1031 if(jettrkvec.ce()>1e-9) {
1032 jpx = jettrkvec.cpx();
1033 jpy = jettrkvec.cpy();
1034 jpt = jettrkvec.sumpt();
1035 jettrkvec -= trkvec;
1036 opx = jettrkvec.cpx();
1037 opy = jettrkvec.cpy();
1038 opt = jettrkvec.sumpt();
1039 ATH_MSG_VERBOSE( "Jet track px, py, sumpt = " << jpx << ", " << jpy << ", " << jpt );
1040 ATH_MSG_VERBOSE( "Jet OR px, py, sumpt = " << opx << ", " << opy << ", " << opt );
1041 } else {
1042 opx = opy = opt = 0;
1043 ATH_MSG_VERBOSE( "This jet has no associated tracks" );
1044 }
1045 if (hardJet) metJet->add(opx,opy,opt);
1046 else if (std::abs(jet->eta())<2.5 || !(coreSoftTrk->source()&MissingETBase::Source::Region::Central)) {
1047 metSoftTrk->add(opx,opy,opt);
1048 // Don't need to add if already done for softclus.
1049 if(!metSoftClus) {
1050 softJetLinks.push_back( jetLink );
1051 softJetWeights.push_back( uniquefrac );
1052 }
1053
1054 // Fill a vector with the soft constituents, if one was provided.
1055 // For now, only setting up to work with those corresponding to the jet constituents.
1056 // Can expand if needed.
1057 // This ignores overlap removal.
1058 //
1059 if(softConst && !m_doPFlow && !m_doSoftTruth) {
1060 std::vector<const IParticle*> jettracks;
1061 jet->getAssociatedObjects<IParticle>(xAOD::JetAttribute::GhostTrack,jettracks);
1062 for(size_t iConst=0; iConst<jettracks.size(); ++iConst) {
1063 const TrackParticle* pTrk = static_cast<const TrackParticle*>(jettracks[iConst]);
1064 if (acceptTrack(pTrk,pv)) softConst->push_back(pTrk);
1065 }
1066 }
1067 }
1068 } // jet loop
1069
1070 ATH_MSG_DEBUG("Number of selected jets: " << dec_constitObjLinks(*metJet).size());
1071
1072 if(metSoftTrk) {
1073 dec_constitObjLinks(*metSoftTrk) = softJetLinks;
1074 ATH_MSG_DEBUG("Number of softtrk jets: " << dec_constitObjLinks(*metSoftTrk).size());
1075 }
1076
1077 if(metSoftClus) {
1078 dec_constitObjLinks(*metSoftClus) = std::move(softJetLinks);
1079 ATH_MSG_DEBUG("Number of softclus jets: " << dec_constitObjLinks(*metSoftClus).size());
1080 }
1081
1082 if(softConst) ATH_MSG_DEBUG(softConst->size() << " soft constituents from core term + jets");
1083
1084 const MissingETAssociation* assoc = map->getMiscAssociation();
1085 if(!assoc) return StatusCode::SUCCESS;
1086
1087 if(metSoftTrk) {
1088 // supplement track term with any tracks associated to isolated muons
1089 // these are recorded in the misc association
1090 MissingETBase::Types::constvec_t trkvec = assoc->overlapTrkVec(helper);
1091 double opx = trkvec.cpx();
1092 double opy = trkvec.cpy();
1093 double osumpt = trkvec.sumpt();
1094 ATH_MSG_VERBOSE( "Misc track px, py, sumpt = " << opx << ", " << opy << ", " << osumpt );
1095 metSoftTrk->add(opx,opy,osumpt);
1096 ATH_MSG_VERBOSE("Final soft track mpx " << metSoftTrk->mpx()
1097 << ", mpy " << metSoftTrk->mpy()
1098 << " sumet " << metSoftTrk->sumet());
1099 }
1100
1101 if(metSoftClus) {
1102 // supplement cluster term with any clusters associated to isolated e/gamma
1103 // these are recorded in the misc association
1104 float total_eloss(0.);
1105 MissingETBase::Types::bitmask_t muons_selflags(0);
1106 MissingETBase::Types::constvec_t calvec = assoc->overlapCalVec(helper);
1107 double opx = calvec.cpx();
1108 double opy = calvec.cpy();
1109 double osumpt = calvec.sumpt();
1110 for(const auto& obj : assoc->objects()) {
1111 if (!obj || obj->type() != xAOD::Type::Muon) continue;
1112 const xAOD::Muon* mu_test(static_cast<const xAOD::Muon*>(obj));
1113 if(acc_originalObject.isAvailable(*mu_test)) mu_test = static_cast<const xAOD::Muon*>(*acc_originalObject(*mu_test));
1114 if(MissingETComposition::objSelected(helper,mu_test)) { //
1115 float mu_Eloss = acc_Eloss(*mu_test);
1116 switch(mu_test->energyLossType()) {
1117 using enum xAOD::Muon::EnergyLossType;
1118 case Parametrized:
1119 case MOP:
1120 case Tail:
1121 case FSRcandidate:
1122 case NotIsolated:
1123 // For now don't differentiate the behaviour
1124 // Remove the Eloss assuming the parameterised value
1125 // The correction is limited to the selected clusters
1126 total_eloss += mu_Eloss;
1127 muons_selflags |= (static_cast<MissingETBase::Types::bitmask_t >(1)<<assoc->findIndex(mu_test));
1128 }
1129 ATH_MSG_VERBOSE("Mu index " << mu_test->index());
1130 }
1131 }
1132 ATH_MSG_VERBOSE("Mu selection flags " << muons_selflags);
1133 ATH_MSG_VERBOSE("Mu total eloss " << total_eloss);
1134
1136 // borrowed from overlapCalVec
1137 for(size_t iKey = 0; iKey < assoc->sizeCal(); iKey++) {
1138 bool selector = (muons_selflags & assoc->calkey()[iKey]);
1139 ATH_MSG_VERBOSE("This key: " << assoc->calkey()[iKey] << ", selector: " << selector
1140 << " this calvec E: " << assoc->calVec(iKey).ce());
1141 if(selector) mu_calovec += assoc->calVec(iKey);
1142 }
1143 if(m_muEloss){
1144 mu_calovec *= std::max<float>(0.,1-(total_eloss/mu_calovec.ce()));
1145 opx += mu_calovec.cpx();
1146 opy += mu_calovec.cpy();
1147 osumpt += mu_calovec.sumpt();
1148 }
1149 ATH_MSG_VERBOSE("Mu cluster sumpt " << mu_calovec.sumpt());
1150
1151 ATH_MSG_VERBOSE( "Misc cluster px, py, sumpt = " << opx << ", " << opy << ", " << osumpt );
1152 metSoftClus->add(opx,opy,osumpt);
1153 ATH_MSG_VERBOSE("Final soft cluster mpx " << metSoftClus->mpx()
1154 << ", mpy " << metSoftClus->mpy()
1155 << " sumet " << metSoftClus->sumet());
1156 }
1157
1158 return StatusCode::SUCCESS;
1159 }
1160
1162 const xAOD::JetContainer* jets,
1164 xAOD::MissingET* metSoftTrk,
1165 const xAOD::MissingET* coreSoftTrk,
1166 bool doJetJVT) const {
1167 return rebuildJetMET(metJet,jets,helper,nullptr,nullptr,metSoftTrk,coreSoftTrk,doJetJVT,true);
1168 }
1169
1170 // **** Remove objects and any overlaps from MET calculation ****
1173 xAOD::MissingETContainer* metCont) const
1174 {
1175 MissingET* met = nullptr;
1176 if( fillMET(met,metCont, "Invisibles" , invisSource) != StatusCode::SUCCESS) {
1177 ATH_MSG_ERROR("failed to fill MET term \"Invisibles\"");
1178 return StatusCode::FAILURE;
1179 }
1181 }
1182
1184 {
1185 return static_cast<bool>(m_trkseltool->accept( *trk, vx ));
1186 }
1187
1189
1191
1192 if(!h_PV.isValid()) {
1193 ATH_MSG_WARNING("Unable to retrieve primary vertex container PrimaryVertices");
1194 return nullptr;
1195 }
1196 ATH_MSG_DEBUG("Successfully retrieved primary vertex container");
1197 if(h_PV->empty()) ATH_MSG_WARNING("Event has no primary vertices!");
1198 for(const xAOD::Vertex* vx : *h_PV) {
1199 if(vx->vertexType()==xAOD::VxType::PriVtx) return vx;
1200 }
1201 return nullptr;
1202 }
1203
1204} //> end namespace met
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
Handle class for reading from StoreGate.
Base class for elements of a container that can have aux data.
std::vector< std::vector< int64_t > > indices
Defines enum to access jet attribute and associated particles/objects.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
const T * front() const
Access the first element in the collection as an rvalue.
SG::OwnershipPolicy ownPolicy() const
Return the ownership policy setting for this container.
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
Helper class to provide type-safe access to aux data.
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode setProperty(const std::string &name, const T &value)
set the given property
an object that can create a AsgTool
::StatusCode makePrivateTool(ToolHandle< T > &toolHandle) const
make a private tool with the given configuration
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
SG::sgkey_t getKey(const void *ptr) const
Get the (hashed) key of an object that is in the event store.
Definition AsgTool.cxx:119
STL class.
bool m_skipSystematicJetSelection
Definition METMaker.h:183
bool m_greedyPhotons
Definition METMaker.h:187
double m_customFwdJetPtCut
Definition METMaker.h:170
double m_jetTrkPtMuPt
Definition METMaker.h:195
METMaker()
Default constructor:
std::string m_customJvtWP
Definition METMaker.h:172
ToolHandle< IAsgSelectionTool > m_JvtTool
Definition METMaker.h:199
bool m_doRemoveElecTrks
Definition METMaker.h:180
bool m_jetCorrectPhi
Definition METMaker.h:155
double m_customJvtPtMax
Definition METMaker.h:171
bool m_doRemoveMuonJets
Definition METMaker.h:179
float m_missObjWarningPtThreshold
Definition METMaker.h:153
std::string m_jetSelection
Definition METMaker.h:166
std::string m_jetRejectionDec
Definition METMaker.h:159
virtual StatusCode rebuildTrackMET(const std::string &metJetKey, const std::string &softTrkKey, xAOD::MissingETContainer *metCont, const xAOD::JetContainer *jets, const xAOD::MissingETContainer *metCoreCont, xAOD::MissingETAssociationHelper &helper, bool doJetJVT) const override final
Definition METMaker.cxx:498
double m_jetMinWeightedPt
Definition METMaker.h:157
bool m_doRemoveElecTrksEM
Definition METMaker.h:181
virtual StatusCode markInvisible(const xAOD::IParticleContainer *collection, xAOD::MissingETAssociationHelper &helper, xAOD::MissingETContainer *metCont) const override final
bool m_doSoftTruth
Definition METMaker.h:175
double m_jetMinEfrac
Definition METMaker.h:156
double m_muIDPTJetPtRatioMuOlap
Definition METMaker.h:196
int m_jetTrkNMuOlap
Definition METMaker.h:191
bool m_doSetMuonJetEMScale
Definition METMaker.h:182
SG::ReadHandleKey< xAOD::VertexContainer > m_PVkey
Definition METMaker.h:147
bool m_doConstJet
Definition METMaker.h:176
double m_jetWidthMuOlap
Definition METMaker.h:192
double m_customCenJetPtCut
Definition METMaker.h:170
bool acceptTrack(const xAOD::TrackParticle *trk, const xAOD::Vertex *vx) const
std::unique_ptr< SG::ConstAccessor< char > > m_acc_jetRejectionDec
Definition METMaker.h:150
ToolHandle< InDet::IInDetTrackSelectionTool > m_trkseltool
Definition METMaker.h:198
bool m_orCaloTaggedMuon
Definition METMaker.h:186
double m_CenJetPtCut
Definition METMaker.h:161
double m_JvtPtMax
Definition METMaker.h:162
SG::ReadHandleKey< xAOD::JetContainer > m_jetContainer
Definition METMaker.h:201
std::string m_jetConstitScaleMom
Definition METMaker.h:158
double m_JetEtaForw
Definition METMaker.h:164
double m_FwdJetPtCut
Definition METMaker.h:161
double m_jetPsEMuOlap
Definition METMaker.h:193
virtual StatusCode rebuildMET(const std::string &metKey, xAOD::Type::ObjectType metType, xAOD::MissingETContainer *metCont, const xAOD::IParticleContainer *collection, xAOD::MissingETAssociationHelper &helper, MissingETBase::UsageHandler::Policy objScale) const override final
Definition METMaker.cxx:222
double m_jetEmfMuOlap
Definition METMaker.h:194
std::string m_JvtWP
Definition METMaker.h:167
double m_JetEtaMax
Definition METMaker.h:163
virtual StatusCode initialize() override final
Dummy implementation of the initialisation function.
Definition METMaker.cxx:154
virtual ~METMaker()
Destructor:
bool m_useGhostMuons
Definition METMaker.h:178
const xAOD::Vertex * getPV() const
bool m_veryGreedyPhotons
Definition METMaker.h:188
virtual StatusCode rebuildJetMET(const std::string &metJetKey, const std::string &softClusKey, const std::string &softTrkKey, xAOD::MissingETContainer *metCont, const xAOD::JetContainer *jets, const xAOD::MissingETContainer *metCoreCont, xAOD::MissingETAssociationHelper &helper, bool doJetJVT) const override final
Definition METMaker.cxx:535
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition Egamma_v1.cxx:66
Class providing the definition of the 4-vector interface.
virtual double pt() const =0
The transverse momentum ( ) of the particle.
virtual Type::ObjectType type() const =0
The type of the object as a simple enumeration.
A vector of jet constituents at the scale used during jet finding.
float sumpt() const
Returns sum of component pt.
bool isMisc() const
Check if this association is a miscellaneous association.
const std::vector< MissingETBase::Types::bitmask_t > & calkey() const
Get the vector of cal keys.
ConstVec trkVec(const IParticle *pPart) const
Get track constituent vector for a given object.
ConstVec overlapTrkVec(const MissingETAssociationHelper &helper) const
Retrieve total track-based vector to be subtracted from the jet.
std::vector< const IParticle * > objects() const
Access contributing objects.
xAOD::JetFourMom_t getAlternateConstVec() const
ConstVec overlapCalVec(const MissingETAssociationHelper &helper) const
Retrieve total cluster-based vector to be subtracted from the jet.
ConstVec jetTrkVec() const
Get track constituent vector for the reference jet.
size_t findIndex(const IParticle *pPart) const
Find index of given object in contributing object store.
ConstVec calVec(const IParticle *pPart) const
Get calo constituent vector for a given object.
float sumet() const
Returns.
void add(const IParticle *particle)
Add particle kinematics to MET.
MissingETBase::Types::bitmask_t source() const
MET object source tag.
const std::string & name() const
Identifier getters.
float mpx() const
Returns .
float mpy() const
Returns .
EnergyLossType energyLossType(void) const
Energy determined from parametrization or not (measured).
Class creating a shallow copy of an existing auxiliary container.
xAOD::MissingETAssociation_v1::ConstVec constvec_t
Type for constituent vector.
uint64_t bitmask_t
Type for status word bit mask.
@ OnlyCluster
CaloCluster based only.
@ ParticleFlow
Particle Flow Object based.
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition sgkey_t.h:32
@ OWN_ELEMENTS
this data object owns its elements
Definition index.py:1
ElementLink< xAOD::IParticleContainer > iplink_t
static const SG::ConstAccessor< float > acc_emf("EMFrac")
static const SG::ConstAccessor< float > acc_psf("PSFrac")
static const SG::ConstAccessor< std::vector< float > > acc_sampleE("EnergyPerSampling")
static const SG::ConstAccessor< std::vector< int > > acc_trkN("NumTrkPt500")
static const SG::ConstAccessor< float > acc_Eloss("EnergyLoss")
static const SG::Accessor< std::vector< float > > dec_constitObjWeights("ConstitObjectWeights")
static const SG::ConstAccessor< std::vector< iplink_t > > acc_ghostElecs("GhostElec")
static const SG::ConstAccessor< std::vector< iplink_t > > acc_ghostMuons("GhostMuon")
static const MissingETBase::Types::bitmask_t invisSource
Definition METHelpers.h:38
static const SG::ConstAccessor< iplink_t > acc_originalObject("originalObjectLink")
static const SG::ConstAccessor< float > acc_width("Width")
static const SG::ConstAccessor< std::vector< float > > acc_trksumpt("SumPtTrkPt500")
static const SG::ConstAccessor< iplink_t > acc_nominalObject("nominalObjectLink")
static const SG::Accessor< std::vector< iplink_t > > dec_constitObjLinks("ConstitObjectLinks")
StatusCode fillMET(xAOD::MissingET *&met, xAOD::MissingETContainer *metCont, const std::string &metKey, const MissingETBase::Types::bitmask_t metSource)
ObjectType
Type of objects that have a representation in the xAOD EDM.
Definition ObjectType.h:32
@ Jet
The object is a jet.
Definition ObjectType.h:40
@ Photon
The object is a photon.
Definition ObjectType.h:47
@ Muon
The object is a muon.
Definition ObjectType.h:48
@ Electron
The object is an electron.
Definition ObjectType.h:46
@ Tau
The object is a tau (jet).
Definition ObjectType.h:49
@ PriVtx
Primary vertex.
Jet_v1 Jet
Definition of the current "jet version".
MissingETAssociation_v1 MissingETAssociation
Version control by type definition.
MissingET_v1 MissingET
Version control by type defintion.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
Muon_v1 Muon
Reference the current persistent version:
setBGCode setTAP setLVL2ErrorBits bool
MissingETAuxContainer_v1 MissingETAuxContainer
JetContainer_v1 JetContainer
Definition of the current "jet container version".
MissingETAssociationMap_v1 MissingETAssociationMap
Version control by type defintion.
Electron_v1 Electron
Definition of the current "egamma version".
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< double > > JetFourMom_t
Base 4 Momentum type for Jet.
Definition JetTypes.h:17
static Types::bitmask_t muon(Region reg=Region::FullAcceptance)
Standard MET term from reconstructed muons.
static Types::bitmask_t jet(Region reg=Region::FullAcceptance)
Standard MET term from reconstructed jets.
@ Calo
Indicator for MET terms reconstructed from calorimeter signals alone.
static Types::bitmask_t track(Region reg=Region::FullAcceptance)
Bit mask for MET term from Track signal objects.
static bool isTrackTerm(Types::bitmask_t bits, Region reg=Region::FullAcceptance)
static Types::bitmask_t tau(Region reg=Region::FullAcceptance)
Standard MET term from reconstructed tau leptons.
static Types::bitmask_t electron(Region reg=Region::FullAcceptance)
Standard MET term from reconstructed electrons.
static Types::bitmask_t photon(Region reg=Region::FullAcceptance)
Standard MET term from reconstructed photons.
@ Central
Indicator for MET contribution from the central region.
static bool objSelected(const MissingETAssociationHelper &helper, const IParticle *obj)
static MissingETBase::Types::constvec_t getConstVec(const MissingETAssociationMap *pMap, const IParticle *pPart, MissingETBase::UsageHandler::Policy p)
static bool selectIfNoOverlaps(MissingETAssociationHelper &helper, const IParticle *obj, MissingETBase::UsageHandler::Policy p)
static const MissingETAssociation * getAssociation(const MissingETAssociationMap *pMap, const Jet *pJet)
Collection of functions managing the MET composition map and association map.
static std::vector< const MissingETAssociation * > getAssociations(const MissingETAssociationMap *pMap, const IParticle *pPart)
Access non-modifiable contribution object.