MiniballSort
Loading...
Searching...
No Matches
MbsConverter.cc
Go to the documentation of this file.
1#include "MbsConverter.hh"
2
3// Function to process header words and then the data
4void MiniballMbsConverter::ProcessBlock( unsigned long nblock ){
5
6 // Get number of 32-bit words and pointer to them
7 ndata = ev->GetNData();
8 data = ev->GetData();
9
10 // Debug events
11 //ev->Show(1);
12
13 // Suppress unused warnings
14 (void)nblock;
15
16 // Decode header
17 UInt_t pos = 3;
18 UInt_t nboards = data[pos++];
19 unsigned int trace = data[pos++];
20 unsigned int filter = data[pos++];
21
22 // Debug header
23 //std::cout << "nboards: " << nboards << std::endl;
24 //std::cout << "trace: " << trace << std::endl;
25 //std::cout << "filter: " << filter << std::endl;
26
27 for( UInt_t i = 0; i < 4; i++ ) {
28 auto pola = data[pos++];
29 (void)pola; // suppress unused warnings
30 }
31
32 // Padding - Nigel
33 //while(1) {
34 // if( (data[pos] & 0xFFFF0000) != 0xADD00000 ) break;
35 // pos++;
36 //}
37
38 // Now the channel data
39 while( pos < ndata ) ProcessFebexData( pos );
40
41 // suppress unused warnings
42 (void)nboards;
43 (void)trace;
44 (void)filter;
45
46 return;
47
48}
49
50//-----------------------------------------------------------------------------
51// Treat a channel - this should always start with a byte 0x34. If chan is 0 to
52// 15, that is a trace for the corresponding channel. If it is 255, this is the
53// special channel, where the energies from the FPGA are stored.
55
56 flag_febex_data0 = false;
57 flag_febex_trace = false;
58
59 // Check for padding - Liam
60 while( (data[pos++] & 0xFFFF0000) == 0xADD00000 ) {
61
62 // Make sure we can still read the channel ID and data header after this
63 if( pos + 2 >= ndata ) {
64 std::cerr << "No data, only padding in this event" << std::endl;
65 pos = ndata;
66 return;
67 }
68
69 }
70 pos--;
71
72 // Padding - Nik
73 //unsigned int first_word = data[pos++];
74 //if( ( first_word & 0xFFF00000 ) == 0xADD00000 ) {
75 //
76 // //std::cout << "Padding found" << std::endl;
77 // pos += ((first_word & 0xFF00) >> 8 );
78 // pos--;
79 //
80 //}
81
82 // Get channel header
83 if( !GetFebexChanID( data[pos++] ) ){
84 pos = ndata;
85 return;
86 }
87
88 // Special channel
89 if( my_ch_id == 255 ) {
90
91 // Get the length in bytes
92 auto length = data[pos++];
93 nsamples = (length - 16) >> 3; // Length in 64-bit (8-byte) words
94 if( pos + 4 + 2*nsamples > ndata ) {
95 std::cerr << "Wrong number of data words (" << (int)nsamples+5;
96 std::cerr << ") for data remaning data size (";
97 std::cerr << ndata-pos << ")" << std::endl;
98 pos = ndata;
99 return;
100 }
101
102 // Get the spec header
103 auto specheader = data[pos++];
104
105 my_tm_stp = data[pos++] & 0xFFFFFF;
106 my_tm_stp <<= 32;
107 my_tm_stp |= data[pos++];
108 my_tm_stp *= 10;
109 //std::cout << "my_tm_stp = " << my_tm_stp << std::endl;
110
111 for( UInt_t i = 0; i < nsamples; i++ ) {
112
113 // hit times and energies
114 // First 32-bit word of data.
115 auto val32 = data[pos++];
116 unsigned char my_hit_ch_id = (val32 & 0xf0000000) >> 28;
117 unsigned char n_hit_in_cha = (val32 & 0xf000000) >> 24;
118 bool more_than_1_hit_in_cha = (val32 & 0x400000) >> 22;
119 bool only_one_hit_in_cha = (val32 & 0x100000) >> 20;
120
121 if( more_than_1_hit_in_cha ){
122
123 //std::cout << "More than one hit found in SFP " << (int)my_sfp_id;
124 //std::cout << ", board " << (int)my_board_id;
125 //std::cout << ", channel " << (int)my_hit_ch_id << std::endl;
126
127 if( only_one_hit_in_cha )
128 std::cerr << "Error: One hit and multiple hits flagged" << std::endl;
129
131
132 }
133
134 else if( only_one_hit_in_cha ) {
135
136 // Hit time negative is before trigger
137 // Hit time positive is after trigger
138 bool hit_time_sign = (val32 & 0x8000) >> 15;
139 my_hit_time = val32 & 0x1fff; // Nik 14/09/2022 confirms mask is 0x1fff by email
140 if( hit_time_sign ) my_hit_time *= -1;
141 my_hit_time *= 10;
142
143 hhit_time->Fill( my_hit_time );
144
146
147 }
148
149 // Second 32-bit word of data
150 val32 = data[pos++];
151 unsigned char my_hit_ch_id2 = (val32 & 0xf0000000) >> 28;
152 my_adc_data_int = val32 & 0x7fffff;
153 bool my_adc_sign = (val32 & 0x800000) >> 23;
154
155 // Make sure that the hit ids match
156 if( my_hit_ch_id != my_hit_ch_id2 ){
157 std::cerr << "Hit IDs don't match in channels: ";
158 std::cerr << (int)my_hit_ch_id << " & ";
159 std::cerr << (int)my_hit_ch_id2 << std::endl;
160 pos = ndata;
161 return;
162 }
163
164 // Test that the channel number is good
165 if( my_hit_ch_id >= set->GetNumberOfFebexChannels() ) {
166 std::cerr << "Bad hit ID: " << (int)my_hit_ch_id;
167 std::cerr << std::endl;
168 pos = ndata;
169 return;
170 }
171
172 // Make an event if we have one trigger
173 if( only_one_hit_in_cha ) {
174
175 // Don't make events for pileups, as they will have a trace?
176 flag_febex_data0 = true;
177
178 if( my_adc_sign ) my_adc_data_int *= -1.0;
179
180 // Make a FebexData item
181 febex_data->SetQint( my_adc_data_int );
182 if( set->GetMbsEventMode() )
183 febex_data->SetTime( my_hit_time );
184 else febex_data->SetTime( my_tm_stp + my_hit_time );
185 febex_data->SetEventID( my_event_id );
186 febex_data->SetSfp( my_sfp_id );
187 febex_data->SetBoard( my_board_id );
188 febex_data->SetChannel( my_hit_ch_id );
189 febex_data->SetPileup( more_than_1_hit_in_cha );
190
192
193 // Close the data packet and clean up
195
196 // suppress unused warnings
197 (void)n_hit_in_cha;
198
199 }
200
201 // suppress unused warnings
202 (void)specheader;
203
204 }
205
206 // Spec trailer
207 auto spectrailer = data[pos++];
208 if( ((spectrailer & 0xff000000) >> 24) != 0xbf ){
209 std::cerr << "Invalid special trailer: ";
210 std::cerr << ((spectrailer & 0xff000000) >> 24);
211 std::cerr << std::endl;
212 pos = ndata;
213 return;
214 }
215
216 }
217
218 else { // Trace
219
220 // Trace size
221 nsamples = (data[pos++]/4) - 2; // In 32-bit words - 2 samples per word?
222 if( pos + 2 + nsamples > ndata ) {
223 std::cerr << "Wrong number of trace samples (" << (int)nsamples+2;
224 std::cerr << ") for data remaning data size (";
225 std::cerr << ndata-pos << ")" << std::endl;
226 pos = ndata;
227 return;
228 }
229
230 // Trace header
231 unsigned int trace_header = data[pos++];
232 if( ((trace_header & 0xff000000) >> 24) != 0xaa ){
233 std::cerr << "Invalid trace header: ";
234 std::cerr << ((trace_header & 0xff000000) >> 24);
235 std::cerr << std::endl;
236 pos = ndata;
237 return;
238 }
239
240 bool adc_type = (trace_header & 0x800000) >> 23;
241 bool filter_on = (trace_header & 0x80000) >> 19;
242 bool filter_mode = (trace_header & 0x40000) >> 18;
243
244 for( UInt_t i = 0; i < nsamples; i++ ) {
245
246 auto sample_packet = data[pos++];
247
248 if( nsamples > 0 ) {
249
250 //std::cout << pos << " : " << sample_packet << std::endl;
251 //std::cout << " " << (( sample_packet >> 16 ) & 0x0000FFFF) << std::endl;
252 //std::cout << " " << (sample_packet & 0x0000FFFF) << std::endl;
253
254 }
255
256 if( filter_on ) {
257
258 if( adc_type ) febex_data->AddSample( ( sample_packet >> 16 ) & 0x00003FFF ); // 14 bit
259 else febex_data->AddSample( ( sample_packet >> 16 ) & 0x00000FFF ); // 12 bit
260
261 bool filter_sign = (sample_packet & 0x800000) >> 23;
262 int filter_energy = sample_packet & 0x7fffff;
263 if( filter_sign ) filter_energy *= -1.0;
264 febex_data->SetQint( filter_energy );
265
266 }
267
268 else {
269
270 if( adc_type ) { // 14 bit
271
272 febex_data->AddSample( sample_packet & 0x00003FFF );
273 febex_data->AddSample( ( sample_packet >> 16 ) & 0x00003FFF );
274
275 }
276
277 else { // 12 bit
278
279 febex_data->AddSample( sample_packet & 0x00000FFF );
280 febex_data->AddSample( ( sample_packet >> 16 ) & 0x00000FFF );
281
282 }
283
284 }
285
286 }
287
288 // suppress unused warnings
289 (void)filter_mode;
290
291 FebexMWD mwd = cal->DoMWD( my_sfp_id, my_board_id, my_ch_id, febex_data->GetTrace() );
292 for( unsigned int i = 0; i < mwd.NumberOfTriggers(); ++i ) {
293
294 flag_febex_trace = true;
295
296 // Make a FebexData item
297 febex_data->SetQint( mwd.GetEnergy(i) );
298 if( set->GetMbsEventMode() )
299 febex_data->SetTime( mwd.GetCfdTime(i) );
300 else febex_data->SetTime( my_tm_stp + mwd.GetCfdTime(i) );
301 febex_data->SetSfp( my_sfp_id );
302 febex_data->SetBoard( my_board_id );
303 febex_data->SetChannel( my_ch_id );
304 if( mwd.NumberOfTriggers() > 1 )
305 febex_data->SetPileup( true );
306 else febex_data->SetPileup( false );
307
308
309 // Close the data packet and clean up
311
312 }
313
314 // Trace trailer
315 auto tracetrailer = data[pos++];
316 if( ((tracetrailer & 0xff000000) >> 24) != 0xbb ){
317 std::cerr << "Invalid trace trailer: ";
318 std::cerr << ((tracetrailer & 0xff000000) >> 24);
319 std::cerr << std::endl;
320 pos = ndata;
321 return;
322 }
323
324 }
325
326 return;
327
328}
329
330
332
333 // Decode the channel ID
334 my_tag_id = (x & 0xFF);
335 my_trig_id = (x & 0xF00) >> 8;
336 my_sfp_id = (x & 0xF000) >> 12;
337 my_board_id = (x & 0xFF0000) >> 16;
338 my_ch_id = (x & 0xFF000000) >> 24;
339
340 // Debug channel ID
341 //std::cout << "channel header: " << (unsigned int)x << std::endl;
342 //std::cout << "my_tag_id: " << (unsigned int)my_tag_id << std::endl;
343 //std::cout << "my_trig_id: " << (unsigned int)my_trig_id << std::endl;
344 //std::cout << "my_sfp_id: " << (unsigned int)my_sfp_id << std::endl;
345 //std::cout << "my_board_id: " << (unsigned int)my_board_id << std::endl;
346 //std::cout << "my_ch_id: " << (unsigned int)my_ch_id << std::endl;
347
348 // Make sure it is valid
349 if( my_tag_id != 0x34 ) {
350
351 std::cerr << "Invalid channel header: ";
352 std::cerr << (int)my_tag_id << std::endl;
353 return false;
354
355 }
356
357 // Check things make sense
358 if( my_sfp_id >= set->GetNumberOfFebexSfps() ||
359 my_board_id >= set->GetNumberOfFebexBoards() ||
360 ( my_ch_id >= set->GetNumberOfFebexChannels()
361 && my_ch_id != 255 ) ) {
362
363 std::cerr << "Bad FEBEX event with sfp_id=" << (unsigned int)my_sfp_id;
364 std::cerr << " board_id=" << (unsigned int)my_board_id;
365 std::cerr << " ch_id=" << (unsigned int)my_ch_id << std::endl;
366 return false;
367
368 }
369
370 else return true;
371
372}
373
375
376 // Timestamp with offset
377 unsigned long long time_corr;
378 time_corr = febex_data->GetTime();
379 time_corr += cal->FebexTime( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() );
380
381 // Check if this is actually just a timestamp or info like event
382 flag_febex_info = false;
383 if( set->IsPulser( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() ) ) {
384
385 flag_febex_info = true;
386 unsigned int pulserID = set->GetPulser( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() );
387 my_info_code = set->GetPulserCode() + pulserID;
388
389 }
390
391 else if( febex_data->GetSfp() == set->GetEBISSfp() &&
392 febex_data->GetBoard() == set->GetEBISBoard() &&
393 febex_data->GetChannel() == set->GetEBISChannel() ){
394
395 flag_febex_info = true;
396 my_info_code = 21; // EBIS is always 21 (defined here)
397
398 }
399
400 else if( febex_data->GetSfp() == set->GetT1Sfp() &&
401 febex_data->GetBoard() == set->GetT1Board() &&
402 febex_data->GetChannel() == set->GetT1Channel() ){
403
404 flag_febex_info = true;
405 my_info_code = 22; // T1 is always 22 (defined here)
406
407 }
408
409 else if( febex_data->GetSfp() == set->GetSCSfp() &&
410 febex_data->GetBoard() == set->GetSCBoard() &&
411 febex_data->GetChannel() == set->GetSCChannel() ){
412
413 flag_febex_info = true;
414 my_info_code = 23; // SC is always 23 (defined here)
415
416 }
417
418 else if( febex_data->GetSfp() == set->GetRILISSfp() &&
419 febex_data->GetBoard() == set->GetRILISBoard() &&
420 febex_data->GetChannel() == set->GetRILISChannel() ){
421
422 flag_febex_info = true;
423 my_info_code = 24; // RILIS is always 24 (defined here)
424
425 }
426
427 // If this is a timestamp, fill an info event
428 if( flag_febex_info ) {
429
430 info_data->SetTime( time_corr );
431 info_data->SetEventID( febex_data->GetEventID() );
432 info_data->SetSfp( febex_data->GetSfp() );
433 info_data->SetBoard( febex_data->GetBoard() );
434 info_data->SetCode( my_info_code );
435
436 if( !flag_source ) {
437 std::shared_ptr<MiniballDataPackets> data_packet =
438 std::make_shared<MiniballDataPackets>( info_data );
439 data_vector.emplace_back( data_packet );
440 data_map.push_back( std::make_pair<unsigned long,double>(
441 data_vector.size()-1, data_packet->GetTime() ) );
442 }
443
444 }
445
446 // Otherwise it is real data, so fill a FEBEX event
447 else if( flag_febex_data0 ) {
448
449 // Calibrate
450 my_energy = cal->FebexEnergy( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel(), febex_data->GetQint() );
451 febex_data->SetEnergy( my_energy );
452 if( febex_data->GetQint() > cal->FebexThreshold( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() ) )
453 febex_data->SetThreshold( true );
454 else
455 febex_data->SetThreshold( false );
456
457 // Fill histograms
458 hfebex_cal[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()]->Fill( my_energy );
459 hfebex_qint[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()]->Fill( febex_data->GetQint() );
460
461 // Set this data and fill event to tree
462 // Also add the time offset when we do this
463 febex_data->SetTime( time_corr );
464 if( !flag_source ) {
465 std::shared_ptr<MiniballDataPackets> data_packet =
466 std::make_shared<MiniballDataPackets>( febex_data );
467 data_vector.emplace_back( data_packet );
468 data_map.push_back( std::make_pair<unsigned long,double>(
469 data_vector.size()-1, data_packet->GetTime() ) );
470 }
471
472 }
473
474 else if( flag_febex_trace ) {
475
476 // TODO: Find a safe way to put these in the event stream (requires separate energy calibration)
477 hfebex_mwd[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()]->Fill( febex_data->GetQint() );
478 return;
479
480 }
481
482
483 // Fill histograms
484 hfebex_hit[febex_data->GetSfp()][febex_data->GetBoard()]->Fill(
485 ctr_febex_hit[febex_data->GetSfp()][febex_data->GetBoard()],
486 febex_data->GetTime(), 1 );
487
488 // Count the hit, even if it's bad
489 ctr_febex_hit[febex_data->GetSfp()][febex_data->GetBoard()]++;
490
491 // Clean up.
492 write_packet->ClearData();
493 febex_data->ClearData();
494 info_data->ClearData();
495
496 return;
497
498}
499
500// Function to run the conversion for a single file
501int MiniballMbsConverter::ConvertFile( std::string input_file_name,
502 unsigned long start_subevt,
503 long end_subevt ) {
504
505 // Uncomment to force only a few subevts - debug
506 //end_subevt = 1000;
507
508 // Read the file.
509 std::ifstream input_file( input_file_name, std::ios::in|std::ios::binary );
510 if( !input_file.is_open() ){
511
512 std::cout << "Cannot open " << input_file_name << std::endl;
513 return -1;
514
515 }
516
517 // Reset counters to zero for every file
518 StartFile();
519
520 // Calculate the size of the file.
521 input_file.seekg( 0, input_file.end );
522 unsigned long long size_end = input_file.tellg();
523 input_file.seekg( 0, input_file.beg );
524 unsigned long long size_beg = input_file.tellg();
525 unsigned long long FILE_SIZE = size_end - size_beg;
526
527 // Calculate the number of blocks in the file.
528 unsigned long BLOCKS_NUM = FILE_SIZE / set->GetBlockSize();
529
530 // a sanity check for file size...
531 if( FILE_SIZE % set->GetBlockSize() != 0 ){
532
533 std::cout << " *WARNING* " << __PRETTY_FUNCTION__;
534 std::cout << "\tMissing data blocks?" << std::endl;
535
536 }
537
538 sslogs << "\t File size = " << FILE_SIZE << std::endl;
539 sslogs << "\tBlock size = " << set->GetBlockSize() << std::endl;
540 sslogs << "\t N blocks = " << BLOCKS_NUM << std::endl;
541
542 std::cout << sslogs.str() << std::endl;
543 sslogs.str( std::string() ); // clean up
544
545 // Close the file
546 input_file.close();
547
548 // Create an MBS data instance and set block/buffer size etc
549 std::cout << "Opening file: " << input_file_name << std::endl;
550 MBS mbs;
551 mbs.SetBufferSize( set->GetBlockSize() );
552 mbs.OpenLmdFile( input_file_name );
553
554 // Loop over all the MBS Events.
555 unsigned long mbsevt = 0, nblock = 0;
556 for( mbsevt = 0; ; mbsevt++ ){
557
558 // Calculate how many blocks we have used and progress
559 nblock = mbs.GetBufferCount();
560 if( nblock % 200 == 0 || nblock+1 == BLOCKS_NUM ) {
561
562 // Percent complete
563 float percent = (float)(nblock+1)*100.0/(float)BLOCKS_NUM;
564
565 // Progress bar in GUI
566 if( _prog_ ){
567
568 prog->SetPosition( percent );
569 gSystem->ProcessEvents();
570
571 }
572
573 // Progress bar in terminal
574 std::cout << " " << std::setw(8) << std::setprecision(4);
575 std::cout << percent << "%\r";
576 std::cout.flush();
577
578 }
579
580 // Get the next event - returns nullptr at the end of the file
581 ev = mbs.GetNextLmdEvent();
582 if( !ev ) break;
584
585 if( my_event_id == 0 )
586 std::cout << "Bad event ID in data" << std::endl;
587
588 // Write the MBS event info
589 mbsinfo_packet->SetTime( my_good_tm_stp );
590 mbsinfo_packet->SetEventID( my_event_id );
591 mbsinfo_tree->Fill();
592
593 // Check if we are before the start sub event or after the end sub events
594 if( mbsevt < start_subevt || ( (long)mbsevt > end_subevt && end_subevt > 0 ) )
595 continue;
596
597 // Process current block
598 ProcessBlock( mbsevt );
599
600 } // loop - mbsevt < MBS_EVENTS
601
602 // Close the file
603 mbs.CloseFile();
604
605 // Print stats
606 std::cout << std::endl;
607 std::cout << "Number of single hits = " << n_single_hits << std::endl;
608 std::cout << "Number of double hits = " << n_double_hits << std::endl;
609
610 return mbsevt;
611
612}
float GetEnergy(unsigned int i)
void DoMWD()
unsigned int NumberOfTriggers()
float GetCfdTime(unsigned int i)
size_t GetNData() const
Definition MbsFormat.hh:289
ULong_t GetEventID() const
Definition MbsFormat.hh:300
const UInt_t * GetData() const
Definition MbsFormat.hh:294
void CloseFile()
Definition MbsFormat.cc:172
const MBSEvent * GetNextLmdEvent()
Definition MbsFormat.cc:235
void OpenLmdFile(std::string _filename)
Definition MbsFormat.cc:72
void SetBufferSize(unsigned int size)
Definition MbsFormat.hh:414
UInt_t GetBufferCount()
Definition MbsFormat.hh:422
std::shared_ptr< FebexData > febex_data
Definition Converter.hh:166
unsigned int my_adc_data_int
Definition Converter.hh:135
std::vector< std::vector< TProfile * > > hfebex_hit
Definition Converter.hh:193
std::vector< std::vector< std::vector< TH1F * > > > hfebex_qint
Definition Converter.hh:202
unsigned char my_board_id
Definition Converter.hh:138
std::vector< std::vector< std::vector< TH1F * > > > hfebex_mwd
Definition Converter.hh:205
std::shared_ptr< MiniballDataPackets > write_packet
Definition Converter.hh:163
unsigned char my_info_code
Definition Converter.hh:129
unsigned char my_ch_id
Definition Converter.hh:139
std::shared_ptr< MiniballCalibration > cal
Definition Converter.hh:220
std::vector< std::vector< std::vector< TH1F * > > > hfebex_cal
Definition Converter.hh:204
std::shared_ptr< MiniballSettings > set
Definition Converter.hh:217
std::vector< std::shared_ptr< MiniballDataPackets > > data_vector
Definition Converter.hh:170
unsigned int nsamples
Definition Converter.hh:149
std::shared_ptr< InfoData > info_data
Definition Converter.hh:167
std::vector< std::pair< unsigned long, double > > data_map
Definition Converter.hh:171
unsigned char my_sfp_id
Definition Converter.hh:137
std::stringstream sslogs
Definition Converter.hh:105
std::shared_ptr< TGProgressBar > prog
Definition Converter.hh:224
std::vector< std::vector< unsigned long int > > ctr_febex_hit
Definition Converter.hh:183
unsigned long long my_good_tm_stp
Definition Converter.hh:116
unsigned char my_tag_id
Definition Converter.hh:136
unsigned long long my_tm_stp
Definition Converter.hh:117
unsigned long long my_event_id
Definition Converter.hh:120
std::shared_ptr< MBSInfoPackets > mbsinfo_packet
Definition Converter.hh:162
unsigned char my_trig_id
Definition Converter.hh:141
int ConvertFile(std::string input_file_name, unsigned long start_block=0, long end_block=-1)
unsigned long n_double_hits
unsigned long n_single_hits
void ProcessBlock(unsigned long nblock)
const MBSEvent * ev
bool GetFebexChanID(unsigned int x)
void ProcessFebexData(UInt_t &pos)
const UInt_t * data