/******************************************************************************* * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved. * * Author: The IceCube RALICE-based Offline Project. * Contributors are mentioned in the code where appropriate. * * Permission to use, copy, modify and distribute this software and its * documentation strictly for non-commercial purposes is hereby granted * without fee, provided that the above copyright notice appears in all * copies and that both the copyright notice and this permission notice * appear in the supporting documentation. * The authors make no claims about the suitability of this software for * any purpose. It is provided "as is" without express or implied warranty. *******************************************************************************/ // $Id$ /////////////////////////////////////////////////////////////////////////// // Class IceF2k // Conversion of Amanda F2K data into IceEvent physics event structures. // This class is derived from AliJob providing a task-based processing // structure on an event-by-event basis. // The main object in the job environment is an IceEvent* pointer. // In case the user has provided sub-tasks, these will be executed // on an event-by-event basis after the IceEvent structure has been filled // with the F2K data and before the final structures are written out. // // Usage example : // --------------- // // gSystem->Load("ralice"); // gSystem->Load("icepack"); // gSystem->Load("iceconvert"); // // IceF2k q("IceF2k","F2K to IcePack data structure conversion"); // // // Limit the number of entries for testing // q.SetMaxEvents(10); // // // Print frequency to produce a short summary print every printfreq events // q.SetPrintFreq(1); // // // Split level for the output structures // q.SetSplitLevel(2); // // // Buffer size for the output structures // q.SetBufferSize(32000); // // // The F2K input filename // q.SetInputFile("run7825.f2k"); // // // Output file for the event structures // TFile* ofile=new TFile("events.root","RECREATE","F2K data in IceEvent structure"); // q.SetOutputFile(ofile); // // /////////////////////////////////////////////////////////////////// // // Here the user can specify his/her sub-tasks to be executed // // on an event-by-event basis after the IceEvent structure // // has been filled and before the data is written out. // // Sub-tasks (i.e. a user classes derived from TTask) are entered // // as follows : // // // // MyXtalk task1("task1","Cross talk correction"); // // MyClean task2("task2","Hit cleaning"); // // q.Add(&task1); // // q.Add(&task2); // // // // The sub-tasks will be executed in the order as they are entered. // /////////////////////////////////////////////////////////////////// // // // Perform the conversion and execute subtasks (if any) // // on an event-by-event basis // q.ExecuteJob(); // // // Select various objects to be added to the output file // // AliObjMatrix* omdb=q.GetOMdbase(); // if (omdb) omdb->Write(); // // AliDevice* fitdefs=q.GetFitdefs(); // if (fitdefs) fitdefs->Write(); // // TDatabasePDG* pdg=q.GetPDG(); // if (pdg) pdg->Write(); // // // Close output file // ofile->Write(); // ofile->Close(); // //--- Author: Nick van Eijndhoven 11-mar-2005 Utrecht University //- Modified: NvE $Date$ Utrecht University /////////////////////////////////////////////////////////////////////////// #include "IceF2k.h" #include "Riostream.h" ClassImp(IceF2k) // Class implementation to enable ROOT I/O IceF2k::IceF2k(const char* name,const char* title) : AliJob(name,title) { // Default constructor. // By default maxevent=-1, split=99, bsize=32000, printfreq=1. fSplit=99; fBsize=32000; fMaxevt=-1; fPrintfreq=1; fInfile=""; fOutfile=0; fPdg=0; fOmdb=0; fFitdefs=0; } /////////////////////////////////////////////////////////////////////////// IceF2k::~IceF2k() { // Default destructor. IceEvent* evt=(IceEvent*)GetMainObject(); if (evt) delete evt; if (fPdg) { delete fPdg; fPdg=0; } if (fOmdb) { delete fOmdb; fOmdb=0; } if (fFitdefs) { delete fFitdefs; fFitdefs=0; } } /////////////////////////////////////////////////////////////////////////// void IceF2k::SetMaxEvents(Int_t n) { // Set the maximum number of events to be processed. // n=-1 implies processing of the complete input file, which is the default // initialisation in the constructor. fMaxevt=n; } /////////////////////////////////////////////////////////////////////////// void IceF2k::SetPrintFreq(Int_t f) { // Set the printfrequency to produce info every f events. // f=1 is the default initialisation in the constructor. if (f>0) fPrintfreq=f; } /////////////////////////////////////////////////////////////////////////// void IceF2k::SetSplitLevel(Int_t split) { // Set the split level for the ROOT data file. // split=99 is the default initialisation in the constructor. if (split>=0) fSplit=split; } /////////////////////////////////////////////////////////////////////////// void IceF2k::SetBufferSize(Int_t bsize) { // Set the buffer size for the ROOT data file. // bsize=32000 is the default initialisation in the constructor. if (bsize>=0) fBsize=bsize; } /////////////////////////////////////////////////////////////////////////// void IceF2k::SetInputFile(TString name) { // Set the name of the F2K input file. fInfile=name; } /////////////////////////////////////////////////////////////////////////// void IceF2k::SetOutputFile(TFile* ofile) { // Set the output file for the ROOT data. fOutfile=ofile; } /////////////////////////////////////////////////////////////////////////// TDatabasePDG* IceF2k::GetPDG() { // Provide pointer to the PDG database return fPdg; } /////////////////////////////////////////////////////////////////////////// AliObjMatrix* IceF2k::GetOMdbase() { // Provide pointer to the OM geometry, calib. etc... database return fOmdb; } /////////////////////////////////////////////////////////////////////////// AliDevice* IceF2k::GetFitdefs() { // Provide pointer to the fit definitions return fFitdefs; } /////////////////////////////////////////////////////////////////////////// void IceF2k::Exec(Option_t* opt) { // Job to loop over the specified number of events and convert the // F2K data into the IceEvent structure. // If maxevents<0 (default) all the entries of the input file // will be processed. // Every "printfreq" events a short event summary will be printed. // The default value is printfreq=1. // The output will be written on a standard output tree named "T". // // Notes : // ------- // 1) This class is derived from AliJob, allowing a task based processing. // After the conversion of an F2K event into an IceEvent structure, // the processing of all available sub-tasks (if any) is invoked. // This provides an event-by-event (sub)task processing before the // final data structures are written out. // 2) The main object in this job environment is an IceEvent* pointer. if (fInfile=="") { cout << " *IceF2k Exec* No data input file 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) { cout << " *IceF2k Exec* No input file found with name : " << fInfile.Data() << endl; return; } // Initialise the event structure rdmc_init_mevt(&fEvent); // Read the file header information rdmc_rarr(fInput,&fHeader); if (!fOutfile) { cout << " *IceF2k Exec* No ROOT output file specified." << endl; return; } TTree* otree=new TTree("T","F2K Data converted to IceEvent structures"); IceEvent* evt=new IceEvent(); evt->SetTrackCopy(1); evt->SetDevCopy(1); // Branch in the tree for the event structure otree->Branch("IceEvent","IceEvent",&evt,fBsize,fSplit); // Create the particle database and extend it with some F2000 specific definitions if (!fPdg) fPdg=new TDatabasePDG(); Double_t me=fPdg->GetParticle(11)->Mass(); fPdg->AddParticle("brems" ,"brems" ,0,1,0,0,"none",10001001,0,0); fPdg->AddParticle("deltae" ,"deltae" ,me,1,0,-3,"Lepton",10001002,0,0); fPdg->AddParticle("pairprod","pairprod",0,1,0,0,"none",10001003,0,0); fPdg->AddParticle("nucl_int","nucl_Int",0,1,0,0,"none",10001004,0,0); fPdg->AddParticle("mu_pair" ,"mu_pair" ,0,1,0,0,"none",10001005,0,0); fPdg->AddParticle("hadrons" ,"hadrons" ,0,1,0,0,"none",10001006,0,0); fPdg->AddParticle("fiberlaser","fiberlaser",0,1,0,0,"none",10002100,0,0); fPdg->AddParticle("n2laser" ,"n2laser" ,0,1,0,0,"none",10002101,0,0); fPdg->AddParticle("yaglaser" ,"yaglaser" ,0,1,0,0,"none",10002201,0,0); 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(); // Initialise the job working environment SetMainObject(evt); AddObject(fOutfile); AddObject(otree); cout << " ***" << endl; cout << " *** Start processing of job " << GetName() << " ***" << endl; cout << " ***" << endl; cout << " F2K input file : " << fInfile.Data() << endl; cout << " Maximum number of events to be processed : " << fMaxevt << endl; cout << " Print frequency : " << fPrintfreq << endl; cout << " ROOT output file : " << fOutfile->GetName() << endl; cout << " Output characteristics : splitlevel = " << fSplit << " buffersize = " << fBsize << endl; ListEnvironment(); Int_t nevt=0; while (!rdmc_revt(fInput,&fHeader,&fEvent)) { if (fMaxevt>-1 && nevt>=fMaxevt) break; // Reset the complete Event structure evt->Reset(); evt->SetRunNumber(fEvent.nrun); evt->SetEventNumber(fEvent.enr); evt->SetMJD(fEvent.mjd,fEvent.secs,fEvent.nsecs); PutMcTracks(); PutRecoTracks(); PutHits(); // Invoke all available sub-tasks (if any) ExecuteTasks(opt); if (!(nevt%fPrintfreq)) evt->HeaderData(); // Write the complete structure to the output Tree otree->Fill(); // Update event counter nevt++; } } /////////////////////////////////////////////////////////////////////////// void IceF2k::FillOMdbase() { // Fill the database with geometry, calib. etc... parameters // for all the devices. if (fHeader.nch<=0) return; if (fOmdb) { fOmdb->Reset(); } else { fOmdb=new AliObjMatrix(); fOmdb->SetNameTitle("OMDBASE","The OM geometry, calib. etc... database"); fOmdb->SetOwner(); } IceAOM* dev=0; Double_t pos[3]={0,0,0}; for (Int_t i=0; iSetUniqueID(i+1); dev->SetSlotName("TYPE",1); dev->SetSlotName("ORIENT",2); dev->SetSlotName("T0",3); dev->SetSlotName("ALPHA",4); dev->SetSlotName("KADC",5); dev->SetSlotName("KTOT",6); dev->SetSlotName("KTDC",7); pos[0]=fHeader.x[i]; pos[1]=fHeader.y[i]; pos[2]=fHeader.z[i]; dev->SetPosition(pos,"car"); dev->SetSignal(fHeader.type[i],1); dev->SetSignal((Float_t)fHeader.costh[i],2); dev->SetSignal(fHeader.cal[i].t_0,3); dev->SetSignal(fHeader.cal[i].alpha_t,4); dev->SetSignal(fHeader.cal[i].beta_a,5); dev->SetSignal(fHeader.cal[i].beta_tot,6); dev->SetSignal(fHeader.cal[i].beta_t,7); fOmdb->EnterObject(i+1,1,dev); } } /////////////////////////////////////////////////////////////////////////// void IceF2k::SetFitdefs() { // Obtain the names of the variables for each fit procedure from the // f2000 header. Each different fit procedure is then stored as a separate // hit of an AliDevice object and the various fit variables are stored // as separate signal slots of the corresponding hit. // Via the GetFitdefs() memberfunction this AliDevice object can be // retrieved and stored in the ROOT output file if wanted. // The name of the object is FitDefinitions and the stored data can be // inspected via the AliDevice::Data() memberfunction and looks as follows : // // *AliDevice::Data* Id :0 Name : FitDefinitions // Position Vector in car coordinates : 0 0 0 // Err. in car coordinates : 0 0 0 // The following 8 hits are registered : // *AliSignal::Data* Id :0 // Position Vector in car coordinates : 0 0 0 // Err. in car coordinates : 0 0 0 // Owned by device : AliDevice Name : FitDefinitions // Slot : 1 Signal value : 1 name : id // Slot : 2 Signal value : 2 name : rchi2 // Slot : 3 Signal value : 3 name : prob // Slot : 4 Signal value : 4 name : sigth // Slot : 5 Signal value : 5 name : covmin // Slot : 6 Signal value : 6 name : covmax // Slot : 7 Signal value : 7 name : cutflag // Slot : 8 Signal value : 8 name : chi2 // *AliSignal::Data* Id :1 // Position Vector in car coordinates : 0 0 0 // Err. in car coordinates : 0 0 0 // Owned by device : AliDevice Name : FitDefinitions // Slot : 1 Signal value : 1 name : id // Slot : 2 Signal value : 2 name : rchi2 // Slot : 3 Signal value : 3 name : prob // etc.... // // This memberfunction is based on the original idea/code by Adam Bouchta. if (fHeader.n_fit<=0) return; if (fFitdefs) { fFitdefs->Reset(1); } else { fFitdefs=new AliDevice(); } fFitdefs->SetName("FitDefinitions"); fFitdefs->SetHitCopy (1); AliSignal s; s.Reset(); for (Int_t i=0; iAddHit(s); s.Reset(1); } } /////////////////////////////////////////////////////////////////////////// void IceF2k::PutMcTracks() { // Get the MC tracks from the F2000 file into the IcePack structure. // Note : MC tracks are given negative track id's in the event structure. // This memberfunction is based on the original code by Adam Bouchta. IceEvent* evt=(IceEvent*)GetMainObject(); if (!evt || fEvent.ntrack<=0) return; // Loop over all the tracks and add them to the current event AliTrack t; Double_t vec[3]; AliPosition r; Ali3Vector p; Int_t tid=0; Int_t idpdg=0; Int_t idf2k=0; for (Int_t i=0; i1000) { idpdg=idf2k+10000000; } else if (idf2k <= 48) { idpdg=fPdg->ConvertGeant3ToPdg(idf2k); } else { if (idf2k==201) idpdg=12; if (idf2k==202) idpdg=14; if (idf2k==203) idpdg=16; if (idf2k==204) idpdg=-12; if (idf2k==205) idpdg=-14; if (idf2k==206) idpdg=-16; } t.SetParticleCode(idpdg); t.SetName(fPdg->GetParticle(idpdg)->GetName()); t.SetTitle("MC track"); t.SetMass(fPdg->GetParticle(idpdg)->Mass()); t.SetCharge(fPdg->GetParticle(idpdg)->Charge()/3.); evt->AddTrack(t); } // Create the pointers to each particle's parent particle. Int_t txid=0; Int_t parid=0; for (Int_t itk=1; itk<=evt->GetNtracks (); itk++) { AliTrack* tx=evt->GetTrack(itk); if (!tx) continue; txid=tx->GetId(); parid=-1; for (Int_t j=0; jGetIdTrack(-abs(parid)); if (!tpar) continue; tx->SetParentTrack(tpar); } } /////////////////////////////////////////////////////////////////////////// void IceF2k::PutRecoTracks() { // Get the reconstructed tracks from the F2000 file into the IcePack structure. // Note : Reco tracks are given positive track id's in the event structure. // This memberfunction is based on the original code by Adam Bouchta. IceEvent* evt=(IceEvent*)GetMainObject(); if (!evt || fEvent.nfit<=0) return; // Loop over all the tracks and add them to the current event AliTrack t; Double_t vec[3]; AliPosition r; Ali3Vector p; Int_t tid=0; Int_t idpdg=0; Int_t idf2k=0; for (Int_t i=0; i 0) { vec[0]=fEvent.rec[i].e*fEvent.rec[i].px*1e-3; vec[1]=fEvent.rec[i].e*fEvent.rec[i].py*1e-3; vec[2]=fEvent.rec[i].e*fEvent.rec[i].pz*1e-3; } else // Give the track a nominal momentum of 1 GeV/c { vec[0]=fEvent.rec[i].px; vec[1]=fEvent.rec[i].py; vec[2]=fEvent.rec[i].pz; } p.SetVector (vec,"car"); t.Set3Momentum(p); // Use the fit number as track id tid=fEvent.rec[i].tag; t.SetId(abs(tid)); idf2k=fEvent.rec[i].id; idpdg=0; if (idf2k>1000) { idpdg=idf2k+10000000; } else if (idf2k <= 48) { idpdg=fPdg->ConvertGeant3ToPdg(idf2k); } else { if (idf2k==201) idpdg=12; if (idf2k==202) idpdg=14; if (idf2k==203) idpdg=16; if (idf2k==204) idpdg=-12; if (idf2k==205) idpdg=-14; if (idf2k==206) idpdg=-16; } t.SetParticleCode(idpdg); t.SetName(fPdg->GetParticle(idpdg)->GetName()); t.SetTitle("RECO track"); t.SetMass(fPdg->GetParticle(idpdg)->Mass()); t.SetCharge(fPdg->GetParticle(idpdg)->Charge()/3.); // Retrieve the various fit parameters for this track AliSignal* fitdata=fFitdefs->GetIdHit(i); for (Int_t jval=0; jvalSetSignal(fEvent.fresult[i].val[jval],jval+1); } // Store the various fit parameters for this track t.SetFitDetails(fitdata); // Store the various reco tracks as track hypotheses. // A copy of the first reco track is entered as a new track instance // into the event and all reco tracks (incl. the first one) are // stored as hypotheses linked to this new reco track. if (i==0) { evt->AddTrack(t); AliTrack* tx=evt->GetTrack(evt->GetNtracks()); Int_t nrec=evt->GetNtracks(1); tx->SetId(nrec+1); } AliTrack* tx=evt->GetTrack(evt->GetNtracks()); if (tx) tx->AddTrackHypothesis(t); } } /////////////////////////////////////////////////////////////////////////// void IceF2k::PutHits() { // Get the hit and waveform info from the F2000 file into the IcePack structure. // This memberfunction is based on the original code by Adam Bouchta. IceEvent* evt=(IceEvent*)GetMainObject(); if (!evt) return; // Loop over all the hits and add them to the current event IceAOM om; AliSignal s; s.SetSlotName("ADC",1); s.SetSlotName("LE",2); s.SetSlotName("TOT",3); Int_t chan=0; Int_t maxchan=800; if (fOmdb) maxchan=fHeader.nch; IceAOM* omx=0; AliSignal* sx=0; Int_t tid=0; AliTrack* tx=0; for (Int_t i=0; imaxchan) continue; // Channels 9001, 9002 etc are trigger channels // Get corresponding device from the current event structure omx=(IceAOM*)evt->GetIdDevice(chan); if (!omx) { if (fOmdb) { omx=(IceAOM*)fOmdb->GetObject(chan,1); evt->AddDevice(omx); } else { om.Reset(1); om.SetUniqueID(chan); evt->AddDevice(om); } omx=(IceAOM*)evt->GetIdDevice(chan); } if (!omx) continue; s.Reset(); s.SetUniqueID(fEvent.h[i].id); s.SetSignal(fEvent.h[i].amp,1); s.SetSignal(fEvent.h[i].t,2); s.SetSignal(fEvent.h[i].tot,3); omx->AddHit(s); sx=omx->GetHit(omx->GetNhits()); if (!sx) continue; // Bi-directional link between this hit and the track that caused the ADC value. // This F2K info is probably only present for MC tracks. tid=fEvent.h[i].ma; if (tid > 0) { tx=evt->GetIdTrack(tid); // Reco tracks if (!tx) tx=evt->GetIdTrack(-tid); // MC tracks if (tx) sx->AddLink(tx); } else { if (tid == -2) s.SetNameTitle("N","Noise"); if (tid == -3) s.SetNameTitle("A","Afterpulse"); } } // Loop over all the waveforms and add the histo(s) to the corresponding OM's TH1F histo; Int_t nbins=0; Float_t xlow=0; Float_t xup=0; TString hname; for (Int_t iwf=0; iwfmaxchan) continue; // Skip trigger channels // Get corresponding device from the current event structure omx=(IceAOM*)evt->GetIdDevice(chan); if (!omx) { if (fOmdb) { omx=(IceAOM*)fOmdb->GetObject(chan,1); evt->AddDevice(omx); } else { om.Reset(1); om.SetUniqueID(chan); evt->AddDevice(om); } omx=(IceAOM*)evt->GetIdDevice(chan); } if (!omx) continue; omx->SetSlotName("BASELINE",omx->GetNnames()+1); omx->SetSignal(fEvent.wf[iwf].baseline,"BASELINE"); // Fill the waveform histogram hname="OM"; hname+=chan; hname+="-WF"; hname+=omx->GetNwaveforms()+1; histo.Reset(); histo.SetName(hname.Data()); nbins=fEvent.wf[iwf].ndigi; xlow=fEvent.wf[iwf].t_start; xup=xlow+float(nbins)*fEvent.wf[iwf].t_bin; histo.SetBins(nbins,xlow,xup); for (Int_t jbin=1; jbin<=fEvent.wf[iwf].ndigi; jbin++) { histo.SetBinContent(jbin,fEvent.wf[iwf].digi[jbin]); } omx->SetWaveform(&histo,omx->GetNwaveforms()+1); } // Set bi-directional links between hits and reco track hypotheses. // Note : Reco tracks are recognised by their positive id. Int_t hid=0; TObjArray* rectracks=evt->GetTracks(1); for (Int_t jtk=0; jtkGetEntries(); jtk++) { tx=(AliTrack*)rectracks->At(jtk); if (!tx) continue; for (Int_t jhyp=1; jhyp<=tx->GetNhypotheses(); jhyp++) { AliTrack* hypx=tx->GetTrackHypothesis(jhyp); if (!hypx) continue; // Loop over all combinations of F2K fits and used OM hits for (Int_t k=0; kGetId()) continue; hid=fEvent.fit_uses[k].hitid; sx=evt->GetIdHit(hid,"IceAOM"); if (sx) sx->AddLink(hypx); } } } } ///////////////////////////////////////////////////////////////////////////