AlcapDAQ  1
MCaenCompProcessRaw.cpp
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: MCaenCompProcessERaw.cpp
4  Created by: Fred Gray
5 
6  Contents: Module to merge raw CAEN TDC and compressor hits into
7  a time-ordered bank in terms of time and physics
8  parameter number.
9 
10 \********************************************************************/
11 
12 /*-- Include files -------------------------------------------------*/
13 
14 /* Standard includes */
15 #include <stdio.h>
16 #include <stdlib.h>
17 
18 /* MIDAS includes */
19 #include "midas.h"
20 
21 /* ROOT includes */
22 #include "TH1.h"
23 #include "TH2.h"
24 
25 /* MuCap includes */
26 #include "common.h"
27 
28 /*-- Parameters ----------------------------------------------------*/
29 
30 /*-- Static parameters ---------------------------------------------*/
31 
33 const int initial_stream_size = 1024;
34 const int max_caen_trailing_hits = 64*1024;
35 
43 
46 static TH1 *hCaenErrorDAQ[kMaxCaens];
48 static TH1 *hCaenErrorEOB[kMaxCaens];
57 static TH1 *hCaenLastTime[kMaxCaens];
58 
64 static TH1 *hCompLastTime[kMaxComps];
65 
66 double beam_rate;
67 
68 /*-- Module declaration --------------------------------------------*/
69 
70 INT MCaenCompProcessRaw_init(void);
71 INT MCaenCompProcessRaw(EVENT_HEADER*, void*);
72 void double_stream_size(channel_hit **output_bank_handle,
73  int *output_bank_size);
74 void sort_hits(int num_hits, channel_hit *hits);
75 INT merge_hits(int num_streams, int *num_hits,
76  channel_hit **hits, channel_hit *output);
77 INT make_caen(int caen, void *pevent, channel_hit **output_bank_handle,
78  int *output_bank_size, bool *bad_block,
79  caen_hit *caen_trailing_hits, int *num_caen_trailing_hits);
80 void init_caen_histograms(int caen);
81 INT make_comp(int comp, void *pevent, channel_hit **output_bank_handle,
82  int *output_bank_size, bool *bad_block);
83 void init_comp_histograms(int comp);
84 
85 extern HNDLE hDB;
86 
88  "MCaenCompProcessRaw", /* module name */
89  "Fred Gray", /* author */
90  MCaenCompProcessRaw, /* event routine */
91  NULL, /* BOR routine */
92  NULL, /* EOR routine */
93  MCaenCompProcessRaw_init, /* init routine */
94  NULL, /* exit routine */
95  NULL, /* parameter structure */
96  0, /* structure size */
97  NULL, /* initial parameters */
98 };
99 
100 /*-- init routine --------------------------------------------------*/
101 
103 {
104  HNDLE hKey;
105 
106  // Search through the ODB for the CAENs' clock and wiring information
107  for (int caen = 0; caen < kMaxCaens; caen++) {
108  for (int crate = 1; crate <= kMaxCrates; crate++) {
109  char key_path[80];
110  char key_name[80];
111  sprintf(key_path, "Equipment/Crate %d/Settings/CAEN %d", crate, caen);
112  if (db_find_key(hDB, 0, key_path, &hKey) == SUCCESS) {
113 
114  // get the clock information
115  sprintf(key_name, "%s/ext clock frequency MHz", key_path);
116  int caen_freq;
117  int size = sizeof(caen_freq);
118  db_get_value(hDB, 0, key_name, &caen_freq, &size, TID_INT, 0);
119  if (caen_freq != 25) {
120  fprintf(stderr, "Error: CAEN %d clock freq found as %d, should be 25 (ODB problem)\n", caen, caen_freq);
121  }
122  caen_clock_period[caen] = 1000.0/caen_freq/32;
123 
124  // get the wiring information
125  sprintf(key_name, "%s/wiring/channel", key_path);
126  int caen_wiring[kNumCaenChannels];
127  size = sizeof(caen_wiring);
128  db_get_value(hDB, 0, key_name, caen_wiring, &size, TID_INT, 0);
129  for (int chan = 0; chan < kNumCaenChannels; chan++) {
130  caen_wiring_map[chan][caen] = caen_wiring[chan];
131  }
132 
133  break;
134  }
135  }
136  }
137 
138  // Search through the ODB for the COMPs' clock and wiring information
139  for (int comp = 0; comp < kMaxComps; comp++) {
140  for (int crate = 1; crate <= kMaxCrates; crate++) {
141  char key_path[80];
142  char key_name[80];
143  sprintf(key_path, "Equipment/Crate %d/Settings/COMP %d", crate, comp);
144  if (db_find_key(hDB, 0, key_path, &hKey) == SUCCESS) {
145 
146  // get the clock information
147  sprintf(key_name, "%s/ext clock frequency MHz", key_path);
148  int comp_freq;
149  int size = sizeof(comp_freq);
150  db_get_value(hDB, 0, key_name, &comp_freq, &size, TID_INT, 0);
151  if (comp_freq != 50) {
152  fprintf(stderr, "Error: COMP %d clock freq found as %d, should be 50 (ODB problem)\n", comp, comp_freq);
153  }
154  comp_clock_period[comp] = 1500.0/comp_freq;
155 
156  // get the wiring information
157  for (int fpga = 0; fpga < kMaxCompFpgas; fpga++) {
158  sprintf(key_name, "%s/wiring/FPGA %d/channel", key_path, fpga);
159  if (db_find_key(hDB, 0, key_name, &hKey) == SUCCESS) {
160  int comp_wiring[kNumCompFpgaChannels];
161  size = sizeof(comp_wiring);
162  db_get_value(hDB, 0, key_name, comp_wiring, &size, TID_INT, 0);
163  for (int chan = 0; chan < kNumCompFpgaChannels; chan++) {
164  comp_wiring_map[chan][fpga][comp] = comp_wiring[chan];
165  }
166  }
167  }
168 
169  break;
170  }
171  }
172  }
173 
174  // Create the hit streams
175  for (int stream=0; stream<max_streams; stream++) {
176  temp_hits[stream] = new channel_hit[initial_stream_size];
178  }
179 
180  // Create a stream for CAEN trailing edge times
181  caen_trailing_hits = new caen_hit[max_caen_trailing_hits];
182 
183  // Set CAEN-specific histogram initialization flags to false
184  for(int caen = 0; caen < kMaxCaens; caen++) {
185  caen_histograms_inited[caen] = false;
186  }
187 
188  // Set COMP-specific histogram initialization flags to false
189  for(int comp = 0; comp < kMaxComps; comp++) {
190  comp_histograms_inited[comp] = false;
191  }
192 
193  // Define general CAEN/COMP histograms
194  char name[80], title[80];
195 
196  sprintf(name, "blocks_skipped_caen_error");
197  sprintf(title, "Blocks skipped due to CAEN errors");
198  hCaenErrorBlocksSkipped = new TH1D(name, title,
199  kMaxEvents, 0.5, kMaxEvents+0.5);
200 
201  sprintf(name, "blocks_skipped_comp_error");
202  sprintf(title, "Blocks skipped due to irresolvable COMP errors");
203  hCompErrorBlocksSkipped = new TH1D(name, title,
204  kMaxEvents, 0.5, kMaxEvents+0.5);
205 
206  return SUCCESS;
207 }
208 
209 /*-- event routine -------------------------------------------------*/
210 
211 INT MCaenCompProcessRaw(EVENT_HEADER *pheader, void *pevent)
212 {
213  int num_hits[max_streams];
214  int stream = 0;
215  bool skip_block = false;
216 
217  // Process CAEN data.
218  int num_caen_trailing_hits = 0;
219  for(int caen = 0; caen < kMaxCaens; caen++) {
220  bool bad_block = false;
221  num_hits[stream] = make_caen(caen, pevent, &temp_hits[stream],
222  &temp_hits_size[stream], &bad_block,
223  caen_trailing_hits, &num_caen_trailing_hits);
224  if(bad_block) skip_block = true;
225  if(num_hits[stream] != 0) {
226  stream++;
227  }
228  }
229 
230  if(skip_block) {
231  fprintf(stderr, "Skipping block %d due to CAEN processing errors.\n", pheader->serial_number);
232  hCaenErrorBlocksSkipped->Fill(pheader->serial_number);
233  return ANA_SKIP;
234  }
235 
236  // Process COMP data.
237  for(int comp = 0; comp < kMaxComps; comp++) {
238  bool bad_block = false;
239  num_hits[stream] = make_comp(comp, pevent, &temp_hits[stream],
240  &temp_hits_size[stream], &bad_block);
241  if(bad_block) skip_block = true;
242  if(num_hits[stream] != 0) {
243  stream++;
244  }
245  }
246 
247  if(skip_block) {
248  fprintf(stderr, "Skipping block %d due to COMP processing errors.\n", pheader->serial_number);
249  hCompErrorBlocksSkipped->Fill(pheader->serial_number);
250  return ANA_SKIP;
251  }
252 
253  // Merge all CAEN and COMP data streams together into "HITS"
254  channel_hit *output_bank;
255  bk_create(pevent, "HITS", TID_DWORD, (DWORD *) &output_bank);
256  int output_bank_size = merge_hits(stream, num_hits, temp_hits, output_bank);
257  bk_close(pevent, output_bank + output_bank_size);
258 
259  // Write the CAEN trailing edge hit info into bank "CAET"
260  caen_hit *caen_trailing_hit_bank;
261  bk_create(pevent, "CAET", TID_DWORD, (DWORD *) &caen_trailing_hit_bank);
262  for (int index = 0; index < num_caen_trailing_hits; index++) {
263  caen_trailing_hit_bank[index].time = caen_trailing_hits[index].time;
264  caen_trailing_hit_bank[index].caen = caen_trailing_hits[index].caen;
265  }
266  bk_close(pevent, caen_trailing_hit_bank + num_caen_trailing_hits);
267 
268  return SUCCESS;
269 }
270 
271 /*-- subroutine ----------------------------------------------------*/
272 
273 void double_stream_size(channel_hit **output_bank_handle, int *output_bank_size)
274 {
275  int new_output_bank_size = *output_bank_size * 2;
276  channel_hit *new_output_bank = new channel_hit[new_output_bank_size];
277  memcpy(new_output_bank, *output_bank_handle,
278  *output_bank_size*sizeof(channel_hit));
279  delete[] *output_bank_handle;
280  *output_bank_handle = new_output_bank;
281  *output_bank_size = new_output_bank_size;
282 }
283 
284 int hits_compare(const void *p1, const void *p2)
285 {
286  channel_hit *hit1 = (channel_hit *) p1;
287  channel_hit *hit2 = (channel_hit *) p2;
288 
289  if(hit1->time > hit2->time) {
290  return 1;
291  } else if(hit1->time < hit2->time) {
292  return -1;
293  } else {
294  return 0;
295  }
296 }
297 
298 void sort_hits(int num_hits, channel_hit *hits)
299 {
300  // For arbitrary inputs, the bubble sort is an extremely poor
301  // algorithmic choice. However, when the input is already nearly
302  // sorted, it can be a very good choice, as is the case here.
303 
304 /*
305  int sorted_through = 0;
306  channel_hit temp;
307 
308  while(sorted_through < num_hits-1) {
309  for(int i = sorted_through; i < num_hits-1; i++) {
310 
311  if(hits[i+1].time < hits[i].time) {
312  // If necessary, swap two adjacent elements
313  temp = hits[i];
314  hits[i] = hits[i+1];
315  hits[i+1] = temp;
316  if(i > 0) {
317  sorted_through = i-1;
318  }
319  break;
320  } else {
321  sorted_through = i+1;
322  }
323  }
324  }
325 */
326  // sorry, the worst case is just too poor
327  qsort(hits, num_hits, sizeof(channel_hit), hits_compare);
328 
329 }
330 
331 /*-- subroutine ----------------------------------------------------*/
332 
333 INT merge_hits(int num_streams, int *num_hits, channel_hit **hits,
334  channel_hit *output)
335 {
336  int stream_ptr[num_streams];
337  int total_num_hits = 0;
338 
339  for(int stream = 0; stream < num_streams; stream++) {
340  total_num_hits += num_hits[stream];
341  stream_ptr[stream] = 0;
342  }
343 
344  for(int i = 0; i < total_num_hits; i++) {
345 
346  // look for the stream whose top-most unused element comes first
347  int best_stream = 0;
348  double best_time = 1e99;
349  for(int stream = 0; stream < num_streams; stream++) {
350  if(stream_ptr[stream] < num_hits[stream] &&
351  hits[stream][stream_ptr[stream]].time < best_time) {
352  best_stream = stream;
353  best_time = hits[stream][stream_ptr[stream]].time;
354  }
355  }
356 
357  // copy this earliest element to the output
358  output[i] = hits[best_stream][stream_ptr[best_stream]];
359  stream_ptr[best_stream]++;
360  }
361 
362  return total_num_hits;
363 }
364 
365 /*-- subroutine ----------------------------------------------------*/
366 
367 INT make_caen(int caen, void *pevent, channel_hit **output_bank_handle,
368  int *output_bank_size, bool *bad_block,
369  caen_hit *caen_trailing_hits, int *num_caen_trailing_hits)
370 {
371  channel_hit *output_bank = *output_bank_handle;
372 
373  // Open CAEN bank ("caen" == CAEN number)
374  caen_word *caen_bank;
375  char bank_name[8];
376  sprintf(bank_name, "CAE%d", caen);
377  int caen_bank_size = bk_locate(pevent, bank_name, (DWORD *) &caen_bank);
378  if(caen_bank == NULL) return 0;
379  int block_number = ((EVENT_HEADER *) pevent - 1)->serial_number;
380 
381  // Initialize caen-specific histograms if necessary
382  if (!caen_histograms_inited[caen]) {
383  init_caen_histograms(caen);
384  }
385 
386  // This section loops over the CAEN data in "caen_bank" and performs
387  // the following tasks:
388  // (1) check for headers, EOBs, and DAQ-introduced error datums;
389  // (2) count the numbers of rising and trailing edges;
390  // (3) track the linearity of the CAEN interpolator;
391  // (4) calculate the absolute times of hit datums;
392  // (5) fill an output bank with leading edge hit info;
393  // (6) fill an output bank with trailing edge hit times.
394 
395  // Define and initialize useful arrays, counters, and flags
396  double caen_bank_abstime[caen_bank_size];
397  int output_pointer = 0;
398  int prev_time_word = 0;
399  int num_overflows = 0;
400  bool header_found = false;
401  bool EOB_found = false;
402  int EOB_reported_data_count = 0;
403  int EOB_reported_error_status = 0;
404  int num_trailing_edges = 0;
405 
406  // Loop over the caen_bank elements
407  for (int j=0; j<caen_bank_size; j++) {
408  if(j<=2)
409  // check for DAQ-introduced error datum; if found, fill appropriate histos
410  // and flag the block so that it can be skipped
411  if(caen_bank[j].r2 == 3) {
412  fprintf(stderr, "Encountered DAQ-generated error flag in block %d CAEN%d data at j=%d.\n",
413  block_number, caen, j);
414  if (!(*bad_block)) {
415  hCaenErrorDAQ[caen]->Fill(1);
416  *bad_block = true;
417  }
418  int error_bits = caen_bank[j].time;
419  for (int TDC=0; TDC<4; TDC++) {
420  if (error_bits & (1<<TDC)) {
421  hCaenErrorDAQ_TDCInfo[caen]->Fill(block_number, TDC);
422  }
423  }
424  }
425 
426  // check for header datum
427  if (caen_bank[j].r2 == 2) {
428  header_found = true;
429  }
430 
431  // check for EOB datum; if found, extract reported data count and TDC chip
432  // error status; if TDC chip error occurred, flag the block to be skipped
433  if(caen_bank[j].r2 == 1) {
434  EOB_found = true;
435  EOB_reported_data_count = (caen_bank[j].time & 0xffff);
436  EOB_reported_error_status = (caen_bank[j].channel & 0x07);
437  if (EOB_reported_error_status) {
438  fprintf(stderr, "Encountered EOB error flag in block %d CAEN%d data.\n",
439  block_number, caen);
440  if (!(*bad_block)) {
441  hCaenErrorEOB[caen]->Fill(1);
442  *bad_block = true;
443  }
444  }
445  }
446 
447  // in preparation for absolute timing calculations and output bank filling,
448  // ignore anything that isn't an ordinary datum
449  if(caen_bank[j].start != 0 ||
450  caen_bank[j].r2 != 0) {
451  continue;
452  }
453 
454  // count/histogram the leading and trailing edge hit info; if there are too
455  // many trailing edges, flag the block to be skipped
456  if(caen_bank[j].edge == 1) {
457  hCaenLeadingEdgesByChannel[caen]->Fill(caen_bank[j].channel);
458  hCaenLeadingEdgesByBlock[caen]->Fill(block_number);
459  hCaenLeadingEdges32BitInterpolator[caen]->Fill(caen_bank[j].time % 32);
460  int parameter = caen_wiring_map[caen_bank[j].channel][caen];
461  if (!((parameter>=6500) && (parameter<=6502))) {
462  hCaenLeadingEdges32BitInterpolatorNoRollover[caen]->Fill(caen_bank[j].time % 32);
463  }
464  } else {
465  num_trailing_edges++;
466  if ((num_trailing_edges > kCaenTrailingEdgeLimit) && !(*bad_block)) {
467  fprintf(stderr, "Encountered too many trailing edges in block %d CAEN%d data (%d).\n",
468  block_number, caen, num_trailing_edges);
470 // *bad_block = true;
471  }
472  hCaenTrailingEdgesByChannel[caen]->Fill(caen_bank[j].channel);
473  hCaenTrailingEdgesByBlock[caen]->Fill(block_number);
474  }
475 
476  // Calculate the absolute times by dealing with time overflows: Because
477  // there are multiple levels of FIFO within the CAEN, backward-going times
478  // are normal features of the data and do not always indicate an overflow.
479  // Empirically, the distribution of these backward-going times seems to cut
480  // off at about -4000. Meanwhile, if the minimum rate is 2.5 kHz, a backward
481  // step of at least 2^10 - 320000 is guaranteed for an overflow; a forward
482  // step of at least 320000 indicates the reversal of an overflow, which can
483  // occur because of the multiple FIFO buffering.
484 
485  if(caen_bank[j].time < prev_time_word &&
486  prev_time_word - caen_bank[j].time > 0x80000) {
487  num_overflows++;
488  } else if(caen_bank[j].time > prev_time_word &&
489  caen_bank[j].time - prev_time_word > 0x80000) {
490  num_overflows--;
491  }
492  prev_time_word = caen_bank[j].time;
493  caen_bank_abstime[j] =
494  caen_clock_period[caen] * (caen_bank[j].time + num_overflows*0x100000);
495 
496  // add leading edge hit information to the output bank
497  if (caen_bank[j].edge == 1) {
498 
499  // double size of array if necessary, copying old entries
500  if(output_pointer >= *output_bank_size) {
501  double_stream_size(output_bank_handle, output_bank_size);
502  output_bank = *output_bank_handle;
503  }
504 
505  output_bank[output_pointer].time = caen_bank_abstime[j];
506  output_bank[output_pointer].parameter =
507  caen_wiring_map[caen_bank[j].channel][caen];
508  output_pointer++;
509  }
510 
511  // add trailing edge hit information to the caen_trailing_hits array
512  // (after performing a caen_trailing_hits array boundary check)
513  if (caen_bank[j].edge == 0) {
514  if (*num_caen_trailing_hits < max_caen_trailing_hits) {
515  caen_trailing_hits[*num_caen_trailing_hits].time = caen_bank_abstime[j];
516  caen_trailing_hits[*num_caen_trailing_hits].caen = caen;
517  (*num_caen_trailing_hits)++;
518  } else if (!(*bad_block)) {
519  fprintf(stderr, "Exceeded trailing edge data stream limit in block %d CAEN%d data.\n",
520  block_number, caen);
522  *bad_block = true;
523  }
524  }
525 
526  } // end loop over caen_bank
527 
528  // sort the output bank into time order
529  sort_hits(output_pointer, output_bank);
530 
531  // fill diagnostic histograms
532  double lastTime = -1;
533  if(output_pointer != 0) {
534  lastTime = output_bank[output_pointer-1].time;
535  }
536  hCaenLastTime[caen]->SetBinContent(block_number, lastTime);
537 
538  return output_pointer;
539 }
540 
541 /*-- subroutine ----------------------------------------------------*/
542 
544 {
545  // This subroutine initializes all caen-specific histograms as needed.
546  char name[80], title[80];
547 
548  sprintf(name, "DAQ_caen%d_edges_leading_by_channel", caen);
549  sprintf(title, "CAEN %d leading edges vs. channel", caen);
551  new TH1D(name, title, kNumCaenChannels, -0.5, (kNumCaenChannels-0.5));
552 
553  sprintf(name, "DAQ_caen%d_edges_leading_by_block", caen);
554  sprintf(title, "CAEN %d leading edges vs. block number", caen);
556  new TH1D(name, title, kMaxEvents, 0.5, kMaxEvents+0.5);
557 
558  sprintf(name, "DAQ_caen%d_edges_leading_32BitInterp", caen);
559  sprintf(title, "CAEN %d leading edges' 32-bit Interpolator Dist", caen);
561  new TH1D(name, title, 32, -0.5, 31.5);
562 
563  sprintf(name, "DAQ_caen%d_edges_leading_32BitInterp_noRollover", caen);
564  sprintf(title, "CAEN %d leading edges' 32-bit Interpolator Dist, No Rollover", caen);
566  new TH1D(name, title, 32, -0.5, 31.5);
567 
568  sprintf(name, "DAQ_caen%d_edges_trailing_by_channel", caen);
569  sprintf(title, "CAEN %d trailing edges vs. channel", caen);
571  new TH1D(name, title, kNumCaenChannels, -0.5, (kNumCaenChannels-0.5));
572 
573  sprintf(name, "DAQ_caen%d_edges_trailing_by_block", caen);
574  sprintf(title, "CAEN %d trailing edges vs. block number", caen);
576  new TH1D(name, title, kMaxEvents, 0.5, kMaxEvents+0.5);
577 
578  sprintf(name, "DAQ_caen%d_error_DAQ", caen);
579  sprintf(title, "Blocks with DAQ-inserted CAEN %d errors", caen);
580  hCaenErrorDAQ[caen] =
581  new TH1D(name, title, 3, -0.5, 2.5);
582  sprintf(name, "DAQ_caen%d_error_DAQ_by_TDC", caen);
583  sprintf(title, "CAEN %d DAQ-inserted errors: TDC vs. block number", caen);
585  new TH2D(name, title, kMaxEvents, 0.5, kMaxEvents+0.5, 4, -0.5, 3.5);
586 
587  sprintf(name, "DAQ_caen%d_error_EOB", caen);
588  sprintf(title, "Blocks with CAEN %d EOB error flag", caen);
589  hCaenErrorEOB[caen] =
590  new TH1D(name, title, 3, -0.5, 2.5);
591 
592  sprintf(name, "DAQ_caen%d_error_trailing_edge_stream_limit", caen);
593  sprintf(title, "Blocks where CAEN %d trailing edges exceeded stream limit", caen);
595  new TH1D(name, title, 3, -0.5, 2.5);
596 
597  sprintf(name, "DAQ_caen%d_error_trailing_edge_block_limit", caen);
598  sprintf(title, "Blocks with too many CAEN %d trailing edges", caen);
600  new TH1D(name, title, 3, -0.5, 2.5);
601 
602  sprintf(name, "DAQ_caen%d_last_time", caen);
603  sprintf(title, "CAEN %d last time vs. block number", caen);
604  hCaenLastTime[caen] =
605  new TH1D(name, title, kMaxEvents, 0.5, kMaxEvents+0.5);
606 
608 }
609 
610 /*-- subroutine ----------------------------------------------------*/
611 
612 INT make_comp(int comp, void *pevent, channel_hit **output_bank_handle,
613  int *output_bank_size, bool *bad_block)
614 {
615  channel_hit *output_bank = *output_bank_handle;
616  int output_pointer = 0;
617  int block_number = ((EVENT_HEADER *) pevent - 1)->serial_number;
618 
619  // Open COMP bank
620  comp_word *comp_bank;
621  char bank_name[8];
622  sprintf(bank_name, "CMP%d", comp);
623  int comp_bank_size = bk_locate(pevent, bank_name, (DWORD *) &comp_bank);
624  if(comp_bank == NULL) {
625  return 0;
626  }
627 
628  // Initialize comp-specific histograms if necessary.
629  if (!comp_histograms_inited[comp]) {
630  init_comp_histograms(comp);
631  }
632 
633  int prev_time[kMaxCompFpgas];
634  for(int i = 0; i < kMaxCompFpgas; i++) {
635  prev_time[i] = 0;
636  }
637 
638  int num_backwards = 0;
639  bool gone_backwards_here[comp_bank_size];
640  for(int i = 0; i < comp_bank_size; i++) {
641  gone_backwards_here[i] = false;
642  }
643 
644  for(int i = 0; i < comp_bank_size; i++) {
645  int fpga = comp_bank[i].r1.fpga;
646  int time = comp_bank[i].r1.time;
647  int a = comp_bank[i].r1.a;
648  int b = comp_bank[i].r1.b;
649 
650  // check for a backward-going time or an impossible A/B combination
651  if((fpga >= kMaxCompFpgas) || (time < prev_time[fpga]) || (!a && !b)) {
652  // printf("Time order error at comp %d block %d word %d (prev_time = 0x%x)\n", comp, block_number, i, prev_time[fpga]);
653  num_backwards++;
654 
655  // According to Rene's note, this condition is probably caused by a
656  // single missing data word that throws off the synchronization.
657  // We should try going back one word, but we need to avoid the
658  // possibility of an infinite loop.
659 
660  if(!gone_backwards_here[i]) {
661  gone_backwards_here[i] = true;
662  i -= 2;
663  }
664 
665  continue;
666  }
667 
668  prev_time[fpga] = time;
669 
670  // deal with word A if it is present
671  if(a) {
672  i++;
673  unsigned int word = comp_bank[i].word;
674  for(int j = 0; j < 32; j++) {
675  if(word & (1 << j)) {
676 
677  // double size of array if necessary, copying old entries
678  if(output_pointer >= *output_bank_size) {
679  double_stream_size(output_bank_handle, output_bank_size);
680  output_bank = *output_bank_handle;
681  }
682 
683  output_bank[output_pointer].time = comp_clock_period[comp] * time;
684  output_bank[output_pointer].parameter =
685  comp_wiring_map[j][fpga][comp];
686  output_pointer++;
687  }
688  }
689  }
690 
691  // deal with word B if it is present
692  if(b) {
693  i++;
694  unsigned int word = comp_bank[i].word;
695  for(int j = 0; j < 32; j++) {
696  if(word & (1 << j)) {
697  // double size of array if necessary, copying old entries
698  if(output_pointer >= *output_bank_size) {
699  double_stream_size(output_bank_handle, output_bank_size);
700  output_bank = *output_bank_handle;
701  }
702 
703  output_bank[output_pointer].time = comp_clock_period[comp] * time;
704  output_bank[output_pointer].parameter =
705  comp_wiring_map[j + 32][fpga][comp];
706  output_pointer++;
707  }
708  }
709  }
710  }
711 
712  // check if there were too many time-ordering errors
713 // if (num_backwards > 0 && num_backwards <= 1000) {
714  if (num_backwards > 0 && num_backwards <= 10) {
715  fprintf(stderr, "Encountered %d backward time steps in block %d COMP%d data.\n",
716  num_backwards, block_number, comp);
717  }
718  //else if (num_backwards > 1000) {
719  else if (num_backwards > 10) {
720  fprintf(stderr, "Encountered too many (%d) backward time steps in block %d COMP%d data: skipping block.\n",
721  num_backwards, block_number, comp);
722  if (!(*bad_block)) {
723  hCompBackwardsLimit[comp]->Fill(1);
724  *bad_block = true;
725  }
726  }
727 
728  // sort the output into time order
729  sort_hits(output_pointer, output_bank);
730 
731  // fill diagnostic histograms
732  hCompBackwards[comp]->SetBinContent(block_number, num_backwards);
733  //if (output_pointer > 0){
734  hCompLastTime[comp]->
735  SetBinContent(block_number, output_bank[output_pointer-1].time);
736  //}
737  return output_pointer;
738 }
739 
740 /*-- subroutine ----------------------------------------------------*/
741 
742 void init_comp_histograms(int comp)
743 {
744  // This subroutine initializes all comp-specific histograms as needed.
745  char name[80], title[80];
746 
747  sprintf(name, "DAQ_comp%d_error_timing_per_block", comp);
748  sprintf(title, "COMP %d timing errors vs. block number", comp);
749  hCompBackwards[comp] =
750  new TH1D(name, title, kMaxEvents, 0.5, kMaxEvents+0.5);
751 
752  sprintf(name, "DAQ_comp%d_error_timing_limit", comp);
753  sprintf(title, "Blocks where COMP %d backwards steps exceeded limit", comp);
754  hCompBackwardsLimit[comp] =
755  new TH1D(name, title, 3, -0.5, 2.5);
756 
757  sprintf(name, "DAQ_comp%d_error_stream_limit", comp);
758  sprintf(title, "Blocks where COMP %d hits exceeded stream limit", comp);
759  hCompErrorStreamLimit[comp] =
760  new TH1D(name, title, 3, -0.5, 2.5);
761 
762  sprintf(name, "DAQ_comp%d_last_time", comp);
763  sprintf(title, "COMP %d last time vs. block number", comp);
764  hCompLastTime[comp] =
765  new TH1D(name, title, kMaxEvents, 0.5, kMaxEvents+0.5);
766 
767  comp_histograms_inited[comp] = true;
768 }
769 
770 /*------------------------------------------------------------------*/