ATLAS Offline Software
Loading...
Searching...
No Matches
CaloClusterCorrectionCommon.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
10
18#include <cmath>
19#include <cassert>
20
21#include "GaudiKernel/MsgStream.h"
22#include "GaudiKernel/ThreadLocalContext.h"
23
26
27
28namespace {
29
30
39bool barrel_p (int region)
40{
41 switch (region) {
44 return true;
47 return false;
48 default:
49 abort();
50 }
51}
52
53
62int sampling (int region)
63{
64 switch (region) {
67 return 1;
70 return 2;
71 default:
72 abort();
73 }
74}
75
76
77} // anonymous namespace
78
79
80namespace CaloClusterCorr {
81
82
84{
85public:
87 DDHelper() = delete;
88
90 DDHelper (const CaloDetDescrManager* dd_man);
91
92
96 find_dd_elt (const CaloDetDescrManager* dd_mgr,
97 int region,
98 const xAOD::CaloCluster* cluster,
99 float eta,
100 float phi) const;
101
102
103private:
105 static const CaloDetDescrElement* find_dd_elt1 (const CaloDetDescrManager* dd_mgr,
106 int region,
107 const CaloCluster* cluster,
108 float eta,
109 float phi) ;
110
111
115 int region,
116 float eta,
117 float phi) const;
118
119
120 static const CaloDetDescrElement* dd_try_gap (const CaloDetDescrManager* dd_man,
121 int region,
122 const CaloCluster* cluster,
123 float eta,
124 float phi) ;
125
126
128 void make_dummy_elts(const CaloDetDescrManager* dd_man);
129
130
132 std::vector<std::unique_ptr<const CaloDetDescrElement> > m_dummy_elts;
133};
134
135
141{
142 make_dummy_elts(dd_man);
143}
144
145
166 int region,
167 const CaloCluster* cluster,
168 float eta,
169 float phi) const
170{
171 const CaloDetDescrElement* elt = nullptr;
172 float eta_offs = 0;
173 float phi_offs = 0;
174 int n = 0;
175 int good = 0;
176
177 while (good != 2) {
178 elt = find_dd_elt1 (dd_man,region, cluster,
179 eta + eta_offs, CaloPhiRange::fix (phi + phi_offs));
180
181 if (!elt) {
182 elt = dd_inner_strip_fixup (dd_man,region, eta, phi);
183 if (elt) return elt;
184 elt = dd_try_gap (dd_man,region, cluster, eta, phi);
185 return elt;
186 }
187
188 // Don't do this more than twice.
189 // Originally, we were aborting if we couldn't find a good element
190 // after two passes. However, it turns out that there are some
191 // small gaps between the @f$\eta@f$ ranges of adjacent cells, so if
192 // we demanded that the @f$\eta@f$ we provide be within the
193 // @f$\eta@f$ range of the element we return, we wouldn't succeed.
194 // Downstream code will just have to Deal With It.
195 if (++n >= 2)
196 return elt;
197
198 float deta = elt->deta();
199 float dphi = elt->dphi();
200
201 good = 0;
202
203 if (eta > elt->eta() + deta/2)
204 eta_offs += deta/2;
205 else if (eta < elt->eta() - deta/2)
206 eta_offs -= deta/2;
207 else
208 ++good;
209
210 // Assume that cells don't wrap around the phi boundary...
211 if (phi > elt->phi() + dphi/2)
212 phi_offs += dphi/2;
213 else if (phi < elt->phi() - dphi/2)
214 phi_offs -= dphi/2;
215 else
216 ++good;
217
218 if (good != 2 && n == 1) {
219 elt = dd_inner_strip_fixup (dd_man,region, eta, phi);
220 if (elt) break;
221 }
222 }
223
224 return elt;
225}
226
227
240 int region,
241 const CaloCluster* cluster,
242 float eta,
243 float phi)
244{
245 const CaloDetDescrElement* elt = nullptr;
246
247 // Decode the region.
248 switch (region) {
253 // Simple case, it's a specific sampling.
254 elt = dd_man->get_element
255 (CaloCell_ID::LAREM, sampling (region), barrel_p (region), eta, phi);
256 break;
257
260 // We're combining both the barrel and endcap.
261 // Look for elements in both.
262 // If we actually get both, make the decision by choosing
263 // the one with the most energy in sampling 2.
264 {
265 const CaloDetDescrElement* elt_b = dd_man->get_element
266 (CaloCell_ID::LAREM, 2, true, eta, phi);
267 const CaloDetDescrElement* elt_e = dd_man->get_element
268 (CaloCell_ID::LAREM, 2, false, eta, phi);
269
270 if (elt_b == nullptr)
271 elt = elt_e;
272 else if (elt_e == nullptr)
273 elt = elt_b;
274 else if (cluster->eSample (CaloSampling::EMB2) >
275 cluster->eSample (CaloSampling::EME2))
276 elt = elt_b;
277 else
278 elt = elt_e;
279 }
280 break;
281 default:
282 abort();
283 }
284
285 return elt;
286}
287
288
308 int region,
309 float eta,
310 float phi) const
311{
312 if (region == CaloClusterCorrectionCommon::EMB1 && fabs(eta) < 0.1) {
313 const CaloDetDescriptor* descr =
315 1, true, eta, phi);
316 if (!descr) return nullptr;
317 int ieta = descr->eta_channel (eta);
318 if (ieta == 0) {
319 // If we get here, then we're looking at one of the problematic cells.
320 int iphi = descr->phi_channel (phi);
321 if (iphi < 0) return nullptr;
322 unsigned int index = iphi;
323 if (eta < 0)
324 index += descr->n_phi();
325 if (m_dummy_elts.size() <= index)
326 return nullptr;
327 return m_dummy_elts[index].get();
328 }
329 }
330
331 return nullptr;
332}
333
334
337 int region,
338 const CaloCluster* cluster,
339 float eta,
340 float phi)
341{
342 const CaloDetDescrElement* elt1 = find_dd_elt1 (dd_man,region, cluster,
343 eta + 1e-4, phi);
344 if (!elt1) return nullptr;
345 const CaloDetDescrElement* elt2 = find_dd_elt1 (dd_man,region, cluster,
346 eta - 1e-4, phi);
347 if (!elt2) return nullptr;
348 if (eta > 0)
349 return elt2;
350 return elt1;
351}
352
353
358{
360 1, true, 0.05, 0);
361 if (descr) {
362 int nphi = descr->n_phi();
363 m_dummy_elts.resize (nphi*2);
364 for (int etasgn = 1; etasgn >= -1; etasgn -= 2) {
365 for (int iphi = 0; iphi < nphi; iphi++) {
366 // Make a new dummy cell.
367 // First, try to find the adjacent strip. Punt if we can't
368 // find _that_!
369 const CaloCell_ID* cellid_mgr = dd_man->getCaloCell_ID();
370 Identifier cellId2 = cellid_mgr->cell_id (descr->identify(),
371 1, iphi);
372 IdentifierHash cellIdHash2 = cellid_mgr->calo_cell_hash (cellId2);
373 // Verify that we don't have another nonexistent cell!
374 if (cellid_mgr->cell_id (cellIdHash2) != cellId2)
375 continue;
376 const CaloDetDescrElement* elt2 = dd_man->get_element (cellIdHash2);
377 if (!elt2) continue;
378
379 auto elt = std::make_unique<DummyDetDescrElement>
380 (descr->subcalo_hash(),
381 0,
382 0,
383 descr);
384
385 // Copy geometry from the adjacent cell, shifting eta.
386 elt->set_cylindric_size (elt2->deta(),
387 elt2->dphi(),
388 elt2->dr());
389 elt->set_cylindric (elt2->eta() - etasgn * elt2->deta(),
390 elt2->phi(),
391 elt2->r());
392 elt->set_cylindric_raw (elt2->eta_raw() - etasgn * elt2->deta(),
393 elt2->phi_raw(),
394 elt2->r_raw());
395
396 int index = iphi;
397 if (etasgn < 0) index += nphi;
398 m_dummy_elts[index] = std::move(elt);
399 }
400 }
401 }
402}
403
404
405} // namespace CaloClusterCorr
406
407
409 const std::string& name,
410 const IInterface* parent)
411 : CaloClusterCorrection (type, name, parent)
412{
413}
414
415
422
423
437 CaloCluster* cluster) const
438{
439 int region = m_region (myctx);
440
442 const CaloDetDescrManager* dd_man = *caloMgrHandle;
443
444 // This causes a lot of overhead (mostly from the MsgStream ctor).
445 // Comment out when not needed.
446 //MsgStream log( msgSvc(), name() );
447 //log << MSG::DEBUG << "Entering makeCorrection" << endmsg;
448 //log << MSG::DEBUG << "e, eta, phi, etasize, phisize" << " " << cluster->e() << " " << cluster->eta() << " " << cluster->phi()
449 // << " " << cluster->etasize(CaloSampling::EMB2) << " " << cluster->phisize(CaloSampling::EMB2) << endmsg;
450 //log << MSG::DEBUG << "B / E " << cluster->inBarrel() << " " << cluster->inEndcap() << endmsg;
451 //log << MSG::DEBUG << "region " << region << endmsg;
452
453 float eta;
454 float phi;
455 CaloSampling::CaloSample samp = CaloSampling::Unknown;
456
457 // Find the proper @f$\eta@f$ and @f$\phi@f$ measures of the cluster.
458 // Also set up the sampling code @c samp.
459 switch (region) {
460 case EMB1:
461 case EMB2:
462 case EME1:
463 case EME2:
464 // Return immediately if we can tell we're in the wrong region.
465 if (barrel_p (region)) {
466 if (!cluster->inBarrel()) return;
467 }
468 else {
469 if (!cluster->inEndcap()) return;
470 }
471
472 switch (region) {
473 case EMB1:
474 samp = CaloSampling::EMB1;
475 break;
476 case EMB2:
477 samp = CaloSampling::EMB2;
478 break;
479 case EME1:
480 samp = CaloSampling::EME1;
481 break;
482 case EME2:
483 samp = CaloSampling::EME2;
484 break;
485 }
486
487 eta = cluster->etaSample (samp);
488 phi = cluster->phiSample (samp);
489 break;
490
491 case COMBINED2:
492 eta = cluster->etaBE (2);
493 phi = cluster->phiBE (2);
494 break;
495
496 case CLUSTER:
497 eta = cluster->eta();
498 phi = cluster->phi();
499 break;
500
501 default:
502 abort();
503 }
504
505 // Give up if one of them is an error flag.
506 if (std::abs (phi) > 900 || std::abs (eta) > 900)
507 return;
508
509 // Sometimes unnormalized @f$\phi@f$ values still come through.
510 // Make sure this is in the proper range before calling the correction.
512
513 // Look up the DD element.
514 // Give up if we can't find one.
515 const CaloDetDescrElement* elt = ddhelper(dd_man).find_dd_elt (dd_man,
516 region,
517 cluster,
518 eta, phi);
519 if (!elt)
520 return;
521
522 // Compute the adjusted eta and phi --- the coordinates shifted
523 // from the actual to the nominal coordinate system.
524 float adj_eta = eta - elt->eta() + elt->eta_raw();
525 float adj_phi = CaloPhiRange::fix (phi - elt->phi() + elt->phi_raw());
526
527 // Call the actual correction.
528 makeTheCorrection (myctx, cluster, elt, eta, adj_eta, phi, adj_phi, samp);
529}
530
531
532namespace {
533
534
544inline
545void docalc (int i,
547 const CaloRec::Array<1>& energies,
549 int& n_good)
550{
551 corrtab[n_good][0] = energies[i];
552 bool good = false;
553 corrtab[n_good][1] = builder.calculate (i, good);
554 if (good)
555 ++n_good;
556}
557
558
559} // anonymous namespace
560
561
562
574float
576 const TableBuilder& builder,
577 const CaloRec::Array<1>&
578 energies,
579 int energy_degree)
580
581{
582 // Calculate the correction for each energy.
583 unsigned int n_energies = energies.size();
584 unsigned int shape[] = {n_energies, 2};
585 CaloRec::WritableArrayData<2> corrtab (shape);
586
587 // If we're outside the range of the table, we'll just be using the
588 // value at the end (no extrapolation). We only need to calculate
589 // that one point in that case.
590 unsigned int beg = 0;
591 unsigned int end = n_energies;
592 if (energy <= energies[0])
593 end = 1;
594 else if (energy >= energies[n_energies-1])
595 beg = n_energies-1;
596
597 // Build the table.
598 int n_good = 0;
599 for (unsigned int i=beg; i<end; i++)
600 docalc (i, builder, energies, corrtab, n_good);
601
602 // If we only evaluated one point, but it wasn't good, keep
603 // searching until we find a good one.
604 while (n_good == 0 && beg > 0) {
605 --beg;
606 docalc (beg, builder, energies, corrtab, n_good);
607 }
608 while (n_good == 0 && end < n_energies) {
609 docalc (end, builder, energies, corrtab, n_good);
610 ++end;
611 }
612
613 // Now interpolate in energy.
614 // But if we're outside of the range of the table, just use the value
615 // at the end (don't extrapolate).
616 if (n_good == 0) {
617 // No good energies --- return a null correction.
618 return 0;
619 }
620 else if (n_good == 1) {
621 // Only one good energy --- nothing to do but to use it.
622 return corrtab[0][1];
623 }
624 else if (energy <= corrtab[0][0]) {
625 // Off the low end of the table --- return the first value.
626 return corrtab[0][1];
627 }
628 else if (energy >= corrtab[n_good-1][0]) {
629 // Off the high end of the table --- return the last value.
630 return corrtab[n_good-1][1];
631 }
632
633 // Do the interpolation.
634 return interpolate (corrtab, energy, energy_degree,
635 1, CaloRec::Array<1>(), n_good);
636}
637
638
639
641{
643 if (!ddhelper) {
644 auto newhelper = std::make_unique<const CaloClusterCorr::DDHelper> (dd_man);
645 ddhelper = m_ddhelper.set (std::move (newhelper));
646 }
647 return *ddhelper;
648}
649
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
Definition of CaloDetDescrManager.
Definition of CaloDetDescriptor.
Calo Subsystem specific Detector Elements + Dummy element for testing.
CaloPhiRange class declaration.
IdentifierHash calo_cell_hash(const Identifier cellId) const
create hash id from 'global' cell id
Identifier cell_id(const int subCalo, const int barec_or_posneg, const int sampling_or_fcalmodule, const int region_or_dummy, const int eta, const int phi) const
Make a cell (== channel) ID from constituting fields and subCalo index; for (Mini)FCAL,...
Helper class for offline cell identifiers.
Definition CaloCell_ID.h:34
const CaloDetDescrElement * dd_inner_strip_fixup(const CaloDetDescrManager *dd_man, int region, float eta, float phi) const
Work around innermost strip problem.
const CaloDetDescrElement * find_dd_elt(const CaloDetDescrManager *dd_mgr, int region, const xAOD::CaloCluster *cluster, float eta, float phi) const
Find the detector descriptor element for a given position, correcting for DD edge bugs.
static const CaloDetDescrElement * find_dd_elt1(const CaloDetDescrManager *dd_mgr, int region, const CaloCluster *cluster, float eta, float phi)
Find the detector descriptor element for a given position.
void make_dummy_elts(const CaloDetDescrManager *dd_man)
Construct dummy DDEs used to work around innermost strip problem.
static const CaloDetDescrElement * dd_try_gap(const CaloDetDescrManager *dd_man, int region, const CaloCluster *cluster, float eta, float phi)
std::vector< std::unique_ptr< const CaloDetDescrElement > > m_dummy_elts
Collection of dummy elements.
DDHelper()=delete
delte default Constructor
Helper, used to calculate the values of the energy interpolation table.
static float energy_interpolation(float energy, const TableBuilder &builder, const CaloRec::Array< 1 > &energies, int energy_degree)
Many of the corrections use the same method for doing the final interpolation in energy.
virtual ~CaloClusterCorrectionCommon()
Destructor.
CaloClusterCorrectionCommon(const std::string &type, const std::string &name, const IInterface *parent)
Inherit constructor.
CxxUtils::CachedUniquePtr< const CaloClusterCorr::DDHelper > m_ddhelper
Helper for detector description lookup.
const CaloClusterCorr::DDHelper & ddhelper(const CaloDetDescrManager *dd_man) const
Retrieve the detector description helper, creating it if needed.
virtual void makeCorrection(const Context &myctx, xAOD::CaloCluster *cluster) const override
Perform the correction.
virtual void makeTheCorrection(const Context &myctx, xAOD::CaloCluster *cluster, const CaloDetDescrElement *elt, float eta, float adj_eta, float phi, float adj_phi, CaloSampling::CaloSample samp) const =0
Virtual function for the correction-specific code.
Constant< int > m_region
Calibration constant: The calorimeter region for which this correction is intended.
SG::ReadCondHandleKey< CaloDetDescrManager > m_caloMgrKey
Principal data class for CaloCell clusters.
double phiSample(sampling_type sampling) const
Retrieve barycenter in a given sample.
double etaBE(int sampling) const
EMB/EMEC combined barycenter .
double phiBE(int sampling) const
EMB/EMEC combined barycenter .
virtual double eta() const
Retrieve eta independent of signal state.
double etaSample(sampling_type sampling) const
Retrieve barycenter in a given sample.
bool inEndcap() const
Returns true if at least one clustered cell in EMEC.
virtual double phi() const
Retrieve phi independent of signal state.
bool inBarrel() const
Returns true if at least one clustered cell in EMB.
This class groups all DetDescr information related to a CaloCell.
const CaloDetDescrElement * get_element(const Identifier &cellId) const
get element by its identifier
const CaloDetDescriptor * get_descriptor(const Identifier &regionId) const
get descriptor by region identifier
This class provides the client interface for accessing the detector description information common to...
const CaloCell_ID * getCaloCell_ID() const
get calo cell ID helper
This is a base class for LAr and Tile Descriptors The primary goal is to speed up loops over all the ...
static double fix(double phi)
Read-only multidimensional array.
unsigned int size(unsigned int dim=0) const
Return the size of the array along one dimension.
Read-write multidimensional array.
This is a "hash" representation of an Identifier.
float eSample(const CaloSample sampling) const
Polynomial interpolation in a table.
float interpolate(const CaloRec::Array< 2 > &a, float x, unsigned int degree, unsigned int ycol=1, const CaloRec::Array< 1 > &regions=CaloRec::Array< 1 >(), int n_points=-1, bool fixZero=false)
Polynomial interpolation in a table.
Definition index.py:1
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
const EventContext & ctx() const