ATLAS Offline Software
Loading...
Searching...
No Matches
PFSubtractionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "PFSubtractionTool.h"
6
7#include "eflowCaloObject.h"
11#include "eflowRecTrack.h"
14#include "PFClusterFiller.h"
15#include "PFTrackFiller.h"
16
20
21using namespace eflowSubtract;
22
23PFSubtractionTool::PFSubtractionTool(const std::string &type, const std::string &name, const IInterface *parent) : base_class(type, name, parent),
25{
26}
27
29= default;
30
32{
33
34 ATH_CHECK(m_theEOverPTool.retrieve());
35
36 ATH_CHECK(m_theEOverPTool->fillBinnedParameters(m_binnedParameters.get()));
37
39 if (!m_trkpos)
40 {
41 ATH_MSG_ERROR("Failed to get TrackPositionProvider for cluster preselection!");
42 return StatusCode::FAILURE;
43 }
44
45 //Retrieve track-cluster matching tools
46 ATH_CHECK(m_theMatchingTool.retrieve());
49
51
52 //Set the level of the helpers to the same as the tool here
53 m_pfSubtractionStatusSetter.msg().setLevel(this->msg().level());
54 m_pfSubtractionEnergyRatioCalculator.msg().setLevel(this->msg().level());
55 m_subtractor.m_facilitator.msg().setLevel(this->msg().level());
56
59 }
60
62
63 return StatusCode::SUCCESS;
64}
65
66void PFSubtractionTool::execute(const EventContext& ctx, eflowCaloObjectContainer *theEflowCaloObjectContainer, eflowRecTrackContainer *recTrackContainer, eflowRecClusterContainer *recClusterContainer) const
67{
68
69 ATH_MSG_DEBUG("Executing");
70
71 PFData data;
72 data.caloObjects = theEflowCaloObjectContainer;
73 const PFTrackFiller pfTrackFiller;
74 if (!m_recoverSplitShowers) PFTrackFiller::fillTracksToConsider(data, *recTrackContainer);
76
77 const PFClusterFiller pfClusterFiller;
78 if (!m_recoverSplitShowers) PFClusterFiller::fillClustersToConsider(data, *recClusterContainer);
80
81 ATH_MSG_DEBUG("This event has " << data.tracks.size() << " tracks " << data.clusters.size() << " clusters ");
82
83 unsigned int numMatches = matchAndCreateEflowCaloObj(ctx, data);
84
85 if (msgLvl(MSG::DEBUG)) printAllClusters(*recClusterContainer);
86
87 if (!m_calcEOverP){
90 else performSubtraction(numMatches,data);
91 }
92 else performTruthSubtraction(data);
93 }
94 //eoverp mode calculation has been moved to a dedicated PFBaseTool.
95
96}
97
98unsigned int PFSubtractionTool::matchAndCreateEflowCaloObj(const EventContext& ctx, PFData &data) const{
99
100 //Counts up how many tracks found at least 1 calorimeter cluster matched to it.
101 unsigned int nMatches(0);
102
103 /* Cache the original number of eflowCaloObjects, if there were any */
104 const unsigned int nCaloObj = data.caloObjects->size();
105
106 /* loop tracks in data.tracks and do matching */
107 for (auto *thisEfRecTrack : data.tracks)
108 {
110 if (!thisEfRecTrack->hasBin()) {
111 std::unique_ptr<eflowCaloObject> thisEflowCaloObject = std::make_unique<eflowCaloObject>();
112 thisEflowCaloObject->addTrack(thisEfRecTrack);
113 data.caloObjects->push_back(std::move(thisEflowCaloObject));
114 continue;
115 }
116
117 if (msgLvl(MSG::DEBUG))
118 {
119 const xAOD::TrackParticle *track = thisEfRecTrack->getTrack();
120 ATH_MSG_DEBUG("Matching track with e,pt, eta and phi " << track->e() << ", " << track->pt() << ", " << track->eta() << " and " << track->phi());
121 }
122
123 std::vector<eflowTrackClusterLink*> bestClusters;
124 std::vector<float> deltaRPrime;
125
127
128 const xAOD::TruthParticle* trackMatchedTruthParticle = nullptr;
130
131 const static SG::Accessor<TruthLink> truthLinkAccessor("truthParticleLink");
132
133 TruthLink truthLink = truthLinkAccessor(*(thisEfRecTrack->getTrack()));
134 //if not valid don't print a WARNING because this is an expected condition as discussed here:
135 //https://indico.cern.ch/event/795039/contributions/3391771/attachments/1857138/3050771/TruthTrackFTAGWS.pdf
136 if (truthLink.isValid()) trackMatchedTruthParticle = *truthLink;
137
138 if (trackMatchedTruthParticle){
139 double uniqueID = HepMC::uniqueID(trackMatchedTruthParticle);
140
142 if (!caloClusterReadDecorHandleNLeadingTruthParticles.isValid()){
143 ATH_MSG_WARNING("Failed to retrieve CaloCluster decoration with key " << caloClusterReadDecorHandleNLeadingTruthParticles.key());
144 }
145
146 for (auto * thisCluster : data.clusters){
147 //accessor for decoration
148 //split key into substring to get the name of the decoration
149
150 std::string decorHandleName = m_caloClusterReadDecorHandleKeyNLeadingTruthParticles.key();
151 std::string::size_type pos = decorHandleName.find(".");
152 std::string decorName = decorHandleName.substr(pos+1);
153
155
156 std::vector<std::pair<unsigned int, double > > uniqueIDTruthPairs = accessor(*(thisCluster->getCluster()));
157
158 for (auto &uniqueIDTruthPair : uniqueIDTruthPairs){
159 if (uniqueIDTruthPair.first == uniqueID){
160 eflowTrackClusterLink* thisLink = eflowTrackClusterLink::getInstance(thisEfRecTrack, thisCluster, ctx);
161 bestClusters.push_back(thisLink);
162 break;
163 }
164 }//loop over calocluster truth pair decorations
165 }//loop over caloclusters
166
167 }//if have truth particle matched to track
168 else ATH_MSG_VERBOSE("Track with pt, eta and phi " << thisEfRecTrack->getTrack()->pt() << ", " << thisEfRecTrack->getTrack()->eta() << " and " << thisEfRecTrack->getTrack()->phi() << " does not have a valid truth pointer");
169 }
170 else if (!m_recoverSplitShowers){
175 std::vector<std::pair<eflowRecCluster *, float>> bestClusters_02 = m_theMatchingToolForPull_02->doMatches(thisEfRecTrack, data.clusters, -1);
176 for (auto &matchpair : bestClusters_02)
177 {
178 eflowRecCluster *theCluster = matchpair.first;
179 float distancesq = matchpair.second;
180 eflowTrackClusterLink *trackClusterLink = eflowTrackClusterLink::getInstance(thisEfRecTrack, theCluster, ctx);
181 if (distancesq < 0.15 * 0.15)
182 {
183 // Narrower cone is a subset of the selected clusters
184 // Distance returned is deltaR^2
185 static const std::string cone15Str{"cone_015"};
186 thisEfRecTrack->addAlternativeClusterMatch(trackClusterLink, cone15Str);
187 }
188 static const std::string cone2Str{"cone_02"};
189 thisEfRecTrack->addAlternativeClusterMatch(trackClusterLink, cone2Str);
190 }//loop over bestClusters_02
191
192 //This matching scheme is used to match the calorimeter cluster(s) to be used in the charged showers subtraction for this track.
193 std::vector<std::pair<eflowRecCluster *, float>> matchedClusters = m_theMatchingTool->doMatches(thisEfRecTrack, data.clusters,m_nClusterMatchesToUse);
194 for (const auto& thePair : matchedClusters) {
195 bestClusters.push_back(eflowTrackClusterLink::getInstance(thisEfRecTrack, thePair.first, ctx));
196 if (m_addCPData) deltaRPrime.push_back(std::sqrt(thePair.second));
197 }
198 }
199 else {
200 const std::vector<eflowTrackClusterLink*>* matchedClusters_02 = thisEfRecTrack->getAlternativeClusterMatches("cone_02");
201 if (!matchedClusters_02) continue;
202 else bestClusters = *matchedClusters_02;
203 }
204
205 if (bestClusters.empty()) continue;
206
207 if (msgLvl(MSG::DEBUG))
208 {
209 for (auto *thisClusterLink : bestClusters ) {
210 xAOD::CaloCluster* thisCluster = thisClusterLink->getCluster()->getCluster();
211 ATH_MSG_DEBUG("Matched this track to cluster with e,pt, eta and phi " << thisCluster->e() << ", " << thisCluster->pt() << ", " << thisCluster->eta() << " and " << thisCluster->phi());
212 }
213 }
214
215 nMatches++;
216
217 //loop over the matched calorimeter clusters and associate tracks and clusters to each other as needed.
218 unsigned int linkIndex = 0;
219 for (auto *trkClusLink : bestClusters){
220
221 eflowRecCluster *thisEFRecCluster = trkClusLink->getCluster();
222
224 // Look up whether this cluster is intended for recovery
225 if (std::find(data.clusters.begin(), data.clusters.end(), trkClusLink->getCluster()) == data.clusters.end()) {
226 linkIndex++;
227 continue;
228 }
229 }
230
231 eflowTrackClusterLink *trackClusterLink = eflowTrackClusterLink::getInstance(thisEfRecTrack, thisEFRecCluster, ctx);
232 thisEfRecTrack->addClusterMatch(trackClusterLink);
234 thisEfRecTrack->addDeltaRPrime(deltaRPrime[linkIndex]);
235 }
236 thisEFRecCluster->addTrackMatch(trackClusterLink);
237 }
238 linkIndex++;
239 }
240
241 /* Create 3 types eflowCaloObjects: track-only, cluster-only, track-cluster-link */
242 std::vector<eflowRecCluster *> clusters(data.clusters.begin(), data.clusters.end());
243 if (m_recoverSplitShowers) std::sort(clusters.begin(), clusters.end(), eflowRecCluster::SortDescendingPt());
244 unsigned int nCaloObjects = eflowCaloObjectMaker::makeTrkCluCaloObjects(data.tracks, clusters, data.caloObjects);
245 ATH_MSG_DEBUG("Created " << nCaloObjects << " eflowCaloObjects.");
246 if (msgLvl(MSG::DEBUG)){
247 for (auto thisEFlowCaloObject : *(data.caloObjects)){
248 ATH_MSG_DEBUG("This eflowCaloObject has " << thisEFlowCaloObject->nTracks() << " tracks and " << thisEFlowCaloObject->nClusters() << " clusters ");
249 for (unsigned int count = 0; count < thisEFlowCaloObject->nTracks(); count++){
250 const xAOD::TrackParticle* thisTrack = thisEFlowCaloObject->efRecTrack(count)->getTrack();
251 ATH_MSG_DEBUG("Have track with e, pt, eta and phi of " << thisTrack->e() << ", " << thisTrack->pt() << ", " << thisTrack->eta() << " and " << thisTrack->phi());
252 }
253 for (unsigned int count = 0; count < thisEFlowCaloObject->nClusters(); count++){
254 const xAOD::CaloCluster* thisCluster = thisEFlowCaloObject->efRecCluster(count)->getCluster();
255 ATH_MSG_DEBUG("Have cluster with e, pt, eta and phi of " << thisCluster->e() << ", " << thisCluster->pt() << ", " << thisCluster->eta() << " and " << thisCluster->phi());
256 }
257 }
258 }
259
260 const double gaussianRadius = 0.032;
261 const double gaussianRadiusError = 1.0e-3;
262 const double maximumRadiusSigma = 3.0;
263
264 eflowLayerIntegrator integrator(gaussianRadius, gaussianRadiusError, maximumRadiusSigma, m_isHLLHC);
265
267 if (!m_recoverSplitShowers && 0 != nCaloObj) ATH_MSG_WARNING("Not in Split Showers Mode and already have " << nCaloObj << " eflowCaloObjects");
268
269 //For each eflowCaloObject we calculate the expected energy deposit in the calorimeter and cell ordering for subtraction.
270 for (unsigned int iCalo = nCaloObj; iCalo < data.caloObjects->size(); ++iCalo) {
271 eflowCaloObject* thisEflowCaloObject = data.caloObjects->at(iCalo);
272 thisEflowCaloObject->simulateShower(ctx, &integrator, m_binnedParameters.get(), m_useNNEnergy ? &(*m_NNEnergyPredictorTool) : nullptr, m_useLegacyEBinIndex);
273 if (m_useTruthForChargedShowerSubtraction) m_theTruthShowerSimulator->simulateShower(*thisEflowCaloObject);
274
275 }
276
277 if (!m_recoverSplitShowers) return nMatches;
278 else return nCaloObj;
279}
280
281void PFSubtractionTool::performSubtraction(unsigned int startingPoint,PFData &data) const{
282 unsigned int nEFCaloObs = data.caloObjects->size();
283 for (unsigned int iCalo = startingPoint; iCalo < nEFCaloObs; ++iCalo) {
284 eflowCaloObject* thisEflowCaloObject = data.caloObjects->at(iCalo);
285 this->performSubtraction(*thisEflowCaloObject);
286 }
287}
288
290
291 ATH_MSG_DEBUG("In performSubtraction");
292
293 unsigned int nClusters = thisEflowCaloObject.nClusters();
294 unsigned int nTrackMatches = thisEflowCaloObject.nTracks();
295
296 ATH_MSG_DEBUG("Have got an eflowCaloObject with " << nClusters << " clusters and " << nTrackMatches << " track matches");
297
298 if (msgLevel(MSG::DEBUG)){
299 for (unsigned int iTrack = 0; iTrack < nTrackMatches; ++iTrack){
300 eflowRecTrack* thisTrack = thisEflowCaloObject.efRecTrack(iTrack);
301 ATH_MSG_DEBUG("eflowCaloObject has track with E, pt and eta " << thisTrack->getTrack()->e() << ", " << thisTrack->getTrack()->pt() << " and " << thisTrack->getTrack()->eta());
302 }
303 }
304
305 //To keep historical behaviour when in recover split showers mode allow tracks with no cluster matches to proceed.
306 if (!m_recoverSplitShowers && nClusters < 1) return;
307
308 //Need at least one track in this eflowCaloObject to continue.
309 if (nTrackMatches < 1) return;
310
311 double expectedEnergy = thisEflowCaloObject.getExpectedEnergy();
312 double clusterEnergy = thisEflowCaloObject.getClusterEnergy();
313 double expectedSigma = std::sqrt(thisEflowCaloObject.getExpectedVariance());
314
315 /* Check e/p, if on first pass - return if e/p not consistent with expected e/p */
317 if (isEOverPFail(expectedEnergy, expectedSigma, clusterEnergy)) return;
318 }
319
320 const std::vector<std::pair<eflowTrackClusterLink *, std::pair<float, float>>> &matchedTrackList = thisEflowCaloObject.efRecLink();
321
322 ATH_MSG_DEBUG("Matched Track List has size " << matchedTrackList.size());
323
324 if (msgLevel(MSG::DEBUG))
325 {
326 for (unsigned int iTrack = 0; iTrack < nTrackMatches; ++iTrack)
327 {
328 const xAOD::TrackParticle *thisTrack = thisEflowCaloObject.efRecTrack(iTrack)->getTrack();
329 ATH_MSG_DEBUG("eflowCaloObject has track match with E, pt and eta " << thisTrack->e() << ", " << thisTrack->pt() << " and " << thisTrack->eta());
330 }
331 }
332
333 ATH_MSG_DEBUG("About to perform subtraction for this eflowCaloObject");
334
335 bool wasAnnihilated = false;
336
337 //First deal with non-split showers mode
339 /* Check if we can annihilate right away - true if matched cluster has only the expected energy deposit */
340 if (canAnnihilate(expectedEnergy, expectedSigma, clusterEnergy)){
341
342 wasAnnihilated = true;
343
344 std::vector<std::pair<xAOD::CaloCluster *, bool>> clusterList;
345 std::map<xAOD::CaloCluster *, double> clusterEnergyMap;
346 unsigned nCluster = thisEflowCaloObject.nClusters();
347 for (unsigned iCluster = 0; iCluster < nCluster; ++iCluster){
348 clusterList.emplace_back(thisEflowCaloObject.efRecCluster(iCluster)->getCluster(), false);
349 }
350
351 ATH_MSG_DEBUG("We are going to annihilate. ExpectedEnergy, expectedSigma and clusterEnergy are " << expectedEnergy << ", " << expectedSigma << " and " << clusterEnergy);
352 if (msgLevel(MSG::DEBUG))
353 for (const auto& thisPair : clusterList)
354 ATH_MSG_DEBUG("Annihilating cluster with E and eta " << thisPair.first->e() << " and " << thisPair.first->eta());
355
356 m_pfSubtractionStatusSetter.markAllTracksAnnihStatus(thisEflowCaloObject);
357
358 //before we remove all the cells, we create a list of the removed cells if in doCPData mode
359 if (m_addCPData) this->addSubtractedCells(thisEflowCaloObject, clusterList);
360
362
363 if (msgLevel(MSG::DEBUG))
364 for (const auto& thisPair : clusterList)
365 ATH_MSG_DEBUG("Have Annihilated cluster with E and eta " << thisPair.first->e() << " and " << thisPair.first->eta());
366
367 /* Flag all tracks in this system as subtracted */
368 for (unsigned iTrack = 0; iTrack < thisEflowCaloObject.nTracks(); ++iTrack){
369 eflowRecTrack *thisEfRecTrack = (matchedTrackList[iTrack].first)->getTrack();
370 if (!thisEfRecTrack->isSubtracted()) thisEfRecTrack->setSubtracted();
371 }
372
373 }//if can annihilate this track-cluster systems matched cluster
374 }//split shower recovery mode or regular mode where above annihilation was not triggered
375 if (m_recoverSplitShowers || !wasAnnihilated){
376
377 for (unsigned iTrack = 0; iTrack < thisEflowCaloObject.nTracks(); ++iTrack){
378
379 eflowRecTrack *thisEfRecTrack = thisEflowCaloObject.efRecTrack(iTrack);
380
381 ATH_MSG_DEBUG("About to subtract track with e, pt, eta and phi of " << thisEfRecTrack->getTrack()->e() << ", " << thisEfRecTrack->getTrack()->pt() << ", " << thisEfRecTrack->getTrack()->eta() << " and "
382 << thisEfRecTrack->getTrack()->eta());
383
384 if (!thisEfRecTrack->hasBin()) continue;
385
386 ATH_MSG_DEBUG("Have bin for this eflowCaloObject");
387
388 if (thisEfRecTrack->isInDenseEnvironment() && !m_recoverSplitShowers) continue;
389
390 ATH_MSG_DEBUG("Am not in dense environment for this eflowCaloObject");
391
392 /* Get matched cluster via Links */
393 std::vector<eflowRecCluster *> matchedClusters;
394 const std::vector<eflowTrackClusterLink *>& links = thisEfRecTrack->getClusterMatches();
395 matchedClusters.reserve(links.size());
396 for (auto* thisEFlowTrackClusterLink : links)
397 matchedClusters.push_back(thisEFlowTrackClusterLink->getCluster());
399 std::sort(matchedClusters.begin(),
400 matchedClusters.end(),
402
403 if (msgLvl(MSG::DEBUG)) {
404 for (auto* thisClus : matchedClusters)
406 "Haved matched cluster "
407 << thisClus->getCluster()->index() << " with e,pt, eta and phi of "
408 << thisClus->getCluster()->e() << ", "
409 << thisClus->getCluster()->pt() << ", "
410 << thisClus->getCluster()->eta() << " and "
411 << thisClus->getCluster()->phi() << " will be subtracted");
412 }
413
414 /* Do subtraction */
415 std::vector<std::pair<xAOD::CaloCluster *, bool>> clusterSubtractionList;
416 clusterSubtractionList.reserve(matchedClusters.size());
417 std::map<xAOD::CaloCluster *, double> clusterEnergyMap;
418 for (auto *thisEFlowRecCluster : matchedClusters){
419 xAOD::CaloCluster *thisCluster = thisEFlowRecCluster->getCluster();
420 clusterSubtractionList.emplace_back(thisCluster, false);
421 clusterEnergyMap[thisCluster] = thisCluster->e();
422 }
423
424 ATH_MSG_DEBUG("Have filled clusterSubtractionList for this eflowCaloObject");
425
426 unsigned int trackIndex = thisEfRecTrack->getTrack()->index();
427
428 //Previously we only checked this in recover split showers, but makes sense to check it in both passes.
429 auto sumClusEnergy = [](double accumulator, std::pair<xAOD::CaloCluster *, bool> thisPair){ return accumulator += thisPair.first->e();};
430 double totalClusterEnergy = std::accumulate(clusterSubtractionList.begin(),clusterSubtractionList.end(),0.0,sumClusEnergy);
431
432 /* Check if we can annihilate right away - true if matched cluster has only the expected energy deposit */
433 if(canAnnihilate(thisEfRecTrack->getEExpect(),std::sqrt(thisEfRecTrack->getVarEExpect()),totalClusterEnergy)){
434
435 if (msgLevel(MSG::DEBUG))
436 for (const auto& thisPair : clusterSubtractionList)
437 ATH_MSG_DEBUG("Annihilating cluster with E and eta " << thisPair.first->e() << " and " << thisPair.first->eta());
438
439 //before we remove all the cells, we create a list of the removed cells if in doCPData mode
440 if (m_addCPData) this->addSubtractedCells(thisEflowCaloObject, clusterSubtractionList);
441
442 Subtractor::annihilateClusters(clusterSubtractionList);
443 //Now we should mark all of these clusters as being subtracted
444 //Now need to mark which clusters were modified in the subtraction procedure
445 std::vector<std::pair<float, float>> clusterSubtractedEnergyRatios;
446 m_pfSubtractionEnergyRatioCalculator.calculateSubtractedEnergyRatiosForAnnih(clusterSubtractionList, clusterEnergyMap, clusterSubtractedEnergyRatios);
447 m_pfSubtractionStatusSetter.markSubtractionStatus(clusterSubtractionList, clusterSubtractedEnergyRatios, thisEflowCaloObject, trackIndex);
448 }
449 else
450 {
451
452 /* Subtract the track from all matched clusters */
453 m_subtractor.subtractTracksFromClusters(thisEfRecTrack, clusterSubtractionList, m_addCPData);
454
455 //recalculate total cluster energy from the clusters afer subtraction
456 totalClusterEnergy = std::accumulate(clusterSubtractionList.begin(),clusterSubtractionList.end(),0.0,sumClusEnergy);
457
458 /* Annihilate the cluster(s) if the remnant is small (i.e. below k*sigma) */
459 if (canAnnihilate(0.0,std::sqrt(thisEfRecTrack->getVarEExpect()), totalClusterEnergy)){
460
461 if (msgLevel(MSG::DEBUG))
462 for (const auto& thisPair : clusterSubtractionList){
463 ATH_MSG_DEBUG("Annihilating remnant cluster with E and eta " << thisPair.first->e() << " and " << thisPair.first->eta());
464 }
465 eflowSubtract::Subtractor::annihilateClusters(clusterSubtractionList);
466 //Now we should mark all of these clusters as being subtracted
467 std::vector<std::pair<float, float>> clusterSubtractedEnergyRatios;
468 m_pfSubtractionEnergyRatioCalculator.calculateSubtractedEnergyRatiosForAnnih(clusterSubtractionList, clusterEnergyMap, clusterSubtractedEnergyRatios);
469 m_pfSubtractionStatusSetter.markSubtractionStatus(clusterSubtractionList, clusterSubtractedEnergyRatios, thisEflowCaloObject, trackIndex);
470 }//if remove the remnant after cell by cell subtraction
471 else
472 {
473 std::vector<std::pair<float, float>> clusterSubtractedEnergyRatios;
474 m_pfSubtractionEnergyRatioCalculator.calculateSubtractedEnergyRatios(clusterSubtractionList, clusterEnergyMap, clusterSubtractedEnergyRatios);
475 m_pfSubtractionStatusSetter.markSubtractionStatus(clusterSubtractionList, clusterSubtractedEnergyRatios, thisEflowCaloObject, trackIndex);
476 }//if don't remove the remnant after cell by cell subtraction
477
478 }//if not annihilating, and instead subtracting cell by cell
479
480 ATH_MSG_DEBUG("Have subtracted charged shower for this eflowRecTrack");
481
482 /* Flag tracks as subtracted */
483 if (!thisEfRecTrack->isSubtracted()) thisEfRecTrack->setSubtracted();
484
485 }//loop over tracks in eflowCaloObject
486 }//cell by cell subtraction
487
488}
489
491
492 ATH_MSG_DEBUG("In performTruthSubtraction");
493
494 unsigned int nEFCaloObs = data.caloObjects->size();
495
496 for (unsigned int iCalo = 0; iCalo < nEFCaloObs; ++iCalo) {
497 eflowCaloObject* thisEflowCaloObject = data.caloObjects->at(iCalo);
498 this->performTruthSubtraction(*thisEflowCaloObject);
499 }
500
501}
502
504
505 for (unsigned iTrack = 0; iTrack < thisEflowCaloObject.nTracks(); ++iTrack){
506 eflowRecTrack *thisEfRecTrack = thisEflowCaloObject.efRecTrack(iTrack);
507
508 //although we are subtracting the truth, to be consistent we only do it if a reco
509 //e/p lookup bin exists for this track
510 if (!thisEfRecTrack->hasBin()) continue;
511
512 //Similarly we skip tracks in a dense environment
513 if (thisEfRecTrack->isInDenseEnvironment()) continue;
514
515 thisEfRecTrack->setSubtracted();
516
517 //get the set of matched clusters
518 const std::vector<eflowTrackClusterLink *>& links = thisEfRecTrack->getClusterMatches();
519
520 for (auto thisLink : links){
521 xAOD::CaloCluster *thisCluster = thisLink->getCluster()->getCluster();
522 CaloClusterCellLink* theCellLinks = thisCluster->getOwnCellLinks();
523 CaloClusterCellLink::iterator theCell = theCellLinks->begin();
524 CaloClusterCellLink::iterator lastCell = theCellLinks->end();
525
526 //loop over the cells in this cluster and subtract shower using truth information
527 //We can either remove a cell entireley if it has any truth deposit (closer to what the real
528 //reco algorithm does) or reweight the cells contribution based on subtracting the truth
529 //energy from the reco cell energy
530 //We only advance the iterator, theCell, if we *dont* call removeCell to avoid issues with
531 //invalid iterators
532 //We also have to reset the lastCell iterator after each call to ensure the loop exits at the end,
533 //instead of being stuck in an infinite loop.
534 for (; theCell != lastCell;){
535 //get the truth energy for this cell
536 double truthEnergy = thisEfRecTrack->getCellTruthEnergy(*theCell);
537 //reweight the cell such that energy*weight gives the new energy
538 double oldCellEnergy = theCell->energy()*(theCell.weight());
539 double subtractedCellWeight = (oldCellEnergy - truthEnergy)/oldCellEnergy;
540
541 if (0.0 != truthEnergy && m_useFullCellTruthSubtraction) {
542 thisCluster->removeCell(*theCell);
543 lastCell = theCellLinks->end();
544 }
546 theCell.reweight(subtractedCellWeight);
547 ++theCell;
548 }
549 else ++theCell;
550
551 }//cell loop
552
553 float oldEnergy = thisCluster->e();
554 CaloClusterKineHelper::calculateKine(thisCluster, true, true);
555 if (0.0 != oldEnergy) {
556 float energyAdjustment = thisCluster->e() / oldEnergy;
557 thisCluster->setRawE(thisCluster->rawE() * energyAdjustment);
558 thisCluster->setRawEta(thisCluster->eta());
559 thisCluster->setRawPhi(thisCluster->phi());
560 }
561 }
562
563 }//eflowCaloObject track loop
564
565}
566
567bool PFSubtractionTool::isEOverPFail(double expectedEnergy, double sigma, double clusterEnergy) const
568{
569 if ((expectedEnergy == 0) && (clusterEnergy > 0)) return false;
570 return clusterEnergy < expectedEnergy - m_consistencySigmaCut * sigma;
571}
572
573bool PFSubtractionTool::canAnnihilate(double expectedEnergy, double sigma, double clusterEnergy) const
574{
575 return clusterEnergy - expectedEnergy < m_subtractionSigmaCut * sigma;
576}
577
579 std::stringstream result;
580 result << " track with E, eta and phi "<< track->e() << ", " << track->eta() << " and " << track->phi();
581 return result.str();
582}
583
585 std::stringstream result;
586 result << " cluster with E, eta and phi of " << cluster->e() << ", " << cluster->eta() << " and " << cluster->phi();
587 return result.str();
588}
589
590void PFSubtractionTool::printAllClusters(const eflowRecClusterContainer& recClusterContainer) const {
591
592 for ( const auto *thisEFRecCluster : recClusterContainer){
593 if (thisEFRecCluster->getTrackMatches().empty()) {
594 ATH_MSG_DEBUG("Isolated" << printCluster(thisEFRecCluster->getCluster()));
595 } else {
596 ATH_MSG_DEBUG("Matched" << printCluster(thisEFRecCluster->getCluster()));
597 std::vector<eflowTrackClusterLink*> theTrackLinks = thisEFRecCluster->getTrackMatches();
598 for ( auto *thisTrack : theTrackLinks){
599 ATH_MSG_DEBUG("Matched" << printTrack(thisTrack->getTrack()->getTrack()));
600 }
601 }
602 }
603}
604
605void PFSubtractionTool::addSubtractedCells(eflowCaloObject& thisEflowCaloObject, const std::vector<std::pair<xAOD::CaloCluster *, bool> >& clusterList) const{
606
607 unsigned int numTracks = thisEflowCaloObject.nTracks();
608 const std::string allCaloStr{"AllCalo"};
609 for (unsigned int iTrack = 0; iTrack < numTracks; ++iTrack){
610 eflowRecTrack* thisTrack = thisEflowCaloObject.efRecTrack(iTrack);
611 for (const auto& thisPair : clusterList){
612 xAOD::CaloCluster* thisCluster = thisPair.first;
613 const CaloClusterCellLink* theCellLink = thisCluster->getCellLinks();
614 CaloClusterCellLink::const_iterator theCell = theCellLink->begin();
615 CaloClusterCellLink::const_iterator lastCell = theCellLink->end();
616 for (; theCell != lastCell; ++theCell) thisTrack->addSubtractedCaloCell(ElementLink<CaloCellContainer>(allCaloStr,theCell.index()),theCell.weight()/numTracks);
617 }
618 }
619}
620
621StatusCode PFSubtractionTool::finalize() { return StatusCode::SUCCESS; }
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Handle class for reading a decoration on an object.
ElementLink< xAOD::TruthParticleContainer > TruthLink
double energy() const
get energy (data member)
Definition CaloCell.h:327
static void calculateKine(xAOD::CaloCluster *clu, const bool useweight=true, const bool updateLayers=true, const bool useGPUCriteria=false)
Helper class to calculate cluster kinematics based on cells.
static void fillClustersToRecover(PFData &data)
static void fillClustersToConsider(PFData &data, eflowRecClusterContainer &recClusterContainer)
static std::unique_ptr< IPositionProvider > Get(const std::string &positionType)
std::unique_ptr< PFMatch::TrackEtaPhiInFixedLayersProvider > m_trkpos
Track position provider to be used to preselect clusters.
Gaudi::Property< bool > m_useNNEnergy
Toggle whether we use the neural net energy.
PFSubtractionEnergyRatioCalculator m_pfSubtractionEnergyRatioCalculator
ToolHandle< IEFlowCellEOverPTool > m_theEOverPTool
Tool for getting e/p values and hadronic shower cell ordering principle parameters.
ToolHandle< PFTrackClusterMatchingTool > m_theMatchingTool
Default track-cluster matching tool.
void performTruthSubtraction(PFData &data) const
ToolHandle< PFEnergyPredictorTool > m_NNEnergyPredictorTool
Tool for getting predictiing the energy using an ONNX model.
Gaudi::Property< double > m_subtractionSigmaCut
Parameter that controls whether to use retain remaining calorimeter energy in track-cluster system,...
Gaudi::Property< double > m_consistencySigmaCut
Parameter that controls whether a track, in a track-cluster system, will be processed by the split sh...
void printAllClusters(const eflowRecClusterContainer &recClusterContainer) const
Gaudi::Property< bool > m_useFullCellTruthSubtraction
Toggle whether we fully remove a cell with a truth deposit or reweight it based on truth contribution...
void addSubtractedCells(eflowCaloObject &thisEflowCaloObject, const std::vector< std::pair< xAOD::CaloCluster *, bool > > &clusterList) const
eflowSubtract::Subtractor m_subtractor
SG::ReadDecorHandleKey< xAOD::CaloClusterContainer > m_caloClusterReadDecorHandleKeyNLeadingTruthParticles
Read handle key to decorate CaloCluster with threeN leading truth particle uniqueID and energy.
Gaudi::Property< int > m_nClusterMatchesToUse
Number of clusters to match to each track if not doing recover split shower subtraction.
PFSubtractionStatusSetter m_pfSubtractionStatusSetter
Gaudi::Property< bool > m_useTruthMatching
Toggle whether to cheat and use truth information for track-cluster matching - only for performance s...
bool canAnnihilate(double expectedEnergy, double sigma, double clusterEnergy) const
Gaudi::Property< bool > m_addCPData
Toggle whether to decorate eflowRecTrack with addutional data for Combined Performance studies.
void execute(const EventContext &ctx, eflowCaloObjectContainer *theEflowCaloObjectContainer, eflowRecTrackContainer *recTrackContainer, eflowRecClusterContainer *recClusterContainer) const
ToolHandle< PFSimulateTruthShowerTool > m_theTruthShowerSimulator
std::unique_ptr< eflowEEtaBinnedParameters > m_binnedParameters
PFSubtractionTool(const std::string &type, const std::string &name, const IInterface *parent)
static std::string printCluster(const xAOD::CaloCluster *cluster)
unsigned int matchAndCreateEflowCaloObj(const EventContext &ctx, PFData &data) const
This matches ID tracks and CaloClusters, and then creates eflowCaloObjects.
Gaudi::Property< bool > m_calcEOverP
Toggle EOverP algorithm mode, whereby no charged shower subtraction is performed.
Gaudi::Property< bool > m_useTruthForChargedShowerSubtraction
Toggle whether we use truth information for the charged shower subtraction or not.
ToolHandle< PFTrackClusterMatchingTool > m_theMatchingToolForPull_02
Gaudi::Property< bool > m_useLegacyEBinIndex
Further discussion about why this flag exists can be found in https://its.cern.ch/jira/browse/ATLJETM...
Gaudi::Property< bool > m_recoverSplitShowers
Toggle whether we are recovering split showers or not.
ToolHandle< PFTrackClusterMatchingTool > m_theMatchingToolForPull_015
static std::string printTrack(const xAOD::TrackParticle *track)
Gaudi::Property< bool > m_isHLLHC
Toggle whether we have the HLLHC setup.
void performSubtraction(unsigned int startingPoint, PFData &data) const
bool isEOverPFail(double expectedEnergy, double sigma, double clusterEnergy) const
static void fillTracksToConsider(PFData &data, eflowRecTrackContainer &recTrackContainer)
static void fillTracksToRecover(PFData &data)
Helper class to provide type-safe access to aux data.
Handle class for reading a decoration on an object.
static unsigned int makeTrkCluCaloObjects(eflowRecTrackContainer *eflowTrackContainer, eflowRecClusterContainer *eflowClusterContainer, eflowCaloObjectContainer *caloObjectContainer)
An internal EDM object which stores information about systems of associated tracks and calorimeter cl...
void simulateShower(const EventContext &ctx, eflowLayerIntegrator *integrator, const eflowEEtaBinnedParameters *binnedParameters, const PFEnergyPredictorTool *energyP, bool useLegacyEnergyBinIndexing)
double getExpectedVariance() const
double getClusterEnergy() const
unsigned nClusters() const
const eflowRecTrack * efRecTrack(int i) const
const std::vector< std::pair< eflowTrackClusterLink *, std::pair< float, float > > > & efRecLink() const
unsigned nTracks() const
double getExpectedEnergy() const
const eflowRecCluster * efRecCluster(int i) const
Inherits from eflowEEtaBinBase.
This class calculates the LHED (Layer of Highest Energy Density) in a cluster or group of clusters.
This class extends the information about a xAOD::CaloCluster.
void addTrackMatch(eflowTrackClusterLink *trackMatch)
xAOD::CaloCluster * getCluster()
This class extends the information about a xAOD::Track.
double getEExpect() const
const std::vector< eflowTrackClusterLink * > & getClusterMatches() const
bool isSubtracted() const
const xAOD::TrackParticle * getTrack() const
void addSubtractedCaloCell(ElementLink< CaloCellContainer > theCellLink, const double &weight)
bool hasBin() const
double getCellTruthEnergy(const CaloCell *cell) const
bool isInDenseEnvironment() const
double getVarEExpect() const
static void annihilateClusters(std::vector< std::pair< xAOD::CaloCluster *, bool > > &clusters)
void setRawEta(flt_t)
Set for signal state UNCALIBRATED.
flt_t rawE() const
void setRawPhi(flt_t)
Set for signal state UNCALIBRATED.
const CaloClusterCellLink * getCellLinks() const
Get a pointer to the CaloClusterCellLink object (const version).
virtual double pt() const
The transverse momentum ( ) of the particle (negative for negative-energy clusters).
void setRawE(flt_t)
Set Energy for signal state UNCALIBRATED.
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double e() const
The total energy of the particle.
virtual double phi() const
The azimuthal angle ( ) of the particle.
CaloClusterCellLink * getOwnCellLinks()
Get a pointer to the owned CaloClusterCellLink object (non-const version).
bool removeCell(const CaloCell *ptr)
Method to remove a cell to the cluster (slow!) (Beware: Kinematics not updated!).
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .).
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
virtual double e() const override final
The total energy of the particle.
static std::string release
Definition computils.h:50
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
int uniqueID(const T &p)
STL namespace.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TruthParticle_v1 TruthParticle
Typedef to implementation.
MsgStream & msg
Definition testRead.cxx:32