ATLAS Offline Software
Loading...
Searching...
No Matches
ParticleCaloCellAssociationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
17#include <cmath>
18#include <memory>
19namespace Rec {
20
22 const std::string& t,
23 const std::string& n,
24 const IInterface* p)
25 : AthAlgTool(t, n, p)
27{
28 declareInterface<IParticleCaloCellAssociationTool>(this);
29}
30
32
33StatusCode
35{
36 /* Retrieve track extrapolator from ToolService */
38
39 m_defaultSelector.setConeSize(m_coneSize);
40
41 if (!m_cellContainerName.key().empty()) {
42 ATH_CHECK(m_cellContainerName.initialize());
43 }
44
45 ATH_CHECK(m_caloMgrKey.initialize());
46 return StatusCode::SUCCESS;
47}
48
49StatusCode
51{
52 return StatusCode::SUCCESS;
53}
54
55std::unique_ptr<ParticleCellAssociation>
57 const xAOD::IParticle& particle,
58 float dr,
59 const CaloCellContainer* container,
60 const CaloExtensionCollection* extensionCache) const
61{
62 ATH_MSG_DEBUG(" particleCellAssociation: ptr " << &particle << " dr " << dr);
63 // get the extrapolation into the calo
64 std::unique_ptr<const Trk::CaloExtension> caloExtensionUPtr;
65 const Trk::CaloExtension* caloExtension = nullptr;
66 if (extensionCache)
67 caloExtension =
68 m_caloExtensionTool->caloExtension(particle, *extensionCache);
69 else {
70 caloExtensionUPtr = m_caloExtensionTool->caloExtension(
71 Gaudi::Hive::currentContext(), particle);
72 caloExtension = caloExtensionUPtr.get();
73 }
74 if (!caloExtension) {
75 ATH_MSG_DEBUG("Failed to get calo extension");
76 return nullptr;
77 }
78 if (caloExtension->caloLayerIntersections().empty()) {
80 "Received a caloExtension object without track extrapolation");
81 return nullptr;
82 }
83 // retrieve the cell container if not provided, return false it retrieval
84 // failed
85 if (!container) {
86 if (m_cellContainerName.key().empty()) {
87 ATH_MSG_DEBUG("Failed to get calo cell container");
88 return nullptr;
89 }
91 container = &(*cccHdl);
92 }
93 std::vector<const CaloCell*> cells;
94 // update cone size in case it is smaller than the default
95 if (dr < m_coneSize) {
96 dr = m_coneSize;
97 }
98 associateCells(*container, *caloExtension, dr, cells);
99
100 // get cell intersections
102 getCellIntersections(*caloExtension, cells, cellIntersections);
103 if (!caloExtensionUPtr)
104 // Have to manually copy the calo extension object. Clearly the class
105 // wants to be shared through a shared_ptr but this clearly is not an
106 // option
107 caloExtensionUPtr = std::make_unique<Trk::CaloExtension>(
108 caloExtension->caloEntryLayerIntersection()
109 ? caloExtension->caloEntryLayerIntersection()->uniqueClone()
110 : nullptr,
111 caloExtension->muonEntryLayerIntersection()
112 ? caloExtension->muonEntryLayerIntersection()->uniqueClone()
113 : nullptr,
114 std::vector<Trk::CurvilinearParameters>(
115 caloExtension->caloLayerIntersections()));
116 return std::make_unique<ParticleCellAssociation>(caloExtensionUPtr.release(),
117 std::move(cells),
118 dr,
119 std::move(cellIntersections),
120 container);
121}
122
125 const xAOD::IParticle& particle,
126 float dr,
128 const CaloCellContainer* container,
129 const CaloExtensionCollection* extensionCache) const
130{
131 /*if not there , default ctor for unique_ptr (nullptr)*/
132 std::unique_ptr<ParticleCellAssociation>& association =
133 cache[particle.index()];
134 if (association == nullptr) {
135 association =
136 particleCellAssociation(particle, dr, container, extensionCache);
137 }
138 return association.get();
139}
140
141void
143 const Trk::CaloExtension& extension,
144 const std::vector<const CaloCell*>& cells,
145 ParticleCellAssociation::CellIntersections& cellIntersections) const
146{
147 // use 3D pathlength in cells
148
149 constexpr bool use3D = true;
150
151 cellIntersections.reserve(extension.caloLayerIntersections().size() * 1.3);
152
154 CaloExtensionHelpers::entryExitLayerMap(extension, entryExitLayerMap);
155 ATH_MSG_DEBUG("EntryExitLayerMap " << entryExitLayerMap.size());
156
157 CaloExtensionHelpers::ScalarLayerMap eLossLayerMap, pathLenLayerMap;
158 CaloExtensionHelpers::eLossLayerMap(extension, eLossLayerMap);
159 CaloExtensionHelpers::pathLenLayerMap(extension, pathLenLayerMap);
160
161 ATH_MSG_DEBUG("Getting cells intersections using cells " << cells.size());
162 for (const auto* cell : cells) {
163 // get sampling and look up entry/exit points
164 CaloSampling::CaloSample sample = cell->caloDDE()->getSampling();
165
166 auto pos = entryExitLayerMap.find(sample);
167 if (pos == entryExitLayerMap.end())
168 continue;
169 //
170 // pos2 and weight2 are introduced because the PreSamplerB has sometimes a
171 // very small size
172 // PresamplerB and EMB1 are merged
173 //
174 auto pos2 = pos;
175 if (sample == CaloSampling::PreSamplerB) {
176 pos2 = entryExitLayerMap.find(CaloSampling::EMB1);
177 if (pos2 == entryExitLayerMap.end()) {
178 pos2 = pos;
179 }
180 }
182 double path = 0.;
183
184 double drFix = cell->caloDDE()->dr();
185 double dzFix = cell->caloDDE()->dz();
186 // double dphi = cell->caloDDE()->dphi();
187
188 int isample = cell->caloDDE()->getSampling();
189 bool barrel = false;
190 if (cell->caloDDE()->getSubCalo() == CaloCell_ID::TILE)
191 barrel = true;
192 if (sample == CaloSampling::PreSamplerB || sample == CaloSampling::EMB1 ||
193 sample == CaloSampling::EMB2 || sample == CaloSampling::EMB3)
194 barrel = true;
195
196 double drTG = fabs((pos->second.first - pos2->second.second).perp());
197 double dzTG = fabs((pos->second.first - pos2->second.second).z());
198
199 if (barrel)
200 ATH_MSG_VERBOSE(" barrel cell sampling "
201 << cell->caloDDE()->getSampling() << " dr "
202 << cell->caloDDE()->dr() << " drTG " << drTG);
203 if (!barrel)
204 ATH_MSG_VERBOSE(" endcap cell sampling "
205 << cell->caloDDE()->getSampling() << " dz "
206 << cell->caloDDE()->dz() << " dzTG " << dzTG);
207
208 if (drFix == 0.) {
209 // recalculate the r values from the other cells
210 // BUG/FEATURE: extract dr from cell container for sampling 4 5 6 7 needed
211 // EME BUG/FEATURE: extract dr from cell container for sampling 8 9 10 11
212 // needed HEC
213 if (cell->caloDDE()->deta() > 0) {
214 double theta = atan2(cell->caloDDE()->r(), cell->z());
215 double dtheta =
216 2 * cell->caloDDE()->deta() * sin(theta / 2.) * cos(theta / 2);
217 if (theta + dtheta < M_PI) {
218 double dr =
219 fabs(cell->z() * tan(theta + dtheta) - cell->z() * tan(theta));
220 drFix = fabs(dr);
221 double detaCheck =
222 -log(tan((theta + dtheta) / 2.)) + log(tan((theta) / 2.));
223 ATH_MSG_VERBOSE(" FIX cell sampling "
224 << cell->caloDDE()->getSampling() << " deta "
225 << cell->caloDDE()->deta() << " detaCheck "
226 << detaCheck << " drFix " << drFix);
227 } else {
228 ATH_MSG_WARNING(" FIXR cell sampling failed: theta "
229 << theta << " dtheta " << dtheta << " sum/pi "
230 << (theta + dtheta) * M_1_PI << " deta "
231 << cell->caloDDE()->deta());
232 }
233 // ATH_MSG_VERBOSE(" FIX cell sampling deta " << deta << "
234 // dtheta " << dtheta << " scale " << scale << " theta " <<
235 // theta );
236 } else {
237 double drMin = 100000.;
238 int dscut = 1;
239 if (!barrel)
240 dscut = 0;
241 const CaloCell* cellFound = nullptr;
242 for (const auto* celln : cells) {
243 if (cell == celln)
244 continue;
245 if (cell->caloDDE()->getSubCalo() == celln->caloDDE()->getSubCalo()) {
246 int dsample = isample - celln->caloDDE()->getSampling();
247 if (abs(dsample) == dscut) {
248 double drNew = fabs(cell->caloDDE()->r() - celln->caloDDE()->r());
249 if (drNew < 1)
250 continue;
251 if (drNew < drMin) {
252 drMin = drNew;
253 cellFound = celln;
254 }
255 }
256 }
257 }
258 drFix = drMin;
259 ATH_MSG_VERBOSE(" Problem cell sampling "
260 << cell->caloDDE()->getSampling() << " x "
261 << cell->caloDDE()->x() << " y " << cell->caloDDE()->y()
262 << " z " << cell->caloDDE()->z() << " dr "
263 << cell->caloDDE()->dr() << " drFix " << drFix
264 << " drTG " << drTG);
265 if (cellFound)
266 ATH_MSG_VERBOSE(" cellFound sampling "
267 << cellFound->caloDDE()->getSampling() << " x "
268 << cellFound->caloDDE()->x() << " y "
269 << cellFound->caloDDE()->y() << " z "
270 << cellFound->caloDDE()->z() << " dr "
271 << cellFound->caloDDE()->dr() << " dscut " << dscut
272 << " drFix " << drFix);
273 }
274 }
275
276 if (dzFix == 0.) {
277 // recalculate z values from the other cells
278 // BUG/FEATURE: extract dz from cell container for sampling 0 1 2 3 needed
279 // EMB
280 if (cell->caloDDE()->deta() > 0) {
281 double theta = atan2(cell->caloDDE()->r(), cell->z());
282 double dtheta =
283 2 * cell->caloDDE()->deta() * sin(theta / 2.) * cos(theta / 2);
284 if (theta + dtheta < M_PI) {
285 double dz = fabs(cell->caloDDE()->r() / tan(theta + dtheta) -
286 cell->caloDDE()->r() / tan(theta));
287 dzFix = dz;
288 } else {
289 ATH_MSG_WARNING(" FIXZ cell sampling failed: theta "
290 << theta << " dtheta " << dtheta << " sum/pi "
291 << (theta + dtheta) * M_1_PI << " deta "
292 << cell->caloDDE()->deta());
293 }
294 double detaCheck =
295 -log(tan((theta + dtheta) / 2.)) + log(tan((theta) / 2.));
296 ATH_MSG_VERBOSE(" Fix cell sampling "
297 << cell->caloDDE()->getSampling() << " deta "
298 << cell->caloDDE()->deta() << " detaCheck "
299 << detaCheck << " dtheta " << dtheta << " dzFix "
300 << dzFix);
301 } else {
302 double dzMin = 100000.;
303 int dscut = 1;
304 if (barrel)
305 dscut = 0;
306 const CaloCell* cellFound = nullptr;
307 for (const auto* celln : cells) {
308 if (cell == celln)
309 continue;
310 if (cell->caloDDE()->getSubCalo() == celln->caloDDE()->getSubCalo()) {
311 int isample2 = celln->caloDDE()->getSampling();
312 if (abs(isample - isample2) == dscut) {
313 double dzNew = fabs(cell->caloDDE()->z() - celln->caloDDE()->z());
314 if (dzNew < 1)
315 continue;
316 if (dzNew < dzMin) {
317 dzMin = dzNew;
318 cellFound = celln;
319 }
320 }
321 }
322 }
323 dzFix = dzMin;
324 ATH_MSG_VERBOSE(" Problem cell sampling "
325 << cell->caloDDE()->getSampling() << " x "
326 << cell->caloDDE()->x() << " y " << cell->caloDDE()->y()
327 << " z " << cell->caloDDE()->z() << " dz "
328 << cell->caloDDE()->dz() << " dzFix " << dzFix
329 << " dzTG " << dzTG);
330 if (cellFound)
331 ATH_MSG_VERBOSE(" cellFound sampling "
332 << cellFound->caloDDE()->getSampling() << " x "
333 << cellFound->caloDDE()->x() << " y "
334 << cellFound->caloDDE()->y() << " z "
335 << cellFound->caloDDE()->z() << " dz "
336 << cellFound->caloDDE()->dz() << " dscut " << dscut
337 << " dzFix " << dzFix);
338 }
339 }
340 //
341 // always use fixed values that correspond to the Calorimeter Tracking
342 // Geometry these are different from the CaloCell values
343 //
344
345 if (cell->energy() > 50.)
346 ATH_MSG_DEBUG(" cell sampling and size "
347 << cell->caloDDE()->getSampling() << " cell energy "
348 << cell->energy() << " dzFix " << dzFix << " dzTG " << dzTG
349 << " drFix " << drFix << " drTG " << drTG << " barrel "
350 << barrel);
351
352 if (!barrel)
353 dzFix = dzTG;
354 if (barrel)
355 drFix = drTG;
356
357 if (use3D) {
358 // m_pathLenUtil.pathInsideCell( *cell, entryExitLayerMap);
359 double pathInMM = PathLengthUtils::get3DPathLength(
360 *cell, pos->second.first, pos2->second.second, drFix, dzFix);
361 double totpath = (pos->second.first - pos2->second.second).mag();
362 path = totpath != 0 ? pathInMM / totpath : 0.;
363 if (path > 0 || cell->energy() > 50.) {
364 ATH_MSG_DEBUG(" cell sampling and size "
365 << cell->caloDDE()->getSampling() << " cell energy "
366 << cell->energy() << " drFix " << drFix << " dzFix "
367 << dzFix << " path " << path << " length TG " << totpath);
368 ATH_MSG_DEBUG(" cell dr " << cell->caloDDE()->dr() << " cell dz "
369 << cell->caloDDE()->dz() << " deta "
370 << cell->caloDDE()->deta());
371 }
372 }
373
375 double path2 = 0.;
376
377 if (!use3D)
378 path2 = pathInsideCell(*cell, pos->second.first, pos2->second.second);
379
380 if (path2 <= 0. && path <= 0.)
381 continue;
382
383 // auto entrancePair = entryExitLayerMap.find(entranceID);
384 auto eLossPair = eLossLayerMap.find(sample);
385 double eLoss = 0.;
386 //
387 // Just store total expected eloss
388 //
389 if (eLossPair != eLossLayerMap.end()) {
390 eLoss = eLossPair->second;
391 if (sample == CaloSampling::PreSamplerB) {
392 auto eLossPair2 = eLossLayerMap.find(CaloSampling::EMB1);
393 if (eLossPair2 != eLossLayerMap.end()) {
394 eLoss = 0.5 * (eLossPair->second) + 0.5 * (eLossPair2->second);
395 }
396 } else if (sample == CaloSampling::EMB1) {
397 auto eLossPair2 = eLossLayerMap.find(CaloSampling::PreSamplerB);
398 if (eLossPair2 != eLossLayerMap.end()) {
399 eLoss = 0.5 * (eLossPair->second) + 0.5 * (eLossPair2->second);
400 }
401 }
402 } // IF
403
404 ATH_MSG_DEBUG(" PATH3D = "
405 << path << " PATH2D = " << path2 << " eLoss " << eLoss
406 << " cell energy " << (cell)->energy() << " radius "
407 << cell->caloDDE()->r() << " phi " << cell->caloDDE()->phi()
408 << " dr " << cell->caloDDE()->dr() << " dphi "
409 << cell->caloDDE()->dphi() << " x " << cell->caloDDE()->x()
410 << " y " << cell->caloDDE()->y() << " z "
411 << cell->caloDDE()->z() << " dx " << cell->caloDDE()->dx()
412 << " dy " << cell->caloDDE()->dy() << " dz "
413 << cell->caloDDE()->dz() << " volume "
414 << cell->caloDDE()->volume());
415
416 cellIntersections.emplace_back(
417 cell, new ParticleCellIntersection(*cell, eLoss, use3D ? path : path2));
418 }
419 ATH_MSG_DEBUG(" added cell intersections " << cellIntersections.size());
420}
421
422void
424 const CaloCellContainer& container,
425 const Trk::CaloExtension& caloExtension,
426 float dr,
427 std::vector<const CaloCell*>& cells) const
428{
429 const Trk::TrackParameters* pars = caloExtension.caloEntryLayerIntersection();
430 if (!pars) {
431 ATH_MSG_DEBUG("associateCells() - NO TrackParameters found in "
432 "caloExtension.caloEntryLayerIntersection()");
433 return;
434 }
435
436 double eta = pars->position().eta();
437 double phi = pars->position().phi();
438
439 // Use Calorimeter list for CPU reasons
441 const CaloDetDescrManager* caloMgr=*caloMgrHandle;
442 CaloCellList myList(caloMgr,&container);
443 myList.select(eta, phi, dr);
444 cells.reserve(myList.ncells());
445 cells.insert(cells.end(), myList.begin(), myList.end());
446 ATH_MSG_DEBUG("associated cells " << cells.size() << " using cone " << dr);
447}
448
449} // namespace Rec
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
Scalar theta() const
theta method
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
double pathInsideCell(const CaloCell &cell, const Amg::Vector3D &entry, const Amg::Vector3D &exit)
Return the % of the path crossed inside the cell, given the parameters for the extrapolation at entra...
DataVector< Trk::CaloExtension > CaloExtensionCollection
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Container class for CaloCell.
list_iterator end() const
void select(double eta, double phi, double deta, double dphi)
int ncells() const
list_iterator begin() const
Data object for each calorimeter readout cell.
Definition CaloCell.h:57
const CaloDetDescrElement * caloDDE() const
get pointer to CaloDetDescrElement (data member)
Definition CaloCell.h:321
CaloCell_ID::CaloSample getSampling() const
cell sampling
This class provides the client interface for accessing the detector description information common to...
static double get3DPathLength(const CaloCell &cell, const Amg::Vector3D &entry, const Amg::Vector3D &exit, double drFix, double dzFix)
std::unordered_map< size_t, std::unique_ptr< ParticleCellAssociation > > Cache
Method to get the ParticleCellAssociation for a given Particle.
ToolHandle< Trk::IParticleCaloExtensionTool > m_caloExtensionTool
void associateCells(const CaloCellContainer &container, const Trk::CaloExtension &caloExtension, float dr, std::vector< const CaloCell * > &cells) const
ParticleCaloCellAssociationTool(const std::string &, const std::string &, const IInterface *)
SG::ReadHandleKey< CaloCellContainer > m_cellContainerName
SG::ReadCondHandleKey< CaloDetDescrManager > m_caloMgrKey
virtual std::unique_ptr< ParticleCellAssociation > particleCellAssociation(const xAOD::IParticle &particle, float dr, const CaloCellContainer *container=nullptr, const CaloExtensionCollection *extensionCache=nullptr) const override final
Method to get the ParticleCellAssociation for a given Particle.
virtual ~ParticleCaloCellAssociationTool() override
void getCellIntersections(const Trk::CaloExtension &caloExtension, const std::vector< const CaloCell * > &cells, ParticleCellAssociation::CellIntersections &cellIntersections) const
class storing calorimeter cell association with IParticle objects
std::vector< std::pair< const CaloCell *, ParticleCellIntersection * > > CellIntersections
typedef for vector of cell intersections
class storing information on the intersection of a track with a cell
Tracking class to hold the extrapolation through calorimeter Layers Both the caloEntryLayerIntersecti...
const std::vector< CurvilinearParameters > & caloLayerIntersections() const
access to the intersections with the calorimeter layers.
const TrackParameters * caloEntryLayerIntersection() const
access to intersection with the calorimeter entry layer return nullptr if the intersection failed
const TrackParameters * muonEntryLayerIntersection() const
access to intersection with the muon entry layer return nullptr if the intersection failed
const Amg::Vector3D & position() const
Access method for the position.
std::unique_ptr< ParametersBase< DIM, T > > uniqueClone() const
clone method for polymorphic deep copy returning unique_ptr; it is not overriden, but uses the existi...
Class providing the definition of the 4-vector interface.
void entryExitLayerMap(const Trk::CaloExtension &extension, EntryExitLayerMap &result, const LayersToSelect *selection=nullptr)
std::map< CaloSampling::CaloSample, double > ScalarLayerMap
void pathLenLayerMap(const Trk::CaloExtension &extension, ScalarLayerMap &result)
void eLossLayerMap(const Trk::CaloExtension &extension, ScalarLayerMap &result)
std::map< CaloSampling::CaloSample, std::pair< Amg::Vector3D, Amg::Vector3D > > EntryExitLayerMap
namespace for combined reconstruction tools and interfaces
ParametersBase< TrackParametersDim, Charged > TrackParameters