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>;
68
72
77
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.
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:569
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
const SG::AuxVectorData * container() const
Return the container holding this element.
size_t index() const
Return the index of this element within its container.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode setProperty(const std::string &name, const T &value)
set the given property
an object that can create a AsgTool
::StatusCode makePrivateTool(ToolHandle< T > &toolHandle) const
make a private tool with the given configuration
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
SG::sgkey_t getKey(const void *ptr) const
Get the (hashed) key of an object that is in the event store.
Definition AsgTool.cxx:119
STL class.
bool m_skipSystematicJetSelection
Definition METMaker.h:183
bool m_greedyPhotons
Definition METMaker.h:187
double m_customFwdJetPtCut
Definition METMaker.h:170
double m_jetTrkPtMuPt
Definition METMaker.h:195
METMaker()
Default constructor:
std::string m_customJvtWP
Definition METMaker.h:172
ToolHandle< IAsgSelectionTool > m_JvtTool
Definition METMaker.h:199
bool m_doRemoveElecTrks
Definition METMaker.h:180
bool m_jetCorrectPhi
Definition METMaker.h:155
double m_customJvtPtMax
Definition METMaker.h:171
bool m_doRemoveMuonJets
Definition METMaker.h:179
float m_missObjWarningPtThreshold
Definition METMaker.h:153
std::string m_jetSelection
Definition METMaker.h:166
std::string m_jetRejectionDec
Definition METMaker.h:159
virtual StatusCode rebuildTrackMET(const std::string &metJetKey, const std::string &softTrkKey, xAOD::MissingETContainer *metCont, const xAOD::JetContainer *jets, const xAOD::MissingETContainer *metCoreCont, xAOD::MissingETAssociationHelper &helper, bool doJetJVT) const override final
Definition METMaker.cxx: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
static const SG::AuxElement::ConstAccessor< iplink_t > acc_nominalObject("nominalObjectLink")
ElementLink< xAOD::IParticleContainer > iplink_t
static const SG::AuxElement::ConstAccessor< float > acc_width("Width")
static const SG::AuxElement::ConstAccessor< std::vector< int > > acc_trkN("NumTrkPt500")
static const SG::AuxElement::ConstAccessor< iplink_t > acc_originalObject("originalObjectLink")
static const SG::AuxElement::ConstAccessor< float > acc_Eloss("EnergyLoss")
static const SG::AuxElement::ConstAccessor< std::vector< iplink_t > > acc_ghostElecs("GhostElec")
static const SG::AuxElement::Accessor< std::vector< iplink_t > > dec_constitObjLinks("ConstitObjectLinks")
static const SG::AuxElement::Accessor< std::vector< float > > dec_constitObjWeights("ConstitObjectWeights")
static const SG::AuxElement::ConstAccessor< std::vector< iplink_t > > acc_ghostMuons("GhostMuon")
static const SG::AuxElement::ConstAccessor< float > acc_emf("EMFrac")
static const SG::AuxElement::ConstAccessor< std::vector< float > > acc_trksumpt("SumPtTrkPt500")
static const MissingETBase::Types::bitmask_t invisSource
Definition METHelpers.h:27
StatusCode fillMET(xAOD::MissingET *&met, xAOD::MissingETContainer *metCont, const std::string &metKey, const MissingETBase::Types::bitmask_t metSource)
static const SG::AuxElement::ConstAccessor< float > acc_psf("PSFrac")
static const SG::AuxElement::ConstAccessor< std::vector< float > > acc_sampleE("EnergyPerSampling")
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.