StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
fcfAfterburner.cxx
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <math.h>
4 #include <string.h>
5 #include <assert.h>
6 
7 #ifdef __ROOT__
8 
9 #define LOG(x,a,v1,v2,v3,v4,v5)
10 
11 #else
12 #include <rtsLog.h>
13 #endif
14 
15 #include <fcfClass.hh>
16 #include <rts.h>
17 #include <TPC/padfinder.h>
18 //#include <fcfAfterburner.hh>
19 
20 
21 // Version: 1.0; 17Sep2003; Tonko
22 //
23 
24 // Tonko: what is this? You can't make these global - someone can step on them
25 // by using common names in their code!
26 
27 //void *lastAfter=0;
28 //int myNext = 0;
29 
30 
31 
32 fcfAfterburner::fcfAfterburner()
33 {
34  last_n = last_count = last_i = last_stage = 0;
35 
36  do_merge = do_cuts = 1 ;
37 
38  verbose = true;
39 
40 // lastAfter=this;
41 }
42 
43 /*
44  This is a small helper function which prints the
45  hit data in "h" to stdout.
46  If "str" is non-NULL it prepends it to the line
47  as a label.
48 */
49 void fcfAfterburner::print_hit(const char *str, struct fcfHit *h)
50 {
51  if(str) {
52  fprintf(stdout,"%s: ",str) ;
53  }
54 
55  fprintf(stdout,"%d %f %f %d %d %d %d %d %d %d %d %d\n",
56  row,(double)h->pad/64.0+0.5,(double)h->tm/64.0+0.5,h->c,h->f,
57  h->p1,h->p2,h->t1,h->t2,h->cl_id,h->id_simtrk,h->id_quality) ;
58 
59  return ;
60 }
61 
62 
63 /*
64  The function returns TRUE of the hit in "hit"
65  satisfies the post-burner cuts.
66 */
67 int fcfAfterburner::output(struct fcfHit *hit)
68 {
69  int ret ;
70 
71  // CUTS - NEVER TOUCH THESE VALUES!
72  if(do_cuts) {
73  if(hit->f & (FCF_ONEPAD | FCF_ROW_EDGE | FCF_DEAD_EDGE)) ret = 0 ; // bad flag
74  else if((hit->t2 - hit->t1) <= 3) ret = 0 ; // too short in timebin
75  else if(hit->t1 == 0) ret = 0 ; // touches timebin 0
76  else if(hit->c < 40) ret = 0 ; // small charge
77  else ret = 1 ; // OK!
78  }
79  else {
80  ret = 1 ;
81  }
82 
83  if(ret) {
84  //print_hit("SAVED",hit) ;
85  }
86  else {
87  //print_hit("REJEC",hit) ;
88  }
89 
90  return ret;
91 
92 }
93 
94 /*
95  The function decodes the FCF-packed data in "ptr" into
96  the local structure "hit".
97  It also uses the FCF-packed simulation data from "sim" (if it
98  exists) and adds it to "hit". "sim" defaults to "NULL" in
99  the function declaration.
100 */
101 void fcfAfterburner::decode(u_int *ptr, struct fcfHit *hit, u_int *sim)
102 {
103  u_int pt, cf ;
104  u_short flags, fl ;
105  u_short tm, pad ;
106  u_short p1,p2,t1,t2 ;
107  u_short charge ;
108 
109 
110 
111  if(sim) {
112  struct FcfSimOutput *s = (struct FcfSimOutput *) sim ;
113 
114  // note that sim is always done on the local machine so
115  // there is no need to check for endianess...
116  hit->id_simtrk = s->id_simtrk ;
117  hit->id_quality = s->id_quality ;
118  hit->cl_id = s->cl_id ;
119  }
120  else {
121  // these are the defaults which FCF will also use - don't change!
122  hit->id_simtrk = 0 ;
123  hit->id_quality = 100 ;
124  hit->cl_id = -1 ;
125  }
126 
127 
128  pt = *ptr++ ;
129  cf = *ptr++ ;
130 
131 
132  if(do_swap) { // bytes swapping...
133  pt = swap32(pt) ;
134  cf = swap32(cf) ;
135  }
136 
137  tm = (pt >> 16) & 0x7FFF ;
138  pad = pt & 0x3FFF ;
139  charge = cf >> 16 ;
140  fl = cf & 0xFFFF ;
141 
142  flags = 0 ;
143  if(pt & 0x8000) flags |= FCF_DOUBLE_PAD ;
144  if(pt & 0x4000) flags |= FCF_DEAD_EDGE ;
145  if(pt & (0x8000 << 16)) flags |= FCF_ONEPAD ;
146  if(fl & 0x8000) flags |= FCF_ROW_EDGE ;
147  if(fl & 0x4000) flags |= FCF_BROKEN_EDGE ;
148 
149  t2 = (fl & 0x00F0) >> 4 ;
150  t1 = fl & 0x000F ;
151 
152  t2 = (tm >> 6) + t2 ;
153  t1 = (tm >> 6) - t1 ;
154 
155  p2 = (fl & 0x3800) >> 11 ;
156  p1 = (fl & 0x0700) >> 8 ;
157 
158  p2 = (pad >> 6) + p2 ;
159  p1 = (pad >> 6) - p1 ;
160 
161  // NOTE: pad,p1,p2 count from "1" whereas tm,t1,t2 count from 0!
162  hit->pad = pad ;
163  hit->tm = tm ;
164  hit->c = charge ;
165  hit->f = flags ;
166  hit->p1 = p1 ;
167  hit->p2 = p2 ;
168  hit->t1 = t1 ;
169  hit->t2 = t2 ;
170 
171  return ;
172 }
173 
174 /*
175  Checks for mergability between the 2 hits and makes
176  a merge by merging into "hit_l" while marking the
177  charge of "hit_r" as 0.
178 */
179 int fcfAfterburner::check_merge(struct fcfHit *hit_l, struct fcfHit *hit_r)
180 {
181  u_int charge ;
182  double tm[2] ;
183 
184  tm[0] = (double)hit_l->tm ;
185  tm[1] = (double)hit_r->tm ;
186 
187  if(fabs(tm[0]/64.0-tm[1]/64.0)<2.0) { // merge!
188  //print_hit("Left",hit_l) ;
189  //print_hit("Right",hit_r) ;
190 
191  charge = hit_r->c + hit_l->c ;
192  if(charge & 0xFFFF0000) { // tooooo big! kill!
193  LOG(ERR,"Merge: charge too big %d %d",hit_r->c, hit_l->c,0,0,0) ;
194  hit_l->c = hit_r->c = 0 ;
195  return 0 ;
196  }
197 
198  // adjust track ids
199  if(hit_r->id_simtrk != hit_l->id_simtrk) {
200  // choose the ID with the larger charge
201  if(hit_r->c > hit_l->c) {
202  hit_l->id_simtrk = hit_r->id_simtrk ;
203  }
204 
205  }
206 
207  // quality is the weighted mean...
208  hit_l->id_quality = (hit_l->id_quality * hit_l->c + hit_r->id_quality * hit_r->c) / charge ;
209 
210 
211  // adjust cluster ids
212  if(hit_r->cl_id != hit_l->cl_id) {
213  hit_l->cl_id = 0xFFFF ; // mark as unknown...
214  }
215 
216  hit_l->tm = (short)((tm[0]*(double)hit_l->c + tm[1]*(double)hit_r->c)/(double)charge) ;
217 
218  tm[0] = (double)hit_l->pad ;
219  tm[1] = (double)hit_r->pad ;
220  hit_l->pad = (short)((tm[0]*(double)hit_l->c + tm[1]*(double)hit_r->c)/(double)charge) ;
221 
222  hit_l->c = charge ;
223  hit_r->c = 0 ; // kill...
224 
225  hit_l->f |= hit_r->f ;
226  hit_l->f &= ~FCF_ONEPAD ; // remove ONEPAD, if any...
227 
228  // adjust maxpad of the left one...
229  hit_l->p2 = hit_r->p2 ;
230 
231  // adjust time extents...
232  if(hit_r->t2 > hit_l->t2) hit_l->t2 = hit_r->t2 ;
233  if(hit_r->t1 < hit_l->t1) hit_l->t1 = hit_r->t1 ;
234 
235 
236  //print_hit("Merged",hit_l) ;
237  return 1 ; // done
238  }
239 
240 
241  return 0 ;
242 }
243 
244 
245 int fcfAfterburner::burn(u_int *ptr_res[3], u_int *ptr_simu_res[3])
246 {
247  u_int i ;
248 
249  last_i = last_n = last_count = last_stage = 0 ; // wrap to the beginning!
250 
251  ptr = ptr_res ; // store arg in member...
252  ptr_simu = ptr_simu_res ;
253 
254  for(i=0;i<3;i++) {
255  if(ptr_res[i]) {
256  row = *ptr_res[i] ; // this should point to "row"
257 
258  if(row < 123) do_swap = 0 ; // same endianes == LOCAL
259  else do_swap = 1 ; // different endianess == SWAP
260 
261  break ; // at least one row
262  }
263  }
264 
265  if(i==3) { // no content
266  row = 0 ;
267  return -1 ;
268  }
269 
270  // get the row + sanity checks
271  row = 123 ;
272  for(i=0;i<3;i++) {
273  if(ptr[i]) {
274  if(row == 123) row = do_swap ? swap32(*ptr[i]) : (*ptr[i]) ;
275  else if(row != (do_swap ? swap32(*ptr[i]) : (*ptr[i]))) {
276  row = 0 ;
277  LOG(ERR,"Corrupted row data pointer %d: is %d expect %d",i,*ptr[i],row,0,0) ;
278  return -1 ;
279  }
280  }
281  }
282 
283 
284  // set the broken edges
285  // 0 signifies none exists...
286  edge[0] = padfinder[row-1][0].maxpad ;
287  edge[1] = padfinder[row-1][1].minpad ;
288  edge[2] = padfinder[row-1][1].maxpad ;
289  edge[3] = padfinder[row-1][2].minpad ;
290 
291  memset(cou_broken,0,sizeof(cou_broken)) ;
292 
293  return 0 ;
294 }
295 
296 int fcfAfterburner::next(fcfHit *h)
297 {
298  // move through (up to) 3 components
299  // and find and tag broken clusters
300  // and output the others at the same time...
301  u_int *res ;
302  u_int *res_sim ;
303 
304  if(row == 0) { // no data to begin with in "burn"
305  return 0 ;
306  }
307 
308  //fprintf(stderr,"stage %d, last_n %d, last_i %d, last_count %d\n",last_stage,last_n,last_i,last_count) ;
309 
310  // where are we?
311  switch(last_stage) {
312  case 0 :
313  goto stage1 ;
314  break ;
315  case 1 :
316  goto stage2 ;
317  break ;
318  case 2 :
319  goto stage3 ;
320  break ;
321  }
322 
323 
324  stage1: ; // the normal clusters + marking of merge candidates...
325  if(last_n >= 3) { // done with stage1
326  goto stage2 ;
327  }
328 
329  res = ptr[last_n] ;
330  if(ptr_simu) {
331  res_sim = ptr_simu[last_n] ;
332  }
333  else {
334  res_sim = 0 ;
335  }
336 
337  if(res == 0) {
338  last_n++ ;
339  last_i = 0 ;
340  goto stage1;
341  }
342 
343  if(last_i == 0) { // need new counters
344  u_int irow = *res++ ;
345  last_count = *res++ ;
346 
347  // need to advance the sim guy as well...
348  if(res_sim) res_sim += 2 ;
349 
350  if(do_swap) {
351  irow = swap32(irow) ;
352  last_count = swap32(last_count) ;
353  }
354 
355  if(irow != row) LOG(ERR,"Row %d and row %d in data don't match!!!",row,irow,0,0,0) ;
356  }
357  else {
358  res += 2 + 2*last_i ;
359  if(res_sim) res_sim += 2 + (sizeof(struct FcfSimOutput)/4)*last_i ;
360  }
361 
362  while(last_i < last_count) {
363 
364  fcfHit hit ;
365  decode(res,&hit,res_sim) ;
366 
367  res += 2 ; // skip to next
368  if(res_sim) {
369  res_sim += (sizeof(struct FcfSimOutput)/4) ;
370  }
371 
372  last_i++ ;
373 
374  if(do_merge && (hit.f & FCF_BROKEN_EDGE)) {
375  int list ;
376 
377  list = -1 ;
378 
379  if(hit.p2 == edge[0]) list = 0 ;
380  else if(hit.p1 == edge[1]) list = 1 ;
381  else if(hit.p2 == edge[2]) list = 2 ;
382  else if(hit.p1 == edge[3]) list = 3 ;
383 
384  if(list >= 0 && cou_broken[list]<kMax_fcfHit) {
385  memcpy(&(broken[list][cou_broken[list]]),&hit,sizeof(hit)) ;
386  cou_broken[list]++ ;
387  //print_hit("Broken",&hit) ;
388  //LOG(NOTE," list %d: %d %d %d %d",list,edge[0],edge[1],edge[2],edge[3]) ;
389  }
390  else { // this happens when the pad width of hit is more than 7 in one direction...
391  LOG(DBG,"Row %d: incorrect edges are %d:%d, %f???",row,hit.p1,hit.p2,(double)hit.pad/64.0+0.5,0) ;
392  LOG(DBG," %d %d %d %d",edge[0],edge[1],edge[2],edge[3],0) ;
393  }
394  }
395  else {
396  if(output(&hit)) {
397  memcpy(h,&hit,sizeof(hit)) ;
398  return 1 ;
399  }
400  }
401  }
402 
403  last_i = 0 ;
404  last_n++ ;
405  goto stage1 ;
406 
407 
408  stage2: ;
409  last_stage = 1 ;
410 
411  if(edge[0] == 0) return 0 ; // non-broken row, no merged found...
412 
413  // If I'm here this means that I'm on a "breakable" row
414  // so let's merge lists 0-1 and 2-3
415  int right ;
416  for(right=0;right<4;right+=2) {
417  u_int i, j ;
418  for(i=0;i<cou_broken[right];i++) {
419  int merged = 0 ;
420  for(j=0;j<cou_broken[right+1];j++) {
421  if(broken[right+1][j].c == 0) continue ; // already merged
422 
423  // check_merge will merge into the first argument and zero out the second...
424  merged = check_merge(&broken[right][i],&broken[right+1][j]) ;
425  if(merged) break ;
426  }
427  }
428  }
429 
430 
431  // output the final resuts
432  last_i = 0 ;
433  last_n = 0 ;
434 
435  stage3: ;
436  last_stage = 2 ;
437 
438  if(last_n >= 4) return 0 ; // done
439  while(last_i<cou_broken[last_n]) {
440  if(output(&broken[last_n][last_i])) {
441  memcpy(h,&broken[last_n][last_i],sizeof(fcfHit)) ;
442  last_i++ ;
443  return 1 ;
444  }
445  last_i++ ;
446  }
447  last_n++ ;
448  last_i = 0 ;
449  goto stage3 ;
450 
451 }
452 
453 /*
454  This function has resursive use of the object.
455  The "p1" data will use the current object while
456  the "p2" data will be placed into a new object...
457 
458  returns # of mismatches
459  0 means match....
460 */
461 int fcfAfterburner::compare(u_int *p1[3], u_int *p2[3])
462 {
463  u_int matched1, count1, count2 ;
464  u_int match ;
465  fcfAfterburner after ;
466  fcfHit h1, h2 ;
467  static u_char marray[2][10000] ; // the size could be a problem!
468  int i ;
469  int ret = 0 ; // return number of mismatches
470  int save_merge, save_cuts ;
471 
472  // save the original steering variables...
473  save_merge = do_merge ;
474  save_cuts = do_cuts ;
475 
476  // ...and reset the merging and cutting to 0 so that we
477  // can compare "raw" data
478 
479  do_merge = do_cuts = 0 ;
480  after.do_merge = after.do_cuts = 0 ;
481 
482  memset(marray,0,sizeof(marray)) ;
483 
484  burn(p1) ;
485  matched1 = count1 = 0 ;
486 
487 
488  while(next(&h1)) {
489 
490  match = 0 ;
491  after.burn(p2) ; // reset!
492 
493  count2 = 0 ;
494  //print_hit("Checking 1",&h1) ;
495  while(after.next(&h2)) {
496  //print_hit(" with",&h2) ;
497  if(marray[1][count2]) {
498  count2++ ;
499  continue ;
500  }
501 
502  if(memcmp(&h1,&h2,sizeof(h1))==0) {
503  marray[1][count2] = 1 ;
504  match = 1 ;
505  break ;
506  }
507  count2++ ;
508  }
509 
510  if(match) {
511  //printf("*MATCH\n") ;
512  marray[0][count1] = 1 ;
513  matched1++ ;
514  }
515  count1++ ;
516  }
517 
518  burn(p1) ;
519  i = 0 ;
520  while(next(&h1)) {
521  if(marray[0][i] == 0) { // unmatched
522 // Tonko: following taken out but left as comments in case we need it
523 // if((h1.f & FCF_BROKEN_EDGE) && h1.c <= 10) {
524 // ;
525 // }
526 // else {
527  {
528  if(verbose) print_hit("UNMATCHED 1",&h1) ;
529  ret++;
530  }
531  }
532  i++ ;
533  }
534 
535  after.burn(p2) ;
536  i = 0 ;
537  while(after.next(&h1)){
538  if(marray[1][i] == 0) { // unmatched
539 // Tonko: following taken out but left as comments in case we need it
540 // if(h1.f & (FCF_DEAD_EDGE | FCF_ROW_EDGE)) {
541 // ;
542 // }
543 // else {
544  {
545  if(verbose) print_hit("UNMATCHED 2",&h1) ;
546  ret++;
547  }
548  }
549  i++ ;
550  }
551 
552  // save the steering before exit!
553  do_cuts = save_cuts ;
554  do_merge = save_merge ;
555  return ret ;
556 }
557