1 /*******************************************************************************
2 * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
4 * Author: The IceCube RALICE-based Offline Project.
5 * Contributors are mentioned in the code where appropriate.
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 *******************************************************************************/
18 ///////////////////////////////////////////////////////////////////////////
20 // Conversion of simple Root data into IceEvent data structures.
21 // This class reads data from the simple Root files as output by the
22 // original version of Martijn Duvoort's Walnut analyser.
23 // This class is only retained for backward compatibility. For output from
24 // newer versions of the Walnut analyser, use IceRoot.
25 // An indication of the active DAQ system is available in the IceEvent structure
26 // via a device named "Daq". Here the various daq systems (TWR, Muon, ...)
27 // from which the actual hits (ADC, LE, TOT) eventually will be composed
28 // are indicated as "signals" of the device itself.
29 // This class is derived from AliJob providing a task-based processing
30 // structure on an event-by-event basis.
31 // The main object in the job environment is an IceEvent* pointer.
32 // In case the user has provided sub-tasks, these will be executed
33 // on an event-by-event basis after the IceEvent structure has been filled
34 // with the simple Root data and before the final structures are written out.
35 // Note that the data structures are only written out if an outputfile has
36 // been specified via the SetOutputFile memberfunction.
37 // In case no outputfile has been specified, this class provides a facility
38 // to investigate/analyse simple Root data using the Ralice/IcePack analysis tools.
43 // gSystem->Load("ralice");
44 // gSystem->Load("icepack");
45 // gSystem->Load("iceconvert");
47 // IceRootx q("IceRootx","Simple Root data to IcePack data structure conversion");
49 // // Limit the number of entries for testing
50 // q.SetMaxEvents(10);
52 // // Print frequency to produce a short summary print every printfreq events
55 // // The simple Root data input filename(s)
56 // q.AddInputFile("test-i3.root");
58 // // Output file for the event structures
59 // q.SetOutputFile("events.root");
61 // ///////////////////////////////////////////////////////////////////
62 // // Here the user can specify his/her sub-tasks to be executed
63 // // on an event-by-event basis after the IceEvent structure
64 // // has been filled and before the data is written out.
65 // // Sub-tasks (i.e. a user classes derived from TTask) are entered
68 // // MyXtalk task1("task1","Cross talk correction");
69 // // MyClean task2("task2","Hit cleaning");
73 // // The sub-tasks will be executed in the order as they are entered.
74 // ///////////////////////////////////////////////////////////////////
76 // // Perform the conversion and execute subtasks (if any)
77 // // on an event-by-event basis
80 //--- Author: Garmt de Vries-Uiterweerd 13-Mar-2007 Utrecht University
81 //- Modified: GdV $Date$ Utrecht University
82 ///////////////////////////////////////////////////////////////////////////
85 #include "Riostream.h"
87 ClassImp(IceRootx) // Class implementation to enable ROOT I/O
89 IceRootx::IceRootx(const char* name,const char* title) : AliJob(name,title)
91 // Default constructor.
92 // By default maxevent=-1, split=0, bsize=32000, printfreq=1.
101 ///////////////////////////////////////////////////////////////////////////
102 IceRootx::~IceRootx()
104 // Default destructor.
112 ///////////////////////////////////////////////////////////////////////////
113 void IceRootx::SetMaxEvents(Int_t n)
115 // Set the maximum number of events to be processed.
116 // n=-1 implies processing of the complete input file, which is the default
117 // initialisation in the constructor.
120 ///////////////////////////////////////////////////////////////////////////
121 void IceRootx::SetPrintFreq(Int_t f)
123 // Set the printfrequency to produce info every f events.
124 // f=1 is the default initialisation in the constructor.
125 if (f>=0) fPrintfreq=f;
127 ///////////////////////////////////////////////////////////////////////////
128 void IceRootx::SetSplitLevel(Int_t split)
130 // Set the split level for the ROOT data file.
131 // split=0 is the default initialisation in the constructor.
132 if (split>=0) fSplit=split;
134 ///////////////////////////////////////////////////////////////////////////
135 void IceRootx::SetBufferSize(Int_t bsize)
137 // Set the buffer size for the ROOT data file.
138 // bsize=32000 is the default initialisation in the constructor.
139 if (bsize>=0) fBsize=bsize;
141 ///////////////////////////////////////////////////////////////////////////
142 void IceRootx::AddInputFile(TString name)
144 // Add the name of this simple Root data input file to the list to be processed.
148 fInfiles=new TObjArray();
149 fInfiles->SetOwner();
152 TObjString* s=new TObjString();
156 ///////////////////////////////////////////////////////////////////////////
157 void IceRootx::SetOutputFile(TFile* ofile)
159 // Set the output file for the ROOT data.
160 if (fOutfile) delete fOutfile;
163 ///////////////////////////////////////////////////////////////////////////
164 void IceRootx::SetOutputFile(TString name)
166 // Create the output file for the ROOT data.
167 if (fOutfile) delete fOutfile;
168 fOutfile=new TFile(name.Data(),"RECREATE","Simple Root data in IceEvent structure");
170 ///////////////////////////////////////////////////////////////////////////
171 TFile* IceRootx::GetOutputFile()
173 // Provide pointer to the ROOT output file.
176 ///////////////////////////////////////////////////////////////////////////
177 void IceRootx::Exec(Option_t* opt)
179 // Job to loop over the specified number of events and convert the
180 // simple Root data into the IceEvent structure.
181 // If maxevents<0 (default) all the entries of the input file
182 // will be processed.
183 // Every "printfreq" events a short event summary will be printed.
184 // The default value is printfreq=1.
185 // The output will be written on a standard output tree named "T".
189 // 1) This class is derived from AliJob, allowing a task based processing.
190 // After the conversion of a simple Root data event into an IceEvent structure,
191 // the processing of all available sub-tasks (if any) is invoked.
192 // This provides an event-by-event (sub)task processing before the
193 // final data structures are written out.
194 // 2) The main object in this job environment is an IceEvent* pointer.
198 cout << " *IceRootx Exec* No data input file(s) specified." << endl;
202 Int_t ninfiles=fInfiles->GetEntries();
205 cout << " *IceRootx Exec* No data input file(s) specified." << endl;
209 // Create output tree if necessary
213 otree=new TTree("T","Simple Root data converted to IceEvent structures");
214 otree->SetDirectory(fOutfile);
217 // Create IceEvent structure
218 IceEvent* evt=new IceEvent();
219 evt->SetTrackCopy(1);
222 // Branch in the tree for the event structure
223 if (otree) otree->Branch("IceEvent","IceEvent",&evt,fBsize,fSplit);
225 // Initialise the job working environment
228 // Some output for the user's convenience
230 cout << " ***" << endl;
231 cout << " *** Start processing of job " << GetName() << " ***" << endl;
232 cout << " ***" << endl;
233 for (Int_t i=0; i<ninfiles; i++)
235 TObjString* sx=(TObjString*)fInfiles->At(i);
237 inputfile=sx->GetString();
238 cout << " Simple Root data input file : " << inputfile.Data() << endl;
240 cout << " Maximum number of events to be processed : " << fMaxevt << endl;
241 cout << " Print frequency : " << fPrintfreq << endl;
244 cout << " ROOT output file : " << fOutfile->GetName() << endl;
245 cout << " Output characteristics : splitlevel = " << fSplit << " buffersize = " << fBsize << endl;
250 // Set DAQ device info
253 daq.SetSlotName("TWR",1);
258 trig.SetNameTitle("Trigger","Amanda/IceCube event triggers");
262 Double_t triggertime=0;
263 Int_t eventtimemjd=0;
264 Int_t eventtimemjds=0;
265 Int_t eventtimemjdns=0;
290 Float_t pi=acos(-1.);
292 Int_t firstomonstring[20];
293 firstomonstring[0]=0;
294 firstomonstring[1]=1;
295 firstomonstring[2]=21;
296 firstomonstring[3]=41;
297 firstomonstring[4]=61;
298 firstomonstring[5]=87;
299 firstomonstring[6]=123;
300 firstomonstring[7]=159;
301 firstomonstring[8]=195;
302 firstomonstring[9]=231;
303 firstomonstring[10]=267;
304 firstomonstring[11]=303;
305 firstomonstring[12]=345;
306 firstomonstring[13]=387;
307 firstomonstring[14]=429;
308 firstomonstring[15]=471;
309 firstomonstring[16]=513;
310 firstomonstring[17]=555;
311 firstomonstring[18]=597;
312 firstomonstring[19]=639;
316 for (Int_t ifile=0; ifile<ninfiles; ifile++)
318 TObjString* sx=(TObjString*)fInfiles->At(ifile);
321 inputfile=sx->GetString();
322 if (inputfile=="") continue;
324 // Open the simple Root data input file
325 input=TFile::Open(inputfile);
329 cout << " *IceRootx Exec* No input file found with name : " << inputfile.Data() << endl;
333 // Get simple Root tree
334 fTree=(TTree*)input->Get("T");
335 fTree->SetBranchAddress("triggertime",&triggertime);
336 fTree->SetBranchAddress("eventtimemjd",&eventtimemjd);
337 fTree->SetBranchAddress("eventtimemjds",&eventtimemjds);
338 fTree->SetBranchAddress("eventtimemjdns",&eventtimemjdns);
339 fTree->SetBranchAddress("eventid",&eventid);
340 fTree->SetBranchAddress("runid",&runid);
341 fTree->SetBranchAddress("String",&String);
342 fTree->SetBranchAddress("OM",&OM);
343 fTree->SetBranchAddress("baseline",&baseline);
344 fTree->SetBranchAddress("type",&type);
345 fTree->SetBranchAddress("numberbins",&numberbins);
346 fTree->SetBranchAddress("starttime",&starttime);
347 fTree->SetBranchAddress("ntracks",&ntracks);
348 if(fTree->GetBranch("binsize")) fTree->SetBranchAddress("binsize",&binsize);
350 Int_t nmaxbins=(Int_t)fTree->GetLeaf("numberbins")->GetMaximum();
351 Float_t* wvform=new Float_t[nmaxbins+1];
352 fTree->SetBranchAddress("wvform",wvform);
354 Int_t nmaxtracks=(Int_t)fTree->GetLeaf("ntracks")->GetMaximum();
355 Float_t* trackx=new Float_t[nmaxtracks];
356 Float_t* tracky=new Float_t[nmaxtracks];
357 Float_t* trackz=new Float_t[nmaxtracks];
358 Double_t* trackenergy=new Double_t[nmaxtracks];
359 Float_t* trackzenith=new Float_t[nmaxtracks];
360 Float_t* trackazimuth=new Float_t[nmaxtracks];
361 Int_t* tracktype=new Int_t[nmaxtracks];
362 fTree->SetBranchAddress("trackx",trackx);
363 fTree->SetBranchAddress("tracky",tracky);
364 fTree->SetBranchAddress("trackz",trackz);
365 fTree->SetBranchAddress("trackenergy",trackenergy);
366 fTree->SetBranchAddress("trackzenith",trackzenith);
367 fTree->SetBranchAddress("trackazimuth",trackazimuth);
368 fTree->SetBranchAddress("tracktype",tracktype);
370 // Prepare for loop over entries
373 // Loop over waveforms in tree
374 for(Int_t ientry=0; ientry<fTree->GetEntries(); ientry++)
376 fTree->GetEntry(ientry);
379 if(eventid!=lastevent)
381 // Write old event to tree (if it contains data)
382 if(evt->GetDevices("IceAOM"))
384 // Invoke all available sub-tasks (if any) and write event to tree
387 if(otree) otree->Fill();
388 if (fPrintfreq) { if (!(nevt%fPrintfreq)) evt->HeaderData(); }
389 // Update event counter
391 if (fMaxevt>-1 && nevt>=fMaxevt)
400 evt->SetRunNumber(runid);
401 evt->SetEventNumber(eventid);
402 evt->SetMJD(eventtimemjd,eventtimemjds,eventtimemjdns,0);
405 // Store trigger information
409 s.SetTitle("First trigger for TWR time reference");
411 s.SetSlotName("trig_pulse_le",1);
412 s.SetSignal(triggertime,1);
414 //// TODO: store other triggers if available
415 evt->AddDevice(trig);
417 // Loop over all the tracks and add them to the current event
420 for (Int_t itrack=0; itrack<ntracks; itrack++)
424 // Beginpoint of the track
425 vec[0]=trackx[itrack];
426 vec[1]=tracky[itrack];
427 vec[2]=trackz[itrack];
428 r.SetPosition(vec,"car");
432 vec[0]=trackenergy[itrack];
433 vec[1]=pi-trackzenith[itrack];
434 vec[2]=trackazimuth[itrack]+pi;
435 if(vec[2]>=2*pi) vec[2]-=2*pi;
436 p.SetVector(vec,"sph");
439 // Check for unreconstructed tracks (NaN values) and reset track if necessary
440 if(trackx[itrack]!=trackx[itrack] || tracky[itrack]!=tracky[itrack] || trackz[itrack]!=trackz[itrack] ||
441 trackzenith[itrack]!=trackzenith[itrack] || trackazimuth[itrack]!=trackazimuth[itrack]){
447 if(tracktype[itrack]==7){
454 t.SetId(nrecotracks);
456 if(tracktype[itrack]==1) { t.SetName("I3CFIRST"); t.SetTitle("IceTray CFIRST track"); }
457 else if(tracktype[itrack]==2) { t.SetName("I3direct"); t.SetTitle("IceTray direct walk track"); }
458 else if(tracktype[itrack]==3) { t.SetName("I3Jams_cluster"); t.SetTitle("IceTray Jams cluster"); }
459 else if(tracktype[itrack]==4) { t.SetName("I3Jams_qual"); t.SetTitle("IceTray Jams quality"); }
460 else if(tracktype[itrack]==5) { t.SetName("I3TOIFit"); t.SetTitle("IceTray TOI fit"); }
461 else if(tracktype[itrack]==6) { t.SetName("I3line-direct"); t.SetTitle("IceTray line direct walk"); }
462 else if(tracktype[itrack]==7) { t.SetName("I3MCTrack"); t.SetTitle("I3MCTrack"); }
463 else { t.SetName("Unknown"); t.SetTitle("IceTray track of unknown type"); }
465 // Add track to event
473 // Get OM from event strcture, or create and add it
474 omid=firstomonstring[-String]+OM-1;
475 if(omid==681) continue; // Skip OM 681, which should never give data: avoid all risk of confusion
476 omx=(IceAOM*)evt->GetIdDevice(omid);
480 om.SetUniqueID(omid);
482 omx=(IceAOM*)evt->GetIdDevice(omid);
486 // Store baseline info
488 hname+=omx->GetNwaveforms()+1;
489 omx->AddNamedSlot(hname);
490 omx->SetSignal(baseline,hname);
492 // Store readout type
493 omx->AddNamedSlot("READOUT");
494 if(type==0) omx->SetSignal(1,"READOUT"); // Electrical
495 else if(type==1) omx->SetSignal(2,"READOUT"); // Optical
496 else if(type==2) omx->SetSignal(3,"READOUT"); // Digital
497 else omx->SetSignal(0,"READOUT"); // Unknown
499 // Fill the waveform histogram with this fragment
503 hname+=omx->GetNwaveforms()+1;
506 histo.SetName(hname.Data());
507 histo.SetBins(numberbins,triggertime+starttime,triggertime+starttime+numberbins*binsize);
509 for (Int_t jbin=1; jbin<=numberbins; jbin++)
511 histo.SetBinContent(jbin,baseline-wvform[jbin-1]);
514 omx->SetWaveform(&histo,omx->GetNwaveforms()+1);
518 // Write last event to tree
519 if(evt->GetDevices("IceAOM"))
523 if (otree) otree->Fill();
524 if (fPrintfreq) { if (!(nevt%fPrintfreq)) evt->HeaderData(); }
525 // Update event counter
527 if (fMaxevt>-1 && nevt>=fMaxevt) break;
541 delete[] trackenergy;
542 delete[] trackzenith;
543 delete[] trackazimuth;
546 // Stop looping over input files if max. nr. of events is reached
547 if (fMaxevt>-1 && nevt>=fMaxevt)
552 } // End of input file loop
554 // Flush possible memory resident data to the output file
555 if (fOutfile) fOutfile->Write();
557 // Remove the IceEvent object from the environment
558 // and delete it as well
565 ///////////////////////////////////////////////////////////////////////////