ATLAS Offline Software
MuonCaloEnergyTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "MuonCaloEnergyTool.h"
6 // forward declares
7 #include <cmath>
8 
10 #include "CaloUtils/CaloCellList.h"
11 #include "GaudiKernel/SystemOfUnits.h"
20 
21 namespace Rec {
22 
23  MuonCaloEnergyTool::MuonCaloEnergyTool(const std::string& t, const std::string& n, const IInterface* p) :
24  AthAlgTool(t, n, p)
25  {
26  declareInterface<IMuonCaloEnergyTool>(this);
27  }
28 
30  // RETRIEVE TOOLS
31  ATH_CHECK(m_caloExtensionTool.retrieve());
33  ATH_CHECK(m_particleCreator.retrieve());
34 
38 
39  return StatusCode::SUCCESS;
40  }
41 
42  void MuonCaloEnergyTool::calculateMuonEnergies(const Trk::Track* trk, double deltaE, double meanIoni, double sigmaIoni, double& E,
43  double& sigma, double& E_FSR, double& E_expected, double& E_em_meas, double& E_em_exp,
44  double& E_tile_meas, double& E_tile_exp, double& E_HEC_meas, double& E_HEC_exp,
45  double& E_dead_exp, std::vector<Identifier>* crossedCells,
46  std::vector<double>* sigmaNoise_cell, std::vector<double>* E_exp_cell) const {
47  const EventContext& ctx = Gaudi::Hive::currentContext();
48  //
49  // Input parameters trk: (muon) track pointer
50  // deltaE: Mean Energy loss in Calorimeter
51  // meanIoni: Mean ionization Energy loss in Calorimeter
52  // sigmaIoni: sigma of the ionization Energy loss in Calorimeter
53  //
54  // Ouput parameters E: Calorimeter energy measured (corrected for dead material etc.)
55  // sigma: Error on measured energy
56  // E_FSR: Energy of Final State Radiation: e.m. = photon energy (if above ET and F1 cut)
57  // if EFSR>0 the corrected hadronic energy is used for the measured Energy E
58  // E_expected: expected meanIonization Energyloss from the TrackingGeometry
59 
60  E = 0.;
61  sigma = 0.;
62  E_FSR = 0.;
63  E_expected = 0.;
64 
65  E_em_meas = 0.;
66  E_em_exp = 0.;
67  E_tile_meas = 0.;
68  E_tile_exp = 0.;
69  E_HEC_meas = 0.;
70  E_HEC_exp = 0.;
71  E_dead_exp = 0.;
72 
73  bool storeCells = false;
74  if (crossedCells != nullptr && sigmaNoise_cell != nullptr && E_exp_cell != nullptr) {
75  storeCells = true;
76  crossedCells->clear();
77  sigmaNoise_cell->clear();
78  E_exp_cell->clear();
79  }
80  //
81  // For the expected Eloss in the dead or not instrumented material we will use the meanIonization loss
82  // this meanIoni is stored on the extended Eloss object
83  // the sigmaIoni corresponds to the Landau width
84  // a factor 3.59524 gives the sigma of the upper tail
85  //
86  // The Eloss derived from the momentum differences on the calo extension correponds to
87  // deltaE on the Eloss object = mean Eloss including ionization and radiation
88  //
89  // To go to the meanIonization loss one needs a scale factor scale_Ionization
90  //
91  if (!trk) return;
92  if (!trk->perigeeParameters()) return;
93  if (trk->perigeeParameters()->parameters()[Trk::qOverP] == 0.) return;
94 
95  // int isign = 1;
96  // if(meanIoni<0) isign = -1;
97  // double mopIoni = meanIoni - isign*3.59524*std::abs(sigmaIoni);
98  double mopIoni = meanIoni;
99 
100  double scale_Ionization = 0.9;
101  if (std::abs(deltaE) > 0 && std::abs(meanIoni) > 0) scale_Ionization = mopIoni / deltaE;
102  double error_ratio = 0.3;
103  if (std::abs(meanIoni) > 0 && sigmaIoni > 0) error_ratio = 3.59524 * std::abs(sigmaIoni / meanIoni);
104 
105  ATH_MSG_DEBUG(" Inputs deltaE " << deltaE << " meanIoni " << meanIoni << " sigmaIoni " << sigmaIoni << " scale_Ionization "
106  << scale_Ionization << " error_ratio " << error_ratio);
107  if (deltaE == 0 || meanIoni == 0 || sigmaIoni < 0)
108  ATH_MSG_WARNING(" Strange Inputs deltaE " << deltaE << " meanIoni " << meanIoni << " sigmaIoni " << sigmaIoni);
109 
110  // associate muon to calorimeter
111 
112  const xAOD::TrackParticle* tp = nullptr;
113 
115  if (indetTrackParticles.isValid()) {
116  // check ID trackparticles
117  for (const auto *it : *indetTrackParticles) {
118  if ((*it).track() == trk) {
119  tp = &(*it);
120  break;
121  }
122  }
123  if (tp) ATH_MSG_DEBUG(" ID xAOD::TrackParticle found " << tp);
124  } else {
125  ATH_MSG_WARNING("Failed to retrieve " << m_indetTrackParticleLocation.key());
126  }
127 
128  // look for Muon trackparticles
129 
131  if (!tp && muonTrackParticles.isValid()) {
132  for (const auto *it : *muonTrackParticles) {
133  if ((*it).track() == trk) {
134  tp = &(*it);
135  break;
136  }
137  }
138  if (tp) ATH_MSG_DEBUG(" Muon xAOD::TrackParticle found " << tp);
139  } else if (!tp) {
140  ATH_MSG_WARNING("Failed to retrieve " << m_muonTrackParticleLocation.key());
141  }
142 
143  std::unique_ptr<const xAOD::TrackParticle> tpholder;
144  if (!tp) {
145  tpholder = std::unique_ptr<const xAOD::TrackParticle>(m_particleCreator->createParticle(*trk, nullptr, nullptr, xAOD::muon));
146 
147  tp = tpholder.get();
148  if (tp) ATH_MSG_DEBUG(" xAOD::TrackParticle created from scratch " << tp);
149  }
150 
151  if (!tp) return;
152 
153  std::unique_ptr<const Rec::ParticleCellAssociation> association =
154  m_caloCellAssociationTool->particleCellAssociation(*tp, 0.2, nullptr);
155 
156  if (!association) { return; }
157  ATH_MSG_DEBUG(" particleCellAssociation done " << association.get());
158 
159  std::vector<std::pair<const CaloCell*, Rec::ParticleCellIntersection*> > cellIntersections = association->cellIntersections();
160 
161  const Trk::CaloExtension& caloExtension = association->caloExtension();
162 
163  if (!caloExtension.caloEntryLayerIntersection()) {
164  ATH_MSG_DEBUG("calculateMuonEnergies() - No caloEntryLayerIntersection found");
165  return;
166  }
167 
168  ATH_MSG_DEBUG(" nr of cell intersections " << cellIntersections.size());
169  if (cellIntersections.size() < 3) ATH_MSG_DEBUG(" Strange nr of calorimeter cell intersections " << cellIntersections.size());
170 
171  double theta = caloExtension.caloEntryLayerIntersection()->position().theta();
172 
173  double Eloss = 0.;
174  double scaleTG = 1.0;
175  if (!caloExtension.muonEntryLayerIntersection()) {
176  if (caloExtension.caloEntryLayerIntersection()->momentum().mag() - std::abs(deltaE) > 1000.) {
178  " No muonEntryLayerIntersection found and therefore the expected Eloss is not calculated properly for momentum "
179  << caloExtension.caloEntryLayerIntersection()->momentum().mag());
180  }
181  ATH_MSG_DEBUG(" No muonEntryLayerIntersection found and therefore the expected Eloss is not calculated properly ");
182  } else {
183  Eloss =
184  caloExtension.caloEntryLayerIntersection()->momentum().mag() - caloExtension.muonEntryLayerIntersection()->momentum().mag();
185  ATH_MSG_DEBUG(" Energy loss from CaloExtension "
186  << Eloss << " R muon Entry " << caloExtension.muonEntryLayerIntersection()->position().perp() << " Z muon Entry "
187  << caloExtension.muonEntryLayerIntersection()->position().z() << " R calo entry "
188  << caloExtension.caloEntryLayerIntersection()->position().perp() << " Z calo entry "
189  << caloExtension.caloEntryLayerIntersection()->position().z());
190  if (Eloss > 25000. && Eloss > 0.1 * caloExtension.muonEntryLayerIntersection()->momentum().mag()) {
191  ATH_MSG_WARNING(" Crazy Energy loss from CaloExtension "
192  << Eloss << " p at CaloEntry " << caloExtension.caloEntryLayerIntersection()->momentum().mag()
193  << " p at Muon Entry " << caloExtension.muonEntryLayerIntersection()->momentum().mag());
194  scaleTG = mopIoni / Eloss;
195  }
196  }
197 
200  ATH_MSG_DEBUG("EntryExitLayerMap " << entryExitLayerMap.size());
201 
204  ATH_MSG_DEBUG("eLossLayerMap " << eLossLayerMap.size());
205 
206  double scale_em_expected = 0.97; // 0.73
207  double scale_tile_expected = 1.17; // 0.89
208  double scale_HEC_expected = 1.11; // 0.84
209  //
210  // TG expectations
211  //
212  double EE_emB = 0.;
213  double EE_emE = 0.;
214  double EE_HEC = 0.;
215  double EE_tile = 0.;
216  //
217  // const char* sampname[24] = {
218  // "PreSamplerB", "EMB1", "EMB2", "EMB3",
219  // "PreSamplerE", "EME1", "EME2", "EME3",
220  // "HEC0", "HEC1","HEC2", "HEC3",
221  // "TileBar0", "TileBar1", "TileBar2",
222  // "TileExt0", "TileExt1", "TileExt2",
223  // "TileGap1", "TileGap2", "TileGap3",
224  // "FCAL0", "FCAL1", "FCAL2"};
225  //
228  auto pos = entryExitLayerMap.find(sample);
229  if (pos == entryExitLayerMap.end()) continue;
230  auto eLossPair = eLossLayerMap.find(sample);
231  double eLoss = 0.;
232  if (eLossPair != eLossLayerMap.end()) {
233  eLoss = eLossPair->second;
234  ATH_MSG_DEBUG(" sample " << i << " eLoss " << scale_Ionization * eLoss);
235  if (i <= 3) {
236  EE_emB += scale_em_expected * scale_Ionization * eLoss;
237  } else if (i <= 7) {
238  EE_emE += scale_em_expected * scale_Ionization * eLoss;
239  } else if (i <= 11) {
240  EE_HEC += scale_HEC_expected * scale_Ionization * eLoss;
241  } else if (i <= 20) {
242  EE_tile += scale_tile_expected * scale_Ionization * eLoss;
243  }
244  }
245  }
246  if (caloExtension.caloEntryLayerIntersection() && caloExtension.muonEntryLayerIntersection()) {
247  double Eloss =
248  caloExtension.caloEntryLayerIntersection()->momentum().mag() - caloExtension.muonEntryLayerIntersection()->momentum().mag();
249  ATH_MSG_DEBUG(" eta " << caloExtension.caloEntryLayerIntersection()->momentum().eta() << " expected energies from TG EE_emB "
250  << EE_emB << " EE_emE " << EE_emE << " EE_tile " << EE_tile << " EE_HEC " << EE_HEC << " total Eloss "
251  << Eloss);
252  }
253  //
254  // do not continue with crazy values for the Eloss from TG
255  //
256  if (scaleTG != 1.0) return;
257 
258  // measured and expected energies
259 
260  // Get Calo-Noise CDO:
262  const CaloNoise* caloNoise = *caloNoiseHdl;
263 
264  double E_em = 0.;
265  double E_em_expected = 0.;
266  double E_em_exptot = 0.;
267  double E_em_expall = 0.;
268  double E_em_threshold = 0.;
269  int nlay_em = 0;
270  double sigma_Noise_em = 0.;
271 
272  double E_HEC = 0.;
273  double E_HEC_expected = 0.;
274  double E_HEC_threshold = 0.;
275  double E_HEC_exptot = 0.;
276  double E_HEC_expall = 0.;
277  int nlay_HEC = 0;
278  double sigma_Noise_HEC = 0.;
279 
280  double E_tile = 0.;
281  double E_tile_expected = 0.;
282  double E_tile_threshold = 0.;
283  double E_tile_exptot = 0.;
284  double E_tile_expall = 0.;
285  int nlay_tile = 0;
286  double sigma_Noise_tile = 0.;
287 
288  E_expected = 0.;
289  const Amg::Vector3D& extension_pos = caloExtension.caloEntryLayerIntersection()->position();
290  const double thetaPos = caloExtension.caloEntryLayerIntersection()->position().theta();
291 
292  for (auto it : cellIntersections) {
293  const CaloCell* curr_cell = it.first;
294  const Amg::Vector3D cell_vec(curr_cell->x(),curr_cell->y(), curr_cell->z());
295  const double cell_perp = cell_vec.perp();
296  int cellSampling = curr_cell->caloDDE()->getSampling();
297  bool badCell = curr_cell->badcell();
298  double cellEn = curr_cell->energy();
299  Identifier id = curr_cell->ID();
300 
301  double f_exp = (it.second)->pathLength();
302  double E_exp = (it.second)->expectedEnergyLoss();
303 
304  if (f_exp > 1.) f_exp = 1.;
305 
306  // if(f_exp<0.1) f_exp = 0.1;
307 
308  double sigma_Noise = caloNoise->getEffectiveSigma(id, curr_cell->gain(), cellEn);
309 
310 
311  double dtheta = cell_vec.theta() - thetaPos;
312  double dphi = cell_vec.deltaPhi(extension_pos);
313  double celldr = curr_cell->caloDDE()->dr();
314  double celldz = curr_cell->caloDDE()->dz();
315  double celldtheta = celldr / (cell_perp ? cell_perp : 1. );
316  double celldphi = curr_cell->caloDDE()->dphi();
317 
318  ATH_MSG_DEBUG(" cell sampling " << cellSampling << " energy " << cellEn << " position R "
319  << cell_perp << " z "
320  << curr_cell->z() << " f_exp " << f_exp << " E_exp " << E_exp << " dtheta " << dtheta
321  << " dphi " << dphi << " cell dtheta " << celldtheta << " cell dr " << celldr << " cell dz "
322  << celldz << " cell dphi " << celldphi);
323  // ATH_MSG_DEBUG( " sigma_Noise totalNoiseRMS from Alan " << sigma_NoiseA << " sigma_Noise getEffectiveSigma " <<
324  // sigma_Noise);
325 
326  // Use expected energy if measured energy below noise level
327  // - this will bias the energy measurement towards too high values
328  // - the bias is corrected in the thresholdCorrection function below
329  //
330  // sum measured, expected energies for crossed cells after noise cuts
331  //
332  if (cellSampling == CaloSampling::PreSamplerB || cellSampling == CaloSampling::PreSamplerE) {
333  if (f_exp > 0 && cellEn > m_sigmasAboveNoise * sigma_Noise && !badCell) {
334  if (storeCells) {
335  crossedCells->push_back(id);
336  sigmaNoise_cell->push_back(sigma_Noise);
337  E_exp_cell->push_back(scale_Ionization * f_exp * E_exp *
338  scale_em_expected); // I don't want sum, but value for each cell
339  }
340  }
341  }
342  if (curr_cell->caloDDE()->getSubCalo() == CaloCell_ID::LAREM) {
343  E_em_exptot += scale_Ionization * f_exp * E_exp * scale_em_expected;
344  if (f_exp > 0) E_em_expall += scale_Ionization * E_exp * scale_em_expected;
345  if (f_exp > 0 && cellEn > m_sigmasAboveNoise * sigma_Noise && !badCell) {
346  // if(f_exp>0&&cellEn>m_sigmasAboveNoise*sigma_Noise&&!badCell) {
347  E_em += cellEn;
348  E_em_expected += scale_Ionization * f_exp * E_exp * scale_em_expected;
349  ATH_MSG_VERBOSE(" EM cell " << cellEn << " sigma_Noise " << sigma_Noise << " f_exp " << f_exp << " E_exp " << E_exp);
350  if (storeCells) {
351  crossedCells->push_back(id);
352  sigmaNoise_cell->push_back(sigma_Noise);
353  E_exp_cell->push_back(scale_Ionization * f_exp * E_exp * scale_em_expected);
354  }
355  }
356  if (f_exp > 0 && !badCell) nlay_em++;
357  if (f_exp > 0 && !badCell) sigma_Noise_em += sigma_Noise;
358  } else if (curr_cell->caloDDE()->getSubCalo() == CaloCell_ID::TILE) {
359  E_tile_exptot += scale_Ionization * f_exp * E_exp * scale_tile_expected;
360  if (f_exp > 0) E_tile_expall += scale_Ionization * E_exp * scale_tile_expected;
361  if (f_exp > 0 && cellEn > m_sigmasAboveNoise * sigma_Noise && !badCell) {
362  // &&f_exp*E_exp>m_sigmasAboveNoise*sigma_Noise/4) {
363  E_tile += cellEn;
364  E_tile_expected += scale_Ionization * f_exp * E_exp * scale_tile_expected;
365  ATH_MSG_VERBOSE(" Tile cell " << cellEn << " sigma_Noise " << sigma_Noise << " f_exp " << f_exp << " E_exp " << E_exp);
366  if (storeCells) {
367  crossedCells->push_back(id);
368  sigmaNoise_cell->push_back(sigma_Noise);
369  E_exp_cell->push_back(scale_Ionization * f_exp * E_exp * scale_tile_expected);
370  }
371  }
372  if (f_exp > 0 && !badCell) nlay_tile++;
373  if (f_exp > 0 && !badCell) sigma_Noise_tile += sigma_Noise;
374  } else if (curr_cell->caloDDE()->getSubCalo() == CaloCell_ID::LARHEC) {
375  E_HEC_exptot += scale_Ionization * f_exp * E_exp * scale_HEC_expected;
376  if (f_exp > 0) E_HEC_expall += scale_Ionization * E_exp * scale_HEC_expected;
377  // lower threshold for HEC
378  if (f_exp > 0 && cellEn > m_sigmasAboveNoise * sigma_Noise / 2. && !badCell) {
379  // &&f_exp*E_exp>m_sigmasAboveNoise*sigma_Noise/4) {
380  E_HEC += cellEn;
381  E_HEC_expected += scale_Ionization * f_exp * E_exp * scale_HEC_expected;
382  ATH_MSG_VERBOSE(" HEC cell " << cellEn << " sigma_Noise " << sigma_Noise << " f_exp " << f_exp << " E_exp " << E_exp);
383  if (storeCells) {
384  crossedCells->push_back(id);
385  sigmaNoise_cell->push_back(sigma_Noise);
386  E_exp_cell->push_back(scale_Ionization * f_exp * E_exp * scale_HEC_expected);
387  }
388  }
389  if (f_exp > 0 && !badCell) nlay_HEC++;
390  if (f_exp > 0 && !badCell) sigma_Noise_HEC += sigma_Noise;
391  }
392  E_expected += scale_Ionization * f_exp * E_exp;
393  }
394  ATH_MSG_DEBUG(" After cuts measured Energies em " << E_em << " tile " << E_tile << " HEC " << E_HEC);
395  ATH_MSG_DEBUG(" After cuts expected Energies em " << E_em_expected << " tile " << E_tile_expected << " HEC " << E_HEC_expected);
396  ATH_MSG_DEBUG(" No cuts with length expected Energies em " << E_em_exptot << " tile " << E_tile_exptot << " HEC " << E_HEC_exptot);
397  ATH_MSG_DEBUG(" No cuts NO length expected Energies em " << E_em_expall << " tile " << E_tile_expall << " HEC " << E_HEC_expall);
398 
399  // E resolution of calorimeters
400  // Resolution of Hadronic at low energies is not 100% but more like 50%/sqrt(E)
401 
402  double scaleError_tile = 0.20 + 0.80 * E_tile / (10000. + E_tile);
403  double scaleError_HEC = 0.20 + 0.80 * E_HEC / (10000. + E_HEC);
404  double sigma_em = std::sqrt(500. * E_em);
405  double sigma_tile = scaleError_tile * std::sqrt(1000. * E_tile);
406  double sigma_HEC = scaleError_HEC * std::sqrt(1000. * E_HEC);
407 
408  // go from e.m. scale to Muon Energy scale
409 
410  E_em *= m_emipEM;
411  E_tile *= m_emipTile;
412  E_HEC *= m_emipHEC;
413  ATH_MSG_DEBUG(" e.m. to Muon scale measured Energies em " << E_em << " tile " << E_tile << " HEC " << E_HEC);
414 
415  // also for errors
416 
417  sigma_em *= m_emipEM;
418  sigma_tile *= m_emipTile;
419  sigma_HEC *= m_emipHEC;
420 
421  // Average Noise per layer
422 
423  if (nlay_em > 0) sigma_Noise_em /= nlay_em;
424  if (nlay_tile > 0) sigma_Noise_tile /= nlay_tile;
425  if (nlay_HEC > 0) sigma_Noise_HEC /= nlay_HEC;
426  ATH_MSG_DEBUG(" Average Noise em " << sigma_Noise_em << " nlay " << nlay_em << " tile " << sigma_Noise_tile << " nlay "
427  << nlay_tile << " HEC " << sigma_Noise_HEC << " nlay " << nlay_HEC);
428 
429  // apply energy correction using the expected Eloss for noise cut
430 
431  E_em_threshold += thresholdCorrection(E_em, E_em_expected, m_sigmasAboveNoise * sigma_Noise_em / m_emipEM / 4);
432  E_tile_threshold += thresholdCorrection(E_tile, E_tile_expected, m_sigmasAboveNoise * sigma_Noise_tile / m_emipTile / 4);
433  E_HEC_threshold += thresholdCorrection(E_HEC, E_HEC_expected, m_sigmasAboveNoise * sigma_Noise_HEC / m_emipHEC / 8);
434 
435  ATH_MSG_DEBUG(" Threshold correction to Energies em " << E_em_threshold << " tile " << E_tile_threshold << " HEC "
436  << E_HEC_threshold);
437 
438  ATH_MSG_DEBUG(" total Energies em " << E_em + E_em_threshold << " tile " << E_tile + E_tile_threshold << " HEC "
439  << E_HEC + E_HEC_threshold);
440 
441  // Eloss in dead material (so everything not accounted for in the measurement)
442 
443  // if(scale_Ionization*Eloss>E_expected) E_expected = scale_Ionization*Eloss;
444  E_expected = scale_Ionization * Eloss;
445 
446  // Corrections for dead material 0.15*E_tile_expected + 0.20*E_HEC_expected;
447 
448  double E_dead = E_expected - E_em_expected - E_tile_expected - E_HEC_expected + 0.12 * E_tile_expected + 0.27 * E_HEC_expected;
449 
450 
451  // treatment of FSR
452 
453  E_FSR = 0.;
454  double E_measured = 0.;
455  double E_measured_expected = E_em_expected + E_tile_expected + E_HEC_expected;
456  if (E_em * std::sin(theta) > m_emEtCut) {
457  // large e.m. deposit starting in first e.m. layer
458  E_FSR = E_em;
459  // do not use measured e.m. energy for muons and use expected (tile and HEC are fine)
460  E = E_em_expected + E_tile + E_tile_threshold + E_HEC + E_HEC_threshold + E_dead;
461  double sigma_expdead = error_ratio * (E_em_expected + E_dead);
462  sigma = std::sqrt(sigma_tile * sigma_tile + sigma_HEC * sigma_HEC + sigma_expdead * sigma_expdead);
463  E_measured = E_tile + E_tile_threshold + E_HEC + E_HEC_threshold;
464  } else {
465  // no FSR
466  E = E_em + E_em_threshold + E_tile + E_tile_threshold + E_HEC + E_HEC_threshold + E_dead;
467  double sigma_threshold = error_ratio * E_dead;
468  sigma = std::sqrt(sigma_em * sigma_em + sigma_tile * sigma_tile + sigma_HEC * sigma_HEC + sigma_threshold * sigma_threshold);
469  E_measured = E_em + E_em_threshold + E_tile + E_tile_threshold + E_HEC + E_HEC_threshold;
470  }
471 
472  // eta dependent correction
473 
474  double etaPos = caloExtension.caloEntryLayerIntersection()->position().eta();
475  E += etaCorr(etaPos) * E_expected;
476 
477  ATH_MSG_DEBUG(" Total energy " << E << " sigma " << sigma << " E calo measured in cells " << E_measured
478  << " E calo expected in cells " << E_measured_expected << " E_expected meanIoni from TG "
479  << E_expected);
480 
481  if (E_em + E_tile + E_HEC < 0.1 * E && E_em + E_tile + E_HEC > 1000.) {
482  ATH_MSG_DEBUG(" Real Measured Calorimeter energy " << E_em + E_tile + E_HEC << " is much lower than total " << E
483  << " expected energy too large " << E_expected
484  << " put measured energy to zero ");
485  E = 0.;
486  sigma = 0.;
487  }
488  //
489  // add for validation (temporarily)
490  //
491  // E_em_meas,E_em_exp,E_tile_meas,E_tile_exp,E_HEC_meas,E_HEC_exp,E_dead_exp
492  //
493 
494  // E_em_meas = E_em + E_em_threshold;
495  // E_em_exp = E_em_expected;
496  // E_tile_meas = E_tile + E_tile_threshold;
497  // E_tile_exp = E_tile_expected;
498  // E_HEC_meas = E_HEC + E_HEC_threshold;
499  // E_HEC_exp = E_HEC_expected;
500  // E_dead_exp = E_dead;
501 
502  // double EE_dead = E_expected - EE_emB - EE_emE - EE_tile - EE_HEC + 0.15*EE_tile + 0.20*EE_HEC;
503  double EE_dead = E_expected - EE_emB - EE_emE - EE_tile - EE_HEC + 0.12 * EE_tile + 0.27 * EE_HEC;
504  //
505  // move expected (to match the TG expected Eloss) and measured energies
506  //
507  E_em_meas = E_em + E_em_threshold + EE_emB + EE_emE - E_em_expected;
508  E_em_exp = EE_emB + EE_emE;
509  E_tile_meas = E_tile + E_tile_threshold + EE_tile - E_tile_expected;
510  E_tile_exp = EE_tile;
511  E_HEC_meas = E_HEC + E_HEC_threshold + EE_HEC - E_HEC_expected;
512  E_HEC_exp = EE_HEC;
513  E_dead_exp = EE_dead;
514 
515  } // calculateMuonEnergies
516 
517  double MuonCaloEnergyTool::etaCorr(double eta) {
518  // measured energy* = measured energy + etaCorr(eta) * expected
519 
520  int eta_index = int(std::abs(eta) * (60. / 3.));
521  if (eta_index > 59) return 0;
522 
523  static constexpr double corr[60] = {0.00368146, 0.0419526, 0.0419322, 0.0392922, 0.030304, 0.0262424, 0.0156346, 0.00590235, 0.00772249,
524  -0.0141775, -0.0152247, -0.0174432, -0.0319056, -0.0670813, -0.128678, -0.0982326, -0.0256406, -0.200244,
525  -0.178975, -0.120156, -0.124606, -0.0961311, -0.0163201, 0.00357829, 0.0292199, 0.0110466, -0.0375598,
526  0.0417912, 0.0386369, -0.0689454, -0.21496, -0.126157, -0.210573, -0.215757, -0.202019, -0.164546,
527  -0.168607, -0.128602, -0.124629, -0.0882631, -0.100869, -0.0460344, -0.0709039, -0.0163041, -0.0521138,
528  -0.0125259, -0.0378681, 0.00396062, -0.0636308, -0.032199, -0.0588335, -0.0470752, -0.0450315, -0.0301302,
529  -0.087378, -0.0115615, -0.0152037, 0, 0, 0}; // corrections
530 
531  // additional correction release 21
532 
533  static constexpr double cor21[20] = {0.999793, 1.00017, 0.990946, 0.995358, 1.01377, 1.02676, 1.03111, 1.01483, 0.995585, 1.00465,
534  1.05224, 1.05238, 1.03208, 1.02373, 1.02305, 1.03975, 1.06547, 1.0364, 1.0361, 1.0361};
535 
536  int i21 = std::abs(eta * 20. / 3.);
537  if (i21 > 19) i21 = 19;
538 
539  return (cor21[i21] * corr[eta_index]);
540  } // etaCorr
541 
542  double MuonCaloEnergyTool::thresholdCorrection(double E_observed, double E_expected, double sigma_Noise) const {
543  //
544  // Total energy observed and expected in cells of LAr, Tile, or HEC after 4*sigma_Noise cut
545  // for a resolution of dE/E of 20%
546  //
547  // returns a correction to the energy based on the expected energy
548  //
549  // one should so use: Etotal = E_observed + E_dead + ThresholdCorrection(E_observed,E_expected,sigma_Noise)
550 
551  static constexpr double par[6] = {1.01431e+00, -2.26317e+01, 1.80901e+02, -2.33105e+01, 1.82930e+02, 1.11356e-02};
552 
553  double E = E_expected;
554 
555  if (E == 0) return 0.;
556 
557  double x = sigma_Noise / E;
558  if (x > 1.) x = 1.;
559 
560  // formula is for a 4 sigma Noise cut and obtained by a small simulation programm
561 
562  double fraction = (par[0] + par[1] * x + par[2] * x * x) / (1. + par[3] * x + par[4] * x * x) + par[5] * x;
563 
564  // for low x values (low thresholds) the fraction is bigger than 1
565  // (1.33) because the observed energy overestimates
566 
567  ATH_MSG_DEBUG(" ThresholdCorrection E " << E << " E_observed not used " << E_observed << " sigma_Noise " << sigma_Noise
568  << " x = sigma_Noise/E " << x << " fraction " << fraction << " E correction "
569  << (1 - fraction) * E);
570 
571  return (1. - fraction) * E;
572  } // thresholdCorrection
573 
574 } // namespace Rec
GetLCDefs::Unknown
@ Unknown
Definition: GetLCDefs.h:21
xAOD::muon
@ muon
Definition: TrackingPrimitives.h:195
Rec::MuonCaloEnergyTool::m_emipTile
static constexpr double m_emipTile
Definition: MuonCaloEnergyTool.h:63
CaloNoise::getEffectiveSigma
float getEffectiveSigma(const Identifier id, const int gain, const float energy) const
Definition: CaloNoise.h:55
pdg_comparison.sigma
sigma
Definition: pdg_comparison.py:324
CaloExtensionHelpers::ScalarLayerMap
std::map< CaloSampling::CaloSample, double > ScalarLayerMap
Definition: CaloExtensionHelpers.h:22
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
Trk::Track
The ATLAS Track class.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/Track.h:73
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
CaloExtensionHelpers.h
CaloCell::y
float y() const
get y (through CaloDetDescrElement)
Definition: CaloCell.h:420
Rec::MuonCaloEnergyTool::etaCorr
static double etaCorr(double eta)
Definition: MuonCaloEnergyTool.cxx:517
Rec::MuonCaloEnergyTool::initialize
virtual StatusCode initialize() override
Definition: MuonCaloEnergyTool.cxx:29
Trk::CaloExtension
Tracking class to hold the extrapolation from a particle from the ID to the muon system (or the other...
Definition: CaloExtension.h:18
Rec::MuonCaloEnergyTool::MuonCaloEnergyTool
MuonCaloEnergyTool(const std::string &, const std::string &, const IInterface *)
Definition: MuonCaloEnergyTool.cxx:23
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
Rec::MuonCaloEnergyTool::m_caloNoiseCDOKey
SG::ReadCondHandleKey< CaloNoise > m_caloNoiseCDOKey
Definition: MuonCaloEnergyTool.h:55
CaloCellList.h
CaloDetDescrElement::dr
float dr() const
cell dr
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:360
skel.it
it
Definition: skel.GENtoEVGEN.py:396
CaloExtension.h
CaloExtensionHelpers::entryExitLayerMap
void entryExitLayerMap(const Trk::CaloExtension &extension, EntryExitLayerMap &result, const LayersToSelect *selection=nullptr)
Definition: CaloExtensionHelpers.h:192
ParticleTest.tp
tp
Definition: ParticleTest.py:25
Trk::CaloExtension::caloEntryLayerIntersection
const TrackParameters * caloEntryLayerIntersection() const
access to intersection with the calorimeter entry layer return NULL if the intersection failed
Definition: CaloExtension.h:64
CaloCell_Base_ID::LARHEC
@ LARHEC
Definition: CaloCell_Base_ID.h:46
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
SG::VarHandleKey::key
const std::string & key() const
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:141
MuonCaloEnergyTool.h
Trk::CaloExtension::muonEntryLayerIntersection
const TrackParameters * muonEntryLayerIntersection() const
access to intersection with the muon entry layer return NULL if the intersection failed
Definition: CaloExtension.h:70
x
#define x
Rec::MuonCaloEnergyTool::m_indetTrackParticleLocation
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_indetTrackParticleLocation
Definition: MuonCaloEnergyTool.h:66
Rec::MuonCaloEnergyTool::m_emEtCut
Gaudi::Property< double > m_emEtCut
Definition: MuonCaloEnergyTool.h:59
Rec::MuonCaloEnergyTool::m_caloExtensionTool
ToolHandle< Trk::IParticleCaloExtensionTool > m_caloExtensionTool
Definition: MuonCaloEnergyTool.h:51
CaloCell::energy
double energy() const
get energy (data member)
Definition: CaloCell.h:311
CaloDetDescrElement::getSubCalo
CaloCell_ID::SUBCALO getSubCalo() const
cell subcalo
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:433
CaloDetDescrElement::dz
float dz() const
cell dz
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:379
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
Rec::MuonCaloEnergyTool::m_particleCreator
ToolHandle< Trk::ITrackParticleCreatorTool > m_particleCreator
Definition: MuonCaloEnergyTool.h:53
FullCPAlgorithmsTest_eljob.sample
sample
Definition: FullCPAlgorithmsTest_eljob.py:113
lumiFormat.i
int i
Definition: lumiFormat.py:85
CaloSampling::CaloSample
CaloSample
Definition: Calorimeter/CaloGeoHelpers/CaloGeoHelpers/CaloSampling.h:22
Rec
Name: MuonSpContainer.h Package : offline/Reconstruction/MuonIdentification/muonEvent.
Definition: FakeTrackBuilder.h:10
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
CaloCell::caloDDE
const CaloDetDescrElement * caloDDE() const
get pointer to CaloDetDescrElement (data member)
Definition: CaloCell.h:305
Trk::association
@ association
Definition: TrackingGeometry.h:46
ParticleCellAssociationCollection.h
CaloCell::badcell
virtual bool badcell() const
check is cell is dead
Definition: CaloCell.cxx:210
Rec::MuonCaloEnergyTool::m_muonTrackParticleLocation
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_muonTrackParticleLocation
Definition: MuonCaloEnergyTool.h:68
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
CaloCell_Base_ID::TILE
@ TILE
Definition: CaloCell_Base_ID.h:46
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
ParticleCellIntersection.h
createCablingJSON.eta_index
int eta_index
Definition: createCablingJSON.py:14
CaloExtensionHelpers::EntryExitLayerMap
std::map< CaloSampling::CaloSample, std::pair< Amg::Vector3D, Amg::Vector3D > > EntryExitLayerMap
Definition: CaloExtensionHelpers.h:21
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
CaloNoise
Definition: CaloNoise.h:16
Trk::Track::perigeeParameters
const Perigee * perigeeParameters() const
return Perigee.
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:163
createCoolChannelIdFile.par
par
Definition: createCoolChannelIdFile.py:29
VP1PartSpect::E
@ E
Definition: VP1PartSpectFlags.h:21
CaloCell::gain
CaloGain::CaloGain gain() const
get gain (data member )
Definition: CaloCell.h:345
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
CaloCell::ID
Identifier ID() const
get ID (from cached data member) non-virtual and inline for fast access
Definition: CaloCell.h:279
CaloExtensionHelpers::eLossLayerMap
void eLossLayerMap(const Trk::CaloExtension &extension, ScalarLayerMap &result)
Definition: CaloExtensionHelpers.h:216
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
CaloCellContainer.h
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
ParticleCaloAssociation.h
Rec::MuonCaloEnergyTool::m_emipEM
static constexpr double m_emipEM
Definition: MuonCaloEnergyTool.h:62
TrackParticle.h
CaloDetDescrElement::dphi
float dphi() const
cell dphi
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:358
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
CaloCell
Data object for each calorimeter readout cell.
Definition: CaloCell.h:57
CaloDetDescrElement::getSampling
CaloCell_ID::CaloSample getSampling() const
cell sampling
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:395
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Rec::MuonCaloEnergyTool::m_caloCellAssociationTool
ToolHandle< Rec::IParticleCaloCellAssociationTool > m_caloCellAssociationTool
Definition: MuonCaloEnergyTool.h:52
CaloCell_ID_FCS::PreSamplerE
@ PreSamplerE
Definition: FastCaloSim_CaloCell_ID.h:23
CaloCell_ID_FCS::PreSamplerB
@ PreSamplerB
Definition: FastCaloSim_CaloCell_ID.h:19
CaloCell::z
float z() const
get z (through CaloDetDescrElement)
Definition: CaloCell.h:427
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
CaloCell::x
float x() const
get x (through CaloDetDescrElement)
Definition: CaloCell.h:413
CaloCellHelpers.h
xAOD::TrackParticle_v1
Class describing a TrackParticle.
Definition: TrackParticle_v1.h:43
Rec::MuonCaloEnergyTool::calculateMuonEnergies
void calculateMuonEnergies(const Trk::Track *trk, double deltaE, double meanIoni, double sigmaIoni, double &E, double &sigma, double &E_FSR, double &E_expected, double &E_em_meas, double &E_em_exp, double &E_tile_meas, double &E_tile_exp, double &E_HEC_meas, double &E_HEC_exp, double &E_dead_exp, std::vector< Identifier > *crossedCells=0, std::vector< double > *sigmaNoise_cell=0, std::vector< double > *E_exp_cell=0) const override
Definition: MuonCaloEnergyTool.cxx:42
Rec::MuonCaloEnergyTool::m_sigmasAboveNoise
Gaudi::Property< double > m_sigmasAboveNoise
Definition: MuonCaloEnergyTool.h:58
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
AthAlgTool
Definition: AthAlgTool.h:26
CaloCell_Base_ID::LAREM
@ LAREM
Definition: CaloCell_Base_ID.h:46
Rec::MuonCaloEnergyTool::m_emipHEC
static constexpr double m_emipHEC
Definition: MuonCaloEnergyTool.h:64
TrackingPrimitives.h
Rec::MuonCaloEnergyTool::thresholdCorrection
double thresholdCorrection(double E_observed, double E_expected, double sigma_Noise) const
Definition: MuonCaloEnergyTool.cxx:542
Identifier
Definition: IdentifierFieldParser.cxx:14