]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RALICE/icepack/iceconvert/IceF2k.cxx
10-aug-2005 NvE AliSignal::GetSignal extended with mode=8 to support dead flag of...
[u/mrichter/AliRoot.git] / RALICE / icepack / iceconvert / IceF2k.cxx
1 /*******************************************************************************
2  * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
3  *
4  * Author: The IceCube RALICE-based Offline Project.
5  * Contributors are mentioned in the code where appropriate.
6  *
7  * Permission to use, copy, modify and distribute this software and its
8  * documentation strictly for non-commercial purposes is hereby granted
9  * without fee, provided that the above copyright notice appears in all
10  * copies and that both the copyright notice and this permission notice
11  * appear in the supporting documentation.
12  * The authors make no claims about the suitability of this software for
13  * any purpose. It is provided "as is" without express or implied warranty.
14  *******************************************************************************/
15
16 // $Id$
17
18 ///////////////////////////////////////////////////////////////////////////
19 // Class IceF2k
20 // Conversion of Amanda F2K data into IceEvent physics event structures.
21 // This class is derived from AliJob providing a task-based processing
22 // structure on an event-by-event basis.
23 // The main object in the job environment is an IceEvent* pointer.
24 // In case the user has provided sub-tasks, these will be executed
25 // on an event-by-event basis after the IceEvent structure has been filled
26 // with the F2K data and before the final structures are written out.
27 // Note that the data structures are only written out if an outputfile has
28 // been specified via the SetOutputFile memberfunction.
29 // In case no outputfile has been specified, this class provides a facility
30 // to investigate/analyse F2K data using the Ralice/IcePack analysis tools. 
31 //
32 // Usage example :
33 // ---------------
34 //
35 // gSystem->Load("ralice");
36 // gSystem->Load("icepack");
37 // gSystem->Load("iceconvert");
38 //
39 // IceF2k q("IceF2k","F2K to IcePack data structure conversion");
40 //
41 // // Limit the number of entries for testing
42 // q.SetMaxEvents(10);
43 //
44 // // Print frequency to produce a short summary print every printfreq events
45 // q.SetPrintFreq(1);
46 //
47 // // Split level for the output structures
48 // q.SetSplitLevel(2);
49 //
50 // // Buffer size for the output structures
51 // q.SetBufferSize(32000);
52 //
53 // // The F2K input filename
54 // q.SetInputFile("run7825.f2k");
55 //
56 // // Output file for the event structures
57 // TFile* ofile=new TFile("events.root","RECREATE","F2K data in IceEvent structure");
58 // q.SetOutputFile(ofile);
59 //
60 // ///////////////////////////////////////////////////////////////////
61 // // Here the user can specify his/her sub-tasks to be executed
62 // // on an event-by-event basis after the IceEvent structure
63 // // has been filled and before the data is written out.
64 // // Sub-tasks (i.e. a user classes derived from TTask) are entered
65 // // as follows :
66 // //
67 // //    MyXtalk task1("task1","Cross talk correction");
68 // //    MyClean task2("task2","Hit cleaning");
69 // //    q.Add(&task1);
70 // //    q.Add(&task2);
71 // //
72 // // The sub-tasks will be executed in the order as they are entered.
73 // ///////////////////////////////////////////////////////////////////
74 //
75 // // Perform the conversion and execute subtasks (if any)
76 // // on an event-by-event basis
77 // q.ExecuteJob();
78 //
79 // // Select various objects to be added to the output file
80 //
81 // ofile->cd(); // Switch to the output file directory
82 //
83 // AliObjMatrix* omdb=q.GetOMdbase();
84 // if (omdb) omdb->Write();
85 //
86 // AliDevice* fitdefs=q.GetFitdefs();
87 // if (fitdefs) fitdefs->Write();
88 //
89 // TDatabasePDG* pdg=q.GetPDG();
90 // if (pdg) pdg->Write();
91 //
92 // // Flush the output file.
93 // // The output file is not explicitly closed here
94 // // to allow ineractive investigation of the data tree
95 // // when this macro is run in an interactive ROOT/CINT session.
96 // ofile->Write();
97 //
98 //--- Author: Nick van Eijndhoven 11-mar-2005 Utrecht University
99 //- Modified: NvE $Date$ Utrecht University
100 ///////////////////////////////////////////////////////////////////////////
101  
102 #include "IceF2k.h"
103 #include "Riostream.h"
104
105 ClassImp(IceF2k) // Class implementation to enable ROOT I/O
106
107 IceF2k::IceF2k(const char* name,const char* title) : AliJob(name,title)
108 {
109 // Default constructor.
110 // By default maxevent=-1, split=99, bsize=32000, printfreq=1.
111
112  fSplit=99;
113  fBsize=32000;
114  fMaxevt=-1;
115  fPrintfreq=1;
116  fInfile="";
117  fOutfile=0;
118
119  fPdg=0;
120  fOmdb=0;
121  fFitdefs=0;
122 }
123 ///////////////////////////////////////////////////////////////////////////
124 IceF2k::~IceF2k()
125 {
126 // Default destructor.
127
128  if (fPdg)
129  {
130   delete fPdg;
131   fPdg=0;
132  }
133
134  if (fOmdb)
135  {
136   delete fOmdb;
137   fOmdb=0;
138  }
139
140  if (fFitdefs)
141  {
142   delete fFitdefs;
143   fFitdefs=0;
144  }
145 }
146 ///////////////////////////////////////////////////////////////////////////
147 void IceF2k::SetMaxEvents(Int_t n)
148 {
149 // Set the maximum number of events to be processed.
150 // n=-1 implies processing of the complete input file, which is the default
151 // initialisation in the constructor.
152  fMaxevt=n;
153 }
154 ///////////////////////////////////////////////////////////////////////////
155 void IceF2k::SetPrintFreq(Int_t f)
156 {
157 // Set the printfrequency to produce info every f events.
158 // f=1 is the default initialisation in the constructor.
159  if (f>=0) fPrintfreq=f;
160 }
161 ///////////////////////////////////////////////////////////////////////////
162 void IceF2k::SetSplitLevel(Int_t split)
163 {
164 // Set the split level for the ROOT data file.
165 // split=99 is the default initialisation in the constructor.
166  if (split>=0) fSplit=split;
167 }
168 ///////////////////////////////////////////////////////////////////////////
169 void IceF2k::SetBufferSize(Int_t bsize)
170 {
171 // Set the buffer size for the ROOT data file.
172 // bsize=32000 is the default initialisation in the constructor.
173  if (bsize>=0) fBsize=bsize;
174 }
175 ///////////////////////////////////////////////////////////////////////////
176 void IceF2k::SetInputFile(TString name)
177 {
178 // Set the name of the F2K input file.
179  fInfile=name;
180 }
181 ///////////////////////////////////////////////////////////////////////////
182 void IceF2k::SetOutputFile(TFile* ofile)
183 {
184 // Set the output file for the ROOT data.
185  fOutfile=ofile;
186 }
187 ///////////////////////////////////////////////////////////////////////////
188 TDatabasePDG* IceF2k::GetPDG()
189 {
190 // Provide pointer to the PDG database
191  return fPdg;
192 }
193 ///////////////////////////////////////////////////////////////////////////
194 AliObjMatrix* IceF2k::GetOMdbase()
195 {
196 // Provide pointer to the OM geometry, calib. etc... database
197  return fOmdb;
198 }
199 ///////////////////////////////////////////////////////////////////////////
200 AliDevice* IceF2k::GetFitdefs()
201 {
202 // Provide pointer to the fit definitions
203  return fFitdefs;
204 }
205 ///////////////////////////////////////////////////////////////////////////
206 void IceF2k::Exec(Option_t* opt)
207 {
208 // Job to loop over the specified number of events and convert the 
209 // F2K data into the IceEvent structure.
210 // If maxevents<0 (default) all the entries of the input file
211 // will be processed.
212 // Every "printfreq" events a short event summary will be printed.
213 // The default value is printfreq=1.
214 // The output will be written on a standard output tree named "T".
215 //
216 // Notes :
217 // -------
218 // 1) This class is derived from AliJob, allowing a task based processing.
219 //    After the conversion of an F2K event into an IceEvent structure,
220 //    the processing of all available sub-tasks (if any) is invoked.
221 //    This provides an event-by-event (sub)task processing before the
222 //    final data structures are written out.
223 // 2) The main object in this job environment is an IceEvent* pointer.
224
225  if (fInfile=="")
226  {
227   cout << " *IceF2k Exec* No data input file specified." << endl;
228   return;
229  }
230
231  // Open the input file in the default ascii format (autodetection) for reading 
232  fInput=rdmc_mcopen(fInfile.Data(),"r",RDMC_DEFAULT_ASCII_F);
233
234  if (!fInput)
235  {
236   cout << " *IceF2k Exec* No input file found with name : " << fInfile.Data() << endl;
237   return;
238  }
239
240  // Initialise the event structure 
241  rdmc_init_mevt(&fEvent);
242
243  // Read the file header information
244  rdmc_rarr(fInput,&fHeader);
245
246  TTree* otree=0;
247  if (fOutfile)
248  {
249   otree=new TTree("T","F2K Data converted to IceEvent structures");
250   otree->SetDirectory(fOutfile);
251  }
252
253  IceEvent* evt=new IceEvent();
254  evt->SetTrackCopy(1);
255  evt->SetDevCopy(1);
256
257  // Branch in the tree for the event structure
258  if (otree) otree->Branch("IceEvent","IceEvent",&evt,fBsize,fSplit); 
259
260  // Create the particle database and extend it with some F2000 specific definitions
261  if (!fPdg) fPdg=new TDatabasePDG();
262  Double_t me=fPdg->GetParticle(11)->Mass();
263  fPdg->AddParticle("brems"   ,"brems"   ,0,1,0,0,"none",10001001,0,0);
264  fPdg->AddParticle("deltae"  ,"deltae"  ,me,1,0,-3,"Lepton",10001002,0,0);
265  fPdg->AddParticle("pairprod","pairprod",0,1,0,0,"none",10001003,0,0);
266  fPdg->AddParticle("nucl_int","nucl_Int",0,1,0,0,"none",10001004,0,0);
267  fPdg->AddParticle("mu_pair" ,"mu_pair" ,0,1,0,0,"none",10001005,0,0);
268  fPdg->AddParticle("hadrons" ,"hadrons" ,0,1,0,0,"none",10001006,0,0);
269  fPdg->AddParticle("fiberlaser","fiberlaser",0,1,0,0,"none",10002100,0,0);
270  fPdg->AddParticle("n2laser"   ,"n2laser"   ,0,1,0,0,"none",10002101,0,0);
271  fPdg->AddParticle("yaglaser"  ,"yaglaser"  ,0,1,0,0,"none",10002201,0,0);
272  fPdg->AddParticle("z_primary","z_primary",0,1,0,0,"none",10003000,0,0);
273  fPdg->AddParticle("a_primary","a_primary",0,1,0,0,"none",10003500,0,0);
274
275  // Fill the database with geometry, calib. etc... parameters
276  // for all the devices
277  FillOMdbase();
278
279  // Set the fit definitions according to the F2000 header info
280  SetFitdefs();
281
282  // Initialise the job working environment
283  SetMainObject(evt);
284  if (fOutfile)
285  {
286   AddObject(fOutfile);
287   AddObject(otree);
288  }
289
290  cout << " ***" << endl;
291  cout << " *** Start processing of job " << GetName() << " ***" << endl;
292  cout << " ***" << endl;
293  cout << " F2K input file : " << fInfile.Data() << endl;
294  cout << " Maximum number of events to be processed : " << fMaxevt << endl;
295  cout << " Print frequency : " << fPrintfreq << endl;
296  if (fOutfile)
297  {
298   cout << " ROOT output file : " << fOutfile->GetName() << endl;
299   cout << " Output characteristics : splitlevel = " << fSplit << " buffersize = " << fBsize << endl;
300  }
301
302  ListEnvironment();
303  
304  Int_t nevt=0;
305  while (!rdmc_revt(fInput,&fHeader,&fEvent))
306  {
307   if (fMaxevt>-1 && nevt>=fMaxevt) break;
308
309   // Reset the complete Event structure
310   evt->Reset();
311
312   evt->SetRunNumber(fEvent.nrun);
313   evt->SetEventNumber(fEvent.enr);
314   evt->SetMJD(fEvent.mjd,fEvent.secs,fEvent.nsecs);
315
316   PutMcTracks();
317
318   PutRecoTracks();
319
320   PutHits();
321
322   // Invoke all available sub-tasks (if any)
323   ExecuteTasks(opt);
324
325   if (fPrintfreq)
326   {
327    if (!(nevt%fPrintfreq)) evt->HeaderData();
328   }
329
330   // Write the complete structure to the output Tree
331   if (otree) otree->Fill();
332
333   // Update event counter
334   nevt++;
335  }
336
337  // Remove the IceEvent object from the environment
338  // and delete it as well
339  if (evt)
340  {
341   RemoveObject(evt);
342   delete evt;
343  }
344 }
345 ///////////////////////////////////////////////////////////////////////////
346 void IceF2k::FillOMdbase()
347 {
348 // Fill the database with geometry, calib. etc... parameters 
349 // for all the devices.
350
351  if (fHeader.nch<=0) return;
352
353  Int_t geocal=fHeader.is_calib.geo;
354  Int_t adccal=fHeader.is_calib.adc;
355  Int_t tdccal=fHeader.is_calib.tdc;
356  Int_t totcal=fHeader.is_calib.tot;
357  Int_t utccal=fHeader.is_calib.utc;
358
359  TF1 fadccal("fadccal","(x-[1])*[0]");
360  TF1 fadcdecal("fadcdecal","(x/[0])+[1]");
361  fadccal.SetParName(0,"BETA-ADC");
362  fadccal.SetParName(1,"PED-ADC");
363  fadcdecal.SetParName(0,"BETA-ADC");
364  fadcdecal.SetParName(1,"PED-ADC");
365
366  TF1 ftdccal("ftdccal","(x*[0])-[1]-([0]-1.)*32767.-[2]/sqrt([3])");
367  TF1 ftdcdecal("ftdcdecal","(x+([0]-1.)*32767.+[1]+[2]/sqrt([3]))/[0]");
368  ftdccal.SetParName(0,"BETA-TDC");
369  ftdccal.SetParName(1,"T0");
370  ftdccal.SetParName(2,"ALPHA-TDC");
371  ftdccal.SetParName(3,"ADC-SLEW");
372  ftdcdecal.SetParName(0,"BETA-TDC");
373  ftdcdecal.SetParName(1,"T0");
374  ftdcdecal.SetParName(2,"ALPHA-TDC");
375  ftdcdecal.SetParName(3,"ADC-SLEW");
376
377  TF1 ftotcal("ftotcal","x*[0]");
378  TF1 ftotdecal("ftotdecal","x/[0]");
379  ftotcal.SetParName(0,"BETA-TOT");
380  ftotdecal.SetParName(0,"BETA-TOT");
381
382  if (fOmdb)
383  {
384   fOmdb->Reset();
385  }
386  else
387  {
388   fOmdb=new AliObjMatrix();
389   fOmdb->SetNameTitle("OMDBASE","The OM geometry, calib. etc... database");
390   fOmdb->SetOwner();
391  }
392
393  IceAOM* dev=0;
394  Double_t pos[3]={0,0,0};
395  for (Int_t i=0; i<fHeader.nch; i++)
396  {
397   dev=new IceAOM();
398   dev->SetUniqueID(i+1);
399
400   dev->SetSlotName("ADC",1);
401   dev->SetSlotName("LE",2);
402   dev->SetSlotName("TOT",3);
403
404   dev->SetSlotName("TYPE",4);
405   dev->SetSlotName("ORIENT",5);
406   dev->SetSlotName("THRESH",6);
407   dev->SetSlotName("SENSIT",7);
408   dev->SetSlotName("BETA-TDC",8);
409   dev->SetSlotName("T0",9);
410   dev->SetSlotName("ALPHA-TDC",10);
411   dev->SetSlotName("PED-ADC",11);
412   dev->SetSlotName("BETA-ADC",12);
413   dev->SetSlotName("KAPPA-ADC",13);
414   dev->SetSlotName("PED-TOT",14);
415   dev->SetSlotName("BETA-TOT",15);
416   dev->SetSlotName("KAPPA-TOT",16);
417
418   pos[0]=fHeader.x[i];
419   pos[1]=fHeader.y[i];
420   pos[2]=fHeader.z[i];
421   dev->SetPosition(pos,"car");
422
423   fadccal.SetParameter(0,fHeader.cal[i].beta_a);
424   fadccal.SetParameter(1,fHeader.cal[i].ped);
425   fadcdecal.SetParameter(0,fHeader.cal[i].beta_a);
426   if (!fHeader.cal[i].beta_a) fadcdecal.SetParameter(0,1);
427   fadcdecal.SetParameter(1,fHeader.cal[i].ped);
428
429   ftdccal.SetParameter(0,fHeader.cal[i].beta_t);
430   ftdccal.SetParameter(1,fHeader.cal[i].t_0);
431   ftdccal.SetParameter(2,fHeader.cal[i].alpha_t);
432   ftdccal.SetParameter(3,1.e20);
433   ftdcdecal.SetParameter(0,fHeader.cal[i].beta_t);
434   if (!fHeader.cal[i].beta_t) ftdcdecal.SetParameter(0,1);
435   ftdcdecal.SetParameter(1,fHeader.cal[i].t_0);
436   ftdcdecal.SetParameter(2,fHeader.cal[i].alpha_t);
437   ftdcdecal.SetParameter(3,1.e20);
438
439   ftotcal.SetParameter(0,fHeader.cal[i].beta_tot);
440   ftotdecal.SetParameter(0,fHeader.cal[i].beta_tot);
441   if (!fHeader.cal[i].beta_tot) ftotdecal.SetParameter(0,1);
442
443   if (adccal)
444   {
445    dev->SetDecalFunction(&fadcdecal,1);
446   }
447   else
448   {
449    dev->SetCalFunction(&fadccal,1);
450   }
451
452   if (tdccal)
453   {
454    dev->SetDecalFunction(&ftdcdecal,2);
455   }
456   else
457   {
458    dev->SetCalFunction(&ftdccal,2);
459   }
460
461   if (totcal)
462   {
463    dev->SetDecalFunction(&ftotdecal,3);
464   }
465   else
466   {
467    dev->SetCalFunction(&ftotcal,3);
468   }
469
470   dev->SetSignal(fHeader.type[i],4);
471   dev->SetSignal((Float_t)fHeader.costh[i],5);
472   dev->SetSignal(fHeader.thresh[i],6);
473   dev->SetSignal(fHeader.sensit[i],7);
474   dev->SetSignal(fHeader.cal[i].beta_t,8);
475   dev->SetSignal(fHeader.cal[i].t_0,9);
476   dev->SetSignal(fHeader.cal[i].alpha_t,10);
477   dev->SetSignal(fHeader.cal[i].ped,11);
478   dev->SetSignal(fHeader.cal[i].beta_a,12);
479   dev->SetSignal(fHeader.cal[i].kappa,13);
480   dev->SetSignal(fHeader.cal[i].ped_tot,14);
481   dev->SetSignal(fHeader.cal[i].beta_tot,15);
482   dev->SetSignal(fHeader.cal[i].kappa_tot,16);
483
484   fOmdb->EnterObject(i+1,1,dev);
485  }
486 }
487 ///////////////////////////////////////////////////////////////////////////
488 void IceF2k::SetFitdefs()
489 {
490 // Obtain the names of the variables for each fit procedure from the
491 // f2000 header. Each different fit procedure is then stored as a separate
492 // hit of an AliDevice object and the various fit variables are stored
493 // as separate signal slots of the corresponding hit.
494 // Via the GetFitdefs() memberfunction this AliDevice object can be
495 // retrieved and stored in the ROOT output file if wanted.
496 // The name of the object is FitDefinitions and the stored data can be
497 // inspected via the AliDevice::Data() memberfunction and looks as follows :
498 //
499 //  *AliDevice::Data* Id :0 Name : FitDefinitions
500 //    Position Vector in car coordinates : 0 0 0
501 //    Err. in car coordinates : 0 0 0
502 //  The following 8 hits are registered :
503 //  *AliSignal::Data* Id :0
504 //    Position Vector in car coordinates : 0 0 0
505 //    Err. in car coordinates : 0 0 0
506 //    Owned by device : AliDevice Name : FitDefinitions
507 //    Slot : 1 Signal value : 1 name : id
508 //    Slot : 2 Signal value : 2 name : rchi2
509 //    Slot : 3 Signal value : 3 name : prob
510 //    Slot : 4 Signal value : 4 name : sigth
511 //    Slot : 5 Signal value : 5 name : covmin
512 //    Slot : 6 Signal value : 6 name : covmax
513 //    Slot : 7 Signal value : 7 name : cutflag
514 //    Slot : 8 Signal value : 8 name : chi2
515 //  *AliSignal::Data* Id :1
516 //    Position Vector in car coordinates : 0 0 0
517 //    Err. in car coordinates : 0 0 0
518 //    Owned by device : AliDevice Name : FitDefinitions
519 //    Slot : 1 Signal value : 1 name : id
520 //    Slot : 2 Signal value : 2 name : rchi2
521 //    Slot : 3 Signal value : 3 name : prob
522 // etc....  
523 //
524 // This memberfunction is based on the original idea/code by Adam Bouchta.
525
526  if (fHeader.n_fit<=0) return;
527
528  if (fFitdefs)
529  {
530   fFitdefs->Reset(1);
531  }
532  else
533  {
534   fFitdefs=new AliDevice();
535  }
536
537  fFitdefs->SetName("FitDefinitions");
538  fFitdefs->SetHitCopy (1);
539
540  AliSignal s;
541  s.Reset();
542
543  for (Int_t i=0; i<fHeader.n_fit; i++)
544  {
545   s.SetUniqueID(fHeader.def_fit[i].id);
546
547   for (Int_t j=0; j<fHeader.def_fit[i].nwords; j++)
548   {
549    s.SetSlotName(TString(fHeader.def_fit[i].words[j]),j+1);
550    s.SetSignal(j+1,j+1);
551   }
552
553   fFitdefs->AddHit(s);
554   s.Reset(1);
555  }
556 }
557 ///////////////////////////////////////////////////////////////////////////
558 void IceF2k::PutMcTracks()
559 {
560 // Get the MC tracks from the F2000 file into the IcePack structure.
561 // Note : MC tracks are given negative track id's in the event structure.
562 // This memberfunction is based on the original code by Adam Bouchta.
563
564  IceEvent* evt=(IceEvent*)GetMainObject();
565  if (!evt || fEvent.ntrack<=0) return;
566
567  // Loop over all the tracks and add them to the current event
568  AliTrack t;
569  Double_t vec[3];
570  AliPosition r;
571  Ali3Vector p;
572  Int_t tid=0;
573  Int_t idpdg=0;
574  Int_t idf2k=0;
575  for (Int_t i=0; i<fEvent.ntrack; i++)
576  {
577   t.Reset ();
578
579   // Beginpoint of the track
580   vec[0]=fEvent.gen[i].x;
581   vec[1]=fEvent.gen[i].y;
582   vec[2]=fEvent.gen[i].z;
583   r.SetPosition(vec,"car");
584   t.SetBeginPoint(r);
585
586   // Endpoint of the track
587   vec[0]+=fEvent.gen[i].length*fEvent.gen[i].px;
588   vec[1]+=fEvent.gen[i].length*fEvent.gen[i].py;
589   vec[2]+=fEvent.gen[i].length*fEvent.gen[i].pz;
590   r.SetPosition(vec,"car");
591   t.SetEndPoint(r);
592
593   // Momentum in GeV/c
594   vec[0]=fEvent.gen[i].e*fEvent.gen[i].px*1e-3;
595   vec[1]=fEvent.gen[i].e*fEvent.gen[i].py*1e-3;
596   vec[2]=fEvent.gen[i].e*fEvent.gen[i].pz*1e-3;
597   p.SetVector (vec,"car");
598   t.Set3Momentum(p);
599
600   // MC tracks are indicated by negative track id's
601   tid=fEvent.gen[i].tag;
602   t.SetId(-abs(tid));
603
604   idf2k=fEvent.gen[i].id;
605   idpdg=0;
606   if (idf2k>1000)
607   {
608    idpdg=idf2k+10000000;
609   }
610   else if (idf2k <= 48)
611   {
612    idpdg=fPdg->ConvertGeant3ToPdg(idf2k);
613   }
614   else
615   {
616    if (idf2k==201) idpdg=12;
617    if (idf2k==202) idpdg=14;
618    if (idf2k==203) idpdg=16;
619    if (idf2k==204) idpdg=-12;
620    if (idf2k==205) idpdg=-14;
621    if (idf2k==206) idpdg=-16;
622   }
623
624   t.SetParticleCode(idpdg);
625   t.SetName(fPdg->GetParticle(idpdg)->GetName());
626   t.SetTitle("MC track");
627   t.SetMass(fPdg->GetParticle(idpdg)->Mass());
628   t.SetCharge(fPdg->GetParticle(idpdg)->Charge()/3.);
629
630   evt->AddTrack(t);
631  }
632
633  // Create the pointers to each particle's parent particle.
634  Int_t txid=0;
635  Int_t parid=0;
636  for (Int_t itk=1; itk<=evt->GetNtracks (); itk++)
637  {
638   AliTrack* tx=evt->GetTrack(itk);
639
640   if (!tx) continue;
641
642   txid=tx->GetId();
643
644   parid=-1;
645   for (Int_t j=0; j<fEvent.ntrack; j++)
646   {
647    tid=fEvent.gen[j].tag;
648    if (-abs(tid) == txid) parid=fEvent.gen[j].parent;
649   }
650
651   if (parid<0) continue;
652
653   AliTrack* tpar=evt->GetIdTrack(-abs(parid));
654
655   if (!tpar) continue;
656
657   tx->SetParentTrack(tpar);
658  }
659 }
660 ///////////////////////////////////////////////////////////////////////////
661 void IceF2k::PutRecoTracks()
662 {
663 // Get the reconstructed tracks from the F2000 file into the IcePack structure.
664 // Note : Reco tracks are given positive track id's in the event structure.
665 // This memberfunction is based on the original code by Adam Bouchta.
666
667  IceEvent* evt=(IceEvent*)GetMainObject();
668  if (!evt || fEvent.nfit<=0) return;
669
670  // Loop over all the tracks and add them to the current event
671  AliTrack t;
672  Double_t vec[3];
673  AliPosition r;
674  Ali3Vector p;
675  Int_t tid=0;
676  Int_t idpdg=0;
677  Int_t idf2k=0;
678  for (Int_t i=0; i<fEvent.nfit; i++)
679  {
680   t.Reset ();
681
682   // Beginpoint of the track
683   vec[0]=fEvent.rec[i].x;
684   vec[1]=fEvent.rec[i].y;
685   vec[2]=fEvent.rec[i].z;
686   r.SetPosition(vec,"car");
687   t.SetBeginPoint(r);
688
689   // Endpoint of the track
690   vec[0]+=fEvent.rec[i].length*fEvent.rec[i].px;
691   vec[1]+=fEvent.rec[i].length*fEvent.rec[i].py;
692   vec[2]+=fEvent.rec[i].length*fEvent.rec[i].pz;
693   r.SetPosition(vec,"car");
694   t.SetEndPoint(r);
695
696   // Momentum in GeV/c
697   if (fEvent.rec[i].e > 0)
698   {
699    vec[0]=fEvent.rec[i].e*fEvent.rec[i].px*1e-3;
700    vec[1]=fEvent.rec[i].e*fEvent.rec[i].py*1e-3;
701    vec[2]=fEvent.rec[i].e*fEvent.rec[i].pz*1e-3;
702   }
703   else // Give the track a nominal momentum of 1 GeV/c
704   {
705    vec[0]=fEvent.rec[i].px;
706    vec[1]=fEvent.rec[i].py;
707    vec[2]=fEvent.rec[i].pz;
708   }
709   p.SetVector (vec,"car");
710   t.Set3Momentum(p);
711
712   // Use the fit number as track id
713   tid=fEvent.rec[i].tag;
714   t.SetId(abs(tid));
715
716   idf2k=fEvent.rec[i].id;
717   idpdg=0;
718   if (idf2k>1000)
719   {
720    idpdg=idf2k+10000000;
721   }
722   else if (idf2k <= 48)
723   {
724    idpdg=fPdg->ConvertGeant3ToPdg(idf2k);
725   }
726   else
727   {
728    if (idf2k==201) idpdg=12;
729    if (idf2k==202) idpdg=14;
730    if (idf2k==203) idpdg=16;
731    if (idf2k==204) idpdg=-12;
732    if (idf2k==205) idpdg=-14;
733    if (idf2k==206) idpdg=-16;
734   }
735
736   t.SetParticleCode(idpdg);
737   t.SetName(fPdg->GetParticle(idpdg)->GetName());
738   t.SetTitle("RECO track");
739   t.SetMass(fPdg->GetParticle(idpdg)->Mass());
740   t.SetCharge(fPdg->GetParticle(idpdg)->Charge()/3.);
741
742   // Retrieve the various fit parameters for this track
743   AliSignal* fitdata=fFitdefs->GetIdHit(i);
744   for (Int_t jval=0; jval<fEvent.fresult[i].nval; jval++)
745   {
746    fitdata->SetSignal(fEvent.fresult[i].val[jval],jval+1);
747   }
748
749   // Store the various fit parameters for this track
750   t.SetFitDetails(fitdata);
751
752   // Store the various reco tracks as track hypotheses.
753   // A copy of the first reco track is entered as a new track instance
754   // into the event and all reco tracks (incl. the first one) are
755   // stored as hypotheses linked to this new reco track.
756   if (i==0)
757   {
758    evt->AddTrack(t);
759    AliTrack* tx=evt->GetTrack(evt->GetNtracks());
760    Int_t nrec=evt->GetNtracks(1);
761    tx->SetId(nrec+1);
762   }
763   AliTrack* tx=evt->GetTrack(evt->GetNtracks());
764   if (tx) tx->AddTrackHypothesis(t);
765  }
766 }
767 ///////////////////////////////////////////////////////////////////////////
768 void IceF2k::PutHits()
769 {
770 // Get the hit and waveform info from the F2000 file into the IcePack structure.
771 // This memberfunction is based on the original code by Adam Bouchta.
772
773  IceEvent* evt=(IceEvent*)GetMainObject();
774  if (!evt) return;
775
776  // Loop over all the hits and add them to the current event
777  IceAOM om;
778  AliSignal s;
779  s.SetSlotName("ADC",1);
780  s.SetSlotName("LE",2);
781  s.SetSlotName("TOT",3);
782  Int_t chan=0;
783  Int_t maxchan=800;
784  if (fOmdb) maxchan=fHeader.nch;
785  IceAOM* omx=0;
786  AliSignal* sx=0;
787  Int_t tid=0;
788  AliTrack* tx=0;
789  Float_t adc=0;
790  for (Int_t i=0; i<fEvent.nhits; i++)
791  {
792   chan=fEvent.h[i].ch+1;
793   if (chan>maxchan) continue; // Channels 9001, 9002 etc are trigger channels
794
795   // Get corresponding device from the current event structure  
796   omx=(IceAOM*)evt->GetIdDevice(chan);
797   if (!omx)
798   {
799    if (fOmdb)
800    {
801     omx=(IceAOM*)fOmdb->GetObject(chan,1);
802     evt->AddDevice(omx);
803    }
804    else
805    {
806     om.Reset(1);
807     om.SetUniqueID(chan);
808     evt->AddDevice(om);
809    }
810    omx=(IceAOM*)evt->GetIdDevice(chan);
811   }
812
813   if (!omx) continue;
814
815   s.Reset();
816   s.SetUniqueID(fEvent.h[i].id);
817   s.SetSignal(fEvent.h[i].amp,1);
818   s.SetSignal(fEvent.h[i].t,2);
819   s.SetSignal(fEvent.h[i].tot,3);
820
821   omx->AddHit(s);
822
823   sx=omx->GetHit(omx->GetNhits());
824   if (!sx) continue;
825
826   // ADC dependent TDC (de)calibration function for this hit
827   TF1* fcal=omx->GetCalFunction("LE");
828   TF1* fdecal=omx->GetDecalFunction("LE");
829   if (fcal) sx->SetCalFunction(fcal,2);
830   if (fdecal) sx->SetDecalFunction(fdecal,2);
831   fcal=sx->GetCalFunction(2);
832   fdecal=sx->GetDecalFunction(2);
833   adc=sx->GetSignal(1,-4);
834   if (adc>0)
835   {
836    if (fcal) fcal->SetParameter(3,adc);
837    if (fdecal) fdecal->SetParameter(3,adc);
838   }
839   else
840   {
841    if (fcal) fcal->SetParameter(3,0);
842    if (fdecal) fdecal->SetParameter(3,0);
843   }
844
845   // Bi-directional link between this hit and the track that caused the ADC value.
846   // This F2K info is probably only present for MC tracks.
847   tid=fEvent.h[i].ma;
848   if (tid > 0)
849   {
850    tx=evt->GetIdTrack(tid); // Reco tracks
851    if (!tx) tx=evt->GetIdTrack(-tid); // MC tracks
852    if (tx) sx->AddLink(tx);
853   }
854   else
855   {
856    if (tid == -2) s.SetNameTitle("N","Noise");
857    if (tid == -3) s.SetNameTitle("A","Afterpulse");
858   }
859  }
860
861  // Loop over all the waveforms and add the histo(s) to the corresponding OM's
862  TH1F histo;
863  Int_t nbins=0;
864  Float_t xlow=0;
865  Float_t xup=0;
866  TString hname;
867  for (Int_t iwf=0; iwf<fEvent.nwf; iwf++)
868  {
869   chan=fEvent.wf[iwf].om;
870   if (chan<=0 || chan>maxchan) continue; // Skip trigger channels
871
872   // Get corresponding device from the current event structure  
873   omx=(IceAOM*)evt->GetIdDevice(chan);
874   if (!omx)
875   {
876    if (fOmdb)
877    {
878     omx=(IceAOM*)fOmdb->GetObject(chan,1);
879     evt->AddDevice(omx);
880    }
881    else
882    {
883     om.Reset(1);
884     om.SetUniqueID(chan);
885     evt->AddDevice(om);
886    }
887    omx=(IceAOM*)evt->GetIdDevice(chan);
888   }
889
890   if (!omx) continue;
891
892   omx->SetSlotName("BASELINE",omx->GetNnames()+1);
893   omx->SetSignal(fEvent.wf[iwf].baseline,"BASELINE");
894
895   // Fill the waveform histogram
896   hname="OM";
897   hname+=chan;
898   hname+="-WF";
899   hname+=omx->GetNwaveforms()+1;
900
901   histo.Reset();
902   histo.SetName(hname.Data());
903   nbins=fEvent.wf[iwf].ndigi;
904   xlow=fEvent.wf[iwf].t_start;
905   xup=xlow+float(nbins)*fEvent.wf[iwf].t_bin;
906   histo.SetBins(nbins,xlow,xup);
907
908   for (Int_t jbin=1; jbin<=fEvent.wf[iwf].ndigi; jbin++)
909   {
910    histo.SetBinContent(jbin,fEvent.wf[iwf].digi[jbin-1]);
911   }
912
913   omx->SetWaveform(&histo,omx->GetNwaveforms()+1);
914  }
915
916  // Set bi-directional links between hits and reco track hypotheses.
917  // Note : Reco tracks are recognised by their positive id.
918  Int_t hid=0;
919  TObjArray* rectracks=evt->GetTracks(1);
920  for (Int_t jtk=0; jtk<rectracks->GetEntries(); jtk++)
921  {
922   tx=(AliTrack*)rectracks->At(jtk);
923   if (!tx) continue;
924   
925   for (Int_t jhyp=1; jhyp<=tx->GetNhypotheses(); jhyp++)
926   {
927    AliTrack* hypx=tx->GetTrackHypothesis(jhyp);
928    if (!hypx) continue;
929
930    // Loop over all combinations of F2K fits and used OM hits
931    for (Int_t k=0; k<fEvent.nfit_uses; k++)
932    {
933     if (fEvent.fit_uses[k].useid != hypx->GetId()) continue;
934     hid=fEvent.fit_uses[k].hitid;
935     sx=evt->GetIdHit(hid,"IceAOM");
936     if (sx) sx->AddLink(hypx);
937    }
938   }
939  }
940 }
941 ///////////////////////////////////////////////////////////////////////////