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