Belle II Software  release-06-01-15
ECLDigitizerPureCsIModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 //This module
9 #include <ecl/modules/eclDigitizer/ECLDigitizerPureCsIModule.h>
10 
11 // ROOT
12 #include <TRandom.h>
13 #include <TFile.h>
14 #include <TTree.h>
15 #include <TH1.h>
16 
17 //Framework
18 #include <framework/gearbox/Unit.h>
19 #include <framework/logging/Logger.h>
20 #include <framework/utilities/FileSystem.h>
21 
22 //ECL
23 #include <ecl/digitization/ECLDspFitterPure.h>
24 #include <ecl/dataobjects/ECLHit.h>
25 #include <ecl/dataobjects/ECLDigit.h>
26 #include <ecl/dataobjects/ECLDsp.h>
27 #include <ecl/dataobjects/ECLPureCsIInfo.h>
28 #include <ecl/geometry/ECLGeometryPar.h>
29 #include <ecl/dbobjects/ECLWaveformData.h>
30 
31 using namespace std;
32 using namespace Belle2;
33 using namespace ECL;
34 
35 //-----------------------------------------------------------------
36 // Register the Module
37 //-----------------------------------------------------------------
38 REG_MODULE(ECLDigitizerPureCsI)
39 
40 //-----------------------------------------------------------------
41 // Implementation
42 //-----------------------------------------------------------------
43 
45 {
46  //Set module properties
47  setDescription("Creates ECLDigiHits from ECLHits for Pure CsI.");
48  setPropertyFlags(c_ParallelProcessingCertified);
49  addParam("FirstRing", m_thetaIdMin, "First ring (0-12)", 0);
50  addParam("LastRing", m_thetaIdMax, "Last ring (0-12)", 12);
51  addParam("Background", m_background, "Flag to use the DigitizerPureCsI configuration with backgrounds; Default is no background",
52  false);
53  addParam("Calibration", m_calibration,
54  "Flag to use the DigitizerPureCsI for Waveform fit Covariance Matrix calibration; Default is false",
55  false);
56  addParam("adcTickFactor", m_tickFactor, "multiplication factor to get adc tick from trigger tick", 8);
57  addParam("sigmaTrigger", m_sigmaTrigger, "Trigger resolution used", 0.);
58  addParam("elecNoise", m_elecNoise, "Electronics noise energy equivalent in MeV", 0.5);
59  /* photo statistics resolution measurement at LNF sigma = 55 % at 1 MeV
60  Csi(Tl) is 12%
61  */
62  addParam("photostatresolution", m_photostatresolution, "sigma for 1 MeV energy deposit", 0.22);
63  addParam("Debug", m_debug, "debug mode on (default off)", false);
64  addParam("debugtrgtime", m_testtrg, "set fixed trigger time for testing purposes", 0);
65  addParam("debugsigtimeshift", m_testsig, "shift signal arrival time for testing purposes (in microsec)", 0.);
66  addParam("debugenergydeposit", m_testenedep, "energy deposit in all crystals for testing purposes", 0.);
67  addParam("NoCovMatrix", m_NoCovMatrix, "Use a diagonal (neutral) Covariance matrix", true);
68 
69 }
70 
71 ECLDigitizerPureCsIModule::~ECLDigitizerPureCsIModule()
72 {
73 }
74 
75 void ECLDigitizerPureCsIModule::initialize()
76 {
77  m_nEvent = 0 ;
78  EclConfigurationPure::m_tickPure = m_tickFactor * EclConfiguration::m_tick / EclConfiguration::m_ntrg;
79 
80  m_ecldsps.registerInDataStore(eclDspArrayName());
81 
82  m_ecldigits.registerInDataStore(eclDigitArrayName());
83 
84  m_ecldigits.registerRelationTo(m_ecldsps);
85 
86 
87  m_eclpurecsiinfo.registerInDataStore(eclPureCsIInfoArrayName());
88  m_ecldigits.registerRelationTo(m_eclpurecsiinfo);
89 
90 
91  m_ecldigits.registerRelationTo(m_hitLists);
92  readDSPDB();
93 
94  m_adc.resize(EclConfigurationPure::m_nch);
95 
96  mapGeometry();
97 }
98 
99 void ECLDigitizerPureCsIModule::beginRun()
100 {
101 }
102 
103 void ECLDigitizerPureCsIModule::event()
104 {
105  /* add trigger resolution defined in a module paramer
106  shifting the waveform starting time by a random deltaT,
107  assuming that t0=0 adc channel is determined by the trigger */
108  double deltaT = m_sigmaTrigger == 0 ? 0 : gRandom->Gaus(0, m_sigmaTrigger);
109 
110  // clear the storage for the event
111  memset(m_adc.data(), 0, m_adc.size()*sizeof(adccounts_type));
112 
113  // emulate response for ECL hits after ADC measurements
114  vector< vector< const ECLHit*> > hitmap(EclConfigurationPure::m_nch);
115 
116  for (const auto& eclHit : m_hitLists) {
117  int j = eclHit.getCellId() - 1; //0~8735
118  if (isPureCsI(j + 1)) {
119  assert(j < EclConfigurationPure::m_nch);
120  double hitE = eclHit.getEnergyDep() / Unit::GeV;
121  double hitTime = eclHit.getTimeAve() / Unit::us;
122  if (m_photostatresolution > 0) {
123  double nphotavg1MeV = 1 / (m_photostatresolution * m_photostatresolution);
124  int nphotavg = round((hitE / 0.001) * nphotavg1MeV);
125  int nphot = gRandom->Poisson(nphotavg);
126  hitE = (nphot / nphotavg1MeV) / 1000;
127 
128  // hitE = gRandom->Gaus(hitE, 0.001 * m_photostatresolution * sqrt(hitE * 1000));
129  }
130  m_adc[j].AddHit(hitE , hitTime + deltaT, m_ss[m_tbl[j].iss]);
131  if (eclHit.getBackgroundTag() == BackgroundMetaData::bg_none) hitmap[j].push_back(&eclHit);
132  }
133  }
134 
135  // loop over entire calorimeter
136 
137  for (int j = 0; j < EclConfigurationPure::m_nch; j++) {
138  if (! isPureCsI(j + 1)) continue;
139 
140  if (m_debug) {
141  m_adc[j].AddHit(m_testenedep, m_testsig, m_ss[m_tbl[j].iss]);
142  //cout << "Adding enedep = " << m_testenedep << " time: " << m_testsig << endl;
143  }
144  adccounts_type& a = m_adc[j];
145  if (! m_calibration && a.total < 0.0001) continue;
146 
147  //Noise generation
148  float adcNoise[EclConfigurationPure::m_nsmp];
149  memset(adcNoise, 0, sizeof(adcNoise));
150  if (m_elecNoise > 0) {
151  float z[EclConfigurationPure::m_nsmp];
152  for (int i = 0; i < EclConfigurationPure::m_nsmp; i++)
153  z[i] = gRandom->Gaus(0, 1);
154  m_noise[0].generateCorrelatedNoise(z, adcNoise);
155  }
156 
157  int FitA[EclConfigurationPure::m_nsmp];
158  for (int i = 0; i < EclConfigurationPure::m_nsmp; i++) {
159  FitA[i] = 20 * (1000 * a.c[i] + adcNoise[i]) + 3000;
160  }
161 
162  int energyFit = 0; // fit output : Amplitude 18 bits
163  double tFit = 0; // fit output : T_ave 12 bits
164  int qualityFit = 0; // fit output : quality 2 bits
165 
166  if (! m_calibration) {
167  double fitChi2 = 0;
168  if (m_debug) {
169  DSPFitterPure(m_fitparams[m_tbl[j].idn], FitA, m_testtrg, energyFit, tFit, fitChi2, qualityFit);
170  /*
171  cout << "energy: " << energyFit
172  << " tFit: " << tFit
173  << " qualityfit: " << qualityFit
174  << endl;
175  */
176  } else {
177  DSPFitterPure(m_fitparams[m_tbl[j].idn], FitA, 0, energyFit, tFit, fitChi2, qualityFit);
178  /*
179  cout << "energy: " << energyFit
180  << " tFit: " << tFit
181  << " qualityfit: " << qualityFit
182  << endl;
183  */
184  }
185  }
186 
187  if (m_calibration || energyFit > 0) {
188  int CellId = j + 1;
189  auto eclDsp = m_ecldsps.appendNew();
190  eclDsp->setCellId(CellId);
191  eclDsp->setDspA(FitA);
192 
193  auto eclDigit = m_ecldigits.appendNew();
194  eclDigit->setCellId(CellId); // cellId in range from 1 to 8736
195  eclDigit->setAmp(energyFit); // E (GeV) = energyFit/20000;
196  eclDigit->setTimeFit(int(tFit * 10)); // time is in 0.1 ns units
197  eclDigit->setQuality(qualityFit);
198 
199  auto AeclPureCsIInfo = m_eclpurecsiinfo.appendNew();
200  eclDigit->addRelationTo(AeclPureCsIInfo);
201  AeclPureCsIInfo->setPureCsI(1);
202  AeclPureCsIInfo->setCellId(CellId);
203 
204  eclDigit->addRelationTo(eclDsp);
205  for (const auto& hit : hitmap[j])
206  eclDigit->addRelationTo(hit);
207  }
208  } //store each crystal hit
209 
210  // temporary solution to run Pure CsI reconstruction
211  // and baseline independently and simultaneously
212  // cloning barrel and bwd digits
213 
214  StoreArray<ECLDigit> baselineDigits("ECLDigits");
215  for (const auto& eclDigit : baselineDigits) {
216  int cellid = eclDigit.getCellId();
217  if (! isPureCsI(cellid)) {
218  auto eclDigitClone = m_ecldigits.appendNew();
219  eclDigitClone->setCellId(cellid);
220  eclDigitClone->setAmp(eclDigit.getAmp());
221  eclDigitClone->setTimeFit(eclDigit.getTimeFit());
222  eclDigitClone->setQuality(eclDigit.getQuality());
223  //eclDigitClone->setPureCsI(0);
224  auto AeclPureCsIInfo = m_eclpurecsiinfo.appendNew();
225  eclDigitClone->addRelationTo(AeclPureCsIInfo);
226  AeclPureCsIInfo->setPureCsI(0);
227  AeclPureCsIInfo->setCellId(cellid);
228  }
229  }
230 
231 
232  m_nEvent++;
233 }
234 
235 void ECLDigitizerPureCsIModule::endRun()
236 {
237 }
238 
239 void ECLDigitizerPureCsIModule::terminate()
240 {
241 }
242 
243 void ECLDigitizerPureCsIModule::readDSPDB()
244 {
245  string dataFileName, dataFileName2;
246  if (m_background) {
247  dataFileName = FileSystem::findFile("/data/ecl/ECL-WF-Pure.root");
248  if (! m_calibration)
249  dataFileName2 = FileSystem::findFile("/data/ecl/ECL-WF-cov-Pure-BG.root");
250  B2INFO("ECLDigitizerPureCsI: Reading configuration data with background from: " << dataFileName);
251  B2INFO("ECLDigitizerPureCsI: Reading configuration data with background from: " << dataFileName2);
252 
253  } else {
254  dataFileName = FileSystem::findFile("/data/ecl/ECL-WF-Pure.root");
255  if (! m_calibration)
256  dataFileName2 = FileSystem::findFile("/data/ecl/ECL-WF-cov-Pure.root");
257  B2INFO("ECLDigitizerPureCsI: Reading configuration data without background from: " << dataFileName);
258  B2INFO("ECLDigitizerPureCsI: Reading configuration data without background from: " << dataFileName2);
259  }
260  assert(! dataFileName.empty());
261 
262  TFile rootfile(dataFileName.c_str());
263  const TH1F* sampledWF = dynamic_cast<TH1F*>(rootfile.Get("sampleddsp"));
264  assert(sampledWF != nullptr);
265  const TH1F* sampledWF1 = dynamic_cast<TH1F*>(rootfile.Get("sampleddsp1"));
266  assert(sampledWF1 != nullptr);
267 
268  m_tbl.resize(EclConfigurationPure::m_nch);
269 
270  // at the moment there is only one sampled signal shape in the pool
271  // since all shaper parameters are the same for all crystals
272  m_ss.resize(1);
273  m_ss[0].InitSample(sampledWF, sampledWF1);
274 
275  for (int i = 0; i < EclConfigurationPure::m_nch; i++) m_tbl[i].iss = 0;
276  B2INFO("ECLDigitizerPureCsI: " << m_ss.size() << " sampled signal templates were created.");
277 
278  rootfile.Close();
279 
280  if (!(m_calibration || m_NoCovMatrix)) {
281  TFile rootfile2(dataFileName2.c_str());
282  TTree* tree = (TTree*) rootfile2.Get("EclWF");
283  ECLWaveformData* eclWFData = new ECLWaveformData;
284  const int maxncellid = 512;
285  int ncellId;
286  vector<int> cellId(maxncellid);//[ncellId] buffer for crystal identification number
287 
288  tree->SetBranchAddress("ncellId", &ncellId);
289  tree->SetBranchAddress("cellId", cellId.data());
290  tree->SetBranchAddress("CovarianceM", &eclWFData);
291  for (Long64_t j = 0, jmax = tree->GetEntries(); j < jmax; j++) {
292  tree->GetEntry(j);
293  assert(ncellId <= maxncellid);
294  for (int i = 0; i < ncellId; ++i)
295  m_tbl[cellId[i]].idn = m_fitparams.size();
296  fitparams_type params;
297  eclWFData->getMatrix(params.invC);
298  m_fitparams.push_back(params);
299  }
300  }
301  B2INFO("ECLDigitizerPureCsI: parameters vector size : " << m_fitparams.size());
302  // at the moment there is one set of fitparams
303  if (m_NoCovMatrix) {
304  m_fitparams.resize(1);
305  for (int i = 0; i < EclConfigurationPure::m_nch; i++)
306  m_tbl[i].idn = 0;
307  for (int i = 0; i < 16; i++)
308  for (int j = 0; j < 16; j++)
309  if (i != j) m_fitparams[0].invC[i][j] = 0;
310  else m_fitparams[0].invC[i][j] = 1.0;
311  initParams(m_fitparams[0], m_ss[0]);
312  } else {
313  for (auto& param : m_fitparams) {
314  initParams(param, m_ss[0]);
315  }
316  }
317 
318  // at the moment same noise for all crystals
319  m_noise.resize(1);
320  int index = 0;
321  for (int i = 0; i < EclConfigurationPure::m_nsmp; i++)
322  for (int j = 0; j <= i; j++)
323  if (i == j) m_noise[0].setMatrixElement(index++, m_elecNoise); // units are MeV energy noise eq from electronics
324  else m_noise[0].setMatrixElement(index++, 0.); //uncorrelated
325 
326  float testM[31][31];
327  m_noise[0].getMatrix(testM);
328 }
329 
330 void ECLDigitizerPureCsIModule::mapGeometry()
331 {
332  ECLGeometryPar* eclgeo = ECLGeometryPar::Instance();
333  for (int cellId0 = 0; cellId0 < EclConfigurationPure::m_nch; cellId0++) {
334  eclgeo->Mapping(cellId0);
335  m_thetaID[cellId0] = eclgeo->GetThetaID();
336  }
337 }
The ECLDigitizerPureCsI module.
ECLWaveformData - container for inverse covariant matrix and shape parameters for time and amplitude ...
void getMatrix(float M[16][16]) const
Getter method for all matrix as two dimentional array (floats)
The Class for ECL Geometry Parameters.
void Mapping(int cid)
Mapping theta, phi Id.
int GetThetaID()
Get Theta Id.
Base class for Modules.
Definition: Module.h:72
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
a struct for the fit parameters for the pure CsI calorimeter
a struct for the fit parameters for the pure CsI calorimeter