Belle II Software development
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
32using namespace std;
33using namespace Belle2;
34using namespace ECL;
35
36//-----------------------------------------------------------------
37// Register the Module
38//-----------------------------------------------------------------
39REG_MODULE(ECLDigitizerPureCsI);
40
41//-----------------------------------------------------------------
42// Implementation
43//-----------------------------------------------------------------
44
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
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.
static constexpr const char * eclPureCsIInfoArrayName()
Pure CsI Info array name.
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).
static constexpr const char * eclDigitArrayName()
Pure CsI digit array name.
double m_testenedep
Fixed energy deposition in all crystals, for testing purposes.
virtual void beginRun() override
Nothing so far.
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.
bool m_calibration
Flag to use the DigitizerPureCsI for Waveform fit Covariance Matrix calibration.
static constexpr const char * eclDspArrayName()
Pure CsI DSP array name.
std::vector< ECLNoiseData > m_noise
Parameters for correlated noise stimation.
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:151
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.
STL namespace.
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,...