Fork me on GitHub

source: git/modules/DualReadoutCalorimeter.cc@ fd4b326

Last change on this file since fd4b326 was fd4b326, checked in by michele <michele.selvaggi@…>, 4 years ago

tracks have now montecarlo mass

  • Property mode set to 100644
File size: 22.1 KB
Line 
1/*
2 * Delphes: a framework for fast simulation of a generic collider experiment
3 * Copyright (C) 2012-2014 Universite catholique de Louvain (UCL), Belgium
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20/** \class DualReadoutCalorimeter
21 *
22
23 // ============ TODO =========================================================
24 // This implementation of dual calorimetry relies on several approximations:
25 // - If hadronic energy is found in the tower the energy resolution then the full tower enrgy is smeared according to hadronic resolution (pessimistic for (e,n) or (pi+,gamma))
26 // - While e+ vs pi+ (or gamma vs n) separation is in principle possible for single particles (using C/S, PMT timing, lateral shower profile) it is not obvious it can be done overlapping particles.
27 // Now we assume that regarless of the number of particle hits per tower we can always distinguish e+ vs pi+, which is probably not true in the case (e+,n) vs (pi+,gamma) without longitudinal segmentation.
28
29 *
30 * \author M. Selvaggi - CERN
31 *
32 */
33
34#include "modules/DualReadoutCalorimeter.h"
35
36#include "classes/DelphesClasses.h"
37#include "classes/DelphesFactory.h"
38#include "classes/DelphesFormula.h"
39
40#include "ExRootAnalysis/ExRootResult.h"
41#include "ExRootAnalysis/ExRootFilter.h"
42#include "ExRootAnalysis/ExRootClassifier.h"
43
44#include "TMath.h"
45#include "TString.h"
46#include "TFormula.h"
47#include "TRandom3.h"
48#include "TObjArray.h"
49#include "TDatabasePDG.h"
50#include "TLorentzVector.h"
51
52#include <algorithm>
53#include <stdexcept>
54#include <iostream>
55#include <sstream>
56
57using namespace std;
58
59//------------------------------------------------------------------------------
60
61DualReadoutCalorimeter::DualReadoutCalorimeter() :
62 fECalResolutionFormula(0), fHCalResolutionFormula(0),
63 fItParticleInputArray(0), fItTrackInputArray(0)
64{
65
66 fECalResolutionFormula = new DelphesFormula;
67 fHCalResolutionFormula = new DelphesFormula;
68
69 fECalTowerTrackArray = new TObjArray;
70 fItECalTowerTrackArray = fECalTowerTrackArray->MakeIterator();
71
72 fHCalTowerTrackArray = new TObjArray;
73 fItHCalTowerTrackArray = fHCalTowerTrackArray->MakeIterator();
74
75 fTowerTrackArray = new TObjArray;
76 fItTowerTrackArray = fTowerTrackArray->MakeIterator();
77
78}
79
80//------------------------------------------------------------------------------
81
82DualReadoutCalorimeter::~DualReadoutCalorimeter()
83{
84
85 if(fECalResolutionFormula) delete fECalResolutionFormula;
86 if(fHCalResolutionFormula) delete fHCalResolutionFormula;
87
88 if(fECalTowerTrackArray) delete fECalTowerTrackArray;
89 if(fItECalTowerTrackArray) delete fItECalTowerTrackArray;
90
91 if(fHCalTowerTrackArray) delete fHCalTowerTrackArray;
92 if(fItHCalTowerTrackArray) delete fItHCalTowerTrackArray;
93
94 if(fTowerTrackArray) delete fTowerTrackArray;
95 if(fItTowerTrackArray) delete fItTowerTrackArray;
96
97}
98
99//------------------------------------------------------------------------------
100
101void DualReadoutCalorimeter::Init()
102{
103 ExRootConfParam param, paramEtaBins, paramPhiBins, paramFractions;
104 Long_t i, j, k, size, sizeEtaBins, sizePhiBins;
105 Double_t ecalFraction, hcalFraction;
106 TBinMap::iterator itEtaBin;
107 set< Double_t >::iterator itPhiBin;
108 vector< Double_t > *phiBins;
109
110 // read eta and phi bins
111 param = GetParam("EtaPhiBins");
112 size = param.GetSize();
113 fBinMap.clear();
114 fEtaBins.clear();
115 fPhiBins.clear();
116 for(i = 0; i < size/2; ++i)
117 {
118 paramEtaBins = param[i*2];
119 sizeEtaBins = paramEtaBins.GetSize();
120 paramPhiBins = param[i*2 + 1];
121 sizePhiBins = paramPhiBins.GetSize();
122
123 for(j = 0; j < sizeEtaBins; ++j)
124 {
125 for(k = 0; k < sizePhiBins; ++k)
126 {
127 fBinMap[paramEtaBins[j].GetDouble()].insert(paramPhiBins[k].GetDouble());
128 }
129 }
130 }
131
132 // for better performance we transform map of sets to parallel vectors:
133 // vector< double > and vector< vector< double >* >
134 for(itEtaBin = fBinMap.begin(); itEtaBin != fBinMap.end(); ++itEtaBin)
135 {
136 fEtaBins.push_back(itEtaBin->first);
137 phiBins = new vector< double >(itEtaBin->second.size());
138 fPhiBins.push_back(phiBins);
139 phiBins->clear();
140 for(itPhiBin = itEtaBin->second.begin(); itPhiBin != itEtaBin->second.end(); ++itPhiBin)
141 {
142 phiBins->push_back(*itPhiBin);
143 }
144 }
145
146 // read energy fractions for different particles
147 param = GetParam("EnergyFraction");
148 size = param.GetSize();
149
150 // set default energy fractions values
151 fFractionMap.clear();
152 fFractionMap[0] = make_pair(0.0, 1.0);
153
154 for(i = 0; i < size/2; ++i)
155 {
156 paramFractions = param[i*2 + 1];
157
158 ecalFraction = paramFractions[0].GetDouble();
159 hcalFraction = paramFractions[1].GetDouble();
160
161 fFractionMap[param[i*2].GetInt()] = make_pair(ecalFraction, hcalFraction);
162 }
163
164 // read min E value for timing measurement in ECAL
165 fTimingEnergyMin = GetDouble("TimingEnergyMin",4.);
166 // For timing
167 // So far this flag needs to be false
168 // Curved extrapolation not supported
169 fElectronsFromTrack = false;
170
171 // read min E value for towers to be saved
172 fECalEnergyMin = GetDouble("ECalEnergyMin", 0.0);
173 fHCalEnergyMin = GetDouble("HCalEnergyMin", 0.0);
174 fEnergyMin = GetDouble("EnergyMin", 0.0);
175
176 fECalEnergySignificanceMin = GetDouble("ECalEnergySignificanceMin", 0.0);
177 fHCalEnergySignificanceMin = GetDouble("HCalEnergySignificanceMin", 0.0);
178 fEnergySignificanceMin = GetDouble("EnergySignificanceMin", 0.0);
179
180 // switch on or off the dithering of the center of DualReadoutCalorimeter towers
181 fSmearTowerCenter = GetBool("SmearTowerCenter", true);
182
183 // read resolution formulas
184 fECalResolutionFormula->Compile(GetString("ECalResolutionFormula", "0"));
185 fHCalResolutionFormula->Compile(GetString("HCalResolutionFormula", "0"));
186
187 // import array with output from other modules
188 fParticleInputArray = ImportArray(GetString("ParticleInputArray", "ParticlePropagator/particles"));
189 fItParticleInputArray = fParticleInputArray->MakeIterator();
190
191 fTrackInputArray = ImportArray(GetString("TrackInputArray", "ParticlePropagator/tracks"));
192 fItTrackInputArray = fTrackInputArray->MakeIterator();
193
194 // create output arrays
195 fTowerOutputArray = ExportArray(GetString("TowerOutputArray", "towers"));
196 fPhotonOutputArray = ExportArray(GetString("PhotonOutputArray", "photons"));
197
198 fEFlowTrackOutputArray = ExportArray(GetString("EFlowTrackOutputArray", "eflowTracks"));
199 fEFlowPhotonOutputArray = ExportArray(GetString("EFlowPhotonOutputArray", "eflowPhotons"));
200 fEFlowNeutralHadronOutputArray = ExportArray(GetString("EFlowNeutralHadronOutputArray", "eflowNeutralHadrons"));
201}
202
203//------------------------------------------------------------------------------
204
205void DualReadoutCalorimeter::Finish()
206{
207 vector< vector< Double_t >* >::iterator itPhiBin;
208 if(fItParticleInputArray) delete fItParticleInputArray;
209 if(fItTrackInputArray) delete fItTrackInputArray;
210 for(itPhiBin = fPhiBins.begin(); itPhiBin != fPhiBins.end(); ++itPhiBin)
211 {
212 delete *itPhiBin;
213 }
214}
215
216//------------------------------------------------------------------------------
217
218void DualReadoutCalorimeter::Process()
219{
220 Candidate *particle, *track;
221 TLorentzVector position, momentum;
222 Short_t etaBin, phiBin, flags;
223 Int_t number;
224 Long64_t towerHit, towerEtaPhi, hitEtaPhi;
225 Double_t ecalFraction, hcalFraction;
226 Double_t ecalEnergy, hcalEnergy;
227 Double_t ecalSigma, hcalSigma, sigma;
228 Double_t energyGuess, energy;
229 Int_t pdgCode;
230
231 TFractionMap::iterator itFractionMap;
232
233 vector< Double_t >::iterator itEtaBin;
234 vector< Double_t >::iterator itPhiBin;
235 vector< Double_t > *phiBins;
236
237 vector< Long64_t >::iterator itTowerHits;
238
239 DelphesFactory *factory = GetFactory();
240 fTowerHits.clear();
241 fECalTowerFractions.clear();
242 fHCalTowerFractions.clear();
243 fECalTrackFractions.clear();
244 fHCalTrackFractions.clear();
245
246 // loop over all particles
247 fItParticleInputArray->Reset();
248 number = -1;
249 while((particle = static_cast<Candidate*>(fItParticleInputArray->Next())))
250 {
251 const TLorentzVector &particlePosition = particle->Position;
252 ++number;
253
254 pdgCode = TMath::Abs(particle->PID);
255
256 itFractionMap = fFractionMap.find(pdgCode);
257 if(itFractionMap == fFractionMap.end())
258 {
259 itFractionMap = fFractionMap.find(0);
260 }
261
262 ecalFraction = itFractionMap->second.first;
263 hcalFraction = itFractionMap->second.second;
264
265 fECalTowerFractions.push_back(ecalFraction);
266 fHCalTowerFractions.push_back(hcalFraction);
267
268 if(ecalFraction < 1.0E-9 && hcalFraction < 1.0E-9) continue;
269
270 // find eta bin [1, fEtaBins.size - 1]
271 itEtaBin = lower_bound(fEtaBins.begin(), fEtaBins.end(), particlePosition.Eta());
272 if(itEtaBin == fEtaBins.begin() || itEtaBin == fEtaBins.end()) continue;
273 etaBin = distance(fEtaBins.begin(), itEtaBin);
274
275 // phi bins for given eta bin
276 phiBins = fPhiBins[etaBin];
277
278 // find phi bin [1, phiBins.size - 1]
279 itPhiBin = lower_bound(phiBins->begin(), phiBins->end(), particlePosition.Phi());
280 if(itPhiBin == phiBins->begin() || itPhiBin == phiBins->end()) continue;
281 phiBin = distance(phiBins->begin(), itPhiBin);
282
283 flags = 0;
284 flags |= (pdgCode == 11 || pdgCode == 22) << 1;
285
286 // make tower hit {16-bits for eta bin number, 16-bits for phi bin number, 8-bits for flags, 24-bits for particle number}
287 towerHit = (Long64_t(etaBin) << 48) | (Long64_t(phiBin) << 32) | (Long64_t(flags) << 24) | Long64_t(number);
288
289 fTowerHits.push_back(towerHit);
290 }
291
292 // loop over all tracks
293 fItTrackInputArray->Reset();
294 number = -1;
295 while((track = static_cast<Candidate*>(fItTrackInputArray->Next())))
296 {
297 const TLorentzVector &trackPosition = track->Position;
298 ++number;
299
300 pdgCode = TMath::Abs(track->PID);
301
302 itFractionMap = fFractionMap.find(pdgCode);
303 if(itFractionMap == fFractionMap.end())
304 {
305 itFractionMap = fFractionMap.find(0);
306 }
307
308 ecalFraction = itFractionMap->second.first;
309 hcalFraction = itFractionMap->second.second;
310
311 fECalTrackFractions.push_back(ecalFraction);
312 fHCalTrackFractions.push_back(hcalFraction);
313
314 // find eta bin [1, fEtaBins.size - 1]
315 itEtaBin = lower_bound(fEtaBins.begin(), fEtaBins.end(), trackPosition.Eta());
316 if(itEtaBin == fEtaBins.begin() || itEtaBin == fEtaBins.end()) continue;
317 etaBin = distance(fEtaBins.begin(), itEtaBin);
318
319 // phi bins for given eta bin
320 phiBins = fPhiBins[etaBin];
321
322 // find phi bin [1, phiBins.size - 1]
323 itPhiBin = lower_bound(phiBins->begin(), phiBins->end(), trackPosition.Phi());
324 if(itPhiBin == phiBins->begin() || itPhiBin == phiBins->end()) continue;
325 phiBin = distance(phiBins->begin(), itPhiBin);
326
327 flags = 1;
328
329 // make tower hit {16-bits for eta bin number, 16-bits for phi bin number, 8-bits for flags, 24-bits for track number}
330 towerHit = (Long64_t(etaBin) << 48) | (Long64_t(phiBin) << 32) | (Long64_t(flags) << 24) | Long64_t(number);
331
332 fTowerHits.push_back(towerHit);
333 }
334
335 // all hits are sorted first by eta bin number, then by phi bin number,
336 // then by flags and then by particle or track number
337 sort(fTowerHits.begin(), fTowerHits.end());
338
339 // loop over all hits
340 towerEtaPhi = 0;
341 fTower = 0;
342 for(itTowerHits = fTowerHits.begin(); itTowerHits != fTowerHits.end(); ++itTowerHits)
343 {
344 towerHit = (*itTowerHits);
345 flags = (towerHit >> 24) & 0x00000000000000FFLL;
346 number = (towerHit) & 0x0000000000FFFFFFLL;
347 hitEtaPhi = towerHit >> 32;
348
349 if(towerEtaPhi != hitEtaPhi)
350 {
351 // switch to next tower
352 towerEtaPhi = hitEtaPhi;
353
354 // finalize previous tower
355 FinalizeTower();
356
357 // create new tower
358 fTower = factory->NewCandidate();
359
360 phiBin = (towerHit >> 32) & 0x000000000000FFFFLL;
361 etaBin = (towerHit >> 48) & 0x000000000000FFFFLL;
362
363 // phi bins for given eta bin
364 phiBins = fPhiBins[etaBin];
365
366 // calculate eta and phi of the tower's center
367 fTowerEta = 0.5*(fEtaBins[etaBin - 1] + fEtaBins[etaBin]);
368 fTowerPhi = 0.5*((*phiBins)[phiBin - 1] + (*phiBins)[phiBin]);
369
370 fTowerEdges[0] = fEtaBins[etaBin - 1];
371 fTowerEdges[1] = fEtaBins[etaBin];
372 fTowerEdges[2] = (*phiBins)[phiBin - 1];
373 fTowerEdges[3] = (*phiBins)[phiBin];
374
375 fECalTowerEnergy = 0.0;
376 fHCalTowerEnergy = 0.0;
377
378 fECalTrackEnergy = 0.0;
379 fHCalTrackEnergy = 0.0;
380 fTrackEnergy = 0.0;
381
382 fECalTrackSigma = 0.0;
383 fHCalTrackSigma = 0.0;
384 fTrackSigma = 0.0;
385
386 fTowerTrackHits = 0;
387 fTowerPhotonHits = 0;
388
389 fECalTowerTrackArray->Clear();
390 fHCalTowerTrackArray->Clear();
391 fTowerTrackArray->Clear();
392
393 }
394
395 // check for track hits
396 if(flags & 1)
397 {
398 ++fTowerTrackHits;
399
400 track = static_cast<Candidate*>(fTrackInputArray->At(number));
401 momentum = track->Momentum;
402 position = track->Position;
403
404 ecalEnergy = momentum.E() * fECalTrackFractions[number];
405 hcalEnergy = momentum.E() * fHCalTrackFractions[number];
406 energy = ecalEnergy + hcalEnergy;
407
408 if(ecalEnergy > fTimingEnergyMin && fTower)
409 {
410 if(fElectronsFromTrack)
411 {
412 fTower->ECalEnergyTimePairs.push_back(make_pair<Float_t, Float_t>(ecalEnergy, track->Position.T()));
413 }
414 }
415
416
417 // in Dual Readout we do not care if tracks are ECAL of HCAL
418 if(fECalTrackFractions[number] > 1.0E-9 || fHCalTrackFractions[number] > 1.0E-9)
419 {
420 fTrackEnergy += energy;
421 // this sigma will be used to determine whether neutral excess is significant. We choose the resolution according to bthe higest deposited fraction (in practice had for charged hadrons and em for electrons)
422 sigma = 0.0;
423 if(fHCalTrackFractions[number] > 0)
424 sigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, momentum.E());
425 else
426 sigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, momentum.E());
427
428 if(sigma/momentum.E() < track->TrackResolution)
429 energyGuess = ecalEnergy + hcalEnergy;
430 else
431 energyGuess = momentum.E();
432
433 fTrackSigma += (track->TrackResolution)*energyGuess*(track->TrackResolution)*energyGuess;
434 fTowerTrackArray->Add(track);
435
436 }
437 else
438 {
439 fEFlowTrackOutputArray->Add(track);
440 }
441
442 continue;
443 }
444
445 // check for photon and electron hits in current tower
446 if(flags & 2) ++fTowerPhotonHits;
447
448 particle = static_cast<Candidate*>(fParticleInputArray->At(number));
449 momentum = particle->Momentum;
450 position = particle->Position;
451
452 // fill current tower
453 ecalEnergy = momentum.E() * fECalTowerFractions[number];
454 hcalEnergy = momentum.E() * fHCalTowerFractions[number];
455
456 fECalTowerEnergy += ecalEnergy;
457 fHCalTowerEnergy += hcalEnergy;
458
459 if(ecalEnergy > fTimingEnergyMin && fTower)
460 {
461 if (abs(particle->PID) != 11 || !fElectronsFromTrack)
462 {
463 fTower->ECalEnergyTimePairs.push_back(make_pair<Float_t, Float_t>(ecalEnergy, particle->Position.T()));
464 }
465 }
466
467 fTower->AddCandidate(particle);
468 }
469
470 // finalize last tower
471 FinalizeTower();
472}
473
474//------------------------------------------------------------------------------
475
476void DualReadoutCalorimeter::FinalizeTower()
477{
478
479 Candidate *track, *tower, *mother;
480 Double_t energy, pt, eta, phi;
481 Double_t ecalEnergy, hcalEnergy;
482 Double_t ecalNeutralEnergy, hcalNeutralEnergy, neutralEnergy;
483
484 Double_t ecalSigma, hcalSigma, sigma;
485 Double_t ecalNeutralSigma, hcalNeutralSigma, neutralSigma;
486
487 Double_t weightTrack, weightCalo, bestEnergyEstimate, rescaleFactor;
488
489 TLorentzVector momentum;
490 TFractionMap::iterator itFractionMap;
491
492 Float_t weight, sumWeightedTime, sumWeight;
493
494 if(!fTower) return;
495
496
497 //if (fHCalTowerEnergy < 30 && fECalTowerEnergy < 30) return;
498 //cout<<"----------- New tower ---------"<<endl;
499
500
501 // here we change behaviour w.r.t to standard calorimeter. Start with worse case scenario. If fHCalTowerEnergy > 0, assume total energy smeared by HCAL resolution.
502 // For example, if overlapping charged pions and photons take hadronic resolution as combined measurement
503
504 // if no hadronic fraction at all, then use ECAL resolution
505
506 //cout<<"fECalTowerEnergy: "<<fECalTowerEnergy<<", fHCalTowerEnergy: "<<fHCalTowerEnergy<<", Eta: "<<fTowerEta<<endl;
507
508 // if no hadronic energy, use ECAL resolution
509 if (fHCalTowerEnergy <= fHCalEnergyMin)
510 {
511 energy = fECalTowerEnergy;
512 sigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy);
513 //cout<<"em energy"<<energy<<", sigma: "<<sigma<<endl;
514 }
515
516 // if hadronic fraction > 0, use HCAL resolution
517 else
518 {
519 energy = fECalTowerEnergy + fHCalTowerEnergy;
520 sigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy);
521 //cout<<"had energy: "<<energy<<", sigma: "<<sigma<<endl;
522 }
523
524 energy = LogNormal(energy, sigma);
525 //cout<<energy<<","<<ecalEnergy<<","<<hcalEnergy<<endl;
526
527 if(energy < fEnergyMin || energy < fEnergySignificanceMin*sigma) energy = 0.0;
528
529 // for now keep this the same
530 ecalSigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, fECalTowerEnergy);
531 hcalSigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, fHCalTowerEnergy);
532
533 ecalEnergy = LogNormal(fECalTowerEnergy, ecalSigma);
534 hcalEnergy = LogNormal(fHCalTowerEnergy, hcalSigma);
535
536 ecalSigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, ecalEnergy);
537 hcalSigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, hcalEnergy);
538
539 if(ecalEnergy < fECalEnergyMin || ecalEnergy < fECalEnergySignificanceMin*ecalSigma) ecalEnergy = 0.0;
540 if(hcalEnergy < fHCalEnergyMin || hcalEnergy < fHCalEnergySignificanceMin*hcalSigma) hcalEnergy = 0.0;
541
542 //cout<<"Measured energy: "<<energy<<endl;
543
544 if(fSmearTowerCenter)
545 {
546 eta = gRandom->Uniform(fTowerEdges[0], fTowerEdges[1]);
547 phi = gRandom->Uniform(fTowerEdges[2], fTowerEdges[3]);
548 }
549 else
550 {
551 eta = fTowerEta;
552 phi = fTowerPhi;
553 }
554
555 pt = energy / TMath::CosH(eta);
556
557 // Time calculation for tower
558 fTower->NTimeHits = 0;
559 sumWeightedTime = 0.0;
560 sumWeight = 0.0;
561
562 for(size_t i = 0; i < fTower->ECalEnergyTimePairs.size(); ++i)
563 {
564 weight = TMath::Sqrt(fTower->ECalEnergyTimePairs[i].first);
565 sumWeightedTime += weight * fTower->ECalEnergyTimePairs[i].second;
566 sumWeight += weight;
567 fTower->NTimeHits++;
568 }
569
570 if(sumWeight > 0.0)
571 {
572 fTower->Position.SetPtEtaPhiE(1.0, eta, phi, sumWeightedTime/sumWeight);
573 }
574 else
575 {
576 fTower->Position.SetPtEtaPhiE(1.0, eta, phi, 999999.9);
577 }
578
579 fTower->Momentum.SetPtEtaPhiE(pt, eta, phi, energy);
580 fTower->Eem = ecalEnergy;
581 fTower->Ehad = hcalEnergy;
582
583 fTower->Edges[0] = fTowerEdges[0];
584 fTower->Edges[1] = fTowerEdges[1];
585 fTower->Edges[2] = fTowerEdges[2];
586 fTower->Edges[3] = fTowerEdges[3];
587
588 if(energy > 0.0)
589 {
590 if(fTowerPhotonHits > 0 && fTowerTrackHits == 0)
591 {
592 fPhotonOutputArray->Add(fTower);
593 }
594 fTowerOutputArray->Add(fTower);
595 }
596
597 // fill energy flow candidates
598
599 fTrackSigma = TMath::Sqrt(fTrackSigma);
600 neutralEnergy = max( (energy - fTrackEnergy) , 0.0);
601 neutralSigma = neutralEnergy / TMath::Sqrt(fTrackSigma*fTrackSigma + sigma*sigma);
602
603 //cout<<"trackEnergy: "<<fTrackEnergy<<", trackSigma: "<<fTrackSigma<<", Ntracks: "<<fTowerTrackArray->GetEntries()<<endl;
604
605 //cout<<"neutralEnergy: "<<neutralEnergy<<", neutralSigma: "<<neutralSigma<<", :fEnergyMin "<<fEnergyMin<<", fEnergySignificanceMin: "<<fEnergySignificanceMin<<endl;
606
607 // For now, if neutral excess is significant, simply create neutral EflowPhoton tower and clone each track into eflowtrack !!! -> Creating only photons !! EFlowNeutralHadron collection will be empy!!! TO BE FIXED
608 if(neutralEnergy > fEnergyMin && neutralSigma > fEnergySignificanceMin)
609 {
610
611 //cout<<"significant neutral excess found:"<<endl;
612 // create new photon tower
613 tower = static_cast<Candidate*>(fTower->Clone());
614 pt = neutralEnergy / TMath::CosH(eta);
615 //cout<<"Creating tower with Pt, Eta, Phi, Energy: "<<pt<<","<<eta<<","<<phi<<","<<neutralEnergy<<endl;
616 tower->Momentum.SetPtEtaPhiE(pt, eta, phi, neutralEnergy);
617
618 // if no hadronic energy, use ECAL resolution
619 if (fHCalTowerEnergy <= fHCalEnergyMin)
620 {
621 tower->Eem = neutralEnergy;
622 tower->Ehad = 0.0;
623 tower->PID = 22;
624 }
625
626 // if hadronic fraction > 0, use HCAL resolution
627 else
628 {
629 tower->Eem = 0;
630 tower->Ehad = neutralEnergy;
631 tower->PID = 130;
632 }
633
634 fEFlowPhotonOutputArray->Add(tower);
635
636
637 //clone tracks
638 fItTowerTrackArray->Reset();
639 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next())))
640 {
641 mother = track;
642 track = static_cast<Candidate*>(track->Clone());
643 track->AddCandidate(mother);
644 fEFlowTrackOutputArray->Add(track);
645 }
646 }
647
648
649 // if neutral excess is not significant, rescale eflow tracks, such that the total charged equals the best measurement given by the DualReadoutCalorimeter and tracking
650 else if(fTrackEnergy > 0.0)
651 {
652 //cout<<"no significant neutral excess found:"<<endl;
653 weightTrack = (fTrackSigma > 0.0) ? 1 / (fTrackSigma*fTrackSigma) : 0.0;
654 weightCalo = (sigma > 0.0) ? 1 / (sigma*sigma) : 0.0;
655
656 bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo);
657 rescaleFactor = bestEnergyEstimate/fTrackEnergy;
658
659 //rescale tracks
660 fItTowerTrackArray->Reset();
661 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next())))
662 {
663 mother = track;
664 track = static_cast<Candidate *>(track->Clone());
665 track->AddCandidate(mother);
666 track->Momentum.SetPtEtaPhiM(track->Momentum.Pt()*rescaleFactor, track->Momentum.Eta(), track->Momentum.Phi(), track->Momentum.M());
667 fEFlowTrackOutputArray->Add(track);
668 }
669 }
670
671
672}
673
674//------------------------------------------------------------------------------
675
676Double_t DualReadoutCalorimeter::LogNormal(Double_t mean, Double_t sigma)
677{
678 Double_t a, b;
679
680 if(mean > 0.0)
681 {
682 b = TMath::Sqrt(TMath::Log((1.0 + (sigma*sigma)/(mean*mean))));
683 a = TMath::Log(mean) - 0.5*b*b;
684
685 return TMath::Exp(a + b*gRandom->Gaus(0.0, 1.0));
686 }
687 else
688 {
689 return 0.0;
690 }
691}
Note: See TracBrowser for help on using the repository browser.