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
25
26
27namespace {
28
29
38bool barrel_p (int region)
39{
40 switch (region) {
43 return true;
46 return false;
47 default:
48 abort();
49 }
50}
51
52
61int sampling (int region)
62{
63 switch (region) {
66 return 1;
69 return 2;
70 default:
71 abort();
72 }
73}
74
75
76} // anonymous namespace
77
78
79namespace CaloClusterCorr {
80
81
83{
84public:
86 DDHelper() = delete;
87
89 DDHelper (const CaloDetDescrManager* dd_man);
90
91
95 find_dd_elt (const CaloDetDescrManager* dd_mgr,
96 int region,
97 const xAOD::CaloCluster* cluster,
98 float eta,
99 float phi) const;
100
101
102private:
104 static const CaloDetDescrElement* find_dd_elt1 (const CaloDetDescrManager* dd_mgr,
105 int region,
106 const CaloCluster* cluster,
107 float eta,
108 float phi) ;
109
110
114 int region,
115 float eta,
116 float phi) const;
117
118
119 static const CaloDetDescrElement* dd_try_gap (const CaloDetDescrManager* dd_man,
120 int region,
121 const CaloCluster* cluster,
122 float eta,
123 float phi) ;
124
125
127 void make_dummy_elts(const CaloDetDescrManager* dd_man);
128
129
131 std::vector<std::unique_ptr<const CaloDetDescrElement> > m_dummy_elts;
132};
133
134
140{
141 make_dummy_elts(dd_man);
142}
143
144
165 int region,
166 const CaloCluster* cluster,
167 float eta,
168 float phi) const
169{
170 const CaloDetDescrElement* elt = nullptr;
171 float eta_offs = 0;
172 float phi_offs = 0;
173 int n = 0;
174 int good = 0;
175
176 while (good != 2) {
177 elt = find_dd_elt1 (dd_man,region, cluster,
178 eta + eta_offs, CaloPhiRange::fix (phi + phi_offs));
179
180 if (!elt) {
181 elt = dd_inner_strip_fixup (dd_man,region, eta, phi);
182 if (elt) return elt;
183 elt = dd_try_gap (dd_man,region, cluster, eta, phi);
184 return elt;
185 }
186
187 // Don't do this more than twice.
188 // Originally, we were aborting if we couldn't find a good element
189 // after two passes. However, it turns out that there are some
190 // small gaps between the @f$\eta@f$ ranges of adjacent cells, so if
191 // we demanded that the @f$\eta@f$ we provide be within the
192 // @f$\eta@f$ range of the element we return, we wouldn't succeed.
193 // Downstream code will just have to Deal With It.
194 if (++n >= 2)
195 return elt;
196
197 float deta = elt->deta();
198 float dphi = elt->dphi();
199
200 good = 0;
201
202 if (eta > elt->eta() + deta/2)
203 eta_offs += deta/2;
204 else if (eta < elt->eta() - deta/2)
205 eta_offs -= deta/2;
206 else
207 ++good;
208
209 // Assume that cells don't wrap around the phi boundary...
210 if (phi > elt->phi() + dphi/2)
211 phi_offs += dphi/2;
212 else if (phi < elt->phi() - dphi/2)
213 phi_offs -= dphi/2;
214 else
215 ++good;
216
217 if (good != 2 && n == 1) {
218 elt = dd_inner_strip_fixup (dd_man,region, eta, phi);
219 if (elt) break;
220 }
221 }
222
223 return elt;
224}
225
226
239 int region,
240 const CaloCluster* cluster,
241 float eta,
242 float phi)
243{
244 const CaloDetDescrElement* elt = nullptr;
245
246 // Decode the region.
247 switch (region) {
252 // Simple case, it's a specific sampling.
253 elt = dd_man->get_element
254 (CaloCell_ID::LAREM, sampling (region), barrel_p (region), eta, phi);
255 break;
256
259 // We're combining both the barrel and endcap.
260 // Look for elements in both.
261 // If we actually get both, make the decision by choosing
262 // the one with the most energy in sampling 2.
263 {
264 const CaloDetDescrElement* elt_b = dd_man->get_element
265 (CaloCell_ID::LAREM, 2, true, eta, phi);
266 const CaloDetDescrElement* elt_e = dd_man->get_element
267 (CaloCell_ID::LAREM, 2, false, eta, phi);
268
269 if (elt_b == nullptr)
270 elt = elt_e;
271 else if (elt_e == nullptr)
272 elt = elt_b;
273 else if (cluster->eSample (CaloSampling::EMB2) >
274 cluster->eSample (CaloSampling::EME2))
275 elt = elt_b;
276 else
277 elt = elt_e;
278 }
279 break;
280 default:
281 abort();
282 }
283
284 return elt;
285}
286
287
307 int region,
308 float eta,
309 float phi) const
310{
311 if (region == CaloClusterCorrectionCommon::EMB1 && fabs(eta) < 0.1) {
312 const CaloDetDescriptor* descr =
314 1, true, eta, phi);
315 if (!descr) return nullptr;
316 int ieta = descr->eta_channel (eta);
317 if (ieta == 0) {
318 // If we get here, then we're looking at one of the problematic cells.
319 int iphi = descr->phi_channel (phi);
320 if (iphi < 0) return nullptr;
321 unsigned int index = iphi;
322 if (eta < 0)
323 index += descr->n_phi();
324 if (m_dummy_elts.size() <= index)
325 return nullptr;
326 return m_dummy_elts[index].get();
327 }
328 }
329
330 return nullptr;
331}
332
333
336 int region,
337 const CaloCluster* cluster,
338 float eta,
339 float phi)
340{
341 const CaloDetDescrElement* elt1 = find_dd_elt1 (dd_man,region, cluster,
342 eta + 1e-4, phi);
343 if (!elt1) return nullptr;
344 const CaloDetDescrElement* elt2 = find_dd_elt1 (dd_man,region, cluster,
345 eta - 1e-4, phi);
346 if (!elt2) return nullptr;
347 if (eta > 0)
348 return elt2;
349 return elt1;
350}
351
352
357{
359 1, true, 0.05, 0);
360 if (descr) {
361 int nphi = descr->n_phi();
362 m_dummy_elts.resize (nphi*2);
363 for (int etasgn = 1; etasgn >= -1; etasgn -= 2) {
364 for (int iphi = 0; iphi < nphi; iphi++) {
365 // Make a new dummy cell.
366 // First, try to find the adjacent strip. Punt if we can't
367 // find _that_!
368 const CaloCell_ID* cellid_mgr = dd_man->getCaloCell_ID();
369 Identifier cellId2 = cellid_mgr->cell_id (descr->identify(),
370 1, iphi);
371 IdentifierHash cellIdHash2 = cellid_mgr->calo_cell_hash (cellId2);
372 // Verify that we don't have another nonexistent cell!
373 if (cellid_mgr->cell_id (cellIdHash2) != cellId2)
374 continue;
375 const CaloDetDescrElement* elt2 = dd_man->get_element (cellIdHash2);
376 if (!elt2) continue;
377
378 auto elt = std::make_unique<DummyDetDescrElement>
379 (descr->subcalo_hash(),
380 0,
381 0,
382 descr);
383
384 // Copy geometry from the adjacent cell, shifting eta.
385 elt->set_cylindric_size (elt2->deta(),
386 elt2->dphi(),
387 elt2->dr());
388 elt->set_cylindric (elt2->eta() - etasgn * elt2->deta(),
389 elt2->phi(),
390 elt2->r());
391 elt->set_cylindric_raw (elt2->eta_raw() - etasgn * elt2->deta(),
392 elt2->phi_raw(),
393 elt2->r_raw());
394
395 int index = iphi;
396 if (etasgn < 0) index += nphi;
397 m_dummy_elts[index] = std::move(elt);
398 }
399 }
400 }
401}
402
403
404} // namespace CaloClusterCorr
405
406
408 const std::string& name,
409 const IInterface* parent)
410 : CaloClusterCorrection (type, name, parent)
411{
412}
413
414
421
422
436 CaloCluster* cluster) const
437{
438 int region = m_region (myctx);
439
440 SG::ReadCondHandle<CaloDetDescrManager> caloMgrHandle{m_caloMgrKey, myctx.ctx()};
441 const CaloDetDescrManager* dd_man = *caloMgrHandle;
442
443 // This causes a lot of overhead (mostly from the MsgStream ctor).
444 // Comment out when not needed.
445 //MsgStream log( msgSvc(), name() );
446 //log << MSG::DEBUG << "Entering makeCorrection" << endmsg;
447 //log << MSG::DEBUG << "e, eta, phi, etasize, phisize" << " " << cluster->e() << " " << cluster->eta() << " " << cluster->phi()
448 // << " " << cluster->etasize(CaloSampling::EMB2) << " " << cluster->phisize(CaloSampling::EMB2) << endmsg;
449 //log << MSG::DEBUG << "B / E " << cluster->inBarrel() << " " << cluster->inEndcap() << endmsg;
450 //log << MSG::DEBUG << "region " << region << endmsg;
451
452 float eta;
453 float phi;
454 CaloSampling::CaloSample samp = CaloSampling::Unknown;
455
456 // Find the proper @f$\eta@f$ and @f$\phi@f$ measures of the cluster.
457 // Also set up the sampling code @c samp.
458 switch (region) {
459 case EMB1:
460 case EMB2:
461 case EME1:
462 case EME2:
463 // Return immediately if we can tell we're in the wrong region.
464 if (barrel_p (region)) {
465 if (!cluster->inBarrel()) return;
466 }
467 else {
468 if (!cluster->inEndcap()) return;
469 }
470
471 switch (region) {
472 case EMB1:
473 samp = CaloSampling::EMB1;
474 break;
475 case EMB2:
476 samp = CaloSampling::EMB2;
477 break;
478 case EME1:
479 samp = CaloSampling::EME1;
480 break;
481 case EME2:
482 samp = CaloSampling::EME2;
483 break;
484 }
485
486 eta = cluster->etaSample (samp);
487 phi = cluster->phiSample (samp);
488 break;
489
490 case COMBINED2:
491 eta = cluster->etaBE (2);
492 phi = cluster->phiBE (2);
493 break;
494
495 case CLUSTER:
496 eta = cluster->eta();
497 phi = cluster->phi();
498 break;
499
500 default:
501 abort();
502 }
503
504 // Give up if one of them is an error flag.
505 if (std::abs (phi) > 900 || std::abs (eta) > 900)
506 return;
507
508 // Sometimes unnormalized @f$\phi@f$ values still come through.
509 // Make sure this is in the proper range before calling the correction.
511
512 // Look up the DD element.
513 // Give up if we can't find one.
514 const CaloDetDescrElement* elt = ddhelper(dd_man).find_dd_elt (dd_man,
515 region,
516 cluster,
517 eta, phi);
518 if (!elt)
519 return;
520
521 // Compute the adjusted eta and phi --- the coordinates shifted
522 // from the actual to the nominal coordinate system.
523 float adj_eta = eta - elt->eta() + elt->eta_raw();
524 float adj_phi = CaloPhiRange::fix (phi - elt->phi() + elt->phi_raw());
525
526 // Call the actual correction.
527 makeTheCorrection (myctx, cluster, elt, eta, adj_eta, phi, adj_phi, samp);
528}
529
530
531namespace {
532
533
543inline
544void docalc (int i,
546 const CaloRec::Array<1>& energies,
548 int& n_good)
549{
550 corrtab[n_good][0] = energies[i];
551 bool good = false;
552 corrtab[n_good][1] = builder.calculate (i, good);
553 if (good)
554 ++n_good;
555}
556
557
558} // anonymous namespace
559
560
561
573float
575 const TableBuilder& builder,
576 const CaloRec::Array<1>&
577 energies,
578 int energy_degree)
579
580{
581 // Calculate the correction for each energy.
582 unsigned int n_energies = energies.size();
583 unsigned int shape[] = {n_energies, 2};
584 CaloRec::WritableArrayData<2> corrtab (shape);
585
586 // If we're outside the range of the table, we'll just be using the
587 // value at the end (no extrapolation). We only need to calculate
588 // that one point in that case.
589 unsigned int beg = 0;
590 unsigned int end = n_energies;
591 if (energy <= energies[0])
592 end = 1;
593 else if (energy >= energies[n_energies-1])
594 beg = n_energies-1;
595
596 // Build the table.
597 int n_good = 0;
598 for (unsigned int i=beg; i<end; i++)
599 docalc (i, builder, energies, corrtab, n_good);
600
601 // If we only evaluated one point, but it wasn't good, keep
602 // searching until we find a good one.
603 while (n_good == 0 && beg > 0) {
604 --beg;
605 docalc (beg, builder, energies, corrtab, n_good);
606 }
607 while (n_good == 0 && end < n_energies) {
608 docalc (end, builder, energies, corrtab, n_good);
609 ++end;
610 }
611
612 // Now interpolate in energy.
613 // But if we're outside of the range of the table, just use the value
614 // at the end (don't extrapolate).
615 if (n_good == 0) {
616 // No good energies --- return a null correction.
617 return 0;
618 }
619 else if (n_good == 1) {
620 // Only one good energy --- nothing to do but to use it.
621 return corrtab[0][1];
622 }
623 else if (energy <= corrtab[0][0]) {
624 // Off the low end of the table --- return the first value.
625 return corrtab[0][1];
626 }
627 else if (energy >= corrtab[n_good-1][0]) {
628 // Off the high end of the table --- return the last value.
629 return corrtab[n_good-1][1];
630 }
631
632 // Do the interpolation.
633 return interpolate (corrtab, energy, energy_degree,
634 1, CaloRec::Array<1>(), n_good);
635}
636
637
638
640{
642 if (!ddhelper) {
643 auto newhelper = std::make_unique<const CaloClusterCorr::DDHelper> (dd_man);
644 ddhelper = m_ddhelper.set (std::move (newhelper));
645 }
646 return *ddhelper;
647}
648
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.