///////////////////////////////////////////////// // TATOFEvent IMPLEMENTATION for s394 // by Arnaud Le Fevre, March 2012 // ver. 1.0 event unpacker // Inspired from W. Mueller's version of s254 ///////////////////////////////////////////////// #include "TATOFEvent.h" TATOFEvent *gatofevent = 0; TATOFparaDsc *p_tmap = 0; TATOFdataDsc *p_datraw = 0; /* TATOFdataDsc *n_trtrk = 0; TATOFaction *an_trtrk =0; TATOFRdataDsc *n_traw = 0; TATOFaction *an_traw = 0; */ TATOFEvent::TATOFEvent() // constructor { if (gatofevent==0) gatofevent = this; if (p_tmap==0) p_tmap = new TATOFparaDsc("p_tmap",new TATOFparMap()); if (p_datraw==0) p_datraw = new TATOFdataDsc("p_datraw",new TATOFdatRaw()); /* if (d_traw==0) d_traw = new TATOFdataDsc("d_traw",new TATOFdatRaw()); if (n_traw==0) n_traw = new TATOFdataDsc("n_traw",new TATOFntuRaw()); if (an_traw==0) an_traw = new TATOFactNtuRaw("an_traw",n_traw, d_traw); if (n_trtrk==0) n_trtrk = new TATOFdataDsc("n_trtrk",new TATOFntuRawTrack()); if (an_trtrk==0) an_trtrk = new TATOFactNtuRawTrack("an_trtrk",n_trtrk, d_traw, p_tmap); */ } TATOFEvent::~TATOFEvent() // destructor { gatofevent = 0; p_tmap = 0; p_datraw = 0; /* n_trtrk = 0; an_trtrk =0; n_traw = 0; an_traw = 0; */ } Bool_t TATOFEvent::LoadMapping(const char *MappingFile){ // Load ToF-Wall mapping and make some other initialisations //p_tmap = new TATOFparaDsc("p_tmap",new TATOFparMap()); //TATOFparaDsc* p_tmap = new TATOFparaDsc("p_tmap",new TATOFparMap()); printf("Load ALADiN ToF-Wall mapping file %s\n",MappingFile); ((TATOFparMap*)p_tmap->Object())->FromFile(MappingFile); return kTRUE; } Bool_t TATOFEvent::ProcessCurrentEventMBS(Int_t* p_se,Int_t i_nw){ // Inputs: size of ATOF sub-event, pointer on ATOF sub-event //printf("i_nw=%d ",i_nw); //printf("p_se[0]=%d\n",p_se[0]); //if (!gTATOFroot->NextEvent(p_se,i_nw)) return kFALSE; // decrypt sub-event into raw hits //TATOFdatFbus* p_datraw; //TATOFparFbusCal* p_parcal; // TATOFparaDsc* p_tmap = new TATOFparaDsc("p_tmap",new TATOFparMap()); //TATOFdatFbus* p_datraw = (TATOFdatFbus*) fpDatRaw->Object(); //TATOFparFbusCal* p_parcal = (TATOFparFbusCal*) fpParCal->Object(); Int_t i_nadc = 0; Int_t i_ntdc = 0; Int_t i_ndrop = 0; Int_t i_glast = -1; Int_t i_clast = -1; for (Int_t i = 0; i < i_nw; i++) { // loop over words UInt_t i_data = p_se[i]; Int_t i_g = (i_data>>27) & 0x001f; // geographical address (slot) on fastbus //printf("test point 1: i_g=%d \n",i_g); // test if (i_g < 2){ i_ndrop++; continue; // not fastbus cards } Int_t i_c = (i_data>>16) & 0x007f; // channel fired on that slot Int_t i_addr = TATOFdatFbus::PackAddress(i_g, i_c); //printf("test point 2: i_g=%d i_c=%d i_addr=%d \n",i_g,i_c,i_addr); // test if (!(((TATOFparMap*)p_tmap->Object())->CheckMap2(i_addr))){ // probleme ici : fiSlat n'est pas accessible //printf("----> not in mapping: i_g=%d i_c=%d i_addr=%d i/i_nw=%d/%d, MaxAddress=%d\n",i_g,i_c,i_addr,i,i_nw,((TATOFparMap*)p_tmap->Object())->MaxAddress()); // test i_ndrop++; continue; // not present in the mapping } if (i_g > 0 && i_g != i_glast) { i_glast = i_g; i_clast = i_c; } else { /* if (i_c <= i_clast) { printf("\n Non-increasing fastbus channel number g,c = %2d,%2d -> %2d,%2d \n", i_glast, i_clast, i_g, i_c); // it happens normally only from empty slots which generate fake hits } */ i_clast = i_c; } //const TATOFparFbusCalInfo* p_calinfo = p_parcal->Find(i_addr); //if (p_calinfo) { Int_t i_val = i_data & 0x00000fff; // value read in that channel (0-4095) Bool_t b_ran = i_data & 0x00800000; // range (low or high) Int_t i_combo = TATOFdatFbus::PackCombo(b_ran, i_val); // i_combo in bits = range (1 or 0) followed by i_val if (i_addr <= ((TATOFparMap*)p_tmap->Object())->MaxAddress()) { //const TATOFparMapAddr& addrinfo = ((TATOFparMap*)p_tmap->Object())->AddrInfo(i_addr); Int_t i_slat = (((TATOFparMap*)p_tmap->Object())->SlatFromAddress(i_addr)); // replacement - ALF, 01/2013 //Int_t i_slat = addrinfo.Slat(); // because this is empty Int_t i_type = (((TATOFparMap*)p_tmap->Object())->TypeFromAddress(i_addr)); // replacement - ALF, 01/2013 //Int_t i_type = addrinfo.Type(); // because this is empty //printf("test point 3: slat=%d type=%d b_ran=%d i_val=%d \n",i_slat,i_type,b_ran,i_val); // test if (i_slat > 0) { ((TATOFdatRaw*)p_datraw->Object())->SetHitData(i_slat, i_type, b_ran, i_val); // fill event list //printf("SetHitData(%d,%d,%d,%d)\n",i_slat, i_type, b_ran, i_val); //test if (i_type <= 2) i_nadc += 1; // ??? parametrise type else i_ntdc += 1; } else { i_ndrop += 1; } } //Int_t i_ran = (b_ran) ? 1 : 0; //printf("i_val=%d i_ran=%d i_combo=%d \n",i_val,i_ran,i_combo); // test // p_datraw->AddHit(i_addr, i_combo, p_calinfo->Calibrate(i_combo)); //} //else { //i_ndrop += 1; //} } // end loop over words ((TATOFdatRaw*)p_datraw->Object())->SortBySlat(); // sort the event list by slat ((TATOFdatRaw*)p_datraw->Object())->SetCounter(i_nadc, i_ntdc, i_ndrop); // fill general informations of the event // ((TATOFdatRaw*)p_datraw->Object())->ToStream(std::cout); // output the event list //((TATOFdatRaw*)p_datraw->Object())->Clear(); // reset return kTRUE; } Bool_t TATOFEvent::LoadCalibrationParameters(const char *InputDir){ // Load ToF-Wall calibration parameters for S394 Int_t slat[2]; // ===== For corrections of ADC top/bottom values of the beam hole slats ===== TFile *finputHole = new TFile(Form("%s/%s",InputDir,InputFileADCcorrHoleSlats),"read"); // 11/2012 hMedianSlopeADCtb_hole = (TH1F*)finputHole->Get("hMedian"); for (slat[0]=SlatMinHole;slat[0]<=SlatMaxHole;slat[0]++){ slat[1]=slat[0]+100; for (Int_t fb=0;fb<2;fb++){ for (Int_t tb=0;tb<2;tb++){ gADCcorrHoleSlat[tb][slat[fb]] = (TGraph*)finputHole->Get(Form("GraphCorr%d_sl%d",tb+1,slat[fb])); } } } // ===== For harmonisation factors of ADC's top/bottom ===== TFile *finputHarmonisation = new TFile(Form("%s/%s",InputDir,InputFileADCharmonisation),"read"); //hp2ADCratio = (TH1F*)finputHarmonisation->Get("hp2ADCratio"); // from ADCtop/bottom spectra hp2ADCratio = (TH1F*)finputHarmonisation->Get("hp2ADCratio_new"); // extra corrected from positions as given by the ADCs // ===== For multihit cut ===== TFile *finputMultihitCut = new TFile(Form("%s/%s",InputDir,InputFileMultihitCut),"read"); // 11/2012 for (slat[0]=SlatMin;slat[0]<=SlatMax;slat[0]++){ slat[1]=slat[0]+100; for (Int_t fb=0;fb<2;fb++){ g2DxtxE[slat[fb]] = (TGraphErrors*) finputMultihitCut->Get(Form("g2DxtxE_sl%d",slat[fb])); } } TFile *finputMultihitCutParam = new TFile(Form("%s/%s",InputDir,InputFileMultihitCutParam),"read"); // 11/2012 hxtmin = (TH1F*)finputMultihitCutParam->Get("hxtmin"); hxtmax = (TH1F*)finputMultihitCutParam->Get("hxtmax"); // ===== For Z identification and final ADC calibration ===== TFile *finputZidGrids = new TFile(Form("%s/%s",InputDir,InputFileZidGrids),"read"); // 11/2012 Int_t sl; for (sl=1;sl<200;sl++){ BadZresolution[sl]=kFALSE; Int_t Zlast=1; // assumes that at least Z=1 grid line exists (when other Z's are described) for (Int_t Z=1;Z<100;Z++){ if ((TGraph*)finputZidGrids->Get(Form("gr_Z%d_sl%d",Z,sl))){ gZidGrid[Z][sl] = (TGraph*)finputZidGrids->Get(Form("gr_Z%d_sl%d",Z,sl)); ZgridAvailable[Z][sl]=kTRUE; if (sl==64){ // reference slat gZidGridRefInv[Z] = new TGraph(gZidGrid[Z][sl]->GetN(),gZidGrid[Z][sl]->GetY(),gZidGrid[Z][sl]->GetX()); // for final ADC calibration ("stretching") Zlast=Z; } } else ZgridAvailable[Z][sl]=kFALSE; if (sl==64) // reference slat ZnextAvailable[Z]=Zlast; } } if (ZgridAvailable[1][64] && ZgridAvailable[2][64]) // calibrated the 0 energy ADC value for the reference slat using Z=1 and 2 lines (in ToF vs ADC representation) RefSlatADCthreshold=(3.*gZidGridRefInv[1]->Eval(ToFprojFrontWall)-gZidGridRefInv[2]->Eval(ToFprojFrontWall))/2.; else RefSlatADCthreshold=0.; ifstream param(InputFileZidQuality); if(param.bad()){ printf("%s not found\n",InputFileZidQuality); exit(1); } Char_t pinfo[100]; for (Int_t i=0;i<5;i++) param.getline(pinfo,100); //printf("%s\n",pinfo); // header Int_t code; while(param >> sl >> code){ if (code==1) BadZresolution[sl]=kTRUE; } param.close(); // ===== For TDC calibration (walk and offset corrections) ===== TFile *finputWalkTDC = new TFile(Form("%s/%s",InputDir,InputFileWalkTDC),"read"); // 11/2012 for (slat[0]=SlatMin;slat[0]<=SlatMax;slat[0]++){ slat[1]=slat[0]+100; for (Int_t fb=0;fb<2;fb++){ for (Int_t tb=0;tb<2;tb++){ gWalkTDC[slat[fb]][tb] = (TGraph*)finputWalkTDC->Get(Form("gWalkTDC_sl%d_%s",slat[fb],ctb[tb])); } } } printf("ATOF calibration parameters are loaded.\n"); return kTRUE; } // ============================================================= // ============= ADC calibration =============================== // ============================================================= Bool_t TATOFEvent::ADCcorrHoleSlat(Int_t ADCtop,Int_t ADCbot,Int_t sl,Int_t &ADCtop_corr,Int_t &ADCbot_corr){ // This function returns, for a given slat number (sl) of the beam hole of the ToF-Wall, // the values of ADC top and bottom // corrected from the atenuation of the light in the hole. // By Arnaud Le Fevre, April 2012. if (!((sl>=SlatMinHole&&sl<=SlatMaxHole)||(sl>=SlatMinHole+100&&sl<=SlatMaxHole+100))) return kFALSE; // input out of range Float_t slope = hMedianSlopeADCtb_hole->GetBinContent(sl); if (ADCbot>slope*ADCtop){ // bottom hit ADCbot_corr=ADCbot; // bottom ADC remains unchanged ADCtop_corr=int(ADCtop*(gADCcorrHoleSlat[1][sl]->Eval(ADCtop))); // top ADC is corrected from uncomplete light transmission through the hole } else{ // top hit ADCtop_corr=ADCtop; // top ADC remains unchanged ADCbot_corr=int(ADCbot*(gADCcorrHoleSlat[0][sl]->Eval(ADCbot))); // bottom ADC is corrected from uncomplete light transmission through the hole } return kTRUE; } Bool_t TATOFEvent::ADCtbHarmonise(Int_t ADCtop,Int_t ADCbot,Int_t sl,Int_t &ADCtop_corr,Int_t &ADCbot_corr){ // This function returns, for a given slat number (sl) of the ToF-Wall, // the values of ADC top and bottom // corrected to the highest gain of both channels. // By Arnaud Le Fevre, April 2012. if (!((sl>=SlatMin&&sl<=SlatMax)||(sl>=SlatMin+100&&sl<=SlatMax+100))) return kFALSE; // input out of range Float_t ratio = hp2ADCratio->GetBinContent(sl); if (ratio==0) return kFALSE; if (ratio>1) { // top PM has the highest gain => correct bottom ADC ADCtop_corr=ADCtop; ADCbot_corr=ADCbot*ratio; } else{ // bottom PM has the highest gain => correct top ADC ADCtop_corr=ADCtop/ratio; ADCbot_corr=ADCbot; } return kTRUE; } Bool_t TATOFEvent::ADCcalibration0(Int_t ADCtop,Int_t ADCbot,Int_t sl,Int_t &ADCtop_corr,Int_t &ADCbot_corr){ if (!((sl>=SlatMin&&sl<=SlatMax)||(sl>=SlatMin+100&&sl<=SlatMax+100))) return kFALSE; // input out of range if ((sl>=SlatMinHole&&sl<=SlatMaxHole)||(sl>=SlatMinHole+100&&sl<=SlatMaxHole+100)){ // hit in beam slat slat => first ADC corrections if (!ADCcorrHoleSlat(ADCtop,ADCbot,sl,ADCtop_corr,ADCbot_corr)) return kFALSE; ADCtop=ADCtop_corr; ADCbot=ADCbot_corr; } // second ADC correction: top/bottom gain harmonisation if (!ADCtbHarmonise(ADCtop,ADCbot,sl,ADCtop_corr,ADCbot_corr)) return kFALSE; return kTRUE; } Bool_t TATOFEvent::ADCcalibrationFinal(Int_t sl,Int_t Z,Float_t ADC,Float_t &E){ // Use the Z grid lines to scale the ADC value to the one that would have the reference slat 64 //printf("\n sl=%d iZ=%d ADC=%f E=%f\n",sl,Z,ADC,E); //if (ZgridAvailable[ZnextAvailable[Z]][sl]) printf("grille Z,sl OK\n"); //if (ZgridAvailable[ZnextAvailable[Z]][64]) printf("grille Z,sl64 OK\n"); if (Z>=1 && Z<100 && ADC>0 && ZgridAvailable[ZnextAvailable[Z]][sl] && ZgridAvailable[ZnextAvailable[Z]][64]){ Double_t TOF=gZidGrid[ZnextAvailable[Z]][sl]->Eval(ADC); E=gZidGridRefInv[ZnextAvailable[Z]]->Eval(TOF) - RefSlatADCthreshold; // add last term in order to have Z=1 at E greater than and close to 0 (reference slat has a high threshold) //printf("\n sl=%d iZ=%d ADC=%f E=%f\n",sl,Z,ADC,E); return kTRUE; } return kFALSE; } // ============================================================= // ============= Charge identification ========================= // ============================================================= Bool_t TATOFEvent::Zid(Int_t slat, Float_t E, Float_t ToF, Float_t &Zreal,Int_t &Zint,Int_t &cptw) { // Outputs the charge determined by the TOF-Wall during S394 experiment. // Inputs: // slat = slat number // E = calibrated pseudo energy (harmonised ADC, sqrt(adct*adcb), not stretched) // ToF = time of flight (ns) // ToF for Zid will be the time of flight that has been used in Z grid determination, i.e. not corrected from offsets (ns) // Ouputs: // Zreal = charge of particle as a float // Zint = charge of particle as an integer // cptw = quality code of particle Z: // 0 = OK // 1 = bad resolution but OK for Zbound // 9 = error : hit outside ADC-TOF grid // 10 = error : no Z id. available for this slat // 13 = error : inputs outside specified range const Float_t ToFmin=-10.; // range of times around the beam time-of-flight const Float_t ToFmax=40.; // (corrected from individual offsets, walk, general offset, ns) const Int_t Zmax=80.; // max. Z for the grid lines of s394 Zreal=-1.; // default values Zint=-1.; cptw=0; if (E<=0||ToF<=0 ||slat<0||slat>=200){ cptw=13; return kFALSE; } if (!ZgridAvailable[1][slat]){ cptw=10; return kFALSE; } if (!ZgridAvailable[1][slat]){ cptw=9; return kFALSE; } if (BadZresolution[slat]){ cptw=1; } if (ToF-ToFprojFrontWall>ToFmax||ToF-ToFprojFrontWallEval(18000.); Float_t ToFoffsetBot = gWalkTDC[slat][1]->Eval(18000.); ToF=ToF+(ToFoffsetTop+ToFoffsetBot)/2. + TimeOffsetRef_DiffOldNew; // the walk offsets and the old general offset are added back, because the id. grids have been determined so } Int_t Z,Zprevious=0; Float_t ToFline=10000.,ToFlineNext,ToFlinePrevious; //Float_t ADCline=10000.,ADClineNext,ADClinePrevious; for (Z=1;Z<=Zmax;Z++){ if (ZgridAvailable[Z][slat]){ ToFline = gZidGrid[Z][slat]->Eval(E); //printf("test grid Z=%d - ToFline=%f - ToF=%f - E=%f - slat=%d\n",Z,ToFline,ToF,E,slat); //if (ADClineEval(E); Zreal=1-(ToF-ToFline)/(ToFline-ToFlineNext); } else if (Z==Zmax){ ToFlinePrevious = gZidGrid[Zprevious][slat]->Eval(E); Zreal=Zmax+float(Zmax-Zprevious)*(ToFline-ToF)/(ToFlinePrevious-ToFline); } else{ ToFlinePrevious = gZidGrid[Zprevious][slat]->Eval(E); Zreal=Z-float(Z-Zprevious)*(ToF-ToFline)/(ToFlinePrevious-ToFline); } Zint=TMath::Nint(Zreal+0.5); return kTRUE; } // ============================================================= // ============= Multihit rejection ============================ // ============================================================= Bool_t TATOFEvent::MultihitCal(Int_t sl, Int_t ADCtop, Int_t ADCbot, Float_t TDCtop, Float_t TDCbot,Float_t &mh) { // As inputs, the ADCs have to be already calibrated //(corrected from loss in beam hole and top/bottom hamonised) and, in this version, the TDCs too. // Checks whether the hit positions given the ADCs and the TDCs correspond // within a given accurracy. Return kFALSE when it is NOT a "Multihit". mh=-100.; if (ADCtop*ADCbot==0||TDCtop*TDCbot==0) return kTRUE; // not all necessary informations present Float_t xE=log(float(ADCtop)/float(ADCbot)); // position from ADCs Float_t xt=(TDCtop-TDCbot)/2.; // position from TDCs //printf("xE=%f - xt=%f - min = %f - max = %f - abs(eval-xE)=%f\n", // xE,xt,hxtmin->GetBinContent(sl),hxtmax->GetBinContent(sl), // TMath::Abs((g2DxtxE[sl]->Eval(xt))-xE)); mh=TMath::Abs((g2DxtxE[sl]->Eval(xt))-xE); if (xtGetBinContent(sl) || xt>hxtmax->GetBinContent(sl)) return kTRUE; // out of spatial range if (mh=SlatMin&&sl<=SlatMax)||(sl>=SlatMin+100&&sl<=SlatMax+100))) return kFALSE; // input out of range if (ADCtop_corr==-1||ADCbot_corr==-1) return kFALSE; Int_t fb; fb = (sl<100) ? 0 : 1; ToFtop = (TDCtop<=0) ? 0 : TimeOffsetRef[fb]-float(TDCtop)/40.-tstart; // top time-of-flight (ns) => walk will include individual offset here ToFbot = (TDCbot<=0) ? 0 : TimeOffsetRef[fb]-float(TDCbot)/40.-tstart; // bottom time-of-flight (ns) => idem Float_t WalkTop = gWalkTDC[sl][0]->Eval(ADCtop_corr); Float_t WalkBot = gWalkTDC[sl][1]->Eval(ADCbot_corr); ToFtop = (TDCtop<=0) ? 0 : ToFtop - WalkTop; ToFbot = (TDCbot<=0) ? 0 : ToFbot - WalkBot; ToFoffsetTop = (TDCtop<=0) ? 0 : gWalkTDC[sl][0]->Eval(18000.); ToFoffsetBot = (TDCbot<=0) ? 0 : gWalkTDC[sl][1]->Eval(18000.); return kTRUE; } // ================================================================= // ============= General calibration =============================== // ================================================================= Bool_t TATOFEvent::Calibration(Int_t sl,Int_t st,Int_t a1,Int_t a2,Int_t t1,Int_t t2,Float_t tstart, Float_t &Z,Float_t &tof,Float_t &E,Float_t &y,Int_t &imh,Float_t &mh, Int_t &cp){ Z=-100.; tof=-100.; E=-100.; y=-100.; imh=0; mh=0.; cp=0; if (st!=15) cp=9; // ==== Z identification === Int_t ac1,ac2; if (!TATOFEvent::ADCcalibration0(a1,a2,sl,ac1,ac2)){ // ADC calibration for Z id. providing ac1=-1; // not yet stretched but harmonised ADC ac2=-1; // values } //printf(" === ADC cal.: a1=%d,a2=%d,sl=%d,ac1=%d,ac2=%d\n",a1,a2,sl,ac1,ac2); Float_t tc1,tc2,toffset1,toffset2;//ToFforZid; if (!TATOFEvent::TDCcalibration(t1,t2,ac1,ac2,tstart,sl,tc1,tc2,toffset1,toffset2)){ cp=13; tof=-100.; y=-100.; //ToFforZid=-100.; } else{ if (tc1>0&&tc2>0){ tof=(tc1+tc2)/2.; // ns y=(tc2-tc1)*30./RefractionIndex; // cm //ToFforZid=(tc1+tc2+toffset1+toffset2)/2. //+ TimeOffsetRef_DiffOldNew; // the walk offsets and the old general offset are added back, because the id. grids have been determined so; THIS IS DONE IN Zid() - ALF, 01/2013 //printf(" === TDC cal.: t1=%d,t2=%d,ac1=%d,ac2=%d,tstart=%f,sl=%d,tc1=%f,tc2=%f,toffset1=%f,toffset2=%f\n",t1,t2,ac1,ac2,tstart,sl,tc1,tc2,toffset1,toffset2); } } Z=-100.; Int_t iZ=-100; if (ac1<=0 || ac2<=0 || tof==-100.) cp=9; else{ if (!TATOFEvent::Zid(sl,sqrt(ac1*ac2),tof,Z,iZ,cp)){ //printf("HERE 1 sl=%d E=%f tof=%f Z=%f iZ=%d cp=%d\n",sl,sqrt(ac1*ac2),tof,Z,iZ,cp); Z=-100.; iZ=-100; } //printf(" === Z id.: sl=%d,sqrt(ac1*ac2)=%f,tof=%f,Z=%f,iZ=%d,cp=%d\n",sl,sqrt(ac1*ac2),tof,Z,iZ,cp); //printf("==== sl=%d iZ=%d - E before = %f \n",sl,iZ,sqrt(ac1*ac2)); if (!TATOFEvent::ADCcalibrationFinal(sl,iZ,sqrt(ac1*ac2),E)) // final ADC calibration for Z id. (harmonised and stretched) E=-100.; //printf("==== E after stretching = %f\n",E); if (TATOFEvent::MultihitCal(sl,ac1,ac2,tc1,tc2,mh)) imh=1; //printf(" === multihit: sl=%d,ac1=%d,ac2=%d,tc1=%f,tc2=%f,mh=%f\n",sl,ac1,ac2,tc1,tc2,mh); } return kTRUE; }