Fork me on GitHub

source: git/modules/SimpleCalorimeter.cc@ d4fb268

Last change on this file since d4fb268 was 5eda6767, checked in by Michele Selvaggi <michele@…>, 4 years ago

fix calo tower position

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