All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
ILDCaloDigi.cc
Go to the documentation of this file.
1 // Calorimeter digitiser for the IDC ECAL and HCAL
2 // For other detectors/models SimpleCaloDigi should be used
3 #include "ILDCaloDigi.h"
4 #include <EVENT/LCCollection.h>
5 #include <EVENT/SimCalorimeterHit.h>
6 #include <IMPL/SimCalorimeterHitImpl.h>
7 #include <IMPL/CalorimeterHitImpl.h>
8 #include <IMPL/LCCollectionVec.h>
9 #include <IMPL/LCRelationImpl.h>
10 #include <marlin/Global.h>
11 #include <gear/GEAR.h>
12 #include <gear/LayerLayout.h>
13 #include <gear/CalorimeterParameters.h>
14 #include <gear/GearParameters.h>
15 #include <EVENT/LCParameters.h>
16 #include <UTIL/CellIDDecoder.h>
17 #include <UTIL/CellIDEncoder.h>
18 #include <iostream>
19 #include <string>
20 #include <algorithm>
21 #include <assert.h>
22 #include <cmath>
23 #include <cstdlib>
24 #include <sstream>
25 
26 #include "CLHEP/Random/RandPoisson.h"
27 #include "CLHEP/Random/RandGauss.h"
28 #include "CLHEP/Random/RandFlat.h"
29 
30 using namespace std;
31 using namespace lcio ;
32 using namespace marlin ;
33 
34 // protect against rounding errors
35 // will not find caps smaller than this
36 const float slop = 0.25; // (mm)
37 const float pi = acos(-1.0);
38 const float twopi = 2.0*pi;
39 
41 
42 
43 // helper struct for string comparision
44 struct XToLower{
45  int operator() ( int ch ) {
46  return std::tolower ( ch );
47  }
48 };
49 
50 ILDCaloDigi::ILDCaloDigi() : Processor("ILDCaloDigi") {
51 
52  _description = "Performs simple digitization of sim calo hits..." ;
53 
54  std::vector<std::string> ecalCollections; // this is for silicon
55  ecalCollections.push_back(std::string("EcalBarrelCollection"));
56  ecalCollections.push_back(std::string("EcalEndcapCollection"));
57  ecalCollections.push_back(std::string("EcalRingCollection"));
58  registerInputCollections( LCIO::SIMCALORIMETERHIT,
59  "ECALCollections" ,
60  "ECAL Collection Names" ,
62  ecalCollections);
63 
64  std::vector<std::string> hcalCollections;
65  hcalCollections.push_back(std::string("HcalBarrelRegCollection"));
66  hcalCollections.push_back(std::string("HcalEndcapRingsCollection"));
67  hcalCollections.push_back(std::string("HcalEndcapsCollection"));
68  registerInputCollections( LCIO::SIMCALORIMETERHIT,
69  "HCALCollections" ,
70  "HCAL Collection Names" ,
72  hcalCollections);
73 
74  // ecal
75 
76  _outputEcalCollections.push_back(std::string("ECALBarrel"));
77  _outputEcalCollections.push_back(std::string("ECALEndcap"));
78  _outputEcalCollections.push_back(std::string("ECALOther"));
79 
80  _outputHcalCollections.push_back(std::string("HCALBarrel"));
81  _outputHcalCollections.push_back(std::string("HCALEndcap"));
82  _outputHcalCollections.push_back(std::string("HCALOther"));
83 
84  registerOutputCollection( LCIO::CALORIMETERHIT,
85  "ECALOutputCollection0" ,
86  "ECAL Collection of real Hits" ,
88  std::string("ECALBarrel") );
89 
90 
91  registerOutputCollection( LCIO::CALORIMETERHIT,
92  "ECALOutputCollection1" ,
93  "ECAL Collection of real Hits" ,
95  std::string("ECALEndcap") );
96 
97  registerOutputCollection( LCIO::CALORIMETERHIT,
98  "ECALOutputCollection2" ,
99  "ECAL Collection of real Hits" ,
101  std::string("ECALOther") ) ;
102 
103 
104  // hcal
105 
106  registerOutputCollection( LCIO::CALORIMETERHIT,
107  "HCALOutputCollection0" ,
108  "HCAL Collection of real Hits" ,
110  std::string("HCALBarrel") );
111 
112  registerOutputCollection( LCIO::CALORIMETERHIT,
113  "HCALOutputCollection1" ,
114  "HCAL Collection of real Hits" ,
116  std::string("HCALEndcap") );
117 
118  registerOutputCollection( LCIO::CALORIMETERHIT,
119  "HCALOutputCollection2" ,
120  "HCAL Collection of real Hits" ,
122  std::string("HCALOther") ) ;
123 
124  registerOutputCollection( LCIO::LCRELATION,
125  "RelationOutputCollection" ,
126  "CaloHit Relation Collection" ,
128  std::string("RelationCaloHit")) ;
129 
130  registerProcessorParameter("ECALThreshold" ,
131  "Threshold for ECAL Hits in GeV" ,
133  (float)5.0e-5);
134 
135  registerProcessorParameter("ECALThresholdUnit" ,
136  "Unit for ECAL Threshold. Can be \"GeV\", \"MIP\" or \"px\". MIP and px need properly set calibration constants" ,
138  std::string("GeV"));
139 
140 
141  std::vector<float> hcalThresholds;
142  hcalThresholds.push_back(0.00004);
143  registerProcessorParameter("HCALThreshold" ,
144  "Threshold for HCAL Hits in GeV" ,
146  hcalThresholds);
147 
148  registerProcessorParameter("HCALThresholdUnit" ,
149  "Unit for HCAL Threshold. Can be \"GeV\", \"MIP\" or \"px\". MIP and px need properly set calibration constants" ,
151  std::string("GeV"));
152 
153 
154  std::vector<int> ecalLayers;
155  ecalLayers.push_back(20);
156  ecalLayers.push_back(100);
157  registerProcessorParameter("ECALLayers" ,
158  "Index of ECal Layers" ,
159  _ecalLayers,
160  ecalLayers);
161 
162  std::vector<int> hcalLayers;
163  hcalLayers.push_back(100);
164  registerProcessorParameter("HCALLayers" ,
165  "Index of HCal Layers" ,
166  _hcalLayers,
167  hcalLayers);
168 
169  std::vector<float> calibrEcal;
170  calibrEcal.push_back(40.91);
171  calibrEcal.push_back(81.81);
172  registerProcessorParameter("CalibrECAL" ,
173  "Calibration coefficients for ECAL" ,
175  calibrEcal);
176 
177  std::vector<float> calibrHcalBarrel;
178  calibrHcalBarrel.push_back(0.);
179  registerProcessorParameter("CalibrHCALBarrel" ,
180  "Calibration coefficients for Barrel HCAL" ,
182  calibrHcalBarrel);
183 
184  std::vector<float> calibrHcalEndCap;
185  calibrHcalEndCap.push_back(0.);
186  registerProcessorParameter("CalibrHCALEndcap",
187  "Calibration coefficients for EndCap HCAL" ,
189  calibrHcalEndCap);
190 
191  std::vector<float> calibrHcalOther;
192  calibrHcalOther.push_back(0.);
193  registerProcessorParameter("CalibrHCALOther" ,
194  "Calibration coefficients for Other (Ring) HCAL" ,
196  calibrHcalOther);
197 
198  registerProcessorParameter("IfDigitalEcal" ,
199  "Digital Ecal" ,
200  _digitalEcal ,
201  0);
202 
203  registerProcessorParameter("MapsEcalCorrection" ,
204  "Ecal correction for theta dependency of calibration for MAPS" ,
206  0);
207 
208  registerProcessorParameter("IfDigitalHcal" ,
209  "Digital Hcal" ,
210  _digitalHcal ,
211  0);
212 
213  registerProcessorParameter("ECALGapCorrection" ,
214  "Correct for ECAL gaps" ,
216  (int)1);
217 
218  registerProcessorParameter("HCALGapCorrection" ,
219  "Correct for ECAL gaps" ,
221  (int)1);
222 
223  registerProcessorParameter("ECALEndcapCorrectionFactor" ,
224  "Energy correction for ECAL endcap" ,
226  (float)1.025);
227 
228  registerProcessorParameter("HCALEndcapCorrectionFactor" ,
229  "Energy correction for HCAL endcap" ,
231  (float)1.025);
232 
233  registerProcessorParameter("ECALGapCorrectionFactor" ,
234  "Factor applied to gap correction" ,
236  (float)1.0);
237 
238  registerProcessorParameter("ECALModuleGapCorrectionFactor" ,
239  "Factor applied to module gap correction" ,
241  (float)0.5);
242 
243  registerProcessorParameter("HCALModuleGapCorrectionFactor" ,
244  "Factor applied to module gap correction" ,
246  (float)0.5);
247 
248 
249  registerProcessorParameter("Histograms" ,
250  "Hit times histograms" ,
251  _histograms,
252  (int)0);
253 
254  registerProcessorParameter("UseEcalTiming" ,
255  "Use ECAL hit times" ,
257  (int)0);
258 
259  registerProcessorParameter("ECALCorrectTimesForPropagation" ,
260  "Correct ECAL hit times for propagation: radial distance/c" ,
262  (int)0);
263 
264  registerProcessorParameter("ECALTimeWindowMin" ,
265  "ECAL Time Window minimum time in ns" ,
267  (float)-10.0);
268 
269  registerProcessorParameter("ECALEndcapTimeWindowMax" ,
270  "ECAL Endcap Time Window maximum time in ns" ,
272  (float)+100.0);
273 
274  registerProcessorParameter("ECALBarrelTimeWindowMax" ,
275  "ECAL BarrelTime Window maximum time in ns" ,
277  (float)+100.0);
278 
279  registerProcessorParameter("ECALDeltaTimeHitResolution" ,
280  "ECAL Minimum Delta Time in ns for resolving two hits" ,
282  (float)+10.0);
283 
284  registerProcessorParameter("ECALTimeResolution" ,
285  "ECAL Time Resolution used to smear hit times" ,
287  (float)10.);
288 
289  registerProcessorParameter("ECALSimpleTimingCut" ,
290  "Use simple time window cut on hit times? If false: use original hit-time clustering algorithm. If true: use time window defined by ECALBarrelTimeWindowMin and ECALBarrelTimeWindowMax" ,
292  (bool)true);
293 
294  registerProcessorParameter("UseHcalTiming" ,
295  "Use HCAL hit times" ,
297  (int)1);
298 
299  registerProcessorParameter("HCALCorrectTimesForPropagation" ,
300  "Correct HCAL hit times for propagation: radial distance/c" ,
302  (int)0);
303 
304 
305  registerProcessorParameter("HCALTimeWindowMin" ,
306  "HCAL Time Window minimum time in ns" ,
308  (float)-10.0);
309 
310  registerProcessorParameter("HCALBarrelTimeWindowMax" ,
311  "HCAL Time Window maximum time in ns" ,
313  (float)+100.0);
314 
315  registerProcessorParameter("HCALEndcapTimeWindowMax" ,
316  "HCAL Time Window maximum time in ns" ,
318  (float)+100.0);
319 
320  registerProcessorParameter("HCALDeltaTimeHitResolution" ,
321  "HCAL Minimum Delta Time in ns for resolving two hits" ,
323  (float)+10.0);
324 
325  registerProcessorParameter("HCALTimeResolution" ,
326  "HCAL Time Resolution used to smear hit times" ,
328  (float)10.);
329 
330  registerProcessorParameter("HCALSimpleTimingCut" ,
331  "Use simple time window cut on hit times? If false: use original hit-time clustering algorithm. If true: use time window defined by HCALBarrelTimeWindowMin and HCALBarrelTimeWindowMax" ,
333  (bool)true);
334 
335  // additional digi effects (Daniel Jeans)
336 
337  registerProcessorParameter("CalibECALMIP" ,
338  "calibration to convert ECAL deposited energy to MIPs" ,
340  (float)1.0e-4);
341 
342  registerProcessorParameter("ECAL_apply_realistic_digi" ,
343  "apply realistic digitisation to ECAL hits? (0=none, 1=silicon, 2=scintillator)" ,
345  int(0));
346 
347  registerProcessorParameter("ECAL_PPD_PE_per_MIP" ,
348  "# Photo-electrons per MIP (scintillator): used to poisson smear #PEs if >0" ,
350  (float)7.);
351 
352  registerProcessorParameter("ECAL_PPD_N_Pixels" ,
353  "ECAL total number of MPPC/SiPM pixels for implementation of saturation effect" ,
355  (int)10000);
356 
357  registerProcessorParameter("ECAL_PPD_N_Pixels_uncertainty" ,
358  "ECAL fractional uncertainty of effective total number of MPPC/SiPM pixels" ,
360  float (0.05) );
361 
362  registerProcessorParameter("ECAL_miscalibration_uncorrel" ,
363  "uncorrelated ECAL random gaussian miscalibration (as a fraction: 1.0 = 100%) " ,
365  (float)0.0);
366 
367  registerProcessorParameter("ECAL_miscalibration_uncorrel_memorise" ,
368  "store oncorrelated ECAL miscalbrations in memory? (WARNING: can take a lot of memory if used...) " ,
370  (bool)false);
371 
372  registerProcessorParameter("ECAL_miscalibration_correl" ,
373  "correlated ECAL random gaussian miscalibration (as a fraction: 1.0 = 100%) " ,
375  (float)0.0);
376 
377  registerProcessorParameter("ECAL_deadCellRate" ,
378  "ECAL random dead cell fraction (as a fraction: 0->1) " ,
380  (float)0.);
381 
382  registerProcessorParameter("ECAL_deadCell_memorise" ,
383  "store dead ECAL cells in memory? (WARNING: can take a lot of memory if used...) " ,
385  (bool)false);
386 
387  registerProcessorParameter("ECAL_strip_absorbtionLength",
388  "length scale for absorbtion along scintillator strip (mm)",
390  (float)1000000.);
391 
392  registerProcessorParameter("ECAL_pixel_spread",
393  "variation of mppc/sipm pixels capacitance in ECAL (as a fraction: 0.01=1%)",
395  float (0.05));
396 
397  registerProcessorParameter("ECAL_elec_noise_mips",
398  "typical electronics noise (ECAL, in MIP units)",
400  float (0));
401 
402  registerProcessorParameter("energyPerEHpair" ,
403  "energy required to create e-h pair in silicon (in eV)" ,
404  _ehEnergy,
405  (float)3.6);
406 
407  registerProcessorParameter("ECAL_maxDynamicRange_MIP",
408  "maximum of dynamic range for ECAL (in MIPs)",
410  float (2500) );
411 
412  registerProcessorParameter("StripEcal_default_nVirtualCells",
413  "default number of virtual cells (used if not found in gear file)",
415  int(9) );
416 
417  registerProcessorParameter("ECAL_default_layerConfig",
418  "default ECAL layer configuration (used if not found in gear file)",
420  std::string("000000000000000") );
421 
422  // HCAL realistic digi parameters
423  registerProcessorParameter("CalibHCALMIP" ,
424  "calibration to convert HCAL deposited energy to MIPs" ,
426  (float)1.0e-4);
427 
428  registerProcessorParameter("HCAL_apply_realistic_digi" ,
429  "apply realistic digitisation to HCAL hits? (0=none, 1=scintillator/SiPM)" ,
431  int(0));
432 
433  registerProcessorParameter("HCAL_PPD_PE_per_MIP" ,
434  "# Photo-electrons per MIP (for AHCAL): used to poisson smear #PEs if >0" ,
436  (float)10.);
437 
438  registerProcessorParameter("HCAL_PPD_N_Pixels" ,
439  "HCAL total number of MPPC/SiPM pixels for implementation of saturation effect" ,
441  (int)400);
442 
443  registerProcessorParameter("HCAL_PPD_N_Pixels_uncertainty" ,
444  "HCAL fractional uncertainty of effective total number of MPPC/SiPM pixels" ,
446  float (0.05) );
447 
448  registerProcessorParameter("HCAL_miscalibration_uncorrel" ,
449  "uncorrelated HCAL random gaussian miscalibration (as a fraction: 1.0 = 100%) " ,
451  (float)0.0);
452 
453  registerProcessorParameter("HCAL_miscalibration_uncorrel_memorise" ,
454  "store oncorrelated HCAL miscalbrations in memory? (WARNING: can take a lot of memory if used...) " ,
456  (bool)false);
457 
458  registerProcessorParameter("HCAL_miscalibration_correl" ,
459  "correlated HCAL random gaussian miscalibration (as a fraction: 1.0 = 100%) " ,
461  (float)0.0);
462 
463  registerProcessorParameter("HCAL_deadCellRate" ,
464  "HCAL random dead cell fraction (as a fraction: 0->1) " ,
466  (float)0.);
467 
468  registerProcessorParameter("HCAL_deadCell_memorise" ,
469  "store dead HCAL cells in memory? (WARNING: can take a lot of memory if used...) " ,
471  (bool)false);
472 
473  registerProcessorParameter("HCAL_pixel_spread",
474  "variation of mppc/sipm pixels capacitance in HCAL (as a fraction: 0.01=1%)",
476  float (0.));
477 
478  registerProcessorParameter("HCAL_elec_noise_mips",
479  "typical electronics noise (HCAL, in MIP units)",
481  float (0.));
482 
483  registerProcessorParameter("HCAL_maxDynamicRange_MIP",
484  "maximum of dynamic range for HCAL (in MIPs)",
486  float (200.) );
487 
488  // end daniel
489 
490  registerProcessorParameter("CellIDLayerString" ,
491  "name of the part of the cellID that holds the layer" ,
493  std::string("K-1")
494  );
495 
496  registerProcessorParameter("CellIDModuleString" ,
497  "name of the part of the cellID that holds the module" ,
499  std::string("M")
500  );
501  registerProcessorParameter("CellIDStaveString" ,
502  "name of the part of the cellID that holds the stave" ,
504  std::string("S-1")
505  );
506 
507  registerProcessorParameter("CellIDIndexIString" ,
508  "name of the part of the cellID that holds the index I" ,
510  std::string("I")
511  );
512 
513  registerProcessorParameter("CellIDIndexJString" ,
514  "name of the part of the cellID that holds the index J" ,
516  std::string("J")
517  );
518 
519 }
520 
522 
523  printParameters();
524 
525  _nRun = -1;
526  _nEvt = 0;
527 
528  if(_histograms){
529  fEcal = new TH1F("fEcal", "Ecal time profile",1000, 0., 1000.0);
530  fHcal = new TH1F("fHcal", "Hcal time profile",1000, 0., 1000.0);
531 
532  fEcalC = new TH1F("fEcalC", "Ecal time profile cor",1000, 0., 1000.0);
533  fHcalC = new TH1F("fHcalC", "Hcal time profile cor",1000, 0., 1000.0);
534 
535  fEcalC1 = new TH1F("fEcalC1", "Ecal time profile cor",100, 0., 1000.0);
536  fHcalC1 = new TH1F("fHcalC1", "Hcal time profile cor",100, 0., 1000.0);
537 
538  fEcalC2 = new TH1F("fEcalC2", "Ecal time profile cor",10, 0., 1000.0);
539  fHcalC2 = new TH1F("fHcalC2", "Hcal time profile cor",10, 0., 1000.0);
540 
541  fHcalLayer1 = new TH2F("fHcalLayer1", "Hcal layer 1 map",300, -4500., 4500.0,300,-4500,4500.);
542  fHcalLayer11 = new TH2F("fHcalLayer11", "Hcal layer 11 map",300, -4500., 4500.0,300,-4500,4500.);
543  fHcalLayer21 = new TH2F("fHcalLayer21", "Hcal layer 21 map",300, -4500., 4500.0,300,-4500,4500.);
544  fHcalLayer31 = new TH2F("fHcalLayer31", "Hcal layer 31 map",300, -4500., 4500.0,300,-4500,4500.);
545  fHcalLayer41 = new TH2F("fHcalLayer41", "Hcal layer 41 map",300, -4500., 4500.0,300,-4500,4500.);
546  fHcalLayer51 = new TH2F("fHcalLayer51", "Hcal layer 51 map",300, -4500., 4500.0,300,-4500,4500.);
547  fHcalLayer61 = new TH2F("fHcalLayer61", "Hcal layer 61 map",300, -4500., 4500.0,300,-4500,4500.);
548  fHcalLayer71 = new TH2F("fHcalLayer71", "Hcal layer 71 map",300, -4500., 4500.0,300,-4500,4500.);
549  fHcalRLayer1 = new TH1F("fHcalRLayer1", "Hcal R layer 1",50, 0., 5000.0);
550  fHcalRLayer11 = new TH1F("fHcalRLayer11", "Hcal R layer 11",50, 0., 5000.0);
551  fHcalRLayer21 = new TH1F("fHcalRLayer21", "Hcal R layer 21",50, 0., 5000.0);
552  fHcalRLayer31 = new TH1F("fHcalRLayer31", "Hcal R layer 31",50, 0., 5000.0);
553  fHcalRLayer41 = new TH1F("fHcalRLayer41", "Hcal R layer 41",50, 0., 5000.0);
554  fHcalRLayer51 = new TH1F("fHcalRLayer51", "Hcal R layer 51",50, 0., 5000.0);
555  fHcalRLayer61 = new TH1F("fHcalRLayer61", "Hcal R layer 61",50, 0., 5000.0);
556  fHcalRLayer71 = new TH1F("fHcalRLayer71", "Hcal R layer 71",50, 0., 5000.0);
557  fHcalRLayerNorm = new TH1F("fHcalRLayerNorm", "Hcal R layer Norm",50, 0., 5000.0);
558 
559  fEcalLayer1 = new TH2F("fEcalLayer1", "Ecal layer 1 map",1800, -4500., 4500.0,1800,-4500,4500.);
560  fEcalLayer11 = new TH2F("fEcalLayer11", "Ecal layer 11 map",1800, -4500., 4500.0,1800,-4500,4500.);
561  fEcalLayer21 = new TH2F("fEcalLayer21", "Ecal layer 21 map",1800, -4500., 4500.0,1800,-4500,4500.);
562  fEcalRLayer1 = new TH1F("fEcalRLayer1", "Ecal R layer 1",100, 0., 5000.0);
563  fEcalRLayer11 = new TH1F("fEcalRLayer11", "Ecal R layer 11",100, 0., 5000.0);
564  fEcalRLayer21 = new TH1F("fEcalRLayer21", "Ecal R layer 21",100, 0., 5000.0);
565  fEcalRLayerNorm = new TH1F("fEcalRLayerNorm", "Ecal R layer Norm",100, 0., 5000.0);
566 
567  //fHcalCvsE = new TH2F("fHcalCvsE", "Hcal time profile cor",100, 0., 500.0,100,0.,10.);
568  }
569 
570  _strip_virt_cells=-999;
571  _countWarnings=0;
572 
573  //fg: need to set default encoding in for reading old files...
574  CellIDDecoder<SimCalorimeterHit>::setDefaultEncoding("M:3,S-1:3,I:9,J:9,K-1:6") ;
575 
576  const gear::GearParameters& pMokka = Global::GEAR->getGearParameters("MokkaParameters");
577 
578  // Calorimeter geometry from GEAR
579 
580 
581  try {
582  const gear::CalorimeterParameters& pEcalBarrel = Global::GEAR->getEcalBarrelParameters();
583  const gear::CalorimeterParameters& pEcalEndcap = Global::GEAR->getEcalEndcapParameters();
584  const gear::LayerLayout& ecalBarrelLayout = pEcalBarrel.getLayerLayout();
585  const gear::LayerLayout& ecalEndcapLayout = pEcalEndcap.getLayerLayout();
586  // determine geometry of ECAL
587  int symmetry = pEcalBarrel.getSymmetryOrder();
588  _zOfEcalEndcap = (float)pEcalEndcap.getExtent()[2];
589 
590  // Determine ECAL polygon angles
591  // Store radial vectors perpendicular to stave layers in _ecalBarrelStaveDir
592  // ASSUMES Mokka Stave numbering 0 = top, then numbering increases anti-clockwise
593  if(symmetry>1){
594  float nFoldSymmetry = static_cast<float>(symmetry);
595  float phi0 = pEcalBarrel.getPhi0();
596  for(int i=0;i<symmetry;++i){
597  float phi = phi0 + i*twopi/nFoldSymmetry;
598  _barrelStaveDir[i][0] = cos(phi);
599  _barrelStaveDir[i][1] = sin(phi);
600  }
601  }
602 
603  for(int i=0;i<ecalBarrelLayout.getNLayers();++i){
604  _barrelPixelSizeT[i] = ecalBarrelLayout.getCellSize0(i);
605  _barrelPixelSizeZ[i] = ecalBarrelLayout.getCellSize1(i);
606  streamlog_out ( DEBUG ) << "barrel pixel size " << i << " " << _barrelPixelSizeT[i] << " " << _barrelPixelSizeZ[i] << endl;
607  }
608 
609  for(int i=0;i<ecalEndcapLayout.getNLayers();++i){
610  _endcapPixelSizeX[i] = ecalEndcapLayout.getCellSize0(i);
611  _endcapPixelSizeY[i] = ecalEndcapLayout.getCellSize1(i);
612  streamlog_out ( DEBUG ) << "endcap pixel size " << i << " " << _endcapPixelSizeX[i] << " " << _endcapPixelSizeY[i] << endl;
613  }
614 
615 
616  // check we are using a recent version of the mokka ecal driver
617  // old ones had a bug in the gear file
618  try {
619  pEcalBarrel.getIntVal("Ecal_barrel_gear_per_sensitiveLayer");
620  } catch(gear::UnknownParameterException &e) {
621  streamlog_out (WARNING) << "You seem to be using an older version of the Mokka ECAL driver, affected by a bug in the gear file output" << endl;
622  streamlog_out (WARNING) << "If you have a mix of silicon/scintillator layers in the ECAL, this may cause some confusion" << endl;
623  streamlog_out (WARNING) << "You are recommended to use a later Mokka version, at least for hybrid (si+sc) ECALs" << endl;
624  }
625 
626  // number of virtual cells in ECAL scint strips
627  try { // first try to get from ECAL barrel section of gear file (it's here for "latest" Mokka versions)
628  _strip_virt_cells=pEcalBarrel.getIntVal("Ecal_Sc_number_of_virtual_cells");
629  streamlog_out (MESSAGE) << "taking number of virtual cells from calo section of gear file: " << _strip_virt_cells << endl;
630  } catch(gear::UnknownParameterException &e1) {
631  try { // otherwise look in the mokka parameters section
632  std::string nVirtualMokkaS = pMokka.getStringVal("Ecal_Sc_number_of_virtual_cells");
633 
634  // _strip_virt_cells = std::atoi( nVirtualMokkaS.c_str() );
635 
636  std::stringstream convert(nVirtualMokkaS);
637  if ( !(convert >> _strip_virt_cells) ) {
638  streamlog_out (ERROR) << "could not decipher number of virtual cells! " << nVirtualMokkaS << " " << _strip_virt_cells << endl;
639  assert(0);
640  }
641 
642  streamlog_out (MESSAGE) << "taking number of virtual cells from Mokka section of gear file: " << nVirtualMokkaS << " " << _strip_virt_cells << endl;
643  } catch(gear::UnknownParameterException &e2) { // if still not found, use default from processor parameter
645  streamlog_out (WARNING) << "taking number of virtual cells from steering file (not found in gear file): " << _strip_virt_cells << endl;
646  }
647  }
648 
649  // the ECAL layer layout code
650  try {
651  _ecalLayout = pEcalBarrel.getStringVal("Ecal_Barrel_Sc_Si_mix");
652  streamlog_out (MESSAGE) << "taking layer layout from calo sections of gear file: " << _ecalLayout << endl;
653  } catch(gear::UnknownParameterException &e1) {
654  try {
655  _ecalLayout = pMokka.getStringVal("Ecal_Sc_Si_mix");
656  streamlog_out (MESSAGE) << "taking layer layout from mokka section of gear file: " << _ecalLayout << endl;
657  } catch(gear::UnknownParameterException &e2) {
659  streamlog_out (WARNING) << "taking layer layout from steering file (not found in gear file): " << _ecalLayout << endl;
660  }
661  }
662 
663  } catch(gear::UnknownParameterException &e) {
664  streamlog_out (WARNING) << "WARNING, could not get ECAL gear parameters!" << endl;
665  }
666 
667 
668  //convert ECAL thresholds to GeV units
669  if (_unitThresholdEcal.compare("GeV") == 0){
670  //ECAL threshold unit is GeV, do nothing
671  } else if (_unitThresholdEcal.compare("MIP") == 0){
672  //ECAL threshold unit is MIP, convert via MIP2GeV
674  } else if (_unitThresholdEcal.compare("px") == 0){
675  //ECAL threshold unit is pixels, convert via MIP2GeV and lightyield
677  } else {
678  streamlog_out(ERROR) << "could not identify ECAL threshold unit. Please use \"GeV\", \"MIP\" or \"px\"! Aborting." << std::endl;
679  assert(0);
680  }
681 
682  //convert HCAL thresholds to GeV units
683  if (_unitThresholdHcal.compare("GeV") == 0){
684  //HCAL threshold unit is GeV, do nothing
685  } else if (_unitThresholdHcal.compare("MIP") == 0){
686  //HCAL threshold unit is MIP, convert via MIP2GeV
687  for (unsigned int i=0; i<_thresholdHcal.size(); i++){
688  _thresholdHcal.at(i) *= _calibHcalMip;
689  }
690  } else if (_unitThresholdHcal.compare("px") == 0){
691  //HCAL threshold unit is pixels, convert via MIP2GeV and lightyield
692  for (unsigned int i=0; i<_thresholdHcal.size(); i++){
694  }
695  } else {
696  streamlog_out(ERROR) << "could not identify HCAL threshold unit. Please use \"GeV\", \"MIP\" or \"px\"! Aborting." << std::endl;
697  assert(0);
698  }
699 
700  // set up the scintillator/MPPC digitiser
709  cout << "ECAL sc digi:" << endl;
711 
720  cout << "HCAL sc digi:" << endl;
722 
723  //set up the random engines for ecal and hcal dead cells: (could use a steering parameter though)
724  if (_deadCellEcal_keep){
725  _randomEngineDeadCellEcal = new CLHEP::MTwistEngine(0, 0);
726  } else {
728  }
729 
730  if (_deadCellHcal_keep){
731  _randomEngineDeadCellHcal = new CLHEP::MTwistEngine(0, 0);
732  } else {
734  }
735 
736 
737 }
738 
739 
740 void ILDCaloDigi::processRunHeader( LCRunHeader* /*run*/) {
741 
742  _nRun++ ;
743  _nEvt = 0;
744 
745 }
746 
747 void ILDCaloDigi::processEvent( LCEvent * evt ) {
748 
749  // create the output collections
750  LCCollectionVec *relcol = new LCCollectionVec(LCIO::LCRELATION);
751 
752  // copy the flags from the input collection
753  _flag.setBit(LCIO::CHBIT_LONG);
754  _flag.setBit(LCIO::RCHBIT_TIME); //store timing on output hits.
755 
756  // decide on this event's correlated miscalibration
757  _event_correl_miscalib_ecal = CLHEP::RandGauss::shoot( 1.0, _misCalibEcal_correl );
758  _event_correl_miscalib_hcal = CLHEP::RandGauss::shoot( 1.0, _misCalibHcal_correl );
759 
760  //
761  // * Reading Collections of ECAL Simulated Hits *
762  //
763 
764  for (unsigned int i(0); i < _ecalCollections.size(); ++i) {
765  std::string colName = _ecalCollections[i] ;
766 
767  streamlog_out ( DEBUG ) << "looking for collection: " << colName << endl;
768 
769  if ( colName.find("dummy")!=string::npos ) {
770  streamlog_out ( DEBUG ) << "ignoring input ECAL collection name (looks like dummy name)" << colName << endl;
771  continue;
772  }
773 
774  //fg: need to establish the subdetetcor part here
775  // use collection name as cellID does not seem to have that information
776  CHT::Layout caloLayout = layoutFromString (colName);
777 
778  try{
779  LCCollection * col = evt->getCollection( colName.c_str() ) ;
780  string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding);
781 
782  CellIDDecoder<SimCalorimeterHit> idDecoder( col );
783 
784  // create new collection
785  LCCollectionVec *ecalcol = new LCCollectionVec(LCIO::CALORIMETERHIT);
786  ecalcol->setFlag(_flag.getFlag());
787 
788  // if making gap corrections clear the vectors holding pointers to calhits
789  if(_ecalGapCorrection!=0){
790  for(int is=0;is<MAX_STAVES;is++){
791  for(int il=0;il<MAX_LAYERS;il++){
792  _calHitsByStaveLayer[is][il].clear();
793  _calHitsByStaveLayerModule[is][il].clear();
794  }
795  }
796  }
797 
798  // deal with strips split into virtual cells
799  // if this collection is a strip which has been split into virtual cells, they need to be recombined
800  int orientation = getStripOrientationFromColName( colName );
801  if ( orientation!=SQUARE && getNumberOfVirtualCells()>1 ) {
802  col = combineVirtualStripCells(col, caloLayout == CHT::barrel , orientation );
803  }
804 
805 
806  int numElements = col->getNumberOfElements();
807  streamlog_out ( DEBUG ) << colName << " number of elements = " << numElements << endl;
808 
809  for (int j(0); j < numElements; ++j) {
810  SimCalorimeterHit * hit = dynamic_cast<SimCalorimeterHit*>( col->getElementAt( j ) ) ;
811  float energy = hit->getEnergy();
812 
813  // apply threshold cut
814  if (energy > _thresholdEcal) {
815  int cellid = hit->getCellID0();
816  int cellid1 = hit->getCellID1();
817  int layer = idDecoder(hit)[_cellIDLayerString];
818  int stave = idDecoder(hit)[_cellIDStaveString];
819  int module= idDecoder(hit)[_cellIDModuleString];
820 
821  // check that layer and assumed layer type are compatible
822  checkConsistency(colName, layer);
823 
824  // save hits by module/stave/layer if required later
825  float calibr_coeff(1.);
826  float x = hit->getPosition()[0];
827  float y = hit->getPosition()[1];
828  float z = hit->getPosition()[2];
829  float r = sqrt(x*x+y*y+z*z);
830  float rxy = sqrt(x*x+y*y);
831  float cost = fabs(z)/r;
832 
833  if(z>0 && _histograms){
834  if(layer==1)fEcalLayer1->Fill(x,y);
835  if(layer==11)fEcalLayer11->Fill(x,y);
836  if(layer==21)fEcalLayer21->Fill(x,y);
837  if(layer==1)fEcalRLayer1->Fill(rxy);
838  if(layer==11)fEcalRLayer11->Fill(rxy);
839  if(layer==21)fEcalRLayer21->Fill(rxy);
840  }
841  if(_digitalEcal){
842  calibr_coeff = this->digitalEcalCalibCoeff(layer);
844  if(caloLayout == CHT::barrel){
845  float correction = 1.1387 - 0.068*cost - 0.191*cost*cost;
846  calibr_coeff/=correction;
847  }else{
848  float correction = 0.592 + 0.590*cost;
849  calibr_coeff/=correction;
850  }
851  }
852  }else{
853  calibr_coeff = this->analogueEcalCalibCoeff(layer);
854  }
855  // if(fabs(hit->getPosition()[2])>=_zOfEcalEndcap)calibr_coeff *= _ecalEndcapCorrectionFactor;
856  if (caloLayout!=CHT::barrel) calibr_coeff *= _ecalEndcapCorrectionFactor; // more robust
857 
858  // if you want to understand the timing cut code, please refer to the hcal timing cut further below. it is functionally identical, but has comments, explanations and excuses.
859  if(_useEcalTiming){
860  float ecalTimeWindowMax = _ecalEndcapTimeWindowMax;
861  if(caloLayout==CHT::barrel)ecalTimeWindowMax = _ecalBarrelTimeWindowMax;
862  float dt = r/300.-0.1;
863  const unsigned int n = hit->getNMCContributions();
864 
865  std::vector<bool> used(n, false) ;
866  //for(unsigned int i =0; i<n;i++) used[i] = false;
867 
868  int count = 0;
869  float eCellInTime = 0.;
870  float eCellOutput = 0.;
871 
872  for(unsigned int i =0; i<n;i++){
873  float timei = hit->getTimeCont(i);
874  float energyi = hit->getEnergyCont(i);
875  float energySum = 0;
876 
877  float deltat = 0;
878  if(_ecalCorrectTimesForPropagation)deltat=dt;
879  if(timei-deltat > _ecalTimeWindowMin && timei-deltat < ecalTimeWindowMax){
880  float ecor = energyi*calibr_coeff;
881  eCellInTime+=ecor;
882  }
883 
884  if(!used[i]){
885  // merge with other hits?
886  used[i] = true;
887  for(unsigned int j =i+1; j<n;j++){
888  if(!used[j]){
889  float timej = hit->getTimeCont(j);
890  float energyj = hit->getEnergyCont(j);
891  float deltat = fabs(timei-timej);
893  float deltat = _ecalCorrectTimesForPropagation?dt:0;
894  if (timej-deltat>_ecalTimeWindowMin && timej-deltat<ecalTimeWindowMax){
895  energySum += energyj;
896  if (timej < timei){
897  timei = timej;
898  }
899  }
900  } else {
901  if(deltat<_ecalDeltaTimeHitResolution){
902  if(energyj>energyi)timei=timej;
903  energyi+=energyj;
904  used[j] = true;
905  }
906  }
907  }
908  }
910  used = vector<bool>(n, true); // mark everything as used to terminate for loop on next run
911  energyi += energySum; //fill energySum back into energyi to have rest of loop behave the same.
912  }
913  if(_digitalEcal){
914  calibr_coeff = this->digitalEcalCalibCoeff(layer);
916  if(caloLayout == CHT::barrel){
917  float correction = 1.1387 - 0.068*cost - 0.191*cost*cost;
918  calibr_coeff/=correction;
919  }else{
920  float correction = 0.592 + 0.590*cost;
921  calibr_coeff/=correction;
922  }
923  }
924  }else{
925  calibr_coeff = this->analogueEcalCalibCoeff(layer);
926  }
927  // if(fabs(hit->getPosition()[2])>=_zOfEcalEndcap)calibr_coeff *= _ecalEndcapCorrectionFactor;
928  if (caloLayout!=CHT::barrel) calibr_coeff *= _ecalEndcapCorrectionFactor; // more robust
929 
930  if(_histograms){
931  fEcal->Fill(timei,energyi*calibr_coeff);
932  fEcalC->Fill(timei-dt,energyi*calibr_coeff);
933  fEcalC1->Fill(timei-dt,energyi*calibr_coeff);
934  fEcalC2->Fill(timei-dt,energyi*calibr_coeff);
935  }
936 
937  // apply extra energy digitisation effects
938  energyi = ecalEnergyDigi(energyi, cellid, cellid1);
939 
940  if (energyi > _thresholdEcal) {
941  float timeCor=0;
942  if(_ecalCorrectTimesForPropagation)timeCor=dt;
943  timei = timei - timeCor;
944  if(timei > _ecalTimeWindowMin && timei < ecalTimeWindowMax){
945  count++;
946  CalorimeterHitImpl * calhit = new CalorimeterHitImpl();
947  if(_ecalGapCorrection!=0){
948  _calHitsByStaveLayer[stave][layer].push_back(calhit);
949  _calHitsByStaveLayerModule[stave][layer].push_back(module);
950  }
951  calhit->setCellID0(cellid);
952  calhit->setCellID1(cellid1);
953  if(_digitalEcal){
954  calhit->setEnergy(calibr_coeff);
955  }else{
956  calhit->setEnergy(calibr_coeff*energyi);
957  // calhit->setEnergy(energyi);
958  }
959 
960  eCellOutput+= energyi*calibr_coeff;
961 
962  calhit->setTime(timei);
963  calhit->setPosition(hit->getPosition());
964  calhit->setType( CHT( CHT::em, CHT::ecal , caloLayout , layer ) );
965  calhit->setRawHit(hit);
966  ecalcol->addElement(calhit);
967  LCRelationImpl *rel = new LCRelationImpl(calhit,hit,1.0);
968  relcol->addElement( rel );
969  }else{
970  // if(caloLayout==CHT::barrel)std::cout << " Drop ECAL Barrel hit : " << timei << " " << calibr_coeff*energyi << std::endl;
971  }
972  }
973  }
974  }
975  }else{ // don't use timing
976  CalorimeterHitImpl * calhit = new CalorimeterHitImpl();
977  if(_ecalGapCorrection!=0){
978  _calHitsByStaveLayer[stave][layer].push_back(calhit);
979  _calHitsByStaveLayerModule[stave][layer].push_back(module);
980  }
981  float energyi = hit->getEnergy();
982 
983  // apply extra energy digitisation effects
984  energyi = ecalEnergyDigi(energyi, cellid, cellid1);
985 
986  calhit->setCellID0(cellid);
987  calhit->setCellID1(cellid1);
988  if(_digitalEcal){
989  calhit->setEnergy(calibr_coeff);
990  }else{
991  calhit->setEnergy(calibr_coeff*energyi);
992  }
993  calhit->setTime(0);
994  calhit->setPosition(hit->getPosition());
995  calhit->setType( CHT( CHT::em, CHT::ecal , caloLayout , layer ) );
996  calhit->setRawHit(hit);
997  ecalcol->addElement(calhit);
998  LCRelationImpl *rel = new LCRelationImpl(calhit,hit,1.0);
999  relcol->addElement( rel );
1000  } // timing if...else
1001 
1002 
1003  // std::cout << hit->getTimeCont(0) << " count = " << count << " E ECAL = " << energyCal << " - " << eCellInTime << " - " << eCellOutput << std::endl;
1004  } // energy threshold
1005  }
1006  // if requested apply gap corrections in ECAL ?
1007  if(_ecalGapCorrection!=0)this->fillECALGaps();
1008  // add ECAL collection to event
1009  ecalcol->parameters().setValue(LCIO::CellIDEncoding,initString);
1010 
1011  evt->addCollection(ecalcol,_outputEcalCollections[i].c_str());
1012  }
1013  catch(DataNotAvailableException &e){
1014  streamlog_out(DEBUG) << "could not find input ECAL collection " << colName << std::endl;
1015  }
1016  }
1017  //}
1018 
1019  if(_histograms){
1020 
1021  // fill normalisation of HCAL occupancy plots
1022  for(float x=15;x<3000; x+=30){
1023  for(float y=15;y<3000; y+=30){
1024  if(x>430||y>430){
1025  float r = sqrt(x*x+y*y);
1026  fHcalRLayerNorm->Fill(r,4.);
1027  }
1028  }
1029  }
1030 
1031  // fill normalisation of ECAL occupancy plots
1032  for(float x=2.5;x<3000; x+=5){
1033  for(float y=2.5;y<3000; y+=5){
1034  float r = sqrt(x*x+y*y);
1035  if(r>235)fEcalRLayerNorm->Fill(r,4.);
1036  }
1037  }
1038  }
1039 
1040  //
1041  // * Reading HCAL Collections of Simulated Hits *
1042  //
1043 
1044  for (unsigned int i(0); i < _hcalCollections.size(); ++i) {
1045 
1046  std::string colName = _hcalCollections[i] ;
1047 
1048  if ( colName.find("dummy")!=string::npos ) {
1049  streamlog_out ( DEBUG ) << "ignoring input HCAL collection name (looks like dummy name)" << colName << endl;
1050  continue;
1051  }
1052 
1053  //fg: need to establish the subdetetcor part here
1054  // use collection name as cellID does not seem to have that information
1055  CHT::Layout caloLayout = layoutFromString (colName);
1056 
1057 
1058  try{
1059  LCCollection * col = evt->getCollection( _hcalCollections[i].c_str() ) ;
1060  string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding);
1061  int numElements = col->getNumberOfElements();
1062  CellIDDecoder<SimCalorimeterHit> idDecoder(col);
1063  LCCollectionVec *hcalcol = new LCCollectionVec(LCIO::CALORIMETERHIT);
1064  hcalcol->setFlag(_flag.getFlag());
1065  for (int j(0); j < numElements; ++j) { //loop over all SimCalorimeterHits in this collection
1066  SimCalorimeterHit * hit = dynamic_cast<SimCalorimeterHit*>( col->getElementAt( j ) ) ;
1067  float energy = hit->getEnergy();
1068 
1069  if (energy > _thresholdHcal[0]/2) { //preselect for SimHits with energySum>threshold. Doubtful at least, as lower energy hit might fluctuate up and still be counted
1070  int cellid = hit->getCellID0();
1071  int cellid1 = hit->getCellID1();
1072  float calibr_coeff(1.);
1073  int layer =idDecoder(hit)[_cellIDLayerString];
1074  // NOTE : for a digital HCAL this does not allow for varying layer thickness
1075  // with depth - would need a simple mod to make response proportional to layer thickness
1076  if(_digitalHcal){
1077  calibr_coeff = this->digitalHcalCalibCoeff(caloLayout,energy);
1078  }else{
1079  calibr_coeff = this->analogueHcalCalibCoeff(caloLayout,layer);
1080  }
1081  // if(fabs(hit->getPosition()[2])>=_zOfEcalEndcap)calibr_coeff*=_hcalEndcapCorrectionFactor;
1082  if (caloLayout!=CHT::barrel) calibr_coeff*=_hcalEndcapCorrectionFactor; // more robust, is applied to ALL hits outside of barrel.
1083 
1084 
1085  //float energyCal = energy*calibr_coeff
1086  float x = hit->getPosition()[0];
1087  float y = hit->getPosition()[1];
1088  float z = hit->getPosition()[2];
1089  // float r = sqrt(x*x+y*y);
1090  if(_useHcalTiming){
1091  float hcalTimeWindowMax;
1092  if(caloLayout==CHT::barrel){ //current SimHit is in barrel, use barrel timing cut
1093  hcalTimeWindowMax = _hcalBarrelTimeWindowMax;
1094  } else { //current simhit is not in barrel, use endcap timing cut
1095  hcalTimeWindowMax = _hcalEndcapTimeWindowMax;
1096  }
1097 
1098  float r = sqrt(x*x+y*y+z*z);//this is a crude approximation. assumes initial particle originated at the very center of the detector.
1099  float dt = r/300-0.1;//magic numbers! ~
1100  const unsigned int n = hit->getNMCContributions(); //number of subhits of this SimHit
1101 
1102  std::vector<bool> used(n, false) ;
1103 
1104  int count = 0;
1105 
1106  for(unsigned int i =0; i<n;i++){ // loop over all subhits
1107  float timei = hit->getTimeCont(i); //absolute hit timing of current subhit
1108  float energyi = hit->getEnergyCont(i); //energy of current subhit
1109  float energySum = 0;
1110  float deltat = 0;
1111  if(_hcalCorrectTimesForPropagation)deltat=dt; //deltat now carries hit timing correction.
1112  //std::cout <<"outer:" << i << " " << n << std::endl;
1113 
1114  //idea of the following section:
1115  //if simpletimingcut == false
1116  //sum up hit energies which lie within one calo timing resolution to "timecluster" of current subhit
1117  //then treat each single timecluster as one hit over threshold and digitise separately. this means there can be more than one CalorimeterHit with the same cellIDs, but different hit times (!)
1118  //
1119  //if simpletimingcut == true
1120  //i'm very sorry. this is the worst code you will ever see.
1121  //sum up hit energies within timeWindowMin and timeWindowMax, use earliest subhit in this window as hit time for resulting calohit.
1122  //only one calorimeterhit will be generated from this.
1123 
1124  if(!used[i]){ //if current subhit has not been merged with previous hits already, take current hit as starting point to merge hits
1125  // merge with other hits?
1126  used[i] = true;
1127  for(unsigned int j =i; j<n;j++){//loop through all hits after current hit
1128  //std::cout << "inner:" << i << " " << j << " " << n << std::endl;
1129  if(!used[j]){
1130  float timej = hit->getTimeCont(j);
1131  float energyj = hit->getEnergyCont(j);
1132  float deltat = fabs(timei-timej);
1133  // std::cout << " HCAL deltat : " << deltat << std::endl;
1134  if (_hcalSimpleTimingCut){
1135  float deltat = _hcalCorrectTimesForPropagation?dt:0;
1136  if (timej-deltat>_hcalTimeWindowMin && timej-deltat<hcalTimeWindowMax){
1137  energySum += energyj;
1138  if (timej<timei){
1139  timei = timej; //use earliest hit time for simpletimingcut
1140  }
1141  }
1142  } else {
1143  if(deltat<_hcalDeltaTimeHitResolution){ //if this subhit is close to current subhit, add this hit's energy to timecluster
1144  if(energyj>energyi)timei=timej; //this is probably not what was intended. i guess this should find the largest hit of one timecluster and use its hittime for the cluster, but instead it compares the current hit energy to the sum of already found hit energies
1145  //std::cout << timei << " - " << timej << std::endl;
1146  //std::cout << energyi << " - " << energyj << std::endl;
1147  energyi+=energyj;
1148  used[j] = true;
1149  //std::cout << timei << " " << energyi << std::endl;
1150  }
1151  }
1152  }
1153  }
1154  if (_hcalSimpleTimingCut){
1155  used = vector<bool>(n, true); //mark everything as used to terminate loop. this is worse than goto. i'm sorry.
1156  energyi += energySum; //fill energySum back into energyi to have rest of loop behave the same.
1157  }
1158 
1159  //variables and their behaviour at this point:
1160  //if SimpleTimingCut == false
1161  //energyi carries the sum of subhit energies within +- one hcal time resolution - the timecluster energy.
1162  //timei carries something vaguely similar to the central hit time of the merged subhits
1163 
1164  //if SimpleTimingCut == true
1165  //energyi carries the sum of subhit energies within timeWindowMin and timeWindowMax
1166  //timei carries the time of the earliest hit within this window
1167 
1168 
1169  // apply extra energy digitisation effects
1170  energyi = ahcalEnergyDigi(energyi, cellid, cellid1); //this only uses the current subhit "timecluster"!
1171 
1172  if (energyi > _thresholdHcal[0]){ //now would be the correct time to do threshold comparison
1173  float timeCor=0;
1174  if(_hcalCorrectTimesForPropagation)timeCor=dt;
1175  timei = timei - timeCor;
1176  if(timei > _hcalTimeWindowMin && timei < hcalTimeWindowMax){ //if current subhit timecluster is within specified timing window, create new CalorimeterHit and add to collections etc.
1177  count++;
1178  CalorimeterHitImpl * calhit = new CalorimeterHitImpl();
1179  calhit->setCellID0(cellid);
1180  calhit->setCellID1(cellid1);
1181  if(_digitalHcal){
1182  calhit->setEnergy(calibr_coeff);
1183  //eCellOutput+= calibr_coeff;
1184  }else{
1185  calhit->setEnergy(calibr_coeff*energyi);
1186  //eCellOutput+= energyi*calibr_coeff;
1187  }
1188  calhit->setTime(timei);
1189  calhit->setPosition(hit->getPosition());
1190  calhit->setType( CHT( CHT::had, CHT::hcal , caloLayout , layer ) );
1191  calhit->setRawHit(hit);
1192  hcalcol->addElement(calhit);
1193  LCRelationImpl *rel = new LCRelationImpl(calhit,hit,1.0);
1194  relcol->addElement( rel );
1195  }else{
1196  // std::cout << "Drop HCAL hit : " << timei << " " << calibr_coeff*energyi << std::endl;
1197  }
1198  }
1199  }
1200  //std::cout <<"hello" << std::endl;
1201  }
1202  }else{ // don't use timing
1203  CalorimeterHitImpl * calhit = new CalorimeterHitImpl();
1204  calhit->setCellID0(cellid);
1205  calhit->setCellID1(cellid1);
1206  float energyi = hit->getEnergy();
1207 
1208  // apply realistic digitisation
1209  energyi = ahcalEnergyDigi(energyi, cellid, cellid1);
1210 
1211 
1212 
1213  if(_digitalHcal){
1214  calhit->setEnergy(calibr_coeff);
1215  }else{
1216  calhit->setEnergy(calibr_coeff*energyi);
1217  }
1218  //eCellOutput+= energyi*calibr_coeff;
1219  calhit->setTime(0);
1220  calhit->setPosition(hit->getPosition());
1221  calhit->setType( CHT( CHT::had, CHT::hcal , caloLayout , layer ) );
1222  calhit->setRawHit(hit);
1223  hcalcol->addElement(calhit);
1224  LCRelationImpl *rel = new LCRelationImpl(calhit,hit,1.0);
1225  relcol->addElement( rel );
1226  }
1227 
1228  // std::cout << hit->getTimeCont(0) << " count = " << count << " EHCAL = " << energyCal << " - " << eCellInTime << " - " << eCellOutput << std::endl;
1229  }
1230  }
1231  // add HCAL collection to event
1232  hcalcol->parameters().setValue(LCIO::CellIDEncoding,initString);
1233  evt->addCollection(hcalcol,_outputHcalCollections[i].c_str());
1234  }
1235  catch(DataNotAvailableException &e){
1236  streamlog_out(DEBUG) << "could not find input HCAL collection " << colName << std::endl;
1237  }
1238  }
1239 
1240  // add relation collection for ECAL/HCAL to event
1241  evt->addCollection(relcol,_outputRelCollection.c_str());
1242 
1243  _nEvt++;
1244 
1245 }
1246 
1247 
1248 void ILDCaloDigi::check( LCEvent * /*evt*/ ) { }
1249 
1251 
1252  if(_histograms){
1253  TFile *hfile = new TFile("calTiming.root","recreate");
1254  fEcal->TH1F::Write();
1255  fHcal->TH1F::Write();
1256  fEcalC->TH1F::Write();
1257  fHcalC->TH1F::Write();
1258  fEcalC1->TH1F::Write();
1259  fHcalC1->TH1F::Write();
1260  fEcalC2->TH1F::Write();
1261  fHcalC2->TH1F::Write();
1262  //fHcalCvsE->TH2F::Write();
1263  fHcalLayer1->TH2F::Write();
1264  fHcalLayer11->TH2F::Write();
1265  fHcalLayer21->TH2F::Write();
1266  fHcalLayer31->TH2F::Write();
1267  fHcalLayer41->TH2F::Write();
1268  fHcalLayer51->TH2F::Write();
1269  fHcalLayer61->TH2F::Write();
1270  fHcalLayer71->TH2F::Write();
1271  fHcalRLayer1->TH1F::Write();
1272  fHcalRLayer11->TH1F::Write();
1273  fHcalRLayer21->TH1F::Write();
1274  fHcalRLayer31->TH1F::Write();
1275  fHcalRLayer41->TH1F::Write();
1276  fHcalRLayer51->TH1F::Write();
1277  fHcalRLayer61->TH1F::Write();
1278  fHcalRLayer71->TH1F::Write();
1279  fHcalRLayerNorm->TH1F::Write();
1280  fEcalLayer1->TH2F::Write();
1281  fEcalLayer11->TH2F::Write();
1282  fEcalLayer21->TH2F::Write();
1283  fEcalRLayer1->TH1F::Write();
1284  fEcalRLayer11->TH1F::Write();
1285  fEcalRLayer21->TH1F::Write();
1286  fEcalRLayerNorm->TH1F::Write();
1287 
1288 
1289  hfile->Close();
1290  delete hfile;
1291  }
1292 
1293  //delete randomengines if needed
1294  if (_randomEngineDeadCellHcal != 0){
1296  }
1297 
1298  if (_randomEngineDeadCellEcal != 0){
1300  }
1301 
1302 }
1303 
1304 
1306 
1307  // Loop over hits in the Barrel
1308  // For each layer calculated differences in hit positions
1309  // Look for gaps based on expected separation of adjacent hits
1310  // loop over staves and layers
1311 
1312  for (int is=0; is < MAX_STAVES; ++is) {
1313  for (int il=0; il < MAX_LAYERS; ++il) {
1314 
1315  if(_calHitsByStaveLayer[is][il].size()>1){
1316  // compare all pairs of hits just once (j>i)
1317 
1318  for (unsigned int i=0;i<_calHitsByStaveLayer[is][il].size()-1;++i){
1319  CalorimeterHitImpl* hiti = _calHitsByStaveLayer[is][il][i];
1320  int modulei = _calHitsByStaveLayerModule[is][il][i];
1321  float xi = hiti->getPosition()[0];
1322  float yi = hiti->getPosition()[1];
1323  float zi = hiti->getPosition()[2];
1324 
1325  for (unsigned int j=i+1;j<_calHitsByStaveLayer[is][il].size();++j){
1326  CalorimeterHitImpl* hitj = _calHitsByStaveLayer[is][il][j];
1327  int modulej = _calHitsByStaveLayerModule[is][il][j];
1328  float xj = hitj->getPosition()[0];
1329  float yj = hitj->getPosition()[1];
1330  float zj = hitj->getPosition()[2];
1331  float dz = fabs(zi-zj);
1332  // *** BARREL CORRECTION ***
1333  if( fabs(zi)<_zOfEcalEndcap && fabs(zj)<_zOfEcalEndcap){
1334  // account for stave directions using normals
1335  // calculate difference in hit postions in z and along stave
1336  float dx = xi-xj;
1337  float dy = yi-yj;
1338  float dt = fabs(dx*_barrelStaveDir[is][0] + dy*_barrelStaveDir[is][1]);
1339  // flags for evidence for gaps
1340  bool zgap = false; // in z direction
1341  bool tgap = false; // along stave
1342  bool ztgap = false; // in both z and along stave
1343  bool mgap = false; // gaps between ECAL modules
1344 
1345  // criteria gaps in the z and t direction
1346  float zminm = 1.0*_barrelPixelSizeZ[il]-slop;
1347  float zmin = 1.0*_barrelPixelSizeZ[il]+slop;
1348  float zmax = 2.0*_barrelPixelSizeZ[il]-slop;
1349  float tminm = 1.0*_barrelPixelSizeT[il]-slop;
1350  float tmin = 1.0*_barrelPixelSizeT[il]+slop;
1351  float tmax = 2.0*_barrelPixelSizeT[il]-slop;
1352 
1353  // criteria for gaps
1354  // WOULD BE BETTER TO USE GEAR TO CHECK GAPS ARE OF EXPECTED SIZE
1355  if( dz > zmin && dz < zmax && dt < tminm )zgap = true;
1356  if( dz < zminm && dt > tmin && dt < tmax )tgap = true;
1357  if( dz > zmin && dz < zmax && dt > tmin && dt < tmax )ztgap=true;
1358 
1359  if(modulei!=modulej){
1360  if( dz > zmin && dz < 3.0*_barrelPixelSizeZ[il]-slop && dt < tmin)mgap = true;
1361  }
1362 
1363  // found a gap now apply a correction based on area of gap/area of pixel
1364  if(zgap||tgap||ztgap||mgap){
1365  float ecor = 1.;
1366  float f = _ecalGapCorrectionFactor; // fudge
1367  if(mgap)f = _ecalModuleGapCorrectionFactor;
1368  if(zgap||mgap)ecor = 1.+f*(dz - _barrelPixelSizeZ[il])/2./_barrelPixelSizeZ[il];
1369  if(tgap)ecor = 1.+f*(dt - _barrelPixelSizeT[il])/2./_barrelPixelSizeT[il];
1370  if(ztgap)ecor= 1.+f*(dt - _barrelPixelSizeT[il])*(dz - _barrelPixelSizeZ[il])/4./_barrelPixelSizeT[il]/_barrelPixelSizeZ[il];
1371  float ei = hiti->getEnergy()*ecor;
1372  float ej = hitj->getEnergy()*ecor;
1373  hiti->setEnergy(ei);
1374  hitj->setEnergy(ej);
1375  }
1376 
1377  // *** ENDCAP CORRECTION ***
1378  }else if(fabs(zi)>_zOfEcalEndcap && fabs(zj)>_zOfEcalEndcap&&dz<100){
1379  float dx = fabs(xi-xj);
1380  float dy = fabs(yi-yj);
1381  bool xgap = false;
1382  bool ygap = false;
1383  bool xygap = false;
1384  // criteria gaps in the z and t direction
1385 
1386  // x and y need to be swapped in different staves of endcap.
1387  float pixsizex, pixsizey;
1388  if ( is%2 == 1 ) {
1389  pixsizex = _endcapPixelSizeY[il];
1390  pixsizey = _endcapPixelSizeX[il];
1391  } else {
1392  pixsizex = _endcapPixelSizeX[il];
1393  pixsizey = _endcapPixelSizeY[il];
1394  }
1395 
1396  float xmin = 1.0*pixsizex+slop;
1397  float xminm = 1.0*pixsizex-slop;
1398  float xmax = 2.0*pixsizex-slop;
1399  float ymin = 1.0*pixsizey+slop;
1400  float yminm = 1.0*pixsizey-slop;
1401  float ymax = 2.0*pixsizey-slop;
1402  // look for gaps
1403  if(dx > xmin && dx < xmax && dy < yminm )xgap = true;
1404  if(dx < xminm && dy > ymin && dy < ymax )ygap = true;
1405  if(dx > xmin && dx < xmax && dy > ymin && dy < ymax )xygap=true;
1406 
1407  if(xgap||ygap||xygap){
1408 
1409  // cout <<"NewLDCCaloDigi found endcap gap, adjusting energy! " << xgap << " " << ygap << " " << xygap << " , " << il << endl;
1410  // cout << "stave " << is << " layer " << il << endl;
1411  // cout << " dx, dy " << dx<< " " << dy << " , sizes = " << pixsizex << " " << pixsizey << endl;
1412  // cout << " xmin... " << xmin << " " << xminm << " " << xmax << " ymin... " << ymin << " " << yminm << " " << ymax << endl;
1413 
1414  // found a gap make correction
1415  float ecor = 1.;
1416  float f = _ecalGapCorrectionFactor; // fudge
1417  if(xgap)ecor = 1.+f*(dx - pixsizex)/2./pixsizex;
1418  if(ygap)ecor = 1.+f*(dy - pixsizey)/2./pixsizey;
1419  if(xygap)ecor= 1.+f*(dx - pixsizex)*(dy - pixsizey)/4./pixsizex/pixsizey;
1420 
1421  // cout << "correction factor = " << ecor << endl;
1422 
1423  hiti->setEnergy( hiti->getEnergy()*ecor );
1424  hitj->setEnergy( hitj->getEnergy()*ecor );
1425  }
1426  }
1427  }
1428  }
1429  }
1430  }
1431  }
1432 
1433  return;
1434 
1435 }
1436 
1437 float ILDCaloDigi::digitalHcalCalibCoeff(CHT::Layout caloLayout, float energy ) {
1438 
1439  float calib_coeff = 0;
1440  unsigned int ilevel = 0;
1441  for(unsigned int ithresh=1;ithresh<_thresholdHcal.size();ithresh++){
1442  // Assume!!! hit energies are stored as floats, i.e. 1, 2 or 3
1443  if(energy>_thresholdHcal[ithresh])ilevel=ithresh; // ilevel = 0 , 1, 2
1444  }
1445 
1446  switch(caloLayout){
1447  case CHT::barrel:
1448  if(ilevel>_calibrCoeffHcalBarrel.size()-1){
1449  streamlog_out(ERROR) << " Semi-digital level " << ilevel << " greater than number of HCAL Calibration Constants (" <<_calibrCoeffHcalBarrel.size() << ")" << std::endl;
1450  }else{
1451  calib_coeff = _calibrCoeffHcalBarrel[ilevel];
1452  }
1453  break;
1454  case CHT::endcap:
1455  if(ilevel>_calibrCoeffHcalEndCap.size()-1){
1456  streamlog_out(ERROR) << " Semi-digital level " << ilevel << " greater than number of HCAL Calibration Constants (" <<_calibrCoeffHcalEndCap.size() << ")" << std::endl;
1457  }else{
1458  calib_coeff = _calibrCoeffHcalEndCap[ilevel];
1459  }
1460  break;
1461  case CHT::plug:
1462  if(ilevel>_calibrCoeffHcalOther.size()-1){
1463  streamlog_out(ERROR) << " Semi-digital level " << ilevel << " greater than number of HCAL Calibration Constants (" <<_calibrCoeffHcalOther.size() << ")" << std::endl;
1464  }else{
1465  calib_coeff = _calibrCoeffHcalOther[ilevel];
1466  }
1467  break;
1468  default:
1469  streamlog_out(ERROR) << " Unknown HCAL Hit Type " << std::endl;
1470  break;
1471  }
1472 
1473 
1474 
1475 
1476 
1477  return calib_coeff;
1478 }
1479 
1480 
1481 float ILDCaloDigi::analogueHcalCalibCoeff(CHT::Layout caloLayout, int layer ) {
1482 
1483  float calib_coeff = 0;
1484 
1485  for (unsigned int k(0); k < _hcalLayers.size(); ++k) {
1486  int min,max;
1487  if (k == 0)
1488  min = 0;
1489  else
1490  min = _hcalLayers[k-1];
1491 
1492  max = _hcalLayers[k];
1493  if (layer >= min && layer < max) {
1494  switch(caloLayout){
1495  case CHT::barrel:
1496  calib_coeff = _calibrCoeffHcalBarrel[k];
1497  break;
1498  case CHT::endcap:
1499  calib_coeff = _calibrCoeffHcalEndCap[k];
1500  break;
1501  case CHT::plug:
1502  case CHT::ring:
1503  calib_coeff = _calibrCoeffHcalOther[k];
1504  break;
1505  default:
1506  streamlog_out(ERROR) << " Unknown HCAL Hit Type " << std::endl;
1507  break;
1508  }
1509  }
1510  }
1511 
1512  return calib_coeff;
1513 }
1514 
1516 
1517  float calib_coeff = 0;
1518 
1519  for (unsigned int k(0); k < _ecalLayers.size(); ++k) {
1520  int min,max;
1521  if (k == 0)
1522  min = 0;
1523  else
1524  min = _ecalLayers[k-1];
1525 
1526  max = _ecalLayers[k];
1527  if (layer >= min && layer < max) {
1528  calib_coeff = _calibrCoeffEcal[k];
1529  break;
1530  }
1531  }
1532 
1533  return calib_coeff;
1534 
1535 }
1536 
1538 
1539  float calib_coeff = 0;
1540 
1541  // retrieve calibration constants
1542  for (unsigned int k(0); k < _ecalLayers.size(); ++k) {
1543  int min,max;
1544  if (k == 0){
1545  min = 0;
1546  }else{
1547  min = _ecalLayers[k-1];
1548  }
1549  max = _ecalLayers[k];
1550  if (layer >= min && layer < max) {
1551  calib_coeff = _calibrCoeffEcal[k];
1552  break;
1553  }
1554  }
1555 
1556  return calib_coeff;
1557 
1558 }
1559 
1560 float ILDCaloDigi::ecalEnergyDigi(float energy, int id0, int id1) {
1561 
1562  // some extra digi effects (daniel)
1563  // controlled by _applyEcalDigi = 0 (none), 1 (silicon), 2 (scintillator)
1564 
1565  // small update for time-constant uncorrelated miscalibrations. DJ, Jan 2015
1566 
1567  float e_out(energy);
1568  if ( _applyEcalDigi==1 ) e_out = siliconDigi(energy); // silicon digi
1569  else if ( _applyEcalDigi==2 ) e_out = scintillatorDigi(energy, true); // scintillator digi
1570 
1571  // add electronics dynamic range
1572  // Sept 2015: Daniel moved this to the ScintillatorDigi part, so it is applied before unfolding of sipm response
1573  // if (_ecalMaxDynMip>0) e_out = min (e_out, _ecalMaxDynMip*_calibEcalMip);
1574 
1575  // random miscalib
1576  if (_misCalibEcal_uncorrel>0) {
1577  float miscal(0);
1579  std::pair <int, int> id(id0, id1);
1580  if ( _ECAL_cell_miscalibs.find(id)!=_ECAL_cell_miscalibs.end() ) { // this cell was previously seen, and a miscalib stored
1581  miscal = _ECAL_cell_miscalibs[id];
1582  } else { // we haven't seen this one yet, get a miscalib for it
1583  miscal = CLHEP::RandGauss::shoot( 1.0, _misCalibEcal_uncorrel );
1584  _ECAL_cell_miscalibs[id]=miscal;
1585  }
1586  } else {
1587  miscal = CLHEP::RandGauss::shoot( 1.0, _misCalibEcal_uncorrel );
1588  }
1589  e_out*=miscal;
1590  }
1591 
1593 
1594  // random cell kill
1595  if (_deadCellFractionEcal>0){
1596  if (_deadCellEcal_keep == true){
1597  std::pair <int, int> id(id0, id1);
1598 
1599  if (_ECAL_cell_dead.find(id)!=_ECAL_cell_dead.end() ) { // this cell was previously seen
1600  if (_ECAL_cell_dead[id] == true){
1601  e_out = 0;
1602  }
1603  } else { // we haven't seen this one yet, get a miscalib for it
1604  bool thisDead = (CLHEP::RandFlat::shoot(_randomEngineDeadCellEcal, .0, 1.0) < _deadCellFractionEcal);
1605  _ECAL_cell_dead[id] = thisDead;
1606  if (thisDead == true){
1607  e_out = 0;
1608  }
1609  }
1610 
1611  } else {
1612  if (CLHEP::RandFlat::shoot(0.0,1.0)<_deadCellFractionEcal ) e_out=0;
1613  }
1614 
1615  }
1616 
1617  return e_out;
1618 }
1619 
1620 
1621 float ILDCaloDigi::ahcalEnergyDigi(float energy, int id0, int id1) {
1622  // some extra digi effects (daniel)
1623  // controlled by _applyHcalDigi = 0 (none), 1 (scintillator/SiPM)
1624 
1625  // small update for time-constant uncorrelated miscalibrations. DJ, Jan 2015
1626 
1627  float e_out(energy);
1628  if ( _applyHcalDigi==1 ) e_out = scintillatorDigi(energy, false); // scintillator digi
1629 
1630  // add electronics dynamic range
1631  // Sept 2015: Daniel moved this to the ScintillatorDigi part, so it is applied before unfolding of sipm response
1632  // if (_hcalMaxDynMip>0) e_out = min (e_out, _hcalMaxDynMip*_calibHcalMip);
1633 
1634  // random miscalib
1635  // if (_misCalibHcal_uncorrel>0) e_out*=CLHEP::RandGauss::shoot( 1.0, _misCalibHcal_uncorrel );
1636  if (_misCalibHcal_uncorrel>0) {
1637  float miscal(0);
1639  std::pair <int, int> id(id0, id1);
1640  if ( _HCAL_cell_miscalibs.find(id)!=_HCAL_cell_miscalibs.end() ) { // this cell was previously seen, and a miscalib stored
1641  miscal = _HCAL_cell_miscalibs[id];
1642  } else { // we haven't seen this one yet, get a miscalib for it
1643  miscal = CLHEP::RandGauss::shoot( 1.0, _misCalibHcal_uncorrel );
1644  _HCAL_cell_miscalibs[id]=miscal;
1645  }
1646  } else {
1647  miscal = CLHEP::RandGauss::shoot( 1.0, _misCalibHcal_uncorrel );
1648  }
1649  e_out*=miscal;
1650  }
1651 
1653 
1654  // random cell kill
1655  if (_deadCellFractionHcal>0){
1656  if (_deadCellHcal_keep == true){
1657  std::pair <int, int> id(id0, id1);
1658 
1659  if (_HCAL_cell_dead.find(id)!=_HCAL_cell_dead.end() ) { // this cell was previously seen
1660  if (_HCAL_cell_dead[id] == true){
1661  e_out = 0;
1662  }
1663  } else { // we haven't seen this one yet, get a miscalib for it
1664  bool thisDead = (CLHEP::RandFlat::shoot(_randomEngineDeadCellHcal, .0, 1.0) < _deadCellFractionHcal);
1665  _HCAL_cell_dead[id] = thisDead;
1666  if (thisDead == true){
1667  e_out = 0;
1668  }
1669  }
1670 
1671  } else {
1672  if (CLHEP::RandFlat::shoot(0.0,1.0)<_deadCellFractionHcal ) e_out=0;
1673  }
1674 
1675  }
1676  return e_out;
1677 }
1678 
1679 
1680 float ILDCaloDigi::siliconDigi(float energy) {
1681  // applies extra digitisation to silicon hits
1682 
1683  // calculate #e-h pairs
1684  float nehpairs = 1e9*energy/_ehEnergy; // check units of energy! _ehEnergy is in eV, energy in GeV
1685 
1686  // fluctuate it by Poisson
1687  float smeared_energy = energy*CLHEP::RandPoisson::shoot( nehpairs )/nehpairs;
1688 
1689  // limited electronics dynamic range // Daniel moved electronics dyn range to here
1690  if (_ecalMaxDynMip>0)
1691  smeared_energy = std::min ( smeared_energy, _ecalMaxDynMip*_calibEcalMip);
1692 
1693  // add electronics noise
1694  if ( _ecal_elec_noise > 0 )
1695  smeared_energy += CLHEP::RandGauss::shoot(0, _ecal_elec_noise*_calibEcalMip);
1696 
1697  return smeared_energy;
1698 }
1699 
1700 float ILDCaloDigi::scintillatorDigi(float energy, bool isEcal) {
1701  // this applies some extra digitisation to scintillator+PPD hits (PPD=SiPM, MPPC)
1702  // - poisson fluctuates the number of photo-electrons according to #PEs/MIP
1703  // - applies PPD saturation according to #pixels
1704  // Daniel Jeans, Jan/Feb 2014.
1705 
1706  float digiEn(0);
1707  if (isEcal) {
1708  digiEn = _scEcalDigi->getDigitisedEnergy(energy);
1709  } else {
1710  digiEn = _scHcalDigi->getDigitisedEnergy(energy);
1711  }
1712  return digiEn;
1713 }
1714 
1715 LCCollection* ILDCaloDigi::combineVirtualStripCells(LCCollection* col, bool isBarrel, int stripOrientation) {
1716  // combines the virtual cells in a strip
1717  // input collection is for virtual cells
1718  // returns collection of strips
1719 
1720  // daniel jeans, jan/feb 2014
1721 
1722  // sanity check
1723  if ( stripOrientation==SQUARE ) {
1724  streamlog_out ( ERROR ) << "ILDCaloDigi::combineVirtualStripCells trying to deal with silicon strips??? I do not know how to do that, refusing to do anything!" << std::endl;
1725  return NULL;
1726  }
1727 
1728  // get the encoding string from the original collection
1729  string initString = col->getParameters().getStringVal(LCIO::CellIDEncoding);
1730  CellIDDecoder<SimCalorimeterHit> idDecoder( col );
1731 
1732  // make the new output collection
1733  LCCollectionVec *tempstripcol = new LCCollectionVec(LCIO::SIMCALORIMETERHIT);
1734  tempstripcol->setFlag(_flag.getFlag());
1735  CellIDEncoder<SimCalorimeterHitImpl> idEncoder( initString, tempstripcol );
1736 
1737  // temporary storage for strip hits
1738  // pair <id0, id1>, (the new combined hit)
1739  std::map < std::pair <int, int> , SimCalorimeterHitImpl* > newhits;
1740 
1741  // loop over input collection
1742  int numElements = col->getNumberOfElements();
1743 
1744  // // sum energy for check
1745  float tempenergysum(0);
1746  for (int j(0); j < numElements; ++j) {
1747  SimCalorimeterHit * hit = dynamic_cast<SimCalorimeterHit*>( col->getElementAt( j ) ) ;
1748  tempenergysum+=hit->getEnergy();
1749  }
1750 
1751  float scTVirtLengthBar(-99);
1752  float scLVirtLengthBar(-99);
1753  float scTVirtLengthEnd(-99);
1754  float scLVirtLengthEnd(-99);
1755 
1756  for (int j(0); j < numElements; ++j) { // loop over virtual cells
1757  SimCalorimeterHit * hit = dynamic_cast<SimCalorimeterHit*>( col->getElementAt( j ) ) ;
1758 
1759  // for now, ignore preshower layer.
1760  // in "usual" (non-preshower) ecal collections, km1 = 0 is the first layer AFTER the preshower
1761  int km1 = idDecoder(hit)[_cellIDLayerString];
1762 
1763  int gearlayer = km1+1; // in "gearlayer", preshower is 0, first layer after absorber is 1
1764 
1765  // after fix of MOKKA, this should be not needed
1766  // int gearlayer(-99); // this is the layer index which the GEAR geometry knows about. depends on driver version...
1767  // if ( _ecal_driver_version == 0 ) { // SEcal04 driver
1768  // } else if ( _ecal_driver_version == 1 ) { // SEcal05 driver
1769  // gearlayer = km1+1;
1770  // } else {
1771  // streamlog_out ( ERROR ) << "ERROR unknown value for ecal driver version, _ecal_driver_version=" << _ecal_driver_version << endl;
1772  // }
1773  // assert (gearlayer>=0);
1774 
1775  int m = idDecoder(hit)[_cellIDModuleString];
1776  int s = idDecoder(hit)[_cellIDStaveString];
1777  int i_index = idDecoder(hit)[_cellIDIndexIString];
1778  int j_index = idDecoder(hit)[_cellIDIndexJString];
1779 
1780  //cout << "ORIG: " << km1 << " " << m << " " << s << " " << i_index << " " << j_index << " : " <<
1781  // hit->getPosition()[0] << " "<< hit->getPosition()[1] << " "<< hit->getPosition()[2] << endl;
1782 
1783  // should we combine virtual cells in the I or J direction?
1784  //
1785  // in barrel:
1786  // i is along slab (phi in barrel)
1787  // j is across slab (z in barrel)
1788  // increasing j = increasing z; increasing i = decreasing phi
1789  //
1790  // in endcap:
1791  // i is across slab
1792  // j is along slab
1793  // different staves are rotated around beam axis.
1794  // in +ve z endcap (m==6),
1795  // stave 0 is at -ve x and +ve y. in this stave, i is parallel to -x, j to +y
1796  // stave 3 is at +ve x and +ve y. in this stave, i is parallel to +y, j to +x
1797  // -ve z endcap (m==0) is same, just everything flipped in x.
1798 
1799  bool collateAlongI = isBarrel ?
1800  stripOrientation==STRIP_ALIGN_ALONG_SLAB : // I is the index along the slab (R-phi in barrel)
1801  stripOrientation==STRIP_ALIGN_ACROSS_SLAB ;// for some reason seems to be reversed in endcap...!!
1802 
1803  streamlog_out ( DEBUG ) << "isBarrel = " << isBarrel << " : stripOrientation= " << stripOrientation << " gear layer = " << gearlayer << endl;
1804 
1805  // let's get the length of the virtual cell in the direction of the strip
1806  // fixed rare crashes, and streamlined code to get virtualCellSizeAlongStrip. Sept 2014
1807  float virtualCellSizeAlongStrip(0);
1808 
1809  float* layerpixsize(0);
1810  float* savedPixSize(0);
1811  if (isBarrel) {
1812  if (stripOrientation==STRIP_ALIGN_ACROSS_SLAB) {
1813  layerpixsize=_barrelPixelSizeT;
1814  savedPixSize=&scTVirtLengthBar;
1815  } else {
1816  layerpixsize=_barrelPixelSizeZ;
1817  savedPixSize=&scLVirtLengthBar;
1818  }
1819  } else {
1820  if (stripOrientation==STRIP_ALIGN_ACROSS_SLAB) {
1821  layerpixsize=_endcapPixelSizeX;
1822  savedPixSize=&scTVirtLengthEnd;
1823  } else {
1824  layerpixsize=_endcapPixelSizeY;
1825  savedPixSize=&scLVirtLengthEnd;
1826  }
1827  }
1828 
1829  virtualCellSizeAlongStrip = layerpixsize[gearlayer];
1830  if ( virtualCellSizeAlongStrip>0 ) { // looks OK
1831  if ( *savedPixSize<0 ) { // no saved size yet, keep this one
1832  *savedPixSize=virtualCellSizeAlongStrip;
1833  }
1834  } else { // no valid info in gear file for this layer
1835  if ( *savedPixSize>0 ) { // use saved value from other layer
1836  virtualCellSizeAlongStrip=*savedPixSize;
1837  } else { // look at previous layers for one with same orientation (extra check, sept 2014)
1838 
1839  std::vector < std::pair <int, int> > layerTypes = getLayerConfig();
1840 
1841  streamlog_out ( DEBUG )
1842  << "could not get valid info from gear file..." << endl
1843  << "looking through previous layers to get a matching orientation" << endl
1844  << "this gear layer " << gearlayer << " type: " << layerTypes[gearlayer].first << " " << layerTypes[gearlayer].second << endl;
1845 
1846 
1847 
1848  for ( int il=gearlayer-1; il>=0; il--) {
1849  // layer types include the preshower at posn "0"
1850  // gearlayer has preshower as layer 0
1851  if ( layerTypes[il] == layerTypes[gearlayer] ) { // found layer with same setup
1852  streamlog_out ( DEBUG )
1853  << "found a match! " << il << " " <<
1854  layerTypes[il].first << " " << layerTypes[il].second << " : " << layerpixsize[il] << endl;
1855  virtualCellSizeAlongStrip=layerpixsize[il];
1856  *savedPixSize=virtualCellSizeAlongStrip;
1857  break;
1858  }
1859  }
1860  }
1861  }
1862  streamlog_out ( DEBUG ) << "virtualCellSizeAlongStrip = " << virtualCellSizeAlongStrip << endl;
1863 
1864  // calculate the new strip's I,J coordinates
1865  int i_new = collateAlongI ? i_index/getNumberOfVirtualCells() : i_index ;
1866  int j_new = collateAlongI ? j_index : j_index/getNumberOfVirtualCells() ;
1867 
1868  // apply position-dependent energy correction
1869  //
1870  // relative virtual cell position within strip (0 = centre)
1871  // distance between centre of virtual cell and centre of strip
1872  int relativeIndx = collateAlongI ? i_index : j_index;
1873  float relativePos = relativeIndx%getNumberOfVirtualCells(); // this is index within strip wrt strip end (0->_strip_virt_cells-1)
1874  relativePos -= (getNumberOfVirtualCells()-1)/2.0; // index wrt strip centre
1875  relativePos *= virtualCellSizeAlongStrip; // distance wrt strip centre
1876 
1877  // effect of absorbtion length within scintillator
1878  // TODO: should check the polarity is consistent with mppc position, to make sure larger response nearer to mppc....
1879  float energy_new = hit->getEnergy();
1880 
1881  float energyNonuniformityScaling(1.);
1882  if (_strip_abs_length>0) {
1883  energyNonuniformityScaling = exp ( -relativePos/_strip_abs_length );
1884  energy_new *= energyNonuniformityScaling;
1885  }
1886 
1887 
1888  // create a new hit for the strip
1889  SimCalorimeterHitImpl * newhit = new SimCalorimeterHitImpl( );
1890 
1891  // set it's ID
1892  idEncoder[_cellIDModuleString] = m;
1893  idEncoder[_cellIDStaveString] = s;
1894  idEncoder[_cellIDLayerString] = km1;
1895  idEncoder[_cellIDIndexIString] = i_new;
1896  idEncoder[_cellIDIndexJString] = j_new;
1897  idEncoder.setCellID( newhit ) ;
1898 
1899  int newid0 = newhit->getCellID0();
1900  int newid1 = newhit->getCellID1();
1901 
1902  std::pair <int, int> cellids(newid0, newid1);
1903 
1904  // calculate position of centre of this new strip
1905  // it depends if we are in the barrel or endcap, and in which stave
1906  // (n.b. we could do this later, after checking for duplicates. however, keeping it here allows us to
1907  // check that we haven't supplied wrong nVirtualCells parameter)
1908 
1909  float stripPos[3]={0};
1910  if (isBarrel) {
1911  if ( stripOrientation == STRIP_ALIGN_ACROSS_SLAB ) { // it's along z
1912  stripPos[0] = hit->getPosition()[0];
1913  stripPos[1] = hit->getPosition()[1];
1914  stripPos[2] = hit->getPosition()[2] - relativePos; // increasing j = increasing z
1915  } else { // it's along t
1916  float phi = atan2(_barrelStaveDir[s][1],_barrelStaveDir[s][0]);
1917  stripPos[0] = hit->getPosition()[0] - relativePos*cos(phi); // negative: increasing I = decreasing phi
1918  stripPos[1] = hit->getPosition()[1] - relativePos*sin(phi);
1919  stripPos[2] = hit->getPosition()[2];
1920  }
1921  } else { // endcap
1922  stripPos[0] = hit->getPosition()[0];
1923  stripPos[1] = hit->getPosition()[1];
1924  stripPos[2] = hit->getPosition()[2]; // z never changes
1925  // there's almost certainly a neater way to get these different polarities in here...DJ
1926  // ....but this is, I believe, correct!
1927  int xsign = m==6 ? -1 : +1; // endcaps are mirrored in x, not in y
1928 
1929  switch (s) {
1930  case 0:
1931  if (collateAlongI) stripPos[0] += - xsign*relativePos;
1932  else stripPos[1] += - relativePos;
1933  break;
1934  case 1:
1935  if (collateAlongI) stripPos[1] += + relativePos;
1936  else stripPos[0] += - xsign*relativePos;
1937  break;
1938  case 2:
1939  if (collateAlongI) stripPos[0] += + xsign*relativePos;
1940  else stripPos[1] += + relativePos;
1941  break;
1942  case 3:
1943  if (collateAlongI) stripPos[1] += - relativePos;
1944  else stripPos[0] += + xsign*relativePos;
1945  break;
1946  }
1947 
1948  } // endcap
1949 
1950  // cout << "new strip pos: " << stripPos[0] << " " << stripPos[1] << " " << stripPos[2] << endl;
1951 
1952 
1953  // check if we have already seen a virtual cell from this strip
1954  if ( newhits.find(cellids)!=newhits.end() ) { // already have one from this strip
1955 
1956  SimCalorimeterHitImpl* htt = newhits.find(cellids)->second; // previously made hit in this stirp
1957  // check that calculated positions are same!
1958  bool isOK=true;
1959  for (int i=0; i<3; i++) {
1960  if ( fabs( htt->getPosition()[i] - stripPos[i] ) > 1 ) { // should be identical, but allow a little slop
1961  isOK=false;
1962  break;
1963  }
1964  }
1965  if (!isOK) {
1966  streamlog_out ( ERROR ) << "strip virtual cell merging: inconsistent position calc!" << std::endl <<
1967  "please check that the parameter ECAL_strip_nVirtualCells is correctly set..." << getNumberOfVirtualCells() << std::endl << " layer = (k-1) " << km1 << " (gear) " << gearlayer << endl;
1968 
1969 
1970  for (int i=0; i<3; i++) {
1971  streamlog_out ( DEBUG ) << stripPos[i] << " ";
1972  }
1973  streamlog_out (DEBUG) << endl;
1974 
1975  for (int i=0; i<3; i++) {
1976  streamlog_out (DEBUG) << htt->getPosition()[i] << " ";
1977  }
1978  streamlog_out (DEBUG) << endl;
1979 
1980  // std::cout << "K-1 = " << km1 ;
1981  // std::cout << "; GEARlay = " << gearlayer;
1982  // std::cout << "; m = " << m;
1983  // std::cout << "; s = " << s;
1984  // std::cout << "; i = " << i_index;
1985  // std::cout << "; j = " << j_index << std::endl;
1986 
1987  assert(0);
1988  }
1989 
1990  // delete the duplicate
1991  delete newhit;
1992 
1993  // set it to the previous one
1994  newhit = htt;
1995 
1996  } else { // it's the first hit from this strip
1997  newhit->setPosition(stripPos);
1998  newhits[cellids] = newhit;
1999  newhit->setEnergy( 0 ); // this is added when we add MC contributions
2000  }
2001 
2002  // add the MC contriutions
2003  float eadd(0);
2004  for (int ij=0; ij<hit->getNMCContributions() ; ij++) {
2005  newhit->addMCParticleContribution( hit->getParticleCont(ij),
2006  hit->getEnergyCont(ij)*energyNonuniformityScaling,
2007  hit->getTimeCont(ij),
2008  hit->getPDGCont(ij) );
2009  eadd+=hit->getEnergyCont(ij)*energyNonuniformityScaling;
2010  }
2011 
2012  float esum(0);
2013  for (int ij=0; ij<newhit->getNMCContributions() ; ij++) {
2014  esum+=newhit->getEnergyCont(ij);
2015  }
2016  } // loop over hits
2017 
2018  // move the hits from the temporary storage to the output collection
2019  for ( std::map < std::pair <int, int> , SimCalorimeterHitImpl* >::iterator itt = newhits.begin(); itt!=newhits.end(); itt++) {
2020  tempstripcol->addElement(itt->second);
2021  }
2022 
2023  // return the new collection
2024  return tempstripcol;
2025 }
2026 
2027 
2029  // if ( _strip_virt_cells < 0 ) { // not yet set, try to get from gear file
2030  // // number of virtual cells in scintillator strip
2031  // try {
2032  // const gear::GearParameters& pMokka = Global::GEAR->getGearParameters("MokkaParameters");
2033  // std::string nVirtualMokkaS = pMokka.getStringVal("Ecal_Sc_number_of_virtual_cells");
2034  // _strip_virt_cells = std::atoi( nVirtualMokkaS.c_str() );
2035  // streamlog_out (MESSAGE) << "INFO: got number of virtual cells from gear file: " << _strip_virt_cells << endl;
2036  // } catch(gear::UnknownParameterException &e) { // not found in gear file, get from steering file parameter...
2037  // streamlog_out (MESSAGE) << "INFO: taking number of virtual cells from steering file (not found in gear file): " << _ecalStrip_default_nVirt << endl;
2038  // _strip_virt_cells = _ecalStrip_default_nVirt;
2039  // }
2040  // }
2041  return _strip_virt_cells;
2042 }
2043 
2044 std::vector < std::pair <int, int> > & ILDCaloDigi::getLayerConfig() {
2045  // get the layer layout (silicon, scintillator)
2046  // first element of layerTypes is the preshower
2047 
2048 
2049  if ( _layerTypes.size()==0 ) {
2050 
2051  for(std::string::size_type i = 0; i < _ecalLayout.size(); ++i) {
2052 
2053  // convert each element of string to integer
2054  // int type = std::atoi( &ccdd ); // this is not well done (must be null-terminated)
2055  int type = _ecalLayout[i] - '0'; // this is less obvious, but works...
2056 
2057  switch ( type ) { // these originally defined in Mokka driver SEcalSD04
2058  case 0:
2059  _layerTypes.push_back(std::pair < int, int > (SIECAL, SQUARE) );
2060  _layerTypes.push_back(std::pair < int, int > (SIECAL, SQUARE) );
2061  break;
2062  case 1:
2063  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ALONG_SLAB) );
2064  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ALONG_SLAB) );
2065  break;
2066  case 2:
2067  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ACROSS_SLAB) );
2068  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ACROSS_SLAB) );
2069  break;
2070  case 3:
2071  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ALONG_SLAB) );
2072  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ACROSS_SLAB) );
2073  break;
2074  case 4:
2075  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ACROSS_SLAB) );
2076  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ALONG_SLAB) );
2077  break;
2078  case 5:
2079  _layerTypes.push_back(std::pair < int, int > (SIECAL, SQUARE) );
2080  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ALONG_SLAB) );
2081  break;
2082  case 6:
2083  _layerTypes.push_back(std::pair < int, int > (SIECAL, SQUARE) );
2084  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ACROSS_SLAB) );
2085  break;
2086  case 7:
2087  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ALONG_SLAB) );
2088  _layerTypes.push_back(std::pair < int, int > (SIECAL, SQUARE) );
2089  break;
2090  case 8:
2091  _layerTypes.push_back(std::pair < int, int > (SCECAL, STRIP_ALIGN_ACROSS_SLAB) );
2092  _layerTypes.push_back(std::pair < int, int > (SIECAL, SQUARE) );
2093  break;
2094  default:
2095  streamlog_out (ERROR) << "ERROR, unknown layer type " << type << endl;
2096  }
2097  }
2098  }
2099 
2100  return _layerTypes;
2101 }
2102 
2103 void ILDCaloDigi::checkConsistency(std::string colName, int layer) {
2104 
2105  if ( _applyEcalDigi==0 || _countWarnings>20 ) return;
2106 
2107  std::pair < int, int > thislayersetup = getLayerProperties(colName, layer);
2108 
2109  if ( _applyEcalDigi == 1 && thislayersetup.first!=SIECAL ) {
2110  streamlog_out (ERROR) << "collection: " << colName << endl;
2111  streamlog_out (ERROR) << "you seem to be trying to apply ECAL silicon digitisation to scintillator? Refusing!" << endl;
2112  streamlog_out (ERROR) << "check setting of ECAL_apply_realistic_digi: " << _applyEcalDigi << endl;
2113  assert(0);
2114  _countWarnings++;
2115  }
2116 
2117  if ( _applyEcalDigi == 2 && thislayersetup.first!=SCECAL ) {
2118  streamlog_out (ERROR) << "collection: " << colName << endl;
2119  streamlog_out (ERROR) << "you seem to be trying to apply ECAL scintillator digitisation to silicon? Refusing!" << endl;
2120  streamlog_out (ERROR) << "check setting of ECAL_apply_realistic_digi: " << _applyEcalDigi << endl;
2121  assert(0);
2122  _countWarnings++;
2123  }
2124 
2125  if ( thislayersetup.second!=getStripOrientationFromColName( colName ) ) {
2126  streamlog_out (ERROR) << "collection: " << colName << endl;
2127  streamlog_out (ERROR) << "some inconsistency in strip orientation?" << endl;
2128  streamlog_out (ERROR) << " from collection name: " << getStripOrientationFromColName( colName ) << endl;
2129  streamlog_out (ERROR) << " from layer config string: " << thislayersetup.second << endl;
2130  _countWarnings++;
2131  }
2132 
2133  return;
2134 }
2135 
2136 std::pair < int, int > ILDCaloDigi::getLayerProperties( std::string colName, int layer ) {
2137  std::pair < int, int > thislayersetup(-99,-99);
2138  std::string colNameLow(colName);
2139  std::transform(colNameLow.begin(), colNameLow.end(), colNameLow.begin(), ::tolower);
2140  if ( colNameLow.find("presh")!=string::npos ) { // preshower
2141  if ( layer != 0 ) {
2142  streamlog_out (WARNING) << "preshower layer with layer index = " << layer << " ??? " << endl;
2143  } else {
2144  thislayersetup = getLayerConfig()[layer];
2145  }
2146  } else if ( colNameLow.find("ring")!=string::npos ) { // ecal ring (has no preshower), and is actually always all silicon
2147  if ( layer < int(getLayerConfig().size()) ) {
2148  // thislayersetup = getLayerConfig()[layer];
2149  thislayersetup = std::pair < int, int > (SIECAL, SQUARE);
2150  } else {
2151  streamlog_out (WARNING) << "unphysical layer number? " << layer << " " << getLayerConfig().size() << endl;
2152  }
2153  } else { // endcap, barrel
2154  if ( layer+1 < int(getLayerConfig().size()) ) {
2155  thislayersetup = getLayerConfig()[layer+1];
2156  } else {
2157  streamlog_out (WARNING) << "unphysical layer number? " << layer << " " << getLayerConfig().size() << endl;
2158  }
2159  }
2160  return thislayersetup;
2161 }
2162 
2164  int orientation(-99);
2165  std::string colNameLow(colName);
2166  std::transform(colNameLow.begin(), colNameLow.end(), colNameLow.begin(), ::tolower);
2167  if ( colNameLow.find("trans")!=string::npos ) {
2168  orientation=STRIP_ALIGN_ACROSS_SLAB;
2169  } else if ( colNameLow.find("long")!=string::npos ) {
2170  orientation=STRIP_ALIGN_ALONG_SLAB;
2171  } else { // assume square...
2172  orientation=SQUARE;
2173  // cout << "WARNING, cannot guess strip orientation! for collection " << colName << endl;
2174  }
2175  return orientation;
2176 }
int _applyEcalDigi
Definition: ILDCaloDigi.h:206
float ecalEnergyDigi(float energy, int id0, int id1)
virtual void check(LCEvent *evt)
int getStripOrientationFromColName(std::string colName)
bool _misCalibEcal_uncorrel_keep
Definition: ILDCaloDigi.h:213
const int MAX_STAVES
Definition: ILDCaloDigi.h:21
TH1F * fEcalC
Definition: ILDCaloDigi.h:278
float digitalHcalCalibCoeff(CHT::Layout, float energy)
float _misCalibEcal_uncorrel
Definition: ILDCaloDigi.h:212
void setElecRange(float x)
int _ecalGapCorrection
Definition: ILDCaloDigi.h:161
float _ecalBarrelTimeWindowMax
Definition: ILDCaloDigi.h:185
float _hcalTimeResolution
Definition: ILDCaloDigi.h:197
float _event_correl_miscalib_ecal
Definition: ILDCaloDigi.h:251
float _misCalibHcal_correl
Definition: ILDCaloDigi.h:235
TH1F * fEcalRLayer1
Definition: ILDCaloDigi.h:307
virtual void fillECALGaps()
std::string _unitThresholdHcal
Definition: ILDCaloDigi.h:145
static const float m
TH1F * fHcalRLayer11
Definition: ILDCaloDigi.h:294
TH2F * fHcalLayer61
Definition: ILDCaloDigi.h:291
virtual void end()
const float pi
Definition: G2CD.cc:34
float _hcal_pixSpread
Definition: ILDCaloDigi.h:239
ScintillatorPpdDigi * _scHcalDigi
Definition: ILDCaloDigi.h:201
float _barrelPixelSizeT[MAX_LAYERS]
Definition: ILDCaloDigi.h:173
float _ehEnergy
Definition: ILDCaloDigi.h:209
int _hcal_PPD_n_pixels
Definition: ILDCaloDigi.h:230
TH1F * fHcalRLayer1
Definition: ILDCaloDigi.h:293
float _calibHcalMip
Definition: ILDCaloDigi.h:227
float _hcalModuleGapCorrectionFactor
Definition: ILDCaloDigi.h:167
ILDCaloDigi aILDCaloDigi
Definition: ILDCaloDigi.cc:40
std::vector< std::pair< int, int > > & getLayerConfig()
std::map< std::pair< int, int >, bool > _ECAL_cell_dead
Definition: ILDCaloDigi.h:258
float analogueEcalCalibCoeff(int layer)
float _endcapPixelSizeY[MAX_LAYERS]
Definition: ILDCaloDigi.h:176
float analogueHcalCalibCoeff(CHT::Layout, int layer)
static const float k
TH1F * fHcalRLayer31
Definition: ILDCaloDigi.h:296
float _misCalibEcal_correl
Definition: ILDCaloDigi.h:214
void setPixSpread(float x)
std::string _ecal_deafult_layer_config
Definition: ILDCaloDigi.h:224
int _applyHcalDigi
Definition: ILDCaloDigi.h:228
float _hcalTimeWindowMin
Definition: ILDCaloDigi.h:193
float _deadCellFractionEcal
Definition: ILDCaloDigi.h:216
int _strip_virt_cells
Definition: ILDCaloDigi.h:247
TH1F * fHcalRLayer21
Definition: ILDCaloDigi.h:295
LCFlagImpl _flag
Definition: ILDCaloDigi.h:133
float _ecalMaxDynMip
Definition: ILDCaloDigi.h:222
int _ecalCorrectTimesForPropagation
Definition: ILDCaloDigi.h:183
float _hcalEndcapTimeWindowMax
Definition: ILDCaloDigi.h:195
std::vector< float > _calibrCoeffHcalEndCap
Definition: ILDCaloDigi.h:155
TH1F * fHcalRLayer61
Definition: ILDCaloDigi.h:299
float _hcal_elec_noise
Definition: ILDCaloDigi.h:240
float _ecalDeltaTimeHitResolution
Definition: ILDCaloDigi.h:187
int _hcalGapCorrection
Definition: ILDCaloDigi.h:166
std::vector< float > _calibrCoeffEcal
Definition: ILDCaloDigi.h:153
int _digitalEcal
Definition: ILDCaloDigi.h:147
TH1F * fEcalC1
Definition: ILDCaloDigi.h:280
std::string _cellIDLayerString
Definition: ILDCaloDigi.h:270
TH2F * fHcalLayer11
Definition: ILDCaloDigi.h:286
float _event_correl_miscalib_hcal
Definition: ILDCaloDigi.h:252
float _calibEcalMip
Definition: ILDCaloDigi.h:205
float _ecalGapCorrectionFactor
Definition: ILDCaloDigi.h:162
std::map< std::pair< int, int >, float > _HCAL_cell_miscalibs
Definition: ILDCaloDigi.h:259
float _strip_abs_length
Definition: ILDCaloDigi.h:219
float _hcal_misCalibNpix
Definition: ILDCaloDigi.h:231
TH2F * fEcalLayer21
Definition: ILDCaloDigi.h:306
std::vector< int > _ecalLayers
Definition: ILDCaloDigi.h:158
float _barrelPixelSizeZ[MAX_LAYERS]
Definition: ILDCaloDigi.h:174
float _barrelStaveDir[MAX_STAVES][2]
Definition: ILDCaloDigi.h:177
std::string _cellIDModuleString
Definition: ILDCaloDigi.h:271
std::string _cellIDStaveString
Definition: ILDCaloDigi.h:272
static const float s
float _hcalMaxDynMip
Definition: ILDCaloDigi.h:241
std::string _ecalLayout
Definition: ILDCaloDigi.h:249
std::map< std::pair< int, int >, float > _ECAL_cell_miscalibs
Definition: ILDCaloDigi.h:257
TH1F * fHcalC
Definition: ILDCaloDigi.h:279
float _ecal_misCalibNpix
Definition: ILDCaloDigi.h:210
float _hcalBarrelTimeWindowMax
Definition: ILDCaloDigi.h:194
TH1F * fHcalC1
Definition: ILDCaloDigi.h:281
float _misCalibHcal_uncorrel
Definition: ILDCaloDigi.h:233
float getDigitisedEnergy(float energy)
bool _deadCellHcal_keep
Definition: ILDCaloDigi.h:238
std::string _cellIDIndexJString
Definition: ILDCaloDigi.h:274
TH1F * fHcalC2
Definition: ILDCaloDigi.h:283
TH1F * fHcalRLayer51
Definition: ILDCaloDigi.h:298
float siliconDigi(float energy)
std::vector< std::pair< int, int > > _layerTypes
Definition: ILDCaloDigi.h:246
LCCollection * combineVirtualStripCells(LCCollection *col, bool isBarrel, int orientation)
TH2F * fHcalLayer71
Definition: ILDCaloDigi.h:292
float _ecal_elec_noise
Definition: ILDCaloDigi.h:221
float _hcalDeltaTimeHitResolution
Definition: ILDCaloDigi.h:196
TH2F * fHcalLayer41
Definition: ILDCaloDigi.h:289
void checkConsistency(std::string colName, int layer)
TH2F * fHcalLayer1
Definition: ILDCaloDigi.h:285
bool _hcalSimpleTimingCut
Definition: ILDCaloDigi.h:198
const float twopi
Definition: ILDCaloDigi.cc:38
std::pair< int, int > getLayerProperties(std::string colName, int layer)
static const float e
TH1F * fEcalRLayer21
Definition: ILDCaloDigi.h:309
int _useHcalTiming
Definition: ILDCaloDigi.h:191
int _digitalHcal
Definition: ILDCaloDigi.h:149
TH2F * fHcalLayer31
Definition: ILDCaloDigi.h:288
float _ecal_pixSpread
Definition: ILDCaloDigi.h:220
std::vector< std::string > _hcalCollections
Definition: ILDCaloDigi.h:136
const int MAX_LAYERS
Definition: ILDCaloDigi.h:20
int _useEcalTiming
Definition: ILDCaloDigi.h:182
int _ecalStrip_default_nVirt
Definition: ILDCaloDigi.h:223
bool _ecalSimpleTimingCut
Definition: ILDCaloDigi.h:189
std::vector< int > _hcalLayers
Definition: ILDCaloDigi.h:159
TH1F * fEcalRLayerNorm
Definition: ILDCaloDigi.h:303
TH1F * fEcalC2
Definition: ILDCaloDigi.h:282
float digitalEcalCalibCoeff(int layer)
std::string _unitThresholdEcal
Definition: ILDCaloDigi.h:143
float _ecalEndcapTimeWindowMax
Definition: ILDCaloDigi.h:186
std::vector< std::string > _outputEcalCollections
Definition: ILDCaloDigi.h:137
std::vector< LCCollection * > LCCollectionVec
Definition: SiStripClus.h:55
std::vector< std::string > _ecalCollections
Definition: ILDCaloDigi.h:135
int _hcalCorrectTimesForPropagation
Definition: ILDCaloDigi.h:192
std::vector< float > _thresholdHcal
Definition: ILDCaloDigi.h:144
int getNumberOfVirtualCells()
float ahcalEnergyDigi(float energy, int id0, int id1)
std::vector< float > _calibrCoeffHcalBarrel
Definition: ILDCaloDigi.h:154
virtual void init()
Definition: ILDCaloDigi.cc:521
CLHEP::MTwistEngine * _randomEngineDeadCellHcal
Definition: ILDCaloDigi.h:255
float _thresholdEcal
Definition: ILDCaloDigi.h:142
TH2F * fEcalLayer1
Definition: ILDCaloDigi.h:304
float _ecalEndcapCorrectionFactor
Definition: ILDCaloDigi.h:164
virtual void processEvent(LCEvent *evt)
Definition: ILDCaloDigi.cc:747
std::vector< int > _calHitsByStaveLayerModule[MAX_STAVES][MAX_LAYERS]
Definition: ILDCaloDigi.h:170
float _ecalTimeWindowMin
Definition: ILDCaloDigi.h:184
TH1F * fEcalRLayer11
Definition: ILDCaloDigi.h:308
TH1F * fHcalRLayer41
Definition: ILDCaloDigi.h:297
TH1F * fHcal
Definition: ILDCaloDigi.h:277
TH2F * fEcalLayer11
Definition: ILDCaloDigi.h:305
int _ecal_PPD_n_pixels
Definition: ILDCaloDigi.h:208
bool _misCalibHcal_uncorrel_keep
Definition: ILDCaloDigi.h:234
float _hcalEndcapCorrectionFactor
Definition: ILDCaloDigi.h:165
void setElecNoise(float x)
float _deadCellFractionHcal
Definition: ILDCaloDigi.h:237
TH1F * fHcalRLayerNorm
Definition: ILDCaloDigi.h:301
TH1F * fEcal
Definition: ILDCaloDigi.h:276
TH2F * fHcalLayer21
Definition: ILDCaloDigi.h:287
float _ecalTimeResolution
Definition: ILDCaloDigi.h:188
bool _deadCellEcal_keep
Definition: ILDCaloDigi.h:217
int _countWarnings
Definition: ILDCaloDigi.h:248
float scintillatorDigi(float energy, bool isEcal)
const float slop
Definition: ILDCaloDigi.cc:36
float _hcal_PPD_pe_per_mip
Definition: ILDCaloDigi.h:229
std::vector< float > _calibrCoeffHcalOther
Definition: ILDCaloDigi.h:156
float _ecal_PPD_pe_per_mip
Definition: ILDCaloDigi.h:207
virtual void processRunHeader(LCRunHeader *run)
Definition: ILDCaloDigi.cc:740
int _mapsEcalCorrection
Definition: ILDCaloDigi.h:148
float _zOfEcalEndcap
Definition: ILDCaloDigi.h:172
std::vector< CalorimeterHitImpl * > _calHitsByStaveLayer[MAX_STAVES][MAX_LAYERS]
Definition: ILDCaloDigi.h:169
CLHEP::MTwistEngine * _randomEngineDeadCellEcal
Definition: ILDCaloDigi.h:254
void setRandomMisCalibNPix(float x)
std::map< std::pair< int, int >, bool > _HCAL_cell_dead
Definition: ILDCaloDigi.h:260
std::string _outputRelCollection
Definition: ILDCaloDigi.h:140
TH2F * fHcalLayer51
Definition: ILDCaloDigi.h:290
float _ecalModuleGapCorrectionFactor
Definition: ILDCaloDigi.h:163
float _endcapPixelSizeX[MAX_LAYERS]
Definition: ILDCaloDigi.h:175
TH1F * fHcalRLayer71
Definition: ILDCaloDigi.h:300
std::string _cellIDIndexIString
Definition: ILDCaloDigi.h:273
std::vector< std::string > _outputHcalCollections
Definition: ILDCaloDigi.h:138
ScintillatorPpdDigi * _scEcalDigi
Definition: ILDCaloDigi.h:200