// Note that the data structures are only written out if an outputfile has
// been specified via the SetOutputFile memberfunction.
// In case no outputfile has been specified, this class provides a facility
-// to investigate/analyse F2K data using the Ralice/IcePack analysis tools.
+// to investigate/analyse F2K data using the Ralice/IcePack analysis tools.
+//
+// Note : Sometimes the filtering/reco process which produced the F2K file
+// may have introduced a shift (i.e. offset) in the hit times w.r.t.
+// the actual trigger time. The aim of this is to obtain the hit times
+// centered more or less around zero.
+// In case of real data, this is recorded in the F2K data itself and
+// as such will be taken automatically into account by this IceF2k
+// processor such that all times will be provided again unshifted.
+// In other words, all times will be w.r.t. the actual trigger time
+// as recorded in the trigger data device named "Trigger" in the IceEvent
+// structure.
+// In case of simulated data this shift is not available in the F2K data.
+// The offset denoted in the F2K record is related to the time of the
+// primary interaction to put it well ahead of the detector trigger.
+// This primary interaction time, however, is irrelevant for the
+// reconstruction of the recorded hit patterns.
+// If a user had introduced a shift in producing the MC data,
+// very frequently (but not always) a value of -19000 is used.
+// For the IceF2k processing, the user can manually introduce a
+// time offset in case of MC data via the memberfunction SetMcToffset().
+// This user defined offset value will then be used to correct all
+// the hit times such that they will be provided again unshifted
+// w.r.t. the actual trigger time as recorded in the device named
+// "Trigger" in the IceEvent structure.
+// By default the MC time offset is set to 0 in the constructor
+// of this class.
//
// Usage example :
// ---------------
// q.SetPrintFreq(1);
//
// // Split level for the output structures
-// q.SetSplitLevel(2);
+// q.SetSplitLevel(0);
//
// // Buffer size for the output structures
// q.SetBufferSize(32000);
//
-// // The F2K input filename
-// q.SetInputFile("run7825.f2k");
+// // The F2K input filename(s)
+// q.AddInputFile("run7825.f2k");
//
// // Output file for the event structures
// q.SetOutputFile("events.root");
IceF2k::IceF2k(const char* name,const char* title) : AliJob(name,title)
{
// Default constructor.
-// By default maxevent=-1, split=99, bsize=32000, printfreq=1.
+// By default maxevent=-1, split=0, bsize=32000, printfreq=1.
- fSplit=99;
+ fSplit=0;
fBsize=32000;
fMaxevt=-1;
fPrintfreq=1;
- fInfile="";
+ fInfiles=0;
fOutfile=0;
fPdg=0;
fOmdb=0;
fFitdefs=0;
fTrigdefs=0;
+ fToffset=0;
+ fMctoffset=0;
+ fMctracks=3;
}
///////////////////////////////////////////////////////////////////////////
IceF2k::~IceF2k()
{
// Default destructor.
+ if (fInfiles)
+ {
+ delete fInfiles;
+ fInfiles=0;
+ }
+
if (fPdg)
{
delete fPdg;
void IceF2k::SetSplitLevel(Int_t split)
{
// Set the split level for the ROOT data file.
-// split=99 is the default initialisation in the constructor.
+// split=0 is the default initialisation in the constructor.
if (split>=0) fSplit=split;
}
///////////////////////////////////////////////////////////////////////////
if (bsize>=0) fBsize=bsize;
}
///////////////////////////////////////////////////////////////////////////
+void IceF2k::SetMcToffset(Float_t toffset)
+{
+// Set a user defined time offset for Monte Carlo data.
+// A very frequently (but not always) used value is -19000.
+// See the introductory docs of this class for further details.
+ fMctoffset=toffset;
+}
+///////////////////////////////////////////////////////////////////////////
+void IceF2k::SelectMcTracks(Int_t mode)
+{
+// User selection of MC tracks to be stored in the event structure.
+//
+// mode = 0 : No MC tracks are stored
+// 1 : Only muon and muon-neutrino MC tracks are stored
+// 2 : All lepton MC tracks are stored
+// 3 : All MC tracks (incl. brems, pairprod etc...) are stored
+//
+// By default mode=3 is set in the constructor of this class.
+
+ if (mode<0 || mode >3) return;
+ fMctracks=mode;
+}
+///////////////////////////////////////////////////////////////////////////
void IceF2k::SetInputFile(TString name)
{
// Set the name of the F2K input file.
- fInfile=name;
+// This function has become obsolete but is kept for backward compatibility.
+// The user is advised to use AddInputFile() instead, which allows processing
+// of multiple F2K input files.
+// This function will reset the list of all F2K input files and put the specified
+// filename at the first position.
+// Additional F2K input files can be specified via AddInputFile().
+
+ if (fInfiles) delete fInfiles;
+
+ fInfiles=new TObjArray();
+ fInfiles->SetOwner();
+
+ TObjString* s=new TObjString();
+ s->SetString(name);
+ fInfiles->Add(s);
+}
+///////////////////////////////////////////////////////////////////////////
+void IceF2k::AddInputFile(TString name)
+{
+// Add the name of this F2K input file to the list to be processed.
+
+ if (!fInfiles)
+ {
+ fInfiles=new TObjArray();
+ fInfiles->SetOwner();
+ }
+
+ TObjString* s=new TObjString();
+ s->SetString(name);
+ fInfiles->Add(s);
}
///////////////////////////////////////////////////////////////////////////
void IceF2k::SetOutputFile(TFile* ofile)
// final data structures are written out.
// 2) The main object in this job environment is an IceEvent* pointer.
- if (fInfile=="")
+ if (!fInfiles)
{
- cout << " *IceF2k Exec* No data input file specified." << endl;
+ cout << " *IceF2k Exec* No data input file(s) specified." << endl;
return;
}
- // Open the input file in the default ascii format (autodetection) for reading
- fInput=rdmc_mcopen(fInfile.Data(),"r",RDMC_DEFAULT_ASCII_F);
-
- if (!fInput)
+ Int_t ninfiles=fInfiles->GetEntries();
+ if (!ninfiles)
{
- cout << " *IceF2k Exec* No input file found with name : " << fInfile.Data() << endl;
+ cout << " *IceF2k Exec* No data input file(s) specified." << endl;
return;
}
- // Initialise the event structure
- rdmc_init_mevt(&fEvent);
-
- // Read the file header information
- rdmc_rarr(fInput,&fHeader);
-
TTree* otree=0;
if (fOutfile)
{
fPdg->AddParticle("z_primary","z_primary",0,1,0,0,"none",10003000,0,0);
fPdg->AddParticle("a_primary","a_primary",0,1,0,0,"none",10003500,0,0);
- // Fill the database with geometry, calib. etc... parameters
- // for all the devices
- FillOMdbase();
-
- // Set the fit definitions according to the F2000 header info
- SetFitdefs();
-
- // Set the trigger definitions according to the F2000 header info
- SetTrigdefs();
-
// Initialise the job working environment
SetMainObject(evt);
if (fOutfile)
AddObject(otree);
}
+ TString inputfile;
+
cout << " ***" << endl;
cout << " *** Start processing of job " << GetName() << " ***" << endl;
cout << " ***" << endl;
- cout << " F2K input file : " << fInfile.Data() << endl;
+ for (Int_t i=0; i<ninfiles; i++)
+ {
+ TObjString* sx=(TObjString*)fInfiles->At(i);
+ if (!sx) continue;
+ inputfile=sx->GetString();
+ cout << " F2K input file : " << inputfile.Data() << endl;
+ }
cout << " Maximum number of events to be processed : " << fMaxevt << endl;
cout << " Print frequency : " << fPrintfreq << endl;
if (fOutfile)
}
ListEnvironment();
-
+
Int_t nevt=0;
- while (!rdmc_revt(fInput,&fHeader,&fEvent))
+ for (Int_t ifile=0; ifile<ninfiles; ifile++)
{
- if (fMaxevt>-1 && nevt>=fMaxevt) break;
+ TObjString* sx=(TObjString*)fInfiles->At(ifile);
+ if (!sx) continue;
- // Reset the complete Event structure
- evt->Reset();
+ inputfile=sx->GetString();
+ if (inputfile=="") continue;
- evt->SetRunNumber(fEvent.nrun);
- evt->SetEventNumber(fEvent.enr);
- evt->SetMJD(fEvent.mjd,fEvent.secs,fEvent.nsecs);
+ // Open the input file in the default ascii format (autodetection) for reading
+ fInput=rdmc_mcopen(inputfile.Data(),"r",RDMC_DEFAULT_ASCII_F);
- PutTrigger();
+ if (!fInput)
+ {
+ cout << " *IceF2k Exec* No input file found with name : " << inputfile.Data() << endl;
+ continue;
+ }
- PutMcTracks();
+ // Initialise the event structure
+ rdmc_init_mevt(&fEvent);
- PutRecoTracks();
+ // Read the file header information
+ rdmc_rarr(fInput,&fHeader);
- PutHits();
+ // Fill the database with geometry, calib. etc... parameters
+ // for all the devices
+ FillOMdbase();
- // Invoke all available sub-tasks (if any)
- CleanTasks();
- ExecuteTasks(opt);
+ // Set the fit definitions according to the F2000 header info
+ SetFitdefs();
- if (fPrintfreq)
+ // Set the trigger definitions according to the F2000 header info
+ SetTrigdefs();
+
+ while (!rdmc_revt(fInput,&fHeader,&fEvent))
{
- if (!(nevt%fPrintfreq)) evt->HeaderData();
- }
+ if (fMaxevt>-1 && nevt>=fMaxevt) break;
- // Write the complete structure to the output Tree
- if (otree) otree->Fill();
+ // Reset the complete Event structure
+ evt->Reset();
- // Update event counter
- nevt++;
+ evt->SetRunNumber(fEvent.nrun);
+ evt->SetEventNumber(fEvent.enr);
+ evt->SetMJD(fEvent.mjd,fEvent.secs,fEvent.nsecs);
+
+ // Take trigger offset into account which might have been
+ // introduced during the filtering process.
+ // For simulated data this will be treated separately in PutMcTracks().
+ fToffset=fEvent.t_offset;
+
+ PutTrigger();
+
+ PutMcTracks();
+
+ PutRecoTracks();
+
+ PutHits();
+
+ // Invoke all available sub-tasks (if any)
+ CleanTasks();
+ ExecuteTasks(opt);
+
+ if (fPrintfreq)
+ {
+ if (!(nevt%fPrintfreq)) evt->HeaderData();
+ }
+
+ // Write the complete structure to the output Tree
+ if (otree) otree->Fill();
+
+ // Update event counter
+ nevt++;
+ }
+ if (fMaxevt>-1 && nevt>=fMaxevt) break;
}
// Flush possible memory resident data to the output file
// Fill the database with geometry, calib. etc... parameters
// for all the devices.
- if (fHeader.nch<=0) return;
+ if (fHeader.nch<=0)
+ {
+ if (fOmdb)
+ {
+ delete fOmdb;
+ fOmdb=0;
+ }
+ return;
+ }
Int_t adccal=fHeader.is_calib.adc;
Int_t tdccal=fHeader.is_calib.tdc;
//
// This memberfunction is based on the original idea/code by Adam Bouchta.
- if (fHeader.n_fit<=0) return;
+ if (fHeader.n_fit<=0)
+ {
+ if (fFitdefs)
+ {
+ delete fFitdefs;
+ fFitdefs=0;
+ }
+ return;
+ }
if (fFitdefs)
{
// Slot : 3 Signal value : 0 name : regi_flag
// etc....
- if (fHeader.n_trigger<=0) return;
+ if (fHeader.n_trigger<=0)
+ {
+ if (fTrigdefs)
+ {
+ delete fTrigdefs;
+ fTrigdefs=0;
+ }
+ return;
+ }
if (fTrigdefs)
{
IceEvent* evt=(IceEvent*)GetMainObject();
if (!evt || fEvent.ntrack<=0) return;
+ // User defined trigger offset in case of simulated data.
+ // The offset in the F2K file is meant to put the primary interaction
+ // well ahead of the detector trigger.
+ // See the introductory docs of this IceF2k class for further details.
+ fToffset=fMctoffset;
+
+ if (!fMctracks) return;
+
// Loop over all the tracks and add them to the current event
AliTrack t;
Double_t vec[3];
if (idf2k==206) idpdg=-16;
}
+ // Check for the user selected MC track storage
+ if (fMctracks==1) // Store only muon and muon-neutrino tracks
+ {
+ if (abs(idpdg)!=13 && abs(idpdg)!=14) continue;
+ }
+ else if (fMctracks==2) // Store all lepton tracks
+ {
+ if (abs(idpdg)<11 || abs(idpdg)>16) continue;
+ }
+
t.SetParticleCode(idpdg);
t.SetName(fPdg->GetParticle(idpdg)->GetName());
t.SetTitle("MC track");
Int_t tid=0;
AliTrack* tx=0;
Float_t adc=0;
+ Float_t adcfirst=0; // Adc value of the first hit of an OM
for (Int_t i=0; i<fEvent.nhits; i++)
{
chan=fEvent.h[i].ch+1;
if (!omx) continue;
+ adc=fEvent.h[i].amp;
+
+ // Multiple hits in the same OM with the same ADC value
+ // are indicated by "*" in the F2K file.
+ // This corresponds to a value of -2 in the data structure.
+ if (int(adc) == -2)
+ {
+ adc=adcfirst;
+ }
+ else
+ {
+ adcfirst=adc;
+ }
s.Reset();
s.SetUniqueID(fEvent.h[i].id);
- s.SetSignal(fEvent.h[i].amp,1);
- s.SetSignal(fEvent.h[i].t,2);
+ s.SetSignal(adc,1);
+ s.SetSignal((fEvent.h[i].t-fToffset),2);
s.SetSignal(fEvent.h[i].tot,3);
omx->AddHit(s);
{
tx=evt->GetIdTrack(tid); // Reco tracks
if (!tx) tx=evt->GetIdTrack(-tid); // MC tracks
- if (tx) sx->AddLink(tx);
+ if (tx) sx->AddTrack(*tx);
}
else
{
- if (tid == -2) s.SetNameTitle("N","Noise");
- if (tid == -3) s.SetNameTitle("A","Afterpulse");
+ if (tid == -2) sx->SetNameTitle("N","Noise");
+ if (tid == -3) sx->SetNameTitle("A","Afterpulse");
}
}
if (!omx) continue;
omx->SetSlotName("BASELINE",omx->GetNnames()+1);
- omx->SetSignal(fEvent.wf[iwf].baseline,"BASELINE");
+ omx->SetSignal(-fEvent.wf[iwf].baseline,"BASELINE");
// Fill the waveform histogram
hname="OM";
for (Int_t jbin=1; jbin<=fEvent.wf[iwf].ndigi; jbin++)
{
- histo.SetBinContent(jbin,fEvent.wf[iwf].digi[jbin-1]);
+ histo.SetBinContent(jbin,-fEvent.wf[iwf].digi[jbin-1]);
}
omx->SetWaveform(&histo,omx->GetNwaveforms()+1);
if (fEvent.fit_uses[k].useid != hypx->GetId()) continue;
hid=fEvent.fit_uses[k].hitid;
sx=evt->GetIdHit(hid,"IceAOM");
- if (sx) sx->AddLink(hypx);
+ if (sx) sx->AddTrack(*hypx);
}
}
}