ATLAS Offline Software
Loading...
Searching...
No Matches
METMaker.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2023 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::AuxElement::ConstAccessor< iplink_t > acc_originalObject("originalObjectLink");
65 static const SG::AuxElement::ConstAccessor< iplink_t > acc_nominalObject("nominalObjectLink");
66 static const SG::AuxElement::ConstAccessor< std::vector<iplink_t > > acc_ghostMuons("GhostMuon");
67 static const SG::AuxElement::ConstAccessor< std::vector<iplink_t > > acc_ghostElecs("GhostElec");
68
69 static const SG::AuxElement::ConstAccessor< std::vector<int> > acc_trkN("NumTrkPt500");
70 static const SG::AuxElement::ConstAccessor< std::vector<float> > acc_trksumpt("SumPtTrkPt500");
71 static const SG::AuxElement::ConstAccessor< std::vector<float> > acc_sampleE("EnergyPerSampling");
72
73 static const SG::AuxElement::ConstAccessor<float> acc_emf("EMFrac");
74 static const SG::AuxElement::ConstAccessor<float> acc_psf("PSFrac");
75 static const SG::AuxElement::ConstAccessor<float> acc_width("Width");
76 static const SG::AuxElement::ConstAccessor<float> acc_Eloss("EnergyLoss");
77
78 static const SG::AuxElement::Accessor< std::vector<iplink_t> > dec_constitObjLinks("ConstitObjectLinks");
79 static const SG::AuxElement::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::AuxElement::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 && orig->type()==xAOD::Type::Muon && static_cast<const xAOD::Muon*>(orig)->muonType()==xAOD::Muon::CaloTagged) {
409 for (size_t i = 0; i < assocs.size(); i++) {
410 std::vector<size_t> ind = assocs[i]->overlapIndices(orig);
411 std::vector<const xAOD::IParticle*> allObjects = assocs[i]->objects();
412 for (size_t indi = 0; indi < ind.size(); indi++) if (allObjects[ind[indi]]) {
413 if (allObjects[ind[indi]]->type()==xAOD::Type::Electron
414 && helper.objSelected(assocs[i], ind[indi])) {
415 selected = false;
416 break;
417 }
418 }
419 }
420 }
421 // Don't overlap remove muons, but flag the non-overlapping muons to take out their tracks from jets
422 // Removed eloss from here -- clusters already flagged.
423 // To be handled in rebuildJetMET
424 if(selected) {
426 ATH_MSG_VERBOSE("Add object with pt " << obj->pt());
427 *met += obj;
428 } else {
430 ATH_MSG_VERBOSE("Add truth object with pt " << constvec.cpt());
431 met->add(constvec.cpx(),constvec.cpy(),constvec.cpt());
432 }
433 iplink_t objLink;
434 if(collectionSgKey == 0) {
435 const xAOD::IParticleContainer* ipc =
436 static_cast<const xAOD::IParticleContainer*>(obj->container());
437 objLink = iplink_t(*ipc, obj->index());
438 } else {
439 objLink = iplink_t(collectionSgKey, obj->index());
440 }
441 uniqueLinks.push_back( objLink );
442 uniqueWeights.push_back( 1. );
443 }
444 }
445 ATH_MSG_DEBUG("Built met term " << met->name() << ", with magnitude " << met->met());
446 return StatusCode::SUCCESS;
447 }
448
449 StatusCode METMaker::rebuildJetMET(const std::string& metJetKey,
450 const std::string& softKey,
452 const xAOD::JetContainer* jets,
453 const xAOD::MissingETContainer* metCoreCont,
455 bool doJetJVT) const
456 {
457 ATH_MSG_VERBOSE("Rebuild jet term: " << metJetKey << " and soft term: " << softKey);
458
459 MissingET* metJet = nullptr;
460 if( fillMET(metJet,metCont, metJetKey, MissingETBase::Source::jet()) != StatusCode::SUCCESS) {
461 ATH_MSG_ERROR("failed to fill MET term \"" << metJetKey << "\"");
462 return StatusCode::FAILURE;
463 }
464
465 const MissingET *coreSoftClus(nullptr), *coreSoftTrk(nullptr);
466 MissingET *metSoftClus(nullptr), *metSoftTrk(nullptr);
467
468 const MissingET* coreSoft = (*metCoreCont)[softKey+"Core"];
469 if(!coreSoft) {
470 ATH_MSG_WARNING("Invalid soft term key supplied: " << softKey);
471 return StatusCode::FAILURE;
472 }
474 coreSoftTrk = coreSoft;
475
476 metSoftTrk = nullptr;
477 if( fillMET(metSoftTrk,metCont, softKey , coreSoftTrk->source() ) != StatusCode::SUCCESS) {
478 ATH_MSG_ERROR("failed to fill MET term \"" << softKey << "\"");
479 return StatusCode::FAILURE;
480 }
481 } else {
482 coreSoftClus = coreSoft;
483
484 metSoftClus = nullptr;
485 if( fillMET(metSoftClus, metCont, softKey , coreSoftClus->source() ) != StatusCode::SUCCESS) {
486 ATH_MSG_ERROR("failed to fill MET term \"" << softKey << "\"");
487 return StatusCode::FAILURE;
488 }
489 }
490
491 return rebuildJetMET(metJet, jets, helper,
492 metSoftClus, coreSoftClus,
493 metSoftTrk, coreSoftTrk,
494 doJetJVT);
495 }
496
497 StatusCode METMaker::rebuildTrackMET(const std::string& metJetKey,
498 const std::string& softKey,
500 const xAOD::JetContainer* jets,
501 const xAOD::MissingETContainer* metCoreCont,
503 bool doJetJVT) const
504 {
505 ATH_MSG_VERBOSE("Rebuild jet term: " << metJetKey << " and soft term: " << softKey);
506
507 MissingET* metJet = nullptr;
508 if( fillMET(metJet , metCont, metJetKey , MissingETBase::Source::jet() | MissingETBase::Source::track() ) != StatusCode::SUCCESS) {
509 ATH_MSG_ERROR("failed to fill MET term \"" << metJetKey << "\"");
510 return StatusCode::FAILURE;
511 }
512
513 const MissingET *coreSoftTrk(nullptr);
514 MissingET *metSoftTrk(nullptr);
515
516 const MissingET* coreSoft = (*metCoreCont)[softKey+"Core"];
517 if(!coreSoft) {
518 ATH_MSG_WARNING("Invalid soft term key supplied: " << softKey);
519 return StatusCode::FAILURE;
520 }
521 coreSoftTrk = coreSoft;
522
523 metSoftTrk = nullptr;
524 if( fillMET(metSoftTrk , metCont, softKey , coreSoftTrk->source()) != StatusCode::SUCCESS) {
525 ATH_MSG_ERROR("failed to fill MET term \"" << softKey << "\"");
526 return StatusCode::FAILURE;
527 }
528
529 return rebuildTrackMET(metJet, jets, helper,
530 metSoftTrk, coreSoftTrk,
531 doJetJVT);
532 }
533
534 StatusCode METMaker::rebuildJetMET(const std::string& metJetKey,
535 const std::string& softClusKey,
536 const std::string& softTrkKey,
538 const xAOD::JetContainer* jets,
539 const xAOD::MissingETContainer* metCoreCont,
541 bool doJetJVT) const
542 {
543
544 ATH_MSG_VERBOSE("Create Jet MET " << metJetKey);
545 MissingET* metJet = nullptr;
546 if( fillMET(metJet , metCont ,metJetKey , MissingETBase::Source::jet()) != StatusCode::SUCCESS) {
547 ATH_MSG_ERROR("failed to fill MET term \"" << metJetKey << "\"");
548 return StatusCode::FAILURE;
549 }
550 ATH_MSG_VERBOSE("Create SoftClus MET " << softClusKey);
551 const MissingET* coreSoftClus = (*metCoreCont)[softClusKey+"Core"];
552 ATH_MSG_VERBOSE("Create SoftTrk MET " << softTrkKey);
553 const MissingET* coreSoftTrk = (*metCoreCont)[softTrkKey+"Core"];
554 if(!coreSoftClus) {
555 ATH_MSG_WARNING("Invalid cluster soft term key supplied: " << softClusKey);
556 return StatusCode::FAILURE;
557 }
558 if(!coreSoftTrk) {
559 ATH_MSG_WARNING("Invalid track soft term key supplied: " << softTrkKey);
560 return StatusCode::FAILURE;
561 }
562 MissingET* metSoftClus = nullptr;
563 if( fillMET(metSoftClus, metCont, softClusKey, coreSoftClus->source()) != StatusCode::SUCCESS) {
564 ATH_MSG_ERROR("failed to fill MET term \"" << softClusKey << "\"");
565 return StatusCode::FAILURE;
566 }
567
568 MissingET* metSoftTrk = nullptr;
569 if( fillMET(metSoftTrk, metCont, softTrkKey, coreSoftTrk->source()) != StatusCode::SUCCESS) {
570 ATH_MSG_ERROR("failed to fill MET term \"" << softTrkKey << "\"");
571 return StatusCode::FAILURE;
572 }
573
574 return rebuildJetMET(metJet, jets, helper,
575 metSoftClus, coreSoftClus,
576 metSoftTrk, coreSoftTrk,
577 doJetJVT);
578 }
579
581 const xAOD::JetContainer* jets,
583 xAOD::MissingET* metSoftClus,
584 const xAOD::MissingET* coreSoftClus,
585 xAOD::MissingET* metSoftTrk,
586 const xAOD::MissingET* coreSoftTrk,
587 bool doJetJVT,
588 bool tracksForHardJets,
589 std::vector<const xAOD::IParticle*>* softConst) const {
590 if(!metJet || !jets) {
591 ATH_MSG_ERROR("Invalid pointer supplied for "
592 << "MET (" << metJet << ") or "
593 << "jet collection (" << jets << ").");
594 return StatusCode::FAILURE;
595 }
596 const xAOD::MissingETAssociationMap* map = helper.map();
597 if(!map){
598 ATH_MSG_ERROR("MET Association Helper isn't associated with a MissingETAssociationMap!");
599 return StatusCode::FAILURE;
600 }
601 if(softConst && m_trkseltool.empty() && !m_doPFlow && !m_doSoftTruth) {
602 ATH_MSG_WARNING( "Requested soft track element links, but no track selection tool supplied.");
603 }
604 const xAOD::Vertex *pv = softConst?getPV():nullptr;
605
606 if(map->empty()) {
607 ATH_MSG_WARNING("Incomplete association map received. Cannot rebuild MET.");
608 ATH_MSG_WARNING("Note: METMaker should only be run on events containing at least one PV");
609 return StatusCode::SUCCESS;
610 }
611
612 if(doJetJVT && m_JvtWP == "None"){
613 ATH_MSG_WARNING("rebuildJetMET requested JVT, which is inconsistent with jet selection " << m_jetSelection << ". Ignoring JVT.");
614 doJetJVT = false;
615 }
616
617 ATH_MSG_VERBOSE("Building MET jet term " << metJet->name());
618 if(!metSoftClus && !metSoftTrk) {
619 ATH_MSG_WARNING("Neither soft cluster nor soft track term has been supplied!");
620 return StatusCode::SUCCESS;
621 }
622 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<IParticleContainer> > > acc_softConst("softConstituents");
623 if(metSoftClus) {
624 dec_constitObjLinks(*metSoftClus) = std::vector<iplink_t>(0);
625 if(!coreSoftClus) {
626 ATH_MSG_ERROR("Soft cluster term provided without a core term!");
627 return StatusCode::FAILURE;
628 }
629 ATH_MSG_VERBOSE("Building MET soft cluster term " << metSoftClus->name());
630 ATH_MSG_VERBOSE("Core soft cluster mpx " << coreSoftClus->mpx()
631 << ", mpy " << coreSoftClus->mpy()
632 << " sumet " << coreSoftClus->sumet());
633 *metSoftClus += *coreSoftClus;
634 // Fill a vector with the soft constituents, if one was provided.
635 // For now, only setting up to work with those corresponding to the jet constituents.
636 // Can expand if needed.
637 if(softConst && acc_softConst.isAvailable(*coreSoftClus)) {
638 for(const auto& constit : acc_softConst(*coreSoftClus)) {
639 softConst->push_back(*constit);
640 }
641 ATH_MSG_DEBUG(softConst->size() << " soft constituents from core term");
642 }
643 }
644 if(metSoftTrk) {
645 dec_constitObjLinks(*metSoftTrk) = std::vector<iplink_t>(0);
646 if(!coreSoftTrk) {
647 ATH_MSG_ERROR("Soft track term provided without a core term!");
648 return StatusCode::FAILURE;
649 }
650 ATH_MSG_VERBOSE("Building MET soft track term " << metSoftTrk->name());
651 ATH_MSG_VERBOSE("Core soft track mpx " << coreSoftTrk->mpx()
652 << ", mpy " << coreSoftTrk->mpy()
653 << " sumet " << coreSoftTrk->sumet());
654 *metSoftTrk += *coreSoftTrk;
655 if(softConst && acc_softConst.isAvailable(*coreSoftTrk) && !m_doPFlow && !m_doSoftTruth) {
656 for(const auto& constit : acc_softConst(*coreSoftTrk)) {
657 softConst->push_back(*constit);
658 }
659 ATH_MSG_DEBUG(softConst->size() << " soft constituents from trk core term");
660 }
661 }
662
663 dec_constitObjLinks(*metJet) = std::vector<iplink_t>(0);
664 dec_constitObjWeights(*metJet) = std::vector<float>(0);
665 std::vector<iplink_t>& uniqueLinks = dec_constitObjLinks(*metJet);
666 std::vector<float>& uniqueWeights = dec_constitObjWeights(*metJet);
667 uniqueLinks.reserve(jets->size());
668 uniqueWeights.reserve(jets->size());
669 std::vector<iplink_t> softJetLinks;
670 std::vector<float> softJetWeights;
671 bool originalInputs = jets->empty() ? false : !acc_originalObject.isAvailable(*jets->front());
672
673 // Get the hashed key of this jet, if we can. Though his only works if
674 // 1. the container is an owning container, and not just a view;
675 // 2. the container is in the event store already.
676 // Since we will be creating ElementLink-s to these jets later on in the
677 // code, and it should work in AnalysisBase, only the first one of these
678 // is checked. Since the code can not work otherwise.
679 SG::sgkey_t jetsSgKey = 0;
680 if(jets->ownPolicy() == SG::OWN_ELEMENTS) {
681 jetsSgKey = getKey(jets);
682 if(jetsSgKey == 0) {
683 ATH_MSG_ERROR("Could not find the jets with pointer: " << jets);
684 return StatusCode::FAILURE;
685 }
686 }
687
688 for(const xAOD::Jet* jet : *jets) {
689 const MissingETAssociation* assoc = nullptr;
690 if(originalInputs) {
692 } else {
693 const IParticle* orig = *acc_originalObject(*jet);
694 assoc = MissingETComposition::getAssociation(map,static_cast<const xAOD::Jet*>(orig));
695 }
696 if(!assoc || assoc->isMisc()){
697 ATH_MSG_WARNING( "Jet without association found!" );
698 continue;
699 }
700
702 // retrieve nominal calibrated jet
703 if (acc_nominalObject.isAvailable(*jet)){
704 ATH_MSG_VERBOSE( "Jet pt before nominal replacement = " << jet->pt());
705 jet = static_cast<const xAOD::Jet*>(*acc_nominalObject(*jet));
706
707 }
708 else
709 ATH_MSG_ERROR("No nominal calibrated jet available for jet " << jet->index() << ". Cannot simplify overlap removal!");
710 }
711 ATH_MSG_VERBOSE( "Jet pt = " << jet->pt());
712
713 bool selected = (std::abs(jet->eta())<m_JetEtaForw && jet->pt()>m_CenJetPtCut) || (std::abs(jet->eta())>=m_JetEtaForw && jet->pt()>m_FwdJetPtCut );
714 bool JVT_reject(false);
715 bool isMuFSRJet(false);
716
717 // 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
718 if (m_JetEtaMax > 0.0 && std::abs(jet->eta()) > m_JetEtaMax)
719 JVT_reject = true;
720
721 if(doJetJVT) {
722 // intrinsically checks that is within range to apply Jvt requirement
723 JVT_reject = !bool(m_JvtTool->accept(jet));
724 ATH_MSG_VERBOSE("Jet " << (JVT_reject ? "fails" : "passes") <<" JVT selection");
725 }
726
727 // if defined apply additional jet criterium
728 if (m_acc_jetRejectionDec && (*m_acc_jetRejectionDec)(*jet)==0) JVT_reject = true;
729 bool hardJet(false);
730 MissingETBase::Types::constvec_t calvec = assoc->overlapCalVec(helper);
731 bool caloverlap = false;
732 caloverlap = calvec.ce()>0;
733 ATH_MSG_DEBUG("Jet " << jet->index() << " is " << ( caloverlap ? "" : "non-") << "overlapping");
734
735 if(m_veryGreedyPhotons && caloverlap) {
736 for(const auto& object : assoc->objects()) {
737 // Correctly handle this jet if we're using very greedy photons
738 if (object && object->type() == xAOD::Type::Photon) hardJet = true;
739 }
740 }
741
742 xAOD::JetFourMom_t constjet;
743 double constSF(1);
744 if(m_jetConstitScaleMom.empty() && assoc->hasAlternateConstVec()){
745 constjet = assoc->getAlternateConstVec();
746 } else {
747 constjet = jet->jetP4(m_jetConstitScaleMom);//grab a constituent scale added by the JetMomentTool/JetConstitFourMomTool.cxx
748 double denom = (assoc->hasAlternateConstVec() ? assoc->getAlternateConstVec() : jet->jetP4("JetConstitScaleMomentum")).E();
749 constSF = denom>1e-9 ? constjet.E()/denom : 0.;
750 ATH_MSG_VERBOSE("Scale const jet by factor " << constSF);
751 calvec *= constSF;
752 }
753 double jpx = constjet.Px();
754 double jpy = constjet.Py();
755 double jpt = constjet.Pt();
756 double opx = jpx - calvec.cpx();
757 double opy = jpy - calvec.cpy();
758
759 MissingET* met_muonEloss(nullptr);
761 // Get a term to hold the Eloss corrections
762 MissingETContainer* metCont = static_cast<MissingETContainer*>(metJet->container());
763 met_muonEloss = (*metCont)["MuonEloss"];
764 if(!met_muonEloss) {
765 ATH_MSG_WARNING("Attempted to apply muon Eloss correction, but corresponding MET term does not exist!");
766 return StatusCode::FAILURE;
767 }
768 }
769
770 float total_eloss(0);
771 MissingETBase::Types::bitmask_t muons_selflags(0);
772 std::vector<const xAOD::Muon*> muons_in_jet;
773 std::vector<const xAOD::Electron*> electrons_in_jet;
774 bool passJetForEl=false;
775 if(m_useGhostMuons) { // for backwards-compatibility
776 if(!acc_ghostMuons.isAvailable(*jet)){
777 ATH_MSG_ERROR("Ghost muons requested but not found!");
778 return StatusCode::FAILURE;
779 }
780 for(const auto& el : acc_ghostMuons(*jet)) {
781 if(!el.isValid()){
782 ATH_MSG_ERROR("Invalid element link to ghost muon! Quitting.");
783 return StatusCode::FAILURE;
784 }
785 muons_in_jet.push_back(static_cast<const xAOD::Muon*>(*el));
786 }
787 }
788 for(const auto& obj : assoc->objects()) {
789 if(!obj) continue;
790 if(obj->type()==xAOD::Type::Muon && !m_useGhostMuons) {
791 const xAOD::Muon* mu_test(static_cast<const xAOD::Muon*>(obj));
792 ATH_MSG_VERBOSE("Muon " << mu_test->index() << " found in jet " << jet->index());
794 if(acc_originalObject.isAvailable(*mu_test)) mu_test = static_cast<const xAOD::Muon*>(*acc_originalObject(*mu_test));
795 if(MissingETComposition::objSelected(helper,mu_test)) { //
796 muons_in_jet.push_back(mu_test);
797 ATH_MSG_VERBOSE("Muon is selected by MET.");
798 }
799 }
800 } else if(obj->type()==xAOD::Type::Electron && m_doRemoveElecTrks) {
801 const xAOD::Electron* el_test(static_cast<const xAOD::Electron*>(obj));
802 ATH_MSG_VERBOSE("Electron " << el_test->index() << " found in jet " << jet->index());
803 if(acc_originalObject.isAvailable(*el_test)) el_test = static_cast<const xAOD::Electron*>(*acc_originalObject(*el_test));
804 if(helper.objSelected(assoc,el_test)){
805 if(el_test->pt()>90.0e3) { // only worry about high-pt electrons?
806 electrons_in_jet.push_back(el_test);
807 ATH_MSG_VERBOSE("High-pt electron is selected by MET.");
808 }
809 }
810 }
811 }
813 MissingETBase::Types::constvec_t initialTrkMom = assoc->jetTrkVec();
814 float jet_ORtrk_sumpt = assoc->overlapTrkVec(helper).sumpt();
815 float jet_all_trk_pt = initialTrkMom.sumpt();
816 float jet_unique_trk_pt = jet_all_trk_pt - jet_ORtrk_sumpt;
819 for(const auto& elec : electrons_in_jet) {
820 el_calvec += assoc->calVec(elec);
821 el_trkvec += assoc->trkVec(elec);
822 }
823 float el_cal_pt = el_calvec.cpt();
824 float el_trk_pt = el_trkvec.cpt();
825 ATH_MSG_VERBOSE("Elec trk: " << el_trk_pt
826 << " jetalltrk: " << jet_all_trk_pt
827 << " jetORtrk: " << jet_ORtrk_sumpt
828 << " electrk-jetORtrk: " << (el_trk_pt-jet_ORtrk_sumpt)
829 << " elec cal: " << el_cal_pt
830 << " jetalltrk-electrk: " << (jet_all_trk_pt-el_trk_pt)
831 << " jetalltrk-jetORtrk: " << (jet_all_trk_pt-jet_ORtrk_sumpt) );
832 // Want to use the jet calo measurement if we had at least one electron
833 // and the jet has a lot of residual track pt
834 // Is the cut appropriate?
835 if(el_trk_pt>1e-9 && jet_unique_trk_pt>10.0e3) passJetForEl=true;
836 } // end ele-track removal
837
838 for(const xAOD::Muon* mu_in_jet : muons_in_jet) {
839 if (!mu_in_jet) continue;
840 float mu_Eloss = acc_Eloss(*mu_in_jet);
841
842 if(!JVT_reject) {
843 if (m_doRemoveMuonJets) {
844 // need to investigate how this is affected by the recording of muon clusters in the map
845 float mu_id_pt = mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) ? mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle)->pt() : 0.;
846 float jet_trk_sumpt = acc_trksumpt.isAvailable(*jet) && this->getPV() ? acc_trksumpt(*jet)[this->getPV()->index()] : 0.;
847
848 // missed the muon, so we should add it back
849 if(0.9999*mu_id_pt>jet_trk_sumpt)
850 jet_trk_sumpt+=mu_id_pt;
851 float jet_trk_N = acc_trkN.isAvailable(*jet) && this->getPV() ? acc_trkN(*jet)[this->getPV()->index()] : 0.;
852 ATH_MSG_VERBOSE("Muon has ID pt " << mu_id_pt);
853 ATH_MSG_VERBOSE("Jet has pt " << jet->pt() << ", trk sumpt " << jet_trk_sumpt << ", trk N " << jet_trk_N);
854 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;
855 if(jet_from_muon) {
856 ATH_MSG_VERBOSE("Jet is from muon -- remove.");
857 JVT_reject = true;
858 }
859 }
860
862 // need to investigate how this is affected by the recording of muon clusters in the map
863 float mu_id_pt = mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) ? mu_in_jet->trackParticle(xAOD::Muon::InnerDetectorTrackParticle)->pt() : 0.;
864 float jet_trk_sumpt = acc_trksumpt.isAvailable(*jet) && this->getPV() ? acc_trksumpt(*jet)[this->getPV()->index()] : 0.;
865 // missed the muon, so we should add it back
866 if(0.9999*mu_id_pt>jet_trk_sumpt)
867 jet_trk_sumpt+=mu_id_pt;
868 float jet_trk_N = acc_trkN.isAvailable(*jet) && this->getPV() ? acc_trkN(*jet)[this->getPV()->index()] : 0.;
869
870 float jet_psE = 0.;
871 if (acc_psf.isAvailable(*jet)){
872 jet_psE = acc_psf(*jet);
873 } else if (acc_sampleE.isAvailable(*jet)){
874 jet_psE = acc_sampleE(*jet)[0] + acc_sampleE(*jet)[4];
875 } else {
876 ATH_MSG_ERROR("Jet PS fraction or sampling energy must be available to calculate MET with doSetMuonJetEMScale");
877 return StatusCode::FAILURE;
878 }
879
880 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;
881 ATH_MSG_VERBOSE("Muon has ID pt " << mu_id_pt);
882 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));
883
884 if(jet_from_muon) {
885 ATH_MSG_VERBOSE("Jet is from muon -- set to EM scale and subtract Eloss.");
886 // Using constjet now because we focus on AntiKt4EMTopo.
887 // Probably not a massive difference to LC, but PF needs some consideration
888 ATH_MSG_VERBOSE("Jet e: " << constjet.E() << ", mu Eloss: " << mu_Eloss);
889 float elosscorr = mu_Eloss >= constjet.e() ? 0. : 1.-mu_Eloss/constjet.e();
890 // Effectively, take the unique fraction of the jet times the eloss-corrected fraction
891 // This might in some cases oversubtract, but should err on the side of undercounting the jet contribution
892 opx *= elosscorr;
893 opy *= elosscorr;
894 ATH_MSG_VERBOSE(" Jet eloss factor " << elosscorr << ", final pt: " << sqrt(opx*opx+opy*opy));
895 // Don't treat this jet normally. Instead, just add to the Eloss term
896 isMuFSRJet = true;
897 }
898 }
899 } // end muon-jet overlap-removal
900
901 switch(mu_in_jet->energyLossType()) {
902 case xAOD::Muon::Parametrized:
903 case xAOD::Muon::MOP:
904 case xAOD::Muon::Tail:
905 case xAOD::Muon::FSRcandidate:
906 case xAOD::Muon::NotIsolated:
907 // For now don't differentiate the behaviour
908 // Remove the Eloss assuming the parameterised value
909 // The correction is limited to the selected clusters
910 total_eloss += mu_Eloss;
911 muons_selflags |= (1<<assoc->findIndex(mu_in_jet));
912 }
913 }
914 ATH_MSG_VERBOSE("Muon selection flags: " << muons_selflags);
915 ATH_MSG_VERBOSE("Muon total eloss: " << total_eloss);
916
918 // borrowed from overlapCalVec
919 for(size_t iKey = 0; iKey < assoc->sizeCal(); iKey++) {
920 bool selector = (muons_selflags & assoc->calkey()[iKey]);
921 if(selector) mu_calovec += assoc->calVec(iKey);
922 ATH_MSG_VERBOSE("This key: " << assoc->calkey()[iKey] << ", selector: " << selector);
923 }
924 ATH_MSG_VERBOSE("Mu calovec pt, no Eloss: " << mu_calovec.cpt());
925 if(m_muEloss) mu_calovec *= std::max<float>(0.,1-(total_eloss/mu_calovec.ce()));
926 ATH_MSG_VERBOSE("Mu calovec pt, with Eloss: " << mu_calovec.cpt());
927
928 // re-add calo components of muons beyond Eloss correction
929 ATH_MSG_VERBOSE("Jet " << jet->index() << " const pT before OR " << jpt);
930 ATH_MSG_VERBOSE("Jet " << jet->index() << " const pT after OR " << sqrt(opx*opx+opy*opy));
931 opx += mu_calovec.cpx();
932 opy += mu_calovec.cpy();
933 double opt = sqrt( opx*opx+opy*opy );
934 ATH_MSG_VERBOSE("Jet " << jet->index() << " const pT diff after OR readding muon clusters " << opt-jpt);
935 double uniquefrac = 1. - (calvec.ce() - mu_calovec.ce()) / constjet.E();
936 ATH_MSG_VERBOSE( "Jet constscale px, py, pt, E = " << jpx << ", " << jpy << ", " << jpt << ", " << constjet.E() );
937 ATH_MSG_VERBOSE( "Jet overlap E = " << calvec.ce() - mu_calovec.ce() );
938 ATH_MSG_VERBOSE( "Jet OR px, py, pt, E = " << opx << ", " << opy << ", " << opt << ", " << constjet.E() - calvec.ce() );
939
940 if(isMuFSRJet) {
941 if(!met_muonEloss){
942 ATH_MSG_ERROR("Attempted to apply muon Eloss correction, but corresponding MET term does not exist!");
943 return StatusCode::FAILURE;
944 }
945 met_muonEloss->add(opx,opy,opt);
946 continue;
947 }
948
949 if(selected && !JVT_reject) {
950 if(!caloverlap) {
951 // add jet full four-vector
952 hardJet = true;
953 if (!tracksForHardJets) {
954 if(m_doConstJet)
955 metJet->add(jpx,jpy,jpt);
956 else
957 *metJet += jet;
958 }
959 }
960 else if((uniquefrac>m_jetMinEfrac || passJetForEl) && opt>m_jetMinWeightedPt){
961 // add jet corrected for overlaps if sufficient unique fraction
962 hardJet = true;
963 if(!tracksForHardJets) {
964 if(m_jetCorrectPhi) {
965 if (m_doConstJet)
966 metJet->add(opx,opy,opt);
967 else {
968 double jesF = jet->pt() / jpt;
969 metJet->add(opx*jesF,opy*jesF,opt*jesF);
970 }
971 } else {
972 if (m_doConstJet)
973 metJet->add(uniquefrac*jpx,uniquefrac*jpy,uniquefrac*jpt);
974 else{
975 if(passJetForEl && m_doRemoveElecTrksEM)
976 metJet->add(opx,opy,opt);
977 else
978 metJet->add(uniquefrac*jet->px(),uniquefrac*jet->py(),uniquefrac*jet->pt());
979 }
980 }
981 }
982 }
983 } // hard jet selection
984
985 // Create the appropriate ElementLink for this jet just the once.
986 iplink_t jetLink;
987 if(jetsSgKey == 0) {
988 const xAOD::IParticleContainer* ipc =
989 static_cast<const xAOD::IParticleContainer*>(jet->container());
990 jetLink = iplink_t(*ipc, jet->index());
991 } else {
992 jetLink = iplink_t(jetsSgKey, jet->index());
993 }
994
995 if(hardJet){
996 ATH_MSG_VERBOSE("Jet added at full scale");
997 uniqueLinks.push_back( jetLink );
998 uniqueWeights.push_back( uniquefrac );
999 } else {
1000 if(metSoftClus && !JVT_reject) {
1001 // add fractional contribution
1002 ATH_MSG_VERBOSE("Jet added at const scale");
1003 if (std::abs(jet->eta())<2.5 || !(coreSoftClus->source()&MissingETBase::Source::Region::Central)) {
1004 softJetLinks.push_back( jetLink );
1005 softJetWeights.push_back( uniquefrac );
1006 metSoftClus->add(opx,opy,opt);
1007 }
1008
1009 // Fill a vector with the soft constituents, if one was provided.
1010 // For now, only setting up to work with those corresponding to the jet constituents.
1011 // Can expand if needed.
1012 // This ignores overlap removal.
1013 //
1014 if(softConst) {
1015 for(size_t iConst=0; iConst<jet->numConstituents(); ++iConst) {
1016 const IParticle* constit = jet->rawConstituent(iConst);
1017 softConst->push_back(constit);
1018 }
1019 }
1020 }
1021 } // hard jet or CST
1022
1023 if(!metSoftTrk || (hardJet && !tracksForHardJets)) continue;
1024
1025 // use jet tracks
1026 // remove any tracks already used by other objects
1027 MissingETBase::Types::constvec_t trkvec = assoc->overlapTrkVec(helper);
1028 MissingETBase::Types::constvec_t jettrkvec = assoc->jetTrkVec();
1029 if(jettrkvec.ce()>1e-9) {
1030 jpx = jettrkvec.cpx();
1031 jpy = jettrkvec.cpy();
1032 jpt = jettrkvec.sumpt();
1033 jettrkvec -= trkvec;
1034 opx = jettrkvec.cpx();
1035 opy = jettrkvec.cpy();
1036 opt = jettrkvec.sumpt();
1037 ATH_MSG_VERBOSE( "Jet track px, py, sumpt = " << jpx << ", " << jpy << ", " << jpt );
1038 ATH_MSG_VERBOSE( "Jet OR px, py, sumpt = " << opx << ", " << opy << ", " << opt );
1039 } else {
1040 opx = opy = opt = 0;
1041 ATH_MSG_VERBOSE( "This jet has no associated tracks" );
1042 }
1043 if (hardJet) metJet->add(opx,opy,opt);
1044 else if (std::abs(jet->eta())<2.5 || !(coreSoftTrk->source()&MissingETBase::Source::Region::Central)) {
1045 metSoftTrk->add(opx,opy,opt);
1046 // Don't need to add if already done for softclus.
1047 if(!metSoftClus) {
1048 softJetLinks.push_back( jetLink );
1049 softJetWeights.push_back( uniquefrac );
1050 }
1051
1052 // Fill a vector with the soft constituents, if one was provided.
1053 // For now, only setting up to work with those corresponding to the jet constituents.
1054 // Can expand if needed.
1055 // This ignores overlap removal.
1056 //
1057 if(softConst && !m_doPFlow && !m_doSoftTruth) {
1058 std::vector<const IParticle*> jettracks;
1059 jet->getAssociatedObjects<IParticle>(xAOD::JetAttribute::GhostTrack,jettracks);
1060 for(size_t iConst=0; iConst<jettracks.size(); ++iConst) {
1061 const TrackParticle* pTrk = static_cast<const TrackParticle*>(jettracks[iConst]);
1062 if (acceptTrack(pTrk,pv)) softConst->push_back(pTrk);
1063 }
1064 }
1065 }
1066 } // jet loop
1067
1068 ATH_MSG_DEBUG("Number of selected jets: " << dec_constitObjLinks(*metJet).size());
1069
1070 if(metSoftTrk) {
1071 dec_constitObjLinks(*metSoftTrk) = softJetLinks;
1072 ATH_MSG_DEBUG("Number of softtrk jets: " << dec_constitObjLinks(*metSoftTrk).size());
1073 }
1074
1075 if(metSoftClus) {
1076 dec_constitObjLinks(*metSoftClus) = softJetLinks;
1077 ATH_MSG_DEBUG("Number of softclus jets: " << dec_constitObjLinks(*metSoftClus).size());
1078 }
1079
1080 if(softConst) ATH_MSG_DEBUG(softConst->size() << " soft constituents from core term + jets");
1081
1082 const MissingETAssociation* assoc = map->getMiscAssociation();
1083 if(!assoc) return StatusCode::SUCCESS;
1084
1085 if(metSoftTrk) {
1086 // supplement track term with any tracks associated to isolated muons
1087 // these are recorded in the misc association
1088 MissingETBase::Types::constvec_t trkvec = assoc->overlapTrkVec(helper);
1089 double opx = trkvec.cpx();
1090 double opy = trkvec.cpy();
1091 double osumpt = trkvec.sumpt();
1092 ATH_MSG_VERBOSE( "Misc track px, py, sumpt = " << opx << ", " << opy << ", " << osumpt );
1093 metSoftTrk->add(opx,opy,osumpt);
1094 ATH_MSG_VERBOSE("Final soft track mpx " << metSoftTrk->mpx()
1095 << ", mpy " << metSoftTrk->mpy()
1096 << " sumet " << metSoftTrk->sumet());
1097 }
1098
1099 if(metSoftClus) {
1100 // supplement cluster term with any clusters associated to isolated e/gamma
1101 // these are recorded in the misc association
1102 float total_eloss(0.);
1103 MissingETBase::Types::bitmask_t muons_selflags(0);
1104 MissingETBase::Types::constvec_t calvec = assoc->overlapCalVec(helper);
1105 double opx = calvec.cpx();
1106 double opy = calvec.cpy();
1107 double osumpt = calvec.sumpt();
1108 for(const auto& obj : assoc->objects()) {
1109 if (!obj || obj->type() != xAOD::Type::Muon) continue;
1110 const xAOD::Muon* mu_test(static_cast<const xAOD::Muon*>(obj));
1111 if(acc_originalObject.isAvailable(*mu_test)) mu_test = static_cast<const xAOD::Muon*>(*acc_originalObject(*mu_test));
1112 if(MissingETComposition::objSelected(helper,mu_test)) { //
1113 float mu_Eloss = acc_Eloss(*mu_test);
1114 switch(mu_test->energyLossType()) {
1115 case xAOD::Muon::Parametrized:
1116 case xAOD::Muon::MOP:
1117 case xAOD::Muon::Tail:
1118 case xAOD::Muon::FSRcandidate:
1119 case xAOD::Muon::NotIsolated:
1120 // For now don't differentiate the behaviour
1121 // Remove the Eloss assuming the parameterised value
1122 // The correction is limited to the selected clusters
1123 total_eloss += mu_Eloss;
1124 muons_selflags |= (1<<assoc->findIndex(mu_test));
1125 }
1126 ATH_MSG_VERBOSE("Mu index " << mu_test->index());
1127 }
1128 }
1129 ATH_MSG_VERBOSE("Mu selection flags " << muons_selflags);
1130 ATH_MSG_VERBOSE("Mu total eloss " << total_eloss);
1131
1133 // borrowed from overlapCalVec
1134 for(size_t iKey = 0; iKey < assoc->sizeCal(); iKey++) {
1135 bool selector = (muons_selflags & assoc->calkey()[iKey]);
1136 ATH_MSG_VERBOSE("This key: " << assoc->calkey()[iKey] << ", selector: " << selector
1137 << " this calvec E: " << assoc->calVec(iKey).ce());
1138 if(selector) mu_calovec += assoc->calVec(iKey);
1139 }
1140 if(m_muEloss){
1141 mu_calovec *= std::max<float>(0.,1-(total_eloss/mu_calovec.ce()));
1142 opx += mu_calovec.cpx();
1143 opy += mu_calovec.cpy();
1144 osumpt += mu_calovec.sumpt();
1145 }
1146 ATH_MSG_VERBOSE("Mu cluster sumpt " << mu_calovec.sumpt());
1147
1148 ATH_MSG_VERBOSE( "Misc cluster px, py, sumpt = " << opx << ", " << opy << ", " << osumpt );
1149 metSoftClus->add(opx,opy,osumpt);
1150 ATH_MSG_VERBOSE("Final soft cluster mpx " << metSoftClus->mpx()
1151 << ", mpy " << metSoftClus->mpy()
1152 << " sumet " << metSoftClus->sumet());
1153 }
1154
1155 return StatusCode::SUCCESS;
1156 }
1157
1159 const xAOD::JetContainer* jets,
1161 xAOD::MissingET* metSoftTrk,
1162 const xAOD::MissingET* coreSoftTrk,
1163 bool doJetJVT) const {
1164 return rebuildJetMET(metJet,jets,helper,nullptr,nullptr,metSoftTrk,coreSoftTrk,doJetJVT,true);
1165 }
1166
1167 // **** Remove objects and any overlaps from MET calculation ****
1170 xAOD::MissingETContainer* metCont) const
1171 {
1172 MissingET* met = nullptr;
1173 if( fillMET(met,metCont, "Invisibles" , invisSource) != StatusCode::SUCCESS) {
1174 ATH_MSG_ERROR("failed to fill MET term \"Invisibles\"");
1175 return StatusCode::FAILURE;
1176 }
1178 }
1179
1181 {
1182 return static_cast<bool>(m_trkseltool->accept( *trk, vx ));
1183 }
1184
1186
1188
1189 if(!h_PV.isValid()) {
1190 ATH_MSG_WARNING("Unable to retrieve primary vertex container PrimaryVertices");
1191 return nullptr;
1192 }
1193 ATH_MSG_DEBUG("Successfully retrieved primary vertex container");
1194 if(h_PV->empty()) ATH_MSG_WARNING("Event has no primary vertices!");
1195 for(const xAOD::Vertex* vx : *h_PV) {
1196 if(vx->vertexType()==xAOD::VxType::PriVtx) return vx;
1197 }
1198 return nullptr;
1199 }
1200
1201} //> end namespace met
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(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.
Base class for elements of a container that can have aux data.
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.
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:497
std::unique_ptr< SG::AuxElement::ConstAccessor< char > > m_acc_jetRejectionDec
Definition METMaker.h:150
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
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:534
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::AuxElement::ConstAccessor< float > acc_emf("EMFrac")
static const SG::AuxElement::Accessor< std::vector< float > > dec_constitObjWeights("ConstitObjectWeights")
static const SG::AuxElement::ConstAccessor< float > acc_Eloss("EnergyLoss")
static const SG::AuxElement::ConstAccessor< float > acc_width("Width")
static const SG::AuxElement::ConstAccessor< iplink_t > acc_nominalObject("nominalObjectLink")
static const SG::AuxElement::Accessor< std::vector< iplink_t > > dec_constitObjLinks("ConstitObjectLinks")
static const SG::AuxElement::ConstAccessor< float > acc_psf("PSFrac")
static const SG::AuxElement::ConstAccessor< std::vector< int > > acc_trkN("NumTrkPt500")
static const MissingETBase::Types::bitmask_t invisSource
Definition METHelpers.h:27
static const SG::AuxElement::ConstAccessor< std::vector< float > > acc_sampleE("EnergyPerSampling")
static const SG::AuxElement::ConstAccessor< iplink_t > acc_originalObject("originalObjectLink")
static const SG::AuxElement::ConstAccessor< std::vector< iplink_t > > acc_ghostMuons("GhostMuon")
static const SG::AuxElement::ConstAccessor< std::vector< float > > acc_trksumpt("SumPtTrkPt500")
StatusCode fillMET(xAOD::MissingET *&met, xAOD::MissingETContainer *metCont, const std::string &metKey, const MissingETBase::Types::bitmask_t metSource)
static const SG::AuxElement::ConstAccessor< std::vector< iplink_t > > acc_ghostElecs("GhostElec")
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.