Belle II Software  release-08-01-10
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 
9 /* Own header. */
10 #include <ecl/modules/eclDigitizer/ECLDigitizerPureCsIModule.h>
11 
12 /* ECL headers. */
13 #include <ecl/dataobjects/ECLDigit.h>
14 #include <ecl/dataobjects/ECLDsp.h>
15 #include <ecl/dataobjects/ECLHit.h>
16 #include <ecl/dataobjects/ECLPureCsIInfo.h>
17 #include <ecl/dbobjects/ECLWaveformData.h>
18 #include <ecl/digitization/ECLDspFitterPure.h>
19 #include <ecl/geometry/ECLGeometryPar.h>
20 
21 /* Basf2 headers. */
22 #include <framework/gearbox/Unit.h>
23 #include <framework/logging/Logger.h>
24 #include <framework/utilities/FileSystem.h>
25 
26 /* ROOT headers. */
27 #include <TFile.h>
28 #include <TH1.h>
29 #include <TRandom.h>
30 #include <TTree.h>
31 
32 using namespace std;
33 using namespace Belle2;
34 using namespace ECL;
35 
36 //-----------------------------------------------------------------
37 // Register the Module
38 //-----------------------------------------------------------------
39 REG_MODULE(ECLDigitizerPureCsI);
40 
41 //-----------------------------------------------------------------
42 // Implementation
43 //-----------------------------------------------------------------
44 
45 ECLDigitizerPureCsIModule::ECLDigitizerPureCsIModule() : Module()
46 {
47  //Set module properties
48  setDescription("Creates ECLDigiHits from ECLHits for Pure CsI.");
50  addParam("FirstRing", m_thetaIdMin, "First ring (0-12)", 0);
51  addParam("LastRing", m_thetaIdMax, "Last ring (0-12)", 12);
52  addParam("Background", m_background, "Flag to use the DigitizerPureCsI configuration with backgrounds; Default is no background",
53  false);
54  addParam("Calibration", m_calibration,
55  "Flag to use the DigitizerPureCsI for Waveform fit Covariance Matrix calibration; Default is false",
56  false);
57  addParam("adcTickFactor", m_tickFactor, "multiplication factor to get adc tick from trigger tick", 8);
58  addParam("sigmaTrigger", m_sigmaTrigger, "Trigger resolution used", 0.);
59  addParam("elecNoise", m_elecNoise, "Electronics noise energy equivalent in MeV", 0.5);
60  /* photo statistics resolution measurement at LNF sigma = 55 % at 1 MeV
61  Csi(Tl) is 12%
62  */
63  addParam("photostatresolution", m_photostatresolution, "sigma for 1 MeV energy deposit", 0.22);
64  addParam("Debug", m_debug, "debug mode on (default off)", false);
65  addParam("debugtrgtime", m_testtrg, "set fixed trigger time for testing purposes", 0);
66  addParam("debugsigtimeshift", m_testsig, "shift signal arrival time for testing purposes (in microsec)", 0.);
67  addParam("debugenergydeposit", m_testenedep, "energy deposit in all crystals for testing purposes", 0.);
68  addParam("NoCovMatrix", m_NoCovMatrix, "Use a diagonal (neutral) Covariance matrix", true);
69 
70 }
71 
73 {
74 }
75 
77 {
78  m_nEvent = 0 ;
80 
81  m_ecldsps.registerInDataStore(eclDspArrayName());
82 
83  m_ecldigits.registerInDataStore(eclDigitArrayName());
84 
85  m_ecldigits.registerRelationTo(m_ecldsps);
86 
87 
88  m_eclpurecsiinfo.registerInDataStore(eclPureCsIInfoArrayName());
89  m_ecldigits.registerRelationTo(m_eclpurecsiinfo);
90 
91 
92  m_ecldigits.registerRelationTo(m_hitLists);
93  readDSPDB();
94 
96 
97  mapGeometry();
98 }
99 
101 {
102 }
103 
105 {
106  /* add trigger resolution defined in a module paramer
107  shifting the waveform starting time by a random deltaT,
108  assuming that t0=0 adc channel is determined by the trigger */
109  double deltaT = m_sigmaTrigger == 0 ? 0 : gRandom->Gaus(0, m_sigmaTrigger);
110 
111  // clear the storage for the event
112  memset(m_adc.data(), 0, m_adc.size()*sizeof(adccounts_type));
113 
114  // emulate response for ECL hits after ADC measurements
115  vector< vector< const ECLHit*> > hitmap(EclConfigurationPure::m_nch);
116 
117  for (const auto& eclHit : m_hitLists) {
118  int j = eclHit.getCellId() - 1; //0~8735
119  if (isPureCsI(j + 1)) {
120  assert(j < EclConfigurationPure::m_nch);
121  double hitE = eclHit.getEnergyDep() / Unit::GeV;
122  double hitTime = eclHit.getTimeAve() / Unit::us;
123  if (m_photostatresolution > 0) {
124  double nphotavg1MeV = 1 / (m_photostatresolution * m_photostatresolution);
125  int nphotavg = round((hitE / 0.001) * nphotavg1MeV);
126  int nphot = gRandom->Poisson(nphotavg);
127  hitE = (nphot / nphotavg1MeV) / 1000;
128 
129  // hitE = gRandom->Gaus(hitE, 0.001 * m_photostatresolution * sqrt(hitE * 1000));
130  }
131  m_adc[j].AddHit(hitE, hitTime + deltaT, m_ss[m_tbl[j].iss]);
132  if (eclHit.getBackgroundTag() == BackgroundMetaData::bg_none) hitmap[j].push_back(&eclHit);
133  }
134  }
135 
136  // loop over entire calorimeter
137 
138  for (int j = 0; j < EclConfigurationPure::m_nch; j++) {
139  if (! isPureCsI(j + 1)) continue;
140 
141  if (m_debug) {
142  m_adc[j].AddHit(m_testenedep, m_testsig, m_ss[m_tbl[j].iss]);
143  //cout << "Adding enedep = " << m_testenedep << " time: " << m_testsig << endl;
144  }
145  adccounts_type& a = m_adc[j];
146  if (! m_calibration && a.total < 0.0001) continue;
147 
148  //Noise generation
149  float adcNoise[EclConfigurationPure::m_nsmp];
150  memset(adcNoise, 0, sizeof(adcNoise));
151  if (m_elecNoise > 0) {
153  for (int i = 0; i < EclConfigurationPure::m_nsmp; i++)
154  z[i] = gRandom->Gaus(0, 1);
155  m_noise[0].generateCorrelatedNoise(z, adcNoise);
156  }
157 
159  for (int i = 0; i < EclConfigurationPure::m_nsmp; i++) {
160  FitA[i] = 20 * (1000 * a.c[i] + adcNoise[i]) + 3000;
161  }
162 
163  int energyFit = 0; // fit output : Amplitude 18 bits
164  double tFit = 0; // fit output : T_ave 12 bits
165  int qualityFit = 0; // fit output : quality 2 bits
166 
167  if (! m_calibration) {
168  double fitChi2 = 0;
169  if (m_debug) {
170  DSPFitterPure(m_fitparams[m_tbl[j].idn], FitA, m_testtrg, energyFit, tFit, fitChi2, qualityFit);
171  /*
172  cout << "energy: " << energyFit
173  << " tFit: " << tFit
174  << " qualityfit: " << qualityFit
175  << endl;
176  */
177  } else {
178  DSPFitterPure(m_fitparams[m_tbl[j].idn], FitA, 0, energyFit, tFit, fitChi2, qualityFit);
179  /*
180  cout << "energy: " << energyFit
181  << " tFit: " << tFit
182  << " qualityfit: " << qualityFit
183  << endl;
184  */
185  }
186  }
187 
188  if (m_calibration || energyFit > 0) {
189  int CellId = j + 1;
190  auto eclDsp = m_ecldsps.appendNew();
191  eclDsp->setCellId(CellId);
192  eclDsp->setDspA(FitA);
193 
194  auto eclDigit = m_ecldigits.appendNew();
195  eclDigit->setCellId(CellId); // cellId in range from 1 to 8736
196  eclDigit->setAmp(energyFit); // E (GeV) = energyFit/20000;
197  eclDigit->setTimeFit(int(tFit * 10)); // time is in 0.1 ns units
198  eclDigit->setQuality(qualityFit);
199 
200  auto AeclPureCsIInfo = m_eclpurecsiinfo.appendNew();
201  eclDigit->addRelationTo(AeclPureCsIInfo);
202  AeclPureCsIInfo->setPureCsI(1);
203  AeclPureCsIInfo->setCellId(CellId);
204 
205  eclDigit->addRelationTo(eclDsp);
206  for (const auto& hit : hitmap[j])
207  eclDigit->addRelationTo(hit);
208  }
209  } //store each crystal hit
210 
211  // temporary solution to run Pure CsI reconstruction
212  // and baseline independently and simultaneously
213  // cloning barrel and bwd digits
214 
215  for (const auto& eclDigit : m_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 
236 {
237 }
238 
240 {
241 }
242 
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 
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 
331 {
333  for (int cellId0 = 0; cellId0 < EclConfigurationPure::m_nch; cellId0++) {
334  eclgeo->Mapping(cellId0);
335  m_thetaID[cellId0] = eclgeo->GetThetaID();
336  }
337 }
StoreArray< ECLDigit > m_BaselineDigits
ECL digits (baseline, i.e.
StoreArray< ECLDigit > m_ecldigits
StoreArray ECLDigit.
bool m_NoCovMatrix
Flag to use a diagonal (neutral) Covariance matrix.
virtual void initialize() override
Initialize variables
int m_thetaIdMax
Ring ID of last pure CsI ring in FWD.
std::vector< signalsample_type > m_ss
Tabulated shape line.
virtual void event() override
Actual digitization of all pure CsI hits in the ECL.
void mapGeometry()
Returns ring ID for a certain crystal.
double m_elecNoise
Electronic Noise energy equivalente in MeV.
virtual void endRun() override
Nothing so far.
StoreArray< ECLHit > m_hitLists
StoreArray ECLHit.
virtual void terminate() override
Free memory.
bool m_background
Flag to set covariance matrix for WF with beam-bkg.
int m_testtrg
Fixed trigger time for testing purposes.
bool isPureCsI(int cellId)
Returns 1 if corresponding crystal is set as pure CsI crystal.
std::vector< adccounts_type > m_adc
Storage for adc hits from entire calorimeter (8736 crystals).
double m_testenedep
Fixed energy deposition in all crystals, for testing purposes.
virtual void beginRun() override
Nothing so far.
static constexpr const char * eclDigitArrayName()
Pure CsI digit array name.
StoreArray< ECLPureCsIInfo > m_eclpurecsiinfo
StoreArray ECLPureCsIInfo.
double m_photostatresolution
Resolution for a 1 MeV energy deposit.
std::vector< fitparams_type > m_fitparams
Fitting parameters.
std::vector< crystallinks_t > m_tbl
Lookup table for ECL channels.
int m_tickFactor
multiplication factor to get adc tick from trigger tick.
StoreArray< ECLDsp > m_ecldsps
StoreArray ECLDsp.
double m_testsig
Shift in signal arrival time, for testing purposes.
static constexpr const char * eclPureCsIInfoArrayName()
Pure CsI Info array name.
bool m_calibration
Flag to use the DigitizerPureCsI for Waveform fit Covariance Matrix calibration.
std::vector< ECLNoiseData > m_noise
Parameters for correlated noise stimation.
static constexpr const char * eclDspArrayName()
Pure CsI DSP array name.
int m_thetaID[ECL::EclConfigurationPure::m_nch]
ECL ring ID.
void readDSPDB()
read Shaper-DSP data from root file.
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.
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
void Mapping(int cid)
Mapping theta, phi Id.
int GetThetaID()
Get Theta Id.
static void setTickPure(double newval)
Setter for m_tickPure.
static constexpr int m_nch
total number of electronic channels (crystals) in fwd endcap calorimeter
static constexpr int m_nsmp
number of ADC measurements for signal fitting
static double getTick()
See m_tick.
static constexpr int m_ntrg
number of trigger counts per ADC clock tick
static std::string findFile(const std::string &path, bool silent=false)
Search for given file or directory in local or central release directory, and return absolute path if...
Definition: FileSystem.cc:148
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
static const double us
[microsecond]
Definition: Unit.h:97
static const double GeV
Standard of [energy, momentum, mass].
Definition: Unit.h:51
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#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 a single channel of the pure CsI calorimeter (in the simulation,...