Belle II Software development
eclPackerModule.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/eclPacker/eclPackerModule.h>
10
11//STL
12#include <ios>
13#include <iomanip>
14
15//Framework
16#include <framework/logging/Logger.h>
17
18//ECL
19#include <ecl/dataobjects/ECLDigit.h>
20#include <ecl/dataobjects/ECLDsp.h>
21
22//Raw data
23#include <rawdata/dataobjects/RawECL.h>
24
25using namespace std;
26using namespace Belle2;
27using namespace ECL;
28
29REG_MODULE(ECLPacker);
30
31ECLPackerModule::ECLPackerModule() :
32 m_bufPos(0),
33 m_bufLength(0),
34 m_bitPos(0),
35 m_EclWaveformSamples(),
36 m_eclMapper(),
37 m_eclRawCOPPERs("", DataStore::c_Event),
38 adcBuffer_temp(),
39 collectorMaskArray(),
40 shaperMaskArray(),
41 shaperADCMaskArray(),
42 shaperNWaveform(),
43 shaperNHits(),
44 iEclDigIndices(),
45 iEclWfIndices()
46{
47 setDescription("The module reads ECLDigits from the DataStore and writes ECLRaw data.");
48 addParam("InitFileName", m_eclMapperInitFileName, "Initialization file", string("/ecl/data/ecl_channels_map.txt"));
49 addParam("RawCOPPERsName", m_eclRawCOPPERsName, "Name of the RawECL container", string("RawECLs"));
50 addParam("CompressMode", m_compressMode, "compress mode for ADC samples", true);
51 addParam("AmpThreshold", m_ampThreshold, "Amplitude threshold", -50);
52 addParam("PackWfRareFactor", m_WaveformRareFactor, "Pack ADC samples for one of N events. No waveform is packed if 0", 100);
53 addParam("Pcie40Data", m_pcie40Data,
54 "If true: pack data as if sent from PCIe40 boards. Otherwise: pack data as if sent from COPPERs", false);
55}
56
57ECLPackerModule::~ECLPackerModule()
58{
59}
60
62{
63 // require input data
64 m_eclDigits.isRequired();
65 m_eclDsps.isOptional();
66
67 // register output container in data store
68 m_eclRawCOPPERs.registerInDataStore(m_eclRawCOPPERsName);
69
70 B2INFO("ECL Packer: Compress mode = " << m_compressMode);
71}
72
74{
75 // Initialize channel mapper at run start to account for possible
76 // changes in ECL mapping between runs.
77 if (!m_eclMapper.initFromDB()) {
78 B2FATAL("ECL Packer: Can't initialize eclChannelMapper!");
79 }
80
81 //TODO
82}
83
85{
86 if (m_eventMetaData.isValid()) {
87 m_EvtNum = m_eventMetaData->getEvent();
88 } else {
89 m_EvtNum = -1;
90 }
91
92 B2DEBUG(50, "EclPacker:: event called ");
93 // output data
94 m_eclRawCOPPERs.clear();
95
96 B2DEBUG(50, "EclPacker:: output data arrays created");
97
98 int nActiveChannelsWithADCData, nActiveDSPChannels;
99 int triggerPhase = 0, dspMask = 0;
100
101 // get total number of hits
102 int nEclDigits = m_eclDigits.getEntries();
103 int nEclWaveform = m_eclDsps.getEntries();
104
105 for (int i = 0; i < ECL_CRATES; i++) {
106 collectorMaskArray[i] = 0;
107 for (int j = 0; j < ECL_BARREL_SHAPERS_IN_CRATE; j++) {
108 shaperMaskArray[i][j] = 0;
109 shaperNHits[i][j] = 0;
110 shaperADCMaskArray[i][j] = 0;
111 shaperNWaveform[i][j] = 0;
112 }
113 }
114
115 for (int j = 0; j < ECL_TOTAL_CHANNELS; j++) {
116 iEclDigIndices[j] = -1;
117 iEclWfIndices[j] = -1;
118 }
119
120 B2DEBUG(100, "EclPacker:: N_Digits = " << nEclDigits);
121 B2DEBUG(100, "EclPacker:: N_Waveforms = " << nEclWaveform);
122
123 int iCOPPER, iFINESSE, iCrate, iShaper, iChannel, nShapers;
124
125 B2DEBUG(100, "EclPacker:: Hits ======>> ");
126 int tot_dsp_hits = 0;
127 // fill number of hits, masks and fill correspondence between cellID and index in container
128 for (int i_digit = 0; i_digit < nEclDigits; i_digit++) {
129 int cid = m_eclDigits[i_digit]->getCellId();
130 int amp = m_eclDigits[i_digit]->getAmp();
131
132 if (amp < m_ampThreshold) continue;
133
134 //TODO: Threshold
135 iCrate = m_eclMapper.getCrateID(cid);
136 iShaper = m_eclMapper.getShaperPosition(cid);
137 iChannel = m_eclMapper.getShaperChannel(cid);
138
139 if (iCrate < 1 && iShaper < 1 && iChannel < 1) {
140 B2ERROR("Wrong crate/shaper/channel ids: " << iCrate << " " << iShaper << " " << iChannel << " for CID " << cid);
141 throw eclPacker_internal_error();
142 }
143 collectorMaskArray[iCrate - 1] |= (1 << (iShaper - 1));
144
145 shaperMaskArray[iCrate - 1][iShaper - 1] |= (1 << (iChannel - 1));
146 shaperNHits[iCrate - 1][iShaper - 1]++;
147
148 iEclDigIndices[cid - 1] = i_digit;
149 tot_dsp_hits++;
150 }
151
152 B2DEBUG(100, "ECL Packer:: N Hits above threshold = " << tot_dsp_hits << " nWaveforms = " << nEclWaveform);
153
154 if (m_WaveformRareFactor != 0)
155 if (m_EvtNum % m_WaveformRareFactor == 0) {
156 B2DEBUG(100, "ECL Packer:: Pack waveform data for this event: " << m_EvtNum);
157 for (int i_wf = 0; i_wf < nEclWaveform; i_wf++) {
158 int cid = m_eclDsps[i_wf]->getCellId();
159 iCrate = m_eclMapper.getCrateID(cid);
160 iShaper = m_eclMapper.getShaperPosition(cid);
161 iChannel = m_eclMapper.getShaperChannel(cid);
162
163 //check corresponding amplitude in ecl digits
164 int amp = 0;
165 for (int i_digit = 0; i_digit < nEclDigits; i_digit++) {
166 if (m_eclDigits[i_digit]->getCellId() == cid) {
167 amp = m_eclDigits[i_digit]->getAmp();
168 break;
169 }
170 }
171 if (amp < m_ampThreshold) continue;
172
173 shaperADCMaskArray[iCrate - 1][iShaper - 1] |= (1 << (iChannel - 1));
174 shaperNWaveform[iCrate - 1][iShaper - 1]++;
175
176 iEclWfIndices[cid - 1] = i_wf;
177 }
178 }
179
180 // fill rawCOPPERPacker data
181 RawCOPPERPackerInfo rawcprpacker_info;
182 rawcprpacker_info.exp_num = 0;
183 rawcprpacker_info.run_subrun_num = 1; // run number : 14bits, subrun # : 8bits
184 rawcprpacker_info.eve_num = m_EvtNum;
185 rawcprpacker_info.tt_ctime = 0x7123456; //??? (copy-past from CDC)
186 rawcprpacker_info.tt_utime = 0xF1234567; //???
187 rawcprpacker_info.b2l_ctime = 0x7654321; //???
188
189
190 B2DEBUG(100, "EclPacker:: proceed COPPERs... ");
191 B2DEBUG(100, "EclPacker:: ECL_COPPERS = " << ECL_COPPERS);
192
193 //Set the number of nodes
194 int max_nodes;
195 if (m_pcie40Data) {
196 max_nodes = 3;
197 } else {
198 max_nodes = ECL_COPPERS;
199 }
200 const static int max_channels = MAX_PCIE40_CH;
201
202 //cycle over all coppers
203 for (iCOPPER = 1; iCOPPER <= max_nodes; iCOPPER++) {
204 std::vector <unsigned int> buff[max_channels];
205 int channels_count;
206 if (m_pcie40Data) {
207 channels_count = iCOPPER < 3 ? 18 : 16;
208 } else {
209 channels_count = 2;
210 }
211
212 for (int i = 0; i < max_channels; i++) buff[i].clear();
213
214 int iCOPPERNode;
215 if (m_pcie40Data) {
216 iCOPPERNode = BECL_ID + iCOPPER;
217 } else {
218 iCOPPERNode = (iCOPPER <= ECL_BARREL_COPPERS) ? BECL_ID + iCOPPER : EECL_ID + iCOPPER - ECL_BARREL_COPPERS;
219 }
220
221 bool skipNode = true;
222
223 //check if at least one of FINESSES have hits
224 for (int i = 0; i < channels_count; i++) {
225 int icr = m_eclMapper.getCrateID(iCOPPERNode, i, m_pcie40Data);
226 B2DEBUG(200, "iCOPPERNode = 0x" << std::hex << iCOPPERNode << std::dec << " nCrate = " << icr);
227 if (!collectorMaskArray[icr - 1]) continue;
228 skipNode = false;
229 break;
230 }
231
232 if (skipNode) continue;
233
234 rawcprpacker_info.node_id = iCOPPERNode;
235
236 // Create RawECL object
237
238 int nwords[max_channels] = {0, 0};
239 const int finesseHeaderNWords = 3;
240
241 //cycle over finesses in copper
242 for (iFINESSE = 0; iFINESSE < channels_count; iFINESSE++) {
243 iCrate = m_eclMapper.getCrateID(iCOPPERNode, iFINESSE, m_pcie40Data);
244
245 nShapers = m_eclMapper.getNShapersInCrate(iCrate);
246 if (!nShapers) B2ERROR("Ecl packer:: Wrong shapers number " << nShapers);
247
248 B2DEBUG(200, "Pack data for iCrate = " << iCrate << " nShapers = " << nShapers);
249
250 // write EclCollector header to the buffer
251 unsigned int eclCollectorHeader = (1 << nShapers) - 1;
252 if (m_compressMode) eclCollectorHeader += (1 << 12);
253 buff[iFINESSE].push_back(eclCollectorHeader);
254
255 for (iShaper = 1; iShaper <= nShapers; iShaper++) {
256
257 nActiveDSPChannels = shaperNHits[iCrate - 1][iShaper - 1];
258 B2DEBUG(200, "iCrate = " << iCrate << " iShaper = " << iShaper << " nActiveDSPChannels = " << nActiveDSPChannels);
259 nActiveChannelsWithADCData = shaperNWaveform[iCrate - 1][iShaper - 1];
260 B2DEBUG(200, "nActiveChannelsWithADCData = " << nActiveChannelsWithADCData);
261
262 // write 4 words of shaper header
263
264 unsigned int shaperDataLength = 4 + nActiveDSPChannels + nActiveChannelsWithADCData * ECL_ADC_SAMPLES_PER_CHANNEL;
265 // fill shaperDsp header
266 unsigned int shaper_header_w0 = (0x10 << 16) + (shaperDataLength & 0xFFFF);
267 buff[iFINESSE].push_back(shaper_header_w0);
268
269 triggerPhase = 0; //?????
270 unsigned int shaper_header_w1 = (nActiveChannelsWithADCData & 0x1F) << 24;
271 shaper_header_w1 |= (ECL_ADC_SAMPLES_PER_CHANNEL & 0x7F) << 16;
272 shaper_header_w1 |= (nActiveDSPChannels & 0x1F) << 8;
273 shaper_header_w1 |= triggerPhase;
274 buff[iFINESSE].push_back(shaper_header_w1);
275
276 dspMask = shaperMaskArray[iCrate - 1][iShaper - 1];
277 B2DEBUG(200, "dspMask = " << std::hex << dspMask);
278 unsigned int shaper_header_w2 = (dspMask & 0xFFFF) << 16;
279 shaper_header_w2 |= (m_EvtNum & 0xFFFF); // trigger tag
280 buff[iFINESSE].push_back(shaper_header_w2);
281
282 unsigned int adcMask = shaperADCMaskArray[iCrate - 1][iShaper - 1];
283 B2DEBUG(100, "adcMask = " << std::hex << adcMask);
284 unsigned int shaper_header_w3 = (adcMask & 0xFFFF);
285 buff[iFINESSE].push_back(shaper_header_w3);
286
287 // cycle over shaper channels and push DSP data to buffer
288 for (iChannel = 1; iChannel <= ECL_CHANNELS_IN_SHAPER; iChannel++) {
289
290 const int cid = m_eclMapper.getCellId(iCrate, iShaper, iChannel);
291
292 if (cid < 1) continue;
293
294 const int i_digit = iEclDigIndices[cid - 1];
295 if (i_digit < 0) continue;
296 const int qua = m_eclDigits[i_digit]->getQuality();
297 const int amp = m_eclDigits[i_digit]->getAmp();
298 const int chi = m_eclDigits[i_digit]->getChi();
299 int tim = 0;
300 if (qua == 2) {
301 // pack chisquare
302
303 int chi_mantissa = 0, chi_exponent = 0;
304 int n_bits = ceil(log2(double(chi)));
305 if (n_bits > 9) {
306 chi_exponent = ceil(float(n_bits - 9) / 2.0);
307 chi_mantissa = chi >> chi_exponent * 2;
308 } else {
309 chi_exponent = 0;
310 chi_mantissa = chi;
311 }
312 tim = (chi_exponent << 9) | chi_mantissa;
313 } else {
314 // pack time
315 tim = m_eclDigits[i_digit]->getTimeFit();
316 }
317 unsigned int hit_data = ((unsigned int)(qua & 3) << 30) & 0xC0000000;
318 hit_data |= (tim & 0xFFF) << 18;
319 hit_data |= ((amp + 128) & 0x3FFFF);
320 buff[iFINESSE].push_back(hit_data);
321
322 B2DEBUG(100, "cid = " << cid << " amp = " << amp << " tim = " << tim);
323 }
324
325 for (int i = 0; i < ECL_CHANNELS_IN_SHAPER; i++) adcBuffer_temp[i] = 0;
327 setBuffLength(static_cast<int>(ECL_ADC_SAMPLES_PER_CHANNEL) * static_cast<int>(ECL_CHANNELS_IN_SHAPER));
328 for (iChannel = 1; iChannel <= ECL_CHANNELS_IN_SHAPER; iChannel++) {
329 int cid = m_eclMapper.getCellId(iCrate, iShaper, iChannel);
330 if (cid < 1) continue;
331 int i_wf = iEclWfIndices[cid - 1];
332 if (i_wf < 0) continue;
333 B2DEBUG(200, "i_wf = " << i_wf);
334 m_eclDsps[i_wf]->getDspA(m_EclWaveformSamples); // Check this method in implementation of ECLDsp.h!!!
335
336 if (m_compressMode) {
337 unsigned int adc_data_base = 0;
338 unsigned int adc_data_diff_width = 0;
339
340 // calculate adc_data_base and adc_data_diff_width for compressed mode
341 unsigned int ampMin = m_EclWaveformSamples[0];
342 unsigned int ampMax = m_EclWaveformSamples[0];
343
344 for (unsigned int iSample = 0; iSample < ECL_ADC_SAMPLES_PER_CHANNEL; iSample++) {
345 if ((unsigned int) m_EclWaveformSamples[iSample] > ampMax) ampMax = m_EclWaveformSamples[iSample];
346 if ((unsigned int) m_EclWaveformSamples[iSample] < ampMin) ampMin = m_EclWaveformSamples[iSample];
347 }
348
349 B2DEBUG(250, "ampMin = " << ampMin << " ampMax = " << ampMax);
350
351 adc_data_base = ampMin & 0x3FFFF;
352 writeNBits(adcBuffer_temp, adc_data_base, 18);
353 adc_data_diff_width = (unsigned int)(log2((float)ampMax - (float)ampMin)) + 1;
354 adc_data_diff_width &= 0x1F;
355 writeNBits(adcBuffer_temp, adc_data_diff_width, 5);
356
357 B2DEBUG(250, "Width = " << adc_data_diff_width << " Base = " << adc_data_base);
358
359 for (unsigned int iSample = 0; iSample < ECL_ADC_SAMPLES_PER_CHANNEL; iSample++) {
360 unsigned int adc_data_offset = m_EclWaveformSamples[iSample] - adc_data_base;
361 B2DEBUG(250, "offset = " << adc_data_offset);
362 writeNBits(adcBuffer_temp, adc_data_offset, adc_data_diff_width);
363 }
364 } else {
365 for (unsigned int iSample = 0; iSample < ECL_ADC_SAMPLES_PER_CHANNEL; iSample++) {
366 buff[iFINESSE].push_back(m_EclWaveformSamples[iSample]);
367 }
368
369 }
370
371 }
372 if (m_compressMode) {
373 if (m_bitPos > 0) m_bufPos++;
374 for (int i = 0; i < m_bufPos; i++) {
375 buff[iFINESSE].push_back(adcBuffer_temp[i]);
376
377 B2DEBUG(500, "Buff word " << std::hex << adcBuffer_temp[i]);
378 }
379 }
380 }
381 }
382
383 RawECL* newRawECL = m_eclRawCOPPERs.appendNew();
384
385 for (int i = 0; i < channels_count; i++) {
386 nwords[i] = buff[i].size();
387
388 buff[i][0] |= (nwords[i] - finesseHeaderNWords) * 4;
389 }
390
391 B2DEBUG(100, "**** iEvt = " << m_EvtNum << " node= " << iCOPPERNode);
392 for (int i = 0; i < channels_count; i++)
393 for (unsigned int j = 0; j < buff[i].size(); j++) {
394 B2DEBUG(210, ">> " << std::hex << setfill('0') << setw(8) << buff[i][j]);
395 }
396
397 B2DEBUG(100, "Call PackDetectorBuf");
398 if (m_pcie40Data) {
399 int* pcie40_words[MAX_PCIE40_CH];
400 int pcie40_nwords[MAX_PCIE40_CH] = {};
401
402 for (int i = 0; i < channels_count; i++) {
403 pcie40_nwords[i] = nwords[i];
404 pcie40_words[i] = new int[ nwords[i] ];
405 for (int j = 0; j < nwords[i]; j++) {
406 pcie40_words[i][j] = buff[i][j];
407 }
408 }
409
410 newRawECL->PackDetectorBuf(pcie40_words, pcie40_nwords, rawcprpacker_info);
411 } else { // COPPER data
412 newRawECL->PackDetectorBuf((int*)buff[0].data(), nwords[0], (int*)buff[1].data(), nwords[1],
413 nullptr, 0, nullptr, 0, rawcprpacker_info);
414 }
415 }
416}
417
419{
420 //TODO
421}
422
424{
425}
426
428{
429 m_bufLength = bufLength;
430}
431
433{
434 m_bufPos = 0;
435 m_bitPos = 0;
436}
437
438void ECLPackerModule::writeNBits(unsigned int* buff, unsigned int value, unsigned int bitsToWrite)
439{
440 if (!bitsToWrite) return;
441
442 if (bitsToWrite > sizeof(value) * 8) {
443 B2ERROR("Error compressing ADC samples: tying to write too long word");
444 throw Write_adc_samples_error();
445 }
446
447 if (m_bitPos + bitsToWrite > 32) {
448 if (m_bufPos == m_bufLength) {
449 B2ERROR("Error compressing ADC samples: unexpectedly reach end of buffer");
450 throw Write_adc_samples_error();
451 } else {
452 unsigned tmpval = (1 << m_bitPos) - 1;
453 buff[m_bufPos] &= tmpval;
454 buff[m_bufPos] += value << m_bitPos;
455 m_bufPos++;
456 buff[m_bufPos] = value >> (32 - m_bitPos);
457 m_bitPos += bitsToWrite;
458 m_bitPos -= 32;
459 }
460 } else {
461 unsigned tmpval = (1 << m_bitPos) - 1;
462 buff[m_bufPos] &= tmpval;
463 buff[m_bufPos] += value << m_bitPos;
464 m_bitPos += bitsToWrite;
465 if (m_bitPos == 32) {
466 m_bufPos++;
467 m_bitPos -= 32;
468 }
469 }
470
471}
In the store you can park objects that have to be accessed by various modules.
Definition: DataStore.h:51
StoreArray< ECLDsp > m_eclDsps
ECLDSP dataStore object.
int m_ampThreshold
DSP amplitude threshold.
int iEclDigIndices[ECL::ECL_TOTAL_CHANNELS]
indexes of related eclDigits
int shaperNHits[ECL::ECL_CRATES][ECL::ECL_BARREL_SHAPERS_IN_CRATE]
Number of hits per shaper.
int shaperMaskArray[ECL::ECL_CRATES][ECL::ECL_BARREL_SHAPERS_IN_CRATE]
triggered shapers
int m_EvtNum
Event number.
ECL::ECLChannelMapper m_eclMapper
channel mapper
int iEclWfIndices[ECL::ECL_TOTAL_CHANNELS]
indexes of related waveforms
int shaperADCMaskArray[ECL::ECL_CRATES][ECL::ECL_BARREL_SHAPERS_IN_CRATE]
shapers with ADC data
virtual void initialize() override
initialize
int m_bufPos
position in the data array
int m_EclWaveformSamples[ECL_ADC_SAMPLES_PER_CHANNEL]
array of ADC samples
virtual void event() override
event
int shaperNWaveform[ECL::ECL_CRATES][ECL::ECL_BARREL_SHAPERS_IN_CRATE]
Number of waveforms per shaper.
int m_WaveformRareFactor
the rate of writing of the ADC samples
virtual void endRun() override
endRun
int m_bitPos
bit position for bit-by-bit data read
virtual void terminate() override
terminate
StoreArray< ECLDigit > m_eclDigits
ECLDigit dataStore object.
StoreObjPtr< EventMetaData > m_eventMetaData
store objptr for EventMetaData
bool m_pcie40Data
true-pack data in PCIe40 format, false-pack data in COPPER format
void setBuffLength(int bufLength)
set buffer length
virtual void beginRun() override
beginRun
StoreArray< RawECL > m_eclRawCOPPERs
Output data
unsigned int adcBuffer_temp[static_cast< int >(ECL::ECL_CHANNELS_IN_SHAPER) *static_cast< int >(ECL_ADC_SAMPLES_PER_CHANNEL)]
temporary buffer to store ADC data
bool m_compressMode
enable/disable compression of waveform data
int m_bufLength
length data
int collectorMaskArray[ECL::ECL_CRATES]
array of triggered collectors
void writeNBits(unsigned int *buff, unsigned int value, unsigned int bitsToWrite)
write N bits to the collector buffer
void resetBuffPosition()
reset current position in the buffer
std::string m_eclRawCOPPERsName
name of output collection for RawCOPPER
bool initFromDB()
Initialize channel mapper from the conditions database.
int getNShapersInCrate(int iCrate)
Get number of ShaperDSP modules in the given VME crate number.
int getCellId(int iCrate, int iShaper, int iChannel)
Get CellId by given crate number, shaper position in the crate and DSP channel number in the shaper.
int getShaperChannel(int cellID)
Get number of DSP channel in the shaper by given number of CellId.
int getShaperPosition(int cellID)
Get position of the shaper in the crate by given CellId.
int getCrateID(int iCOPPERNode, int iFINESSE, bool pcie40=false)
Get crate number by given COPPER node number and FINESSE number.
struct to contain header information used by RawCOPPERFormat::Packer()
unsigned int b2l_ctime
32bit unitx time at trigger timing distributed by FTSW. For details, see Nakao-san's belle2link user ...
unsigned int eve_num
Run # and subrun # ( 22bit )
unsigned int tt_ctime
Node ID (32bit)
unsigned int tt_utime
27bit clock ticks at trigger timing distributed by FTSW. For details, see Nakao-san's belle2link user...
unsigned int node_id
Event Number (32bit)
unsigned int run_subrun_num
Experiment number (10bit)
unsigned int exp_num
Experiment number (10bit)
void PackDetectorBuf(int *detector_buf_1st, int nwords_1st, int *detector_buf_2nd, int nwords_2nd, int *detector_buf_3rd, int nwords_3rd, int *detector_buf_4th, int nwords_4th, RawCOPPERPackerInfo rawcprpacker_info)
Packer for RawCOPPER class Pack data (format ver.
Definition: RawCOPPER.cc:183
The Raw ECL class Class for RawCOPPER class data taken by ECL Currently, this class is almost same as...
Definition: RawECL.h:26
#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.