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
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 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
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.