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
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 /* add trigger resolution defined in a module parameter
103 shifting the waveform starting time by a random deltaT,
104 assuming that t0=0 adc channel is determined by the trigger */
105 double deltaT = m_sigmaTrigger == 0 ? 0 : gRandom->Gaus(0, m_sigmaTrigger);
106
107 // clear the storage for the event
108 memset(m_adc.data(), 0, m_adc.size()*sizeof(adccounts_type));
109
110 // emulate response for ECL hits after ADC measurements
111 vector< vector< const ECLHit*> > hitmap(EclConfigurationPure::m_nch);
112
113 for (const auto& eclHit : m_hitLists) {
114 int j = eclHit.getCellId() - 1; //0~8735
115 if (isPureCsI(j + 1)) {
116 assert(j < EclConfigurationPure::m_nch);
117 double hitE = eclHit.getEnergyDep() / Unit::GeV;
118 double hitTime = eclHit.getTimeAve() / Unit::us;
119 if (m_photostatresolution > 0) {
120 double nphotavg1MeV = 1 / (m_photostatresolution * m_photostatresolution);
121 int nphotavg = round((hitE / 0.001) * nphotavg1MeV);
122 int nphot = gRandom->Poisson(nphotavg);
123 hitE = (nphot / nphotavg1MeV) / 1000;
124
125 // hitE = gRandom->Gaus(hitE, 0.001 * m_photostatresolution * sqrt(hitE * 1000));
126 }
127 m_adc[j].AddHit(hitE, hitTime + deltaT, m_ss[m_tbl[j].iss]);
128 if (eclHit.getBackgroundTag() == BackgroundMetaData::bg_none) hitmap[j].push_back(&eclHit);
129 }
130 }
131
132 // loop over entire calorimeter
133
134 for (int j = 0; j < EclConfigurationPure::m_nch; j++) {
135 if (! isPureCsI(j + 1)) continue;
136
137 if (m_debug) {
138 m_adc[j].AddHit(m_testenedep, m_testsig, m_ss[m_tbl[j].iss]);
139 //cout << "Adding enedep = " << m_testenedep << " time: " << m_testsig << endl;
140 }
141 const adccounts_type& a = m_adc[j];
142 if (! m_calibration && a.total < 0.0001) continue;
143
144 //Noise generation
145 float adcNoise[EclConfigurationPure::m_nsmp];
146 memset(adcNoise, 0, sizeof(adcNoise));
147 if (m_elecNoise > 0) {
149 for (int i = 0; i < EclConfigurationPure::m_nsmp; i++)
150 z[i] = gRandom->Gaus(0, 1);
151 m_noise[0].generateCorrelatedNoise(z, adcNoise);
152 }
153
155 for (int i = 0; i < EclConfigurationPure::m_nsmp; i++) {
156 FitA[i] = 20 * (1000 * a.c[i] + adcNoise[i]) + 3000;
157 }
158
159 int energyFit = 0; // fit output : Amplitude 18 bits
160 double tFit = 0; // fit output : T_ave 12 bits
161 int qualityFit = 0; // fit output : quality 2 bits
162
163 if (! m_calibration) {
164 double fitChi2 = 0;
165 if (m_debug) {
166 DSPFitterPure(m_fitparams[m_tbl[j].idn], FitA, m_testtrg, energyFit, tFit, fitChi2, qualityFit);
167 /*
168 cout << "energy: " << energyFit
169 << " tFit: " << tFit
170 << " qualityfit: " << qualityFit
171 << endl;
172 */
173 } else {
174 DSPFitterPure(m_fitparams[m_tbl[j].idn], FitA, 0, energyFit, tFit, fitChi2, qualityFit);
175 /*
176 cout << "energy: " << energyFit
177 << " tFit: " << tFit
178 << " qualityfit: " << qualityFit
179 << endl;
180 */
181 }
182 }
183
184 if (m_calibration || energyFit > 0) {
185 int CellId = j + 1;
186 auto eclDsp = m_ecldsps.appendNew();
187 eclDsp->setCellId(CellId);
188 eclDsp->setDspA(FitA);
189
190 auto eclDigit = m_ecldigits.appendNew();
191 eclDigit->setCellId(CellId); // cellId in range from 1 to 8736
192 eclDigit->setAmp(energyFit); // E (GeV) = energyFit/20000;
193 eclDigit->setTimeFit(int(tFit * 10)); // time is in 0.1 ns units
194 eclDigit->setQuality(qualityFit);
195
196 auto AeclPureCsIInfo = m_eclpurecsiinfo.appendNew();
197 eclDigit->addRelationTo(AeclPureCsIInfo);
198 AeclPureCsIInfo->setPureCsI(1);
199 AeclPureCsIInfo->setCellId(CellId);
200
201 eclDigit->addRelationTo(eclDsp);
202 for (const auto& hit : hitmap[j])
203 eclDigit->addRelationTo(hit);
204 }
205 } //store each crystal hit
206
207 // temporary solution to run Pure CsI reconstruction
208 // and baseline independently and simultaneously
209 // cloning barrel and bwd digits
210
211 for (const auto& eclDigit : m_BaselineDigits) {
212 int cellid = eclDigit.getCellId();
213 if (! isPureCsI(cellid)) {
214 auto eclDigitClone = m_ecldigits.appendNew();
215 eclDigitClone->setCellId(cellid);
216 eclDigitClone->setAmp(eclDigit.getAmp());
217 eclDigitClone->setTimeFit(eclDigit.getTimeFit());
218 eclDigitClone->setQuality(eclDigit.getQuality());
219 //eclDigitClone->setPureCsI(0);
220 auto AeclPureCsIInfo = m_eclpurecsiinfo.appendNew();
221 eclDigitClone->addRelationTo(AeclPureCsIInfo);
222 AeclPureCsIInfo->setPureCsI(0);
223 AeclPureCsIInfo->setCellId(cellid);
224 }
225 }
226
227
228 m_nEvent++;
229}
230
232{
233 string dataFileName, dataFileName2;
234 if (m_background) {
235 dataFileName = FileSystem::findFile("/data/ecl/ECL-WF-Pure.root");
236 if (! m_calibration)
237 dataFileName2 = FileSystem::findFile("/data/ecl/ECL-WF-cov-Pure-BG.root");
238 B2INFO("ECLDigitizerPureCsI: Reading configuration data with background from: " << dataFileName);
239 B2INFO("ECLDigitizerPureCsI: Reading configuration data with background from: " << dataFileName2);
240
241 } else {
242 dataFileName = FileSystem::findFile("/data/ecl/ECL-WF-Pure.root");
243 if (! m_calibration)
244 dataFileName2 = FileSystem::findFile("/data/ecl/ECL-WF-cov-Pure.root");
245 B2INFO("ECLDigitizerPureCsI: Reading configuration data without background from: " << dataFileName);
246 B2INFO("ECLDigitizerPureCsI: Reading configuration data without background from: " << dataFileName2);
247 }
248 assert(! dataFileName.empty());
249
250 TFile rootfile(dataFileName.c_str());
251 const TH1F* sampledWF = dynamic_cast<TH1F*>(rootfile.Get("sampleddsp"));
252 assert(sampledWF != nullptr);
253 const TH1F* sampledWF1 = dynamic_cast<TH1F*>(rootfile.Get("sampleddsp1"));
254 assert(sampledWF1 != nullptr);
255
257
258 // at the moment there is only one sampled signal shape in the pool
259 // since all shaper parameters are the same for all crystals
260 m_ss.resize(1);
261 m_ss[0].InitSample(sampledWF, sampledWF1);
262
263 for (int i = 0; i < EclConfigurationPure::m_nch; i++) m_tbl[i].iss = 0;
264 B2INFO("ECLDigitizerPureCsI: " << m_ss.size() << " sampled signal templates were created.");
265
266 rootfile.Close();
267
268 if (!(m_calibration || m_NoCovMatrix)) {
269 TFile rootfile2(dataFileName2.c_str());
270 TTree* tree = static_cast<TTree*>(rootfile2.Get("EclWF"));
271 ECLWaveformData* eclWFData = new ECLWaveformData;
272 const int maxncellid = 512;
273 int ncellId;
274 vector<int> cellId(maxncellid);//[ncellId] buffer for crystal identification number
275
276 tree->SetBranchAddress("ncellId", &ncellId);
277 tree->SetBranchAddress("cellId", cellId.data());
278 tree->SetBranchAddress("CovarianceM", &eclWFData);
279 for (Long64_t j = 0, jmax = tree->GetEntries(); j < jmax; j++) {
280 tree->GetEntry(j);
281 assert(ncellId <= maxncellid);
282 for (int i = 0; i < ncellId; ++i)
283 m_tbl[cellId[i]].idn = m_fitparams.size();
284 fitparams_type params;
285 eclWFData->getMatrix(params.invC);
286 m_fitparams.push_back(params);
287 }
288 }
289 B2INFO("ECLDigitizerPureCsI: parameters vector size : " << m_fitparams.size());
290 // at the moment there is one set of fitparams
291 if (m_NoCovMatrix) {
292 m_fitparams.resize(1);
293 for (int i = 0; i < EclConfigurationPure::m_nch; i++)
294 m_tbl[i].idn = 0;
295 for (int i = 0; i < 16; i++)
296 for (int j = 0; j < 16; j++)
297 if (i != j) m_fitparams[0].invC[i][j] = 0;
298 else m_fitparams[0].invC[i][j] = 1.0;
299 initParams(m_fitparams[0], m_ss[0]);
300 } else {
301 for (auto& param : m_fitparams) {
302 initParams(param, m_ss[0]);
303 }
304 }
305
306 // at the moment same noise for all crystals
307 m_noise.resize(1);
308 int index = 0;
309 for (int i = 0; i < EclConfigurationPure::m_nsmp; i++)
310 for (int j = 0; j <= i; j++)
311 if (i == j) m_noise[0].setMatrixElement(index++, m_elecNoise); // units are MeV energy noise eq from electronics
312 else m_noise[0].setMatrixElement(index++, 0.); //uncorrelated
313
314 float testM[31][31];
315 m_noise[0].getMatrix(testM);
316}
317
319{
321 for (int cellId0 = 0; cellId0 < EclConfigurationPure::m_nch; cellId0++) {
322 eclgeo->Mapping(cellId0);
323 m_thetaID[cellId0] = eclgeo->GetThetaID();
324 }
325}
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.
ECL::EclConfigurationPure::adccountspure_t adccounts_type
Type of ADC counts.
virtual void event() override
Actual digitization of all pure CsI hits in the ECL.
ECL::EclConfigurationPure::fitparamspure_t fitparams_type
Type of fitting parameters.
void mapGeometry()
Returns ring ID for a certain crystal.
double m_elecNoise
Electronic Noise energy equivalente in MeV.
StoreArray< ECLHit > m_hitLists
StoreArray ECLHit.
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.
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 dimensional 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...
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
Module()
Constructor.
Definition Module.cc:30
@ 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:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
Abstract base class for different kinds of events.
STL namespace.