Fork me on GitHub

source: git/modules/SimpleCalorimeter.cc@ ff9f67fb

ImprovedOutputFile Timing dual_readout llp
Last change on this file since ff9f67fb was d67b86b, checked in by Pavel Demin <pavel.demin@…>, 9 years ago

remove unneeded condition from SimpleCalorimeter

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