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 correspondance 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 if (!shaperMaskArray[iCrate - 1]) continue;
249 B2DEBUG(200, "Pack data for iCrate = " << iCrate << " nShapers = " << nShapers);
250
251 // write EclCollector header to the buffer
252 unsigned int eclCollectorHeader = (1 << nShapers) - 1;
253 if (m_compressMode) eclCollectorHeader += (1 << 12);
254 buff[iFINESSE].push_back(eclCollectorHeader);
255
256 for (iShaper = 1; iShaper <= nShapers; iShaper++) {
257
258 nActiveDSPChannels = shaperNHits[iCrate - 1][iShaper - 1];
259 B2DEBUG(200, "iCrate = " << iCrate << " iShaper = " << iShaper << " nActiveDSPChannels = " << nActiveDSPChannels);
260 nActiveChannelsWithADCData = shaperNWaveform[iCrate - 1][iShaper - 1];
261 B2DEBUG(200, "nActiveChannelsWithADCData = " << nActiveChannelsWithADCData);
262
263 // write 4 words of shaper header
264
265 unsigned int shaperDataLength = 4 + nActiveDSPChannels + nActiveChannelsWithADCData * ECL_ADC_SAMPLES_PER_CHANNEL;
266 // fill shaperDsp header
267 unsigned int shaper_header_w0 = (0x10 << 16) + (shaperDataLength & 0xFFFF);
268 buff[iFINESSE].push_back(shaper_header_w0);
269
270 triggerPhase = 0; //?????
271 unsigned int shaper_header_w1 = (nActiveChannelsWithADCData & 0x1F) << 24;
272 shaper_header_w1 |= (ECL_ADC_SAMPLES_PER_CHANNEL & 0x7F) << 16;
273 shaper_header_w1 |= (nActiveDSPChannels & 0x1F) << 8;
274 shaper_header_w1 |= triggerPhase;
275 buff[iFINESSE].push_back(shaper_header_w1);
276
277 dspMask = shaperMaskArray[iCrate - 1][iShaper - 1];
278 B2DEBUG(200, "dspMask = " << std::hex << dspMask);
279 unsigned int shaper_header_w2 = (dspMask & 0xFFFF) << 16;
280 shaper_header_w2 |= (m_EvtNum & 0xFFFF); // trigger tag
281 buff[iFINESSE].push_back(shaper_header_w2);
282
283 unsigned int adcMask = shaperADCMaskArray[iCrate - 1][iShaper - 1];
284 B2DEBUG(100, "adcMask = " << std::hex << adcMask);
285 unsigned int shaper_header_w3 = (adcMask & 0xFFFF);
286 buff[iFINESSE].push_back(shaper_header_w3);
287
288 // cycle over shaper channels and push DSP data to buffer
289 for (iChannel = 1; iChannel <= ECL_CHANNELS_IN_SHAPER; iChannel++) {
290
291 const int cid = m_eclMapper.getCellId(iCrate, iShaper, iChannel);
292
293 if (cid < 1) continue;
294
295 const int i_digit = iEclDigIndices[cid - 1];
296 if (i_digit < 0) continue;
297 const int qua = m_eclDigits[i_digit]->getQuality();
298 const int amp = m_eclDigits[i_digit]->getAmp();
299 const int chi = m_eclDigits[i_digit]->getChi();
300 int tim = 0;
301 if (qua == 2) {
302 // pack chisquare
303
304 int chi_mantissa = 0, chi_exponent = 0;
305 int n_bits = ceil(log2(double(chi)));
306 if (n_bits > 9) {
307 chi_exponent = ceil(float(n_bits - 9) / 2.0);
308 chi_mantissa = chi >> chi_exponent * 2;
309 } else {
310 chi_exponent = 0;
311 chi_mantissa = chi;
312 }
313 tim = (chi_exponent << 9) | chi_mantissa;
314 } else {
315 // pack time
316 tim = m_eclDigits[i_digit]->getTimeFit();
317 }
318 unsigned int hit_data = ((unsigned int)(qua & 3) << 30) & 0xC0000000;
319 hit_data |= (tim & 0xFFF) << 18;
320 hit_data |= ((amp + 128) & 0x3FFFF);
321 buff[iFINESSE].push_back(hit_data);
322
323 B2DEBUG(100, "cid = " << cid << " amp = " << amp << " tim = " << tim);
324 }
325
326 for (int i = 0; i < ECL_CHANNELS_IN_SHAPER; i++) adcBuffer_temp[i] = 0;
328 setBuffLength(static_cast<int>(ECL_ADC_SAMPLES_PER_CHANNEL) * static_cast<int>(ECL_CHANNELS_IN_SHAPER));
329 for (iChannel = 1; iChannel <= ECL_CHANNELS_IN_SHAPER; iChannel++) {
330 int cid = m_eclMapper.getCellId(iCrate, iShaper, iChannel);
331 if (cid < 1) continue;
332 int i_wf = iEclWfIndices[cid - 1];
333 if (i_wf < 0) continue;
334 B2DEBUG(200, "i_wf = " << i_wf);
335 m_eclDsps[i_wf]->getDspA(m_EclWaveformSamples); // Check this method in implementation of ECLDsp.h!!!
336
337 if (m_compressMode) {
338 unsigned int adc_data_base = 0;
339 unsigned int adc_data_diff_width = 0;
340
341 // calculate adc_data_base and adc_data_diff_width for compressed mode
342 unsigned int ampMin = m_EclWaveformSamples[0];
343 unsigned int ampMax = m_EclWaveformSamples[0];
344
345 for (unsigned int iSample = 0; iSample < ECL_ADC_SAMPLES_PER_CHANNEL; iSample++) {
346 if ((unsigned int) m_EclWaveformSamples[iSample] > ampMax) ampMax = m_EclWaveformSamples[iSample];
347 if ((unsigned int) m_EclWaveformSamples[iSample] < ampMin) ampMin = m_EclWaveformSamples[iSample];
348 }
349
350 B2DEBUG(250, "ampMin = " << ampMin << " ampMax = " << ampMax);
351
352 adc_data_base = ampMin & 0x3FFFF;
353 writeNBits(adcBuffer_temp, adc_data_base, 18);
354 adc_data_diff_width = (unsigned int)(log2((float)ampMax - (float)ampMin)) + 1;
355 adc_data_diff_width &= 0x1F;
356 writeNBits(adcBuffer_temp, adc_data_diff_width, 5);
357
358 B2DEBUG(250, "Width = " << adc_data_diff_width << " Base = " << adc_data_base);
359
360 for (unsigned int iSample = 0; iSample < ECL_ADC_SAMPLES_PER_CHANNEL; iSample++) {
361 unsigned int adc_data_offset = m_EclWaveformSamples[iSample] - adc_data_base;
362 B2DEBUG(250, "offset = " << adc_data_offset);
363 writeNBits(adcBuffer_temp, adc_data_offset, adc_data_diff_width);
364 }
365 } else {
366 for (unsigned int iSample = 0; iSample < ECL_ADC_SAMPLES_PER_CHANNEL; iSample++) {
367 buff[iFINESSE].push_back(m_EclWaveformSamples[iSample]);
368 }
369
370 }
371
372 }
373 if (m_compressMode) {
374 if (m_bitPos > 0) m_bufPos++;
375 for (int i = 0; i < m_bufPos; i++) {
376 buff[iFINESSE].push_back(adcBuffer_temp[i]);
377
378 B2DEBUG(500, "Buff word " << std::hex << adcBuffer_temp[i]);
379 }
380 }
381 }
382 }
383
384 RawECL* newRawECL = m_eclRawCOPPERs.appendNew();
385
386 for (int i = 0; i < channels_count; i++) {
387 nwords[i] = buff[i].size();
388
389 buff[i][0] |= (nwords[i] - finesseHeaderNWords) * 4;
390 }
391
392 B2DEBUG(100, "**** iEvt = " << m_EvtNum << " node= " << iCOPPERNode);
393 for (int i = 0; i < channels_count; i++)
394 for (unsigned int j = 0; j < buff[i].size(); j++) {
395 B2DEBUG(210, ">> " << std::hex << setfill('0') << setw(8) << buff[i][j]);
396 }
397
398 B2DEBUG(100, "Call PackDetectorBuf");
399 if (m_pcie40Data) {
400 int* pcie40_words[MAX_PCIE40_CH];
401 int pcie40_nwords[MAX_PCIE40_CH] = {};
402
403 for (int i = 0; i < channels_count; i++) {
404 pcie40_nwords[i] = nwords[i];
405 pcie40_words[i] = new int[ nwords[i] ];
406 for (int j = 0; j < nwords[i]; j++) {
407 pcie40_words[i][j] = buff[i][j];
408 }
409 }
410
411 newRawECL->PackDetectorBuf(pcie40_words, pcie40_nwords, rawcprpacker_info);
412 } else { // COPPER data
413 newRawECL->PackDetectorBuf((int*)buff[0].data(), nwords[0], (int*)buff[1].data(), nwords[1],
414 nullptr, 0, nullptr, 0, rawcprpacker_info);
415 }
416 }
417}
418
420{
421 //TODO
422}
423
425{
426}
427
429{
430 m_bufLength = bufLength;
431}
432
434{
435 m_bufPos = 0;
436 m_bitPos = 0;
437}
438
439void ECLPackerModule::writeNBits(unsigned int* buff, unsigned int value, unsigned int bitsToWrite)
440{
441 if (!bitsToWrite) return;
442
443 if (bitsToWrite > sizeof(value) * 8) {
444 B2ERROR("Error compressing ADC samples: tying to write too long word");
445 throw Write_adc_samples_error();
446 }
447
448 if (m_bitPos + bitsToWrite > 32) {
449 if (m_bufPos == m_bufLength) {
450 B2ERROR("Error compressing ADC samples: unexpectedly reach end of buffer");
451 throw Write_adc_samples_error();
452 } else {
453 unsigned tmpval = (1 << m_bitPos) - 1;
454 buff[m_bufPos] &= tmpval;
455 buff[m_bufPos] += value << m_bitPos;
456 m_bufPos++;
457 buff[m_bufPos] = value >> (32 - m_bitPos);
458 m_bitPos += bitsToWrite;
459 m_bitPos -= 32;
460 }
461 } else {
462 unsigned tmpval = (1 << m_bitPos) - 1;
463 buff[m_bufPos] &= tmpval;
464 buff[m_bufPos] += value << m_bitPos;
465 m_bitPos += bitsToWrite;
466 if (m_bitPos == 32) {
467 m_bufPos++;
468 m_bitPos -= 32;
469 }
470 }
471
472}
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
eneble/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:650
Abstract base class for different kinds of events.
STL namespace.