Fork me on GitHub

source: git/modules/SimpleCalorimeter.cc@ e5ea42e

Last change on this file since e5ea42e was 7da1826, checked in by Michele Selvaggi <michele.selvaggi@…>, 8 years ago

apply better energy estimate also for simple calo

  • Property mode set to 100644
File size: 15.5 KB
RevLine 
[01f457a]1/*
2 * Delphes: a framework for fast simulation of a generic collider experiment
3 * Copyright (C) 2012-2014 Universite catholique de Louvain (UCL), Belgium
[1fa50c2]4 *
[01f457a]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.
[1fa50c2]9 *
[01f457a]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.
[1fa50c2]14 *
[01f457a]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
[82575a3]19
20/** \class SimpleCalorimeter
21 *
22 * Fills SimpleCalorimeter towers, performs SimpleCalorimeter resolution smearing,
23 * and creates energy flow objects (tracks, photons, and neutral hadrons).
24 *
25 * \author P. Demin - UCL, Louvain-la-Neuve
26 *
27 */
28
29#include "modules/SimpleCalorimeter.h"
30
31#include "classes/DelphesClasses.h"
32#include "classes/DelphesFactory.h"
33#include "classes/DelphesFormula.h"
34
35#include "ExRootAnalysis/ExRootResult.h"
36#include "ExRootAnalysis/ExRootFilter.h"
37#include "ExRootAnalysis/ExRootClassifier.h"
38
39#include "TMath.h"
40#include "TString.h"
41#include "TFormula.h"
42#include "TRandom3.h"
43#include "TObjArray.h"
44#include "TDatabasePDG.h"
45#include "TLorentzVector.h"
46
47#include <algorithm>
48#include <stdexcept>
49#include <iostream>
50#include <sstream>
51
52using namespace std;
53
54//------------------------------------------------------------------------------
55
56SimpleCalorimeter::SimpleCalorimeter() :
57 fResolutionFormula(0),
[df636c74]58 fItParticleInputArray(0), fItTrackInputArray(0)
[82575a3]59{
[efac6f9]60
[82575a3]61 fResolutionFormula = new DelphesFormula;
[efac6f9]62 fTowerTrackArray = new TObjArray;
63 fItTowerTrackArray = fTowerTrackArray->MakeIterator();
64
[82575a3]65}
66
67//------------------------------------------------------------------------------
68
69SimpleCalorimeter::~SimpleCalorimeter()
70{
[efac6f9]71
[82575a3]72 if(fResolutionFormula) delete fResolutionFormula;
[efac6f9]73 if(fTowerTrackArray) delete fTowerTrackArray;
74 if(fItTowerTrackArray) delete fItTowerTrackArray;
75
[82575a3]76}
77
78//------------------------------------------------------------------------------
79
80void SimpleCalorimeter::Init()
81{
82 ExRootConfParam param, paramEtaBins, paramPhiBins, paramFractions;
83 Long_t i, j, k, size, sizeEtaBins, sizePhiBins;
84 Double_t fraction;
85 TBinMap::iterator itEtaBin;
86 set< Double_t >::iterator itPhiBin;
87 vector< Double_t > *phiBins;
88
89 // read eta and phi bins
90 param = GetParam("EtaPhiBins");
91 size = param.GetSize();
92 fBinMap.clear();
93 fEtaBins.clear();
94 fPhiBins.clear();
95 for(i = 0; i < size/2; ++i)
96 {
97 paramEtaBins = param[i*2];
98 sizeEtaBins = paramEtaBins.GetSize();
99 paramPhiBins = param[i*2 + 1];
100 sizePhiBins = paramPhiBins.GetSize();
101
102 for(j = 0; j < sizeEtaBins; ++j)
103 {
104 for(k = 0; k < sizePhiBins; ++k)
105 {
106 fBinMap[paramEtaBins[j].GetDouble()].insert(paramPhiBins[k].GetDouble());
107 }
108 }
109 }
110
111 // for better performance we transform map of sets to parallel vectors:
112 // vector< double > and vector< vector< double >* >
113 for(itEtaBin = fBinMap.begin(); itEtaBin != fBinMap.end(); ++itEtaBin)
114 {
115 fEtaBins.push_back(itEtaBin->first);
116 phiBins = new vector< double >(itEtaBin->second.size());
117 fPhiBins.push_back(phiBins);
118 phiBins->clear();
119 for(itPhiBin = itEtaBin->second.begin(); itPhiBin != itEtaBin->second.end(); ++itPhiBin)
120 {
121 phiBins->push_back(*itPhiBin);
122 }
123 }
124
125 // read energy fractions for different particles
126 param = GetParam("EnergyFraction");
127 size = param.GetSize();
128
129 // set default energy fractions values
130 fFractionMap.clear();
131 fFractionMap[0] = 1.0;
132
133 for(i = 0; i < size/2; ++i)
134 {
135 paramFractions = param[i*2 + 1];
136 fraction = paramFractions[0].GetDouble();
137 fFractionMap[param[i*2].GetInt()] = fraction;
138 }
[e5767b57]139
[4b9a2dc]140 // read min E value for towers to be saved
[e5767b57]141 fEnergyMin = GetDouble("EnergyMin", 0.0);
142
143 fEnergySignificanceMin = GetDouble("EnergySignificanceMin", 0.0);
144
[fc6300d]145 // flag that says if current calo is Ecal of Hcal (will then fill correct values of Eem and Ehad)
146 fIsEcal = GetBool("IsEcal", false);
147
[e5767b57]148 // switch on or off the dithering of the center of calorimeter towers
[4e09c3a]149 fSmearTowerCenter = GetBool("SmearTowerCenter", true);
[e5767b57]150
[82575a3]151 // read resolution formulas
152 fResolutionFormula->Compile(GetString("ResolutionFormula", "0"));
[e5767b57]153
[82575a3]154 // import array with output from other modules
155 fParticleInputArray = ImportArray(GetString("ParticleInputArray", "ParticlePropagator/particles"));
156 fItParticleInputArray = fParticleInputArray->MakeIterator();
157
158 fTrackInputArray = ImportArray(GetString("TrackInputArray", "ParticlePropagator/tracks"));
159 fItTrackInputArray = fTrackInputArray->MakeIterator();
160
161 // create output arrays
162 fTowerOutputArray = ExportArray(GetString("TowerOutputArray", "towers"));
[df636c74]163
[a98c7ef]164 fEFlowTrackOutputArray = ExportArray(GetString("EFlowTrackOutputArray", "eflowTracks"));
[82575a3]165 fEFlowTowerOutputArray = ExportArray(GetString("EFlowTowerOutputArray", "eflowTowers"));
166}
167
168//------------------------------------------------------------------------------
169
170void SimpleCalorimeter::Finish()
171{
172 vector< vector< Double_t >* >::iterator itPhiBin;
173 if(fItParticleInputArray) delete fItParticleInputArray;
174 if(fItTrackInputArray) delete fItTrackInputArray;
175 for(itPhiBin = fPhiBins.begin(); itPhiBin != fPhiBins.end(); ++itPhiBin)
176 {
177 delete *itPhiBin;
178 }
179}
180
181//------------------------------------------------------------------------------
182
183void SimpleCalorimeter::Process()
184{
185 Candidate *particle, *track;
186 TLorentzVector position, momentum;
187 Short_t etaBin, phiBin, flags;
188 Int_t number;
189 Long64_t towerHit, towerEtaPhi, hitEtaPhi;
190 Double_t fraction;
191 Double_t energy;
[7da1826]192 Double_t sigma;
193 Double_t energyGuess;
194
[82575a3]195 Int_t pdgCode;
196
197 TFractionMap::iterator itFractionMap;
198
199 vector< Double_t >::iterator itEtaBin;
200 vector< Double_t >::iterator itPhiBin;
201 vector< Double_t > *phiBins;
202
203 vector< Long64_t >::iterator itTowerHits;
204
205 DelphesFactory *factory = GetFactory();
206 fTowerHits.clear();
207 fTowerFractions.clear();
208 fTrackFractions.clear();
[e5767b57]209
[82575a3]210 // loop over all particles
211 fItParticleInputArray->Reset();
212 number = -1;
213 while((particle = static_cast<Candidate*>(fItParticleInputArray->Next())))
214 {
215 const TLorentzVector &particlePosition = particle->Position;
216 ++number;
217
218 pdgCode = TMath::Abs(particle->PID);
219
220 itFractionMap = fFractionMap.find(pdgCode);
221 if(itFractionMap == fFractionMap.end())
222 {
223 itFractionMap = fFractionMap.find(0);
224 }
225
226 fraction = itFractionMap->second;
227 fTowerFractions.push_back(fraction);
[e5767b57]228
[82575a3]229 if(fraction < 1.0E-9) continue;
230
231 // find eta bin [1, fEtaBins.size - 1]
232 itEtaBin = lower_bound(fEtaBins.begin(), fEtaBins.end(), particlePosition.Eta());
233 if(itEtaBin == fEtaBins.begin() || itEtaBin == fEtaBins.end()) continue;
234 etaBin = distance(fEtaBins.begin(), itEtaBin);
235
236 // phi bins for given eta bin
237 phiBins = fPhiBins[etaBin];
238
239 // find phi bin [1, phiBins.size - 1]
240 itPhiBin = lower_bound(phiBins->begin(), phiBins->end(), particlePosition.Phi());
241 if(itPhiBin == phiBins->begin() || itPhiBin == phiBins->end()) continue;
242 phiBin = distance(phiBins->begin(), itPhiBin);
243
244 flags = 0;
245 flags |= (pdgCode == 11 || pdgCode == 22) << 1;
246
247 // make tower hit {16-bits for eta bin number, 16-bits for phi bin number, 8-bits for flags, 24-bits for particle number}
248 towerHit = (Long64_t(etaBin) << 48) | (Long64_t(phiBin) << 32) | (Long64_t(flags) << 24) | Long64_t(number);
249
250 fTowerHits.push_back(towerHit);
251 }
252
253 // loop over all tracks
254 fItTrackInputArray->Reset();
255 number = -1;
256 while((track = static_cast<Candidate*>(fItTrackInputArray->Next())))
257 {
258 const TLorentzVector &trackPosition = track->Position;
259 ++number;
260
261 pdgCode = TMath::Abs(track->PID);
262
263 itFractionMap = fFractionMap.find(pdgCode);
264 if(itFractionMap == fFractionMap.end())
265 {
266 itFractionMap = fFractionMap.find(0);
267 }
268
269 fraction = itFractionMap->second;
[e5767b57]270
[82575a3]271 fTrackFractions.push_back(fraction);
[e5767b57]272
[82575a3]273 // find eta bin [1, fEtaBins.size - 1]
274 itEtaBin = lower_bound(fEtaBins.begin(), fEtaBins.end(), trackPosition.Eta());
275 if(itEtaBin == fEtaBins.begin() || itEtaBin == fEtaBins.end()) continue;
276 etaBin = distance(fEtaBins.begin(), itEtaBin);
277
278 // phi bins for given eta bin
279 phiBins = fPhiBins[etaBin];
280
281 // find phi bin [1, phiBins.size - 1]
282 itPhiBin = lower_bound(phiBins->begin(), phiBins->end(), trackPosition.Phi());
283 if(itPhiBin == phiBins->begin() || itPhiBin == phiBins->end()) continue;
284 phiBin = distance(phiBins->begin(), itPhiBin);
285
286 flags = 1;
287
288 // make tower hit {16-bits for eta bin number, 16-bits for phi bin number, 8-bits for flags, 24-bits for track number}
289 towerHit = (Long64_t(etaBin) << 48) | (Long64_t(phiBin) << 32) | (Long64_t(flags) << 24) | Long64_t(number);
290
291 fTowerHits.push_back(towerHit);
292 }
293
294 // all hits are sorted first by eta bin number, then by phi bin number,
295 // then by flags and then by particle or track number
296 sort(fTowerHits.begin(), fTowerHits.end());
297
298 // loop over all hits
299 towerEtaPhi = 0;
300 fTower = 0;
301 for(itTowerHits = fTowerHits.begin(); itTowerHits != fTowerHits.end(); ++itTowerHits)
302 {
303 towerHit = (*itTowerHits);
304 flags = (towerHit >> 24) & 0x00000000000000FFLL;
305 number = (towerHit) & 0x0000000000FFFFFFLL;
306 hitEtaPhi = towerHit >> 32;
307
308 if(towerEtaPhi != hitEtaPhi)
309 {
310 // switch to next tower
311 towerEtaPhi = hitEtaPhi;
312
313 // finalize previous tower
314 FinalizeTower();
315
316 // create new tower
317 fTower = factory->NewCandidate();
318
319 phiBin = (towerHit >> 32) & 0x000000000000FFFFLL;
320 etaBin = (towerHit >> 48) & 0x000000000000FFFFLL;
321
322 // phi bins for given eta bin
323 phiBins = fPhiBins[etaBin];
324
325 // calculate eta and phi of the tower's center
326 fTowerEta = 0.5*(fEtaBins[etaBin - 1] + fEtaBins[etaBin]);
327 fTowerPhi = 0.5*((*phiBins)[phiBin - 1] + (*phiBins)[phiBin]);
328
329 fTowerEdges[0] = fEtaBins[etaBin - 1];
330 fTowerEdges[1] = fEtaBins[etaBin];
331 fTowerEdges[2] = (*phiBins)[phiBin - 1];
332 fTowerEdges[3] = (*phiBins)[phiBin];
333
334 fTowerEnergy = 0.0;
[df636c74]335
[efac6f9]336 fTrackEnergy = 0.0;
337 fTrackSigma = 0.0;
[e5767b57]338
[82575a3]339 fTowerTime = 0.0;
340 fTrackTime = 0.0;
[e5767b57]341
342 fTowerTimeWeight = 0.0;
343
[82575a3]344 fTowerTrackHits = 0;
345 fTowerPhotonHits = 0;
[e5767b57]346
[efac6f9]347 fTowerTrackArray->Clear();
348 }
[82575a3]349
350 // check for track hits
351 if(flags & 1)
352 {
353 ++fTowerTrackHits;
354
355 track = static_cast<Candidate*>(fTrackInputArray->At(number));
356 momentum = track->Momentum;
357 position = track->Position;
[e5767b57]358
[82575a3]359 energy = momentum.E() * fTrackFractions[number];
[e5767b57]360
[efac6f9]361 fTrackTime += TMath::Sqrt(energy)*position.T();
362 fTrackTimeWeight += TMath::Sqrt(energy);
[e5767b57]363
[df636c74]364 if(fTrackFractions[number] > 1.0E-9)
365 {
[efac6f9]366
367 // compute total charged energy
368 fTrackEnergy += energy;
[7da1826]369 sigma = fResolutionFormula->Eval(0.0, fTowerEta, 0.0, momentum.E());
370 if(sigma/momentum.E() < track->TrackResolution) energyGuess = energy;
371 else energyGuess = momentum.E();
372
373 fTrackSigma += ((track->TrackResolution)*energyGuess)*((track->TrackResolution)*energyGuess);
[efac6f9]374 fTowerTrackArray->Add(track);
[df636c74]375 }
[efac6f9]376
[d67b86b]377 else
[df636c74]378 {
379 fEFlowTrackOutputArray->Add(track);
380 }
[82575a3]381
382 continue;
383 }
[e5767b57]384
[82575a3]385 // check for photon and electron hits in current tower
386 if(flags & 2) ++fTowerPhotonHits;
[e5767b57]387
[82575a3]388 particle = static_cast<Candidate*>(fParticleInputArray->At(number));
389 momentum = particle->Momentum;
390 position = particle->Position;
391
392 // fill current tower
393 energy = momentum.E() * fTowerFractions[number];
[e5767b57]394
[82575a3]395 fTowerEnergy += energy;
[e5767b57]396
[e0f8f99]397 fTowerTime += energy*position.T();
398 fTowerTimeWeight += energy;
[e5767b57]399
[82575a3]400 fTower->AddCandidate(particle);
401 }
402
403 // finalize last tower
404 FinalizeTower();
405}
406
407//------------------------------------------------------------------------------
408
409void SimpleCalorimeter::FinalizeTower()
410{
[df636c74]411 Candidate *tower, *track, *mother;
[efac6f9]412 Double_t energy,neutralEnergy, pt, eta, phi;
413 Double_t sigma, neutralSigma;
[82575a3]414 Double_t time;
[efac6f9]415
416 Double_t weightTrack, weightCalo, bestEnergyEstimate, rescaleFactor;
[82575a3]417
[a98c7ef]418 TLorentzVector momentum;
419 TFractionMap::iterator itFractionMap;
[df636c74]420
[82575a3]421 if(!fTower) return;
422
423 sigma = fResolutionFormula->Eval(0.0, fTowerEta, 0.0, fTowerEnergy);
424
425 energy = LogNormal(fTowerEnergy, sigma);
[e5767b57]426
427 time = (fTowerTimeWeight < 1.0E-09 ) ? 0.0 : fTowerTime/fTowerTimeWeight;
[82575a3]428
[4b9a2dc]429 sigma = fResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy);
[e5767b57]430
431 if(energy < fEnergyMin || energy < fEnergySignificanceMin*sigma) energy = 0.0;
432
[efac6f9]433
[4e09c3a]434 if(fSmearTowerCenter)
[e5767b57]435 {
436 eta = gRandom->Uniform(fTowerEdges[0], fTowerEdges[1]);
437 phi = gRandom->Uniform(fTowerEdges[2], fTowerEdges[3]);
438 }
439 else
440 {
441 eta = fTowerEta;
442 phi = fTowerPhi;
443 }
[82575a3]444
445 pt = energy / TMath::CosH(eta);
446
447 fTower->Position.SetPtEtaPhiE(1.0, eta, phi, time);
448 fTower->Momentum.SetPtEtaPhiE(pt, eta, phi, energy);
[e5767b57]449
[fc6300d]450 fTower->Eem = (!fIsEcal) ? 0 : energy;
[df636c74]451 fTower->Ehad = (fIsEcal) ? 0 : energy;
[fc6300d]452
[82575a3]453 fTower->Edges[0] = fTowerEdges[0];
454 fTower->Edges[1] = fTowerEdges[1];
455 fTower->Edges[2] = fTowerEdges[2];
456 fTower->Edges[3] = fTowerEdges[3];
457
458 // fill SimpleCalorimeter towers
459 if(energy > 0.0) fTowerOutputArray->Add(fTower);
460
[efac6f9]461
462 // e-flow candidates
463
464 //compute neutral excess
465
466 fTrackSigma = TMath::Sqrt(fTrackSigma);
467 neutralEnergy = max( (energy - fTrackEnergy) , 0.0);
468
469 //compute sigma_trk total
470 neutralSigma = neutralEnergy / TMath::Sqrt(fTrackSigma*fTrackSigma+ sigma*sigma);
471
472 // if neutral excess is significant, simply create neutral Eflow tower and clone each track into eflowtrack
473 if(neutralEnergy > fEnergyMin && neutralSigma > fEnergySignificanceMin)
[a98c7ef]474 {
[efac6f9]475 // create new photon tower
476 tower = static_cast<Candidate*>(fTower->Clone());
477 pt = neutralEnergy / TMath::CosH(eta);
[df636c74]478
[efac6f9]479 tower->Eem = (!fIsEcal) ? 0 : neutralEnergy;
480 tower->Ehad = (fIsEcal) ? 0 : neutralEnergy;
481 tower->PID = (fIsEcal) ? 22 : 0;
482
483 tower->Momentum.SetPtEtaPhiE(pt, eta, phi, neutralEnergy);
484 fEFlowTowerOutputArray->Add(tower);
485
486 fItTowerTrackArray->Reset();
487 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next())))
488 {
489 mother = track;
490 track = static_cast<Candidate*>(track->Clone());
491 track->AddCandidate(mother);
[df636c74]492
[efac6f9]493 fEFlowTrackOutputArray->Add(track);
494 }
[df636c74]495 }
[efac6f9]496
497 // if neutral excess is not significant, rescale eflow tracks, such that the total charged equals the best measurement given by the calorimeter and tracking
498 else if (fTrackEnergy > 0.0)
[df636c74]499 {
[efac6f9]500 weightTrack = (fTrackSigma > 0.0) ? 1 / (fTrackSigma*fTrackSigma) : 0.0;
501 weightCalo = (sigma > 0.0) ? 1 / (sigma*sigma) : 0.0;
502
503 bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo);
504 rescaleFactor = bestEnergyEstimate/fTrackEnergy;
505
506 fItTowerTrackArray->Reset();
507 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next())))
508 {
509 mother = track;
510 track = static_cast<Candidate*>(track->Clone());
511 track->AddCandidate(mother);
[a98c7ef]512
[efac6f9]513 track->Momentum *= rescaleFactor;
[e5767b57]514
[efac6f9]515 fEFlowTrackOutputArray->Add(track);
516 }
[82575a3]517 }
[efac6f9]518
519 }
[82575a3]520
521//------------------------------------------------------------------------------
522
523Double_t SimpleCalorimeter::LogNormal(Double_t mean, Double_t sigma)
524{
525 Double_t a, b;
526
527 if(mean > 0.0)
528 {
529 b = TMath::Sqrt(TMath::Log((1.0 + (sigma*sigma)/(mean*mean))));
530 a = TMath::Log(mean) - 0.5*b*b;
531
[e5767b57]532 return TMath::Exp(a + b*gRandom->Gaus(0.0, 1.0));
[82575a3]533 }
534 else
535 {
536 return 0.0;
537 }
538}
Note: See TracBrowser for help on using the repository browser.