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 &&
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::AuxElement::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) = 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 |= (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_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:498
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: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::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:38
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.