void KVIVRawDataReconstructor::InitRun()
{
   // Creates new ROOT file with TTree for reconstructed/calibrated events.
   // By default this file will be written in the same data repository as the raw data file we are reading.
   // This can be changed by setting the environment variable(s):
   //
   //     Reconstruction.DataAnalysisTask.OutputRepository:     [name of repository]
   //     [name of dataset].Reconstruction.DataAnalysisTask.OutputRepository:         [name of repository]
   //
   // If no value is set for the current dataset (second variable), the value of the
   // first variable will be used. If neither is defined, the new file will be written in the same repository as
   // the raw file (if possible, i.e. if repository is not remote).

   // Create new KVIVReconEvent used to reconstruct & store events
   // The condition used to seed new reconstructed particles (see KVReconstructedEvent::AnalyseTelescopes)
   // is set by reading the value of the environment variables:
   //     Reconstruction.DataAnalysisTask.ParticleSeedCond:        [all/any]
   //     [name of dataset].Reconstruction.DataAnalysisTask.ParticleSeedCond:     [all/any]
   // If no value is set for the current dataset (second variable), the value of the
   // first variable will be used.

   if (!recev) recev = fIVevent = new KVIVReconEvent;
   KVINDRARawDataReconstructor::InitRun();

   //Remove the first branch 'INDRAReconEvent' of tree created by KVINDRARawDataReconstructor::InitRun()
   //and replace it by new branch 'IVReconEvent' with a KVIVReconEvent object
   TObjArray* branches = tree->GetListOfBranches();
   delete branches->RemoveAt(0);
   branches->Compress();
   KVEvent::MakeEventBranch(tree, "IVReconEvent", "KVIVReconEvent", &fIVevent);

   //Detector events for INDRA and VAMOS
   fINDRADetEv = new KVDetectorEvent;
   fVAMOSDetEv = new KVDetectorEvent;

   //initialise number of reconstructed VAMOS events
   fNbVAMOSrecon = 0;
}
Example #2
0
int mergeDigits(TString digitdir, Int_t /*simEvOffset*/)
{

    AliRunLoader *rl = AliRunLoader::Open(digitdir+TString("/galice.root"));

    AliPHOSLoader *prl = (AliPHOSLoader*)rl->GetDetectorLoader("PHOS");

    prl->LoadDigits("UPDATE");
    
    //prl->LoadDigits();

    Int_t nEvents = rl->GetNumberOfEvents();

    TClonesArray *mydigits = 0;
    simTree->SetBranchAddress("Digits", &mydigits);

    Int_t nDigits = 0;
    Int_t nEmbedDigits = 0;
    Int_t nOverlappingDigits = 0;
    Int_t nNewDigits = 0;
    
    Int_t nPhosDigits = prl->Digits()->GetEntries();

    Int_t nMyEvents = simTree->GetEntries();
    
    std::cout << "Number of real events: " << nEvents << std::endl;
    std::cout << "Number of sim events: " << nMyEvents << std::endl;
    nEvents = TMath::Min(nEvents, nMyEvents);
    std::cout << "Looping over: " << nEvents << std::endl;
	
    for (Int_t ev = 0; ev < nEvents; ev++)
    {
        rl->GetEvent(ev);
        
        simTree->GetEntry(ev);
        Int_t nMyDigits = mydigits->GetEntries();

        //Int_t nDigsFound = 0;
        nEmbedDigits += nMyDigits;
        TClonesArray *phosDigits = prl->Digits();
	nPhosDigits = prl->Digits()->GetEntries();
	
        for (Int_t iDig = 0; iDig < nPhosDigits; iDig++)
        {
            //const AliPHOSDigit *digit = prl->Digit(iDig);
            AliPHOSDigit *digit = (AliPHOSDigit*)phosDigits->At(iDig);
            nDigits++;
            for (Int_t n = 0; n < nMyDigits; n++)
            {
                AliPHOSDigit *myDigit = (AliPHOSDigit*)mydigits->At(n);
                if (digit->GetId() == myDigit->GetId())
                {
                    nOverlappingDigits++;
                    break;
                }
            }
        }
        if(nOverlappingDigits == nMyDigits)
        {
            std::cout << "Digits alredy embedded!" << std::endl;
            continue;
        }
        for (Int_t iDig = 0; iDig < nMyDigits; iDig++)
        {
            AliPHOSDigit *myDigit = (AliPHOSDigit*)mydigits->At(iDig);
            if (myDigit)
            {
                for (Int_t n = 0; n < nPhosDigits; n++)
                {
                    //const AliPHOSDigit *digit = prl->Digit(n);

                    AliPHOSDigit *digit = (AliPHOSDigit*)phosDigits->At(n);
                    if (digit->GetId() == myDigit->GetId())
                    {
                        digit->SetALTROSamplesHG(0, 0);
                        digit->SetALTROSamplesLG(0, 0);

                        *digit += *myDigit;
                        myDigit = 0;
                        break;
                    }
                }
                if (myDigit)
                {
                    TClonesArray *digArray = prl->Digits();
                    AliPHOSDigit *newDig =  new((*digArray)[nPhosDigits+nNewDigits]) AliPHOSDigit(*myDigit);

                    newDig->SetALTROSamplesHG(0, 0);
                    newDig->SetALTROSamplesLG(0, 0);
                    nNewDigits++;
                }
            }
        }
        phosDigits->Compress();
        Int_t ndigits = phosDigits->GetEntries() ;
	phosDigits->Sort();
        // Remove digits that are flagged bad in BCM. Then remove digits that are below threshold
        for (Int_t i = 0 ; i < ndigits ; i++)
        {
            AliPHOSDigit *digit = static_cast<AliPHOSDigit*>( phosDigits->At(i) ) ;
	    //std::cout << digit->GetId() << std::endl;
            if(digit->GetId())
            {
                vector<Int_t>::iterator it;
                it = std::find (badChannels.begin(), badChannels.end(), digit->GetId() );
                if(*it)
                {
                    digit->SetEnergy(0.0);
                }
            }
            if(digit->GetEnergy() <= recoParam->GetGlobalAltroThreshold())
	    {
	      phosDigits->RemoveAt(i);
	    }
        }
        //Set indexes in list of digits and make true digitization of the energy
        phosDigits->Compress();
        phosDigits->Sort();
	ndigits = phosDigits->GetEntries();
        for (Int_t i = 0 ; i < ndigits ; i++)
        {
            AliPHOSDigit *digit = static_cast<AliPHOSDigit*>( phosDigits->At(i) ) ;
            digit->SetIndexInList(i) ;
        }
        // -- create Digits branch
        Int_t bufferSize = 32000 ;

        TObjArray *branchList = prl->TreeD()->GetListOfBranches();

        branchList->RemoveAt(0);

        TBranch * digitsBranch = prl->TreeD()->Branch("PHOS","TClonesArray",&phosDigits,bufferSize);

        digitsBranch->Fill() ;
        prl->WriteDigits("OVERWRITE");
    }
    prl->WriteDigits("OVERWRITE");
    std::cout << "# Digits: " << nDigits << std::endl;
    std::cout << "# Embedded digits: " << nEmbedDigits << std::endl;
    std::cout << "# Overlapping digits: " << nOverlappingDigits << std::endl;
    std::cout << "# New digits: " << nNewDigits << std::endl;
    
    return 0;
}
Example #3
0
void PlotPubHisto(TObjArray histograms,TEnv *params){
    // This is a modification of the AddHistos macro
    
    // Number of histos to plot:
    Int_t ntot = histograms.GetEntries();
    
    // Check we have what we expect (the order should be: data, qcd, wjets, etc...)
    for(Int_t i = 0; i<ntot; i++){
	if(histograms[i]==0) {
	    cout<<"Error in AddHistos: histogram "<<i<<" is a NULL pointer!"<<endl;
	    return;
	}
	TH1F * hthis = (TH1F*) histograms[i];
	// include the overflow/underflow bins:
	int numbins = hthis->GetNbinsX(); //this is the last bin plotted
	double hicontent = hthis->GetBinContent(numbins);
	double overflow  = hthis->GetBinContent(numbins+1);// this bin contains the overflow
	double locontent = hthis->GetBinContent(1);// this is the first bin plotted
	double underflow = hthis->GetBinContent(0);// this bin contains the underflow
	if (underflow>0 || overflow>0){
	    //printf("%-20s numbins=%4i hicontent=%4.2f over=%4.2f locontent=%4.2f underflow=%4.2f \n",
	    //	 title.Data(),numbins,hicontent,overflow,locontent,underflow);
	}
	hthis->SetBinContent(numbins,hicontent+overflow);
	hthis->SetBinContent(1,locontent+underflow);
    }
    
    // define a few additional line styles:
    gStyle->SetLineStyleString(5,"20 12 4 12");
    gStyle->SetLineStyleString(6,"20 12 4 12 4 12 4 12");
    gStyle->SetLineStyleString(7,"20 20");
    gStyle->SetLineStyleString(8,"20 12 4 12 4 12");
    gStyle->SetLineStyleString(9,"80 25");
    gStyle->SetLineStyleString(10,"50 10 10 10");
    gStyle->SetLineStyleString(17,"30 25");
    gStyle->SetLineStyleString(20,"60 20");
    gStyle->SetLineStyleString(21,"60 20 20 20");
    int lineStyle[20];
    for(int i=0;i<20;i++) {
	lineStyle[i]=i;
    }

    // the first histogram in the list:
    TH1F *h0=((TH1F*) histograms[0])->Clone();
    
    // histogram output filename
    TString oFileName=params->GetValue("Histo.Output.Filename","bogus.eps");
    
    // figure out the number of signals
    Int_t nsig=1;
    if(params->Defined("Histo.Signal.Title.1")) nsig=1;
    if(params->Defined("Histo.Signal.Title.2")) nsig=2;
    if(params->Defined("Histo.Signal.Title.3")) nsig=3;
    
    cout << " I will use nsig = " << nsig << " signal sources" << endl;
    
    // Do the cumulative summing, except for the data
    TObjArray addedhistos; addedhistos.Clear();
    TObjArray signalhistos; signalhistos.Clear();
    TString sampletitles[20];
    Int_t nbkg=0;
    for(Int_t i = 1; i<ntot; i++){// i runs over histograms[i], so data is for i=0
	ostringstream baseSrcName;
	baseSrcName << "Files." << i+1 << ".";// Counting starts at 1: Files.1.Name: Data
	TString bSrcName(baseSrcName.str().c_str());
	// skip some if we want to show them as lines
	TString htitle=params->GetValue(bSrcName+"Title","");
	sampletitles[i-1]=htitle;
	if(params->GetValue("Histo.ShowSignalSeparately",0)==1 &&
	   // skip the last two if the signal title is not defined:
	   ( ( !(params->Defined("Histo.Signal.Title")||params->Defined("Histo.Signal.Title.1")) && i>=ntot-nsig) 
	     // skip the signal if the signal title is defined
	     || params->GetValue("Histo.Signal.Title",".")==htitle
	     || params->GetValue("Histo.Signal.Title.1",".")==htitle
	     || params->GetValue("Histo.Signal.Title.2",".")==htitle
	     || params->GetValue("Histo.Signal.Title.3",".")==htitle
	     ) ) {
	    TH1F * hthis = (TH1F*) histograms[i]->Clone();
	    cout<<" Found signal in location "<<i+1<<" with name "<<htitle.Data()<<endl;
	    signalhistos.Add(hthis);
	} else {
	    TH1F * hthis = (TH1F*) histograms[i]->Clone();
	    addedhistos.Add(hthis); // Fill in the new TObjArray with a copy 
	    //cout << " Adding bkg " << i << " " << htitle.Data() << " " << hthis->Integral() << endl;
	    // add all of the backgrounds
	    if (i>1) {// i=0 is the data, and we must start with the second
		      // background to add the previous
		TH1F * hprevious = (TH1F*) addedhistos[i-2];
		if ( hthis->GetXaxis()->GetNbins() != hprevious->GetXaxis()->GetNbins() ) {
		    // Protection against _whoran histogram. 
		    // We cannot add two histograms with different numbers of bins!
		    cout<<"Error in AddHistos: incompatible number of bins!"<<endl;  
		    return;
		}
		hthis->Add(hprevious); // Do the addition
		addedhistos.RemoveAt(i-1); // And substitute whatever we had 
		addedhistos.AddAt(hthis,i-1);
		nbkg++;
		//cout << "Substituing bkg " << i << " + " << i-1 << " in addedhistos["<< i-1 <<"]" << endl;
	    }	    
	} // end of: if adding histograms
    }
    cout << " nbkg = " << nbkg << endl; 
    
    // Rebin histos if necessary, but first calculate KS:
    TH1F *hbkg = (TH1F*) addedhistos[nbkg];
    double KS = h0->KolmogorovTest(hbkg);
    double chi2ndf = h0->Chi2Test(hbkg, "UWUFOFCHI2/NDF");
    //cout << title.Data() << " KS = " << KS << " chi2/NDF = " << chi2ndf << endl;
    // Rebin? Set nrebin = 0 to NOT do rebinning. 
    // Will rebin only histos whose maximum x axis value exceeds 20. 
    // Anything with less will most probably be already made of integers, so no
    // need to rebin that! 
    Int_t nbinsx = h0->GetXaxis()->GetNbins();
    Int_t nbinsy = 100;
    Int_t nrebin = 5;
    if ( nbinsx > 750 && nbinsx <= 1000) nrebin = 30;
    if ( nbinsx > 400 && nbinsx <= 750 ) nrebin = 25;//20
    if ( nbinsx > 300 && nbinsx <= 400 ) nrebin = 25;//15
    if ( nbinsx > 200 && nbinsx <= 300 ) nrebin = 25;//15
    if ( nbinsx > 150 && nbinsx <= 200 ) nrebin = 10;//10
    if ( nbinsx > 100 && nbinsx <= 150 ) nrebin = 10;//10
    if ( nbinsx > 50 && nbinsx <= 100 )  nrebin = 10;//10
    if ( nbinsx > 20 && nbinsx <= 50 )   nrebin = 2;
    if ( nbinsx <= 20 ) nrebin = 1;  
    
    printf(" Saw nbins =%4i, rebinning by nrebin =%2i to final %3i bins \n",nbinsx,nrebin,int(nbinsx/nrebin));	

    if ( nrebin != 0 ) {
	h0->Rebin(nrebin); // data
	for (Int_t i = 0; i<=nbkg; i++){
	    TH1F * h = (TH1F*) addedhistos[i];
	    h->Rebin(nrebin);
	}
	for (Int_t i = 0; i<nsig; i++){
	    TH1F * h = (TH1F*) signalhistos[i];
	    h->Rebin(nrebin);
	}
    }

    // default text size: 0.045
    // make it bigger for the paper
    float textSize = 0.045;
    if(params->GetValue("Histo.Preliminary","yes")==TString("paper")) textSize=0.07;
    if(params->Defined("Histo.TextSize")) textSize=params->GetValue("Histo.TextSize",0.07);
    
    // Now, check largest dimensions so that we can plot all histograms at once.
    Float_t xmin=9999., xmax=-9999., ymin=9999., ymax=-9999.;
    for(Int_t i = 0; i<=nbkg; i++){
	TH1F * h = (TH1F*) addedhistos[i];
	ostringstream baseSrcName;
	baseSrcName << "Files." << i+1 << ".";
	TString bSrcName(baseSrcName.str().c_str());
	
	TAxis *axis = h->GetXaxis();
	if( axis->GetXmin() < xmin ) xmin = axis->GetXmin();
	if( axis->GetXmax() > xmax ) xmax = axis->GetXmax();
	if( h->GetMinimum() < ymin ) ymin = h->GetMinimum();
	if( h->GetMaximum() > ymax ) ymax = h->GetMaximum();
    }
    ymax = TMath::Nint(ymax*1.25+1); // Make enough room for the big legend
    TString title = h0->GetTitle();
    
    //
    // now check if we should simply use the ranges that was passed to us.
    if(params->Defined("Histo.Xmin")) xmin = params->GetValue("Histo.Xmin",0.);
    if(params->Defined("Histo.Xmax")) xmax = params->GetValue("Histo.Xmax",0.);
    if(params->Defined("Histo.Ymin")) ymin = params->GetValue("Histo.Ymin",0.);
    if(params->Defined("Histo.Ymax")) ymax = params->GetValue("Histo.Ymax",0.);
    
    // Now make the frame:
    TH2F * frame = new TH2F("frame","",nbinsx,xmin,xmax,nbinsy,ymin,ymax);
    cout<<" frame has xmin "<<xmin<<", xmax "<<xmax<<", ymax "<<ymax<<endl;
    
    // get the x- and y-axis titles
    TString ytitle=params->GetValue("Histo.YTitle","");
    if ( params->Defined("Histo.XTitle")) {
	frame->SetXTitle(params->GetValue("Histo.XTitle",""));
    } else {
	frame->SetXTitle(h0->GetTitle());
    }
    frame->SetYTitle(ytitle.Data()); 
    // also set the text size for the X and Y axis titles and numbers
    // do this globally for the style we are using
    float axisLabelSize=textSize;
    frame->GetXaxis()->SetLabelSize(axisLabelSize);
    frame->GetYaxis()->SetLabelSize(axisLabelSize);
    frame->GetXaxis()->SetTitleSize(axisLabelSize);
    frame->GetYaxis()->SetTitleSize(axisLabelSize);
    
    frame->SetStats(false);
    // reduce the axis title offset if the fonts are very large
    if(textSize>0.055) frame->GetXaxis()->SetTitleOffset(1.0);
    // also change the X axis title offset to move it farther away from the numbers
    if(params->Defined("Histo.XTitle.Offset")) {
	float xtitoffset=params->GetValue("Histo.XTitle.Offset",1.0);
	frame->GetXaxis()->SetTitleOffset(xtitoffset);
    }
    
    // also change the y axis title offset to move it farther away from the numbers
    frame->GetYaxis()->SetTitleOffset(1.0);
    // reduce the axis title offset if the fonts are very large
    if(textSize>0.055) frame->GetYaxis()->SetTitleOffset(1.0);
    
    // set the axes divisions
    frame->GetXaxis()->SetNdivisions(505,true);
    if(params->Defined("Histo.XNdivisions")) frame->GetXaxis()->SetNdivisions(params->GetValue("Histo.XNdivisions",505),kTRUE);
    if(params->Defined("Histo.YNdivisions")) frame->GetYaxis()->SetNdivisions(params->GetValue("Histo.YNdivisions",505),kTRUE);
    
    // make sure the X axis title and Y axis title are in black!
    frame->GetXaxis()->SetTitleColor(1);
    frame->GetYaxis()->SetTitleColor(1);

    // Could plot in log scale...
    //gPad->SetLogy();

    // finally: Draw
    frame->Draw();
    
    // Draw the background ones:
    for(Int_t i=nbkg; i>=0; i--){
	TH1F * h = (TH1F*) addedhistos[i];
	h->SetStats(kFALSE);
	
	ostringstream baseSrcName;
	baseSrcName << "Files." << i+2 << ".";// to account for the data which is Files.1
	TString bSrcName(baseSrcName.str().c_str());
	Int_t hcolor=params->GetValue(bSrcName+"Color",1); 	
	h->SetLineColor(1);      
	h->SetFillColor(hcolor);
        if (i==nbkg) printf(" Data Yield = %5.2f ; SumBkg = %5.2f ; Data-SumBkg diff = %5.2f%% \n",
	   		     h0->Integral(),h->Integral(),(h0->Integral()-h->Integral())*100./h0->Integral());
	printf(" plotting bkg i=%2i name=%20.20s file=%2i integral=%5.1f color=%2i\n",
	       i,sampletitles[i].Data(),i+2,h->Integral(),hcolor);
	int fillStyle=params->GetValue(bSrcName+"FillStyle",1001);
	h->SetFillStyle(fillStyle);
	h->DrawCopy("Hist,Same");
    }
    //
    // and draw the signal ones
    // draw them in reverse order so that the last one will be on top.
    //for(Int_t i=ntot-3; i<ntot; i++){
    for(Int_t i=nsig-1; i>=0; i--){
	ostringstream baseSrcName;
	baseSrcName << "Files." << ntot+1-nsig+i << ".";
	TString bSrcName(baseSrcName.str().c_str());
	
	Int_t hcolor=params->GetValue(bSrcName+"Color",1);
	TH1F * h = (TH1F*) signalhistos[i];
       	if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=90"))        h->Add (h, 1.07874865  -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=100"))  h->Add (h, 1.62317373  -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=110"))  h->Add (h, 2.31347600  -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=120"))  h->Add (h, 3.25275183  -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=130"))  h->Add (h, 4.54142919  -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=140"))  h->Add (h, 6.19195046  -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=150"))  h->Add (h, 8.38307290  -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=160"))  h->Add (h, 11.31721008 -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=170"))  h->Add (h, 14.85376469 -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=180"))  h->Add (h, 19.54537459 -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=190"))  h->Add (h, 25.44594010 -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=200"))  h->Add (h, 32.94784356 -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=220"))  h->Add (h, 54.09499080 -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=240"))  h->Add (h, 86.85079034 -1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=260"))  h->Add (h, 136.31406761-1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=280"))  h->Add (h, 210.70375053-1.000);
	else if (sampletitles[ntot-1-nsig+i].Contains("m_{H}=300"))  h->Add (h, 319.79533099-1.000);
	
	printf(" plotting sig i=%2i name=%20.20s file=%2i integral=%5.1f color=%2i\n",
	       i,sampletitles[ntot-1-nsig+i].Data(),ntot+1-nsig+i,h->Integral(),hcolor);
	// create a white background around each line (helps readibility):
	TH1F *h1=h->Clone();
	h1->SetStats(kFALSE);
	h1->SetLineWidth(6);
	h1->SetLineColor(0);h1->SetFillColor(0);
	h1->SetLineStyle(1);
	h1->SetFillStyle(0);
	h1->Draw("HIST,SAME");
	// now draw the proper line:
	h->SetStats(kFALSE);
	h->SetLineWidth(6);
	h->SetLineColor(hcolor);h->SetFillColor(0);	
	Int_t hlinestyle = params->GetValue(bSrcName+"LineStyle",1);
	h->SetLineStyle(hlinestyle);
	h->SetFillStyle(0);	
	// finally, draw!
	h->Draw("HIST,SAME");      
    } // end of: drawing signal as separate lines
    
    // Data is special: 
    // change the default size of the little bar at the end of the error bar here
    gStyle->SetEndErrorSize(3);
    // also, maybe don't display the error bars along the X axis:
    //gStyle->SetErrorX(0);  // X error bars not displayed
    gStyle->SetErrorX(0.5);  // X error bars have width of a bin
    // now set the rest
    h0->SetMarkerSize(2);
    // if there are too many points (>80), keep the marker size smaller
    if(h0->GetNbinsX()>=50) h0->SetMarkerSize(1);
    //if(h0->GetNbinsX()>=100) h0->SetMarkerSize(1);
    h0->SetLineWidth(3);
    h0->SetMarkerStyle(8);
    h0->SetMarkerColor(1);
    h0->Draw("E1,SAME");
    
    // Print some comparison:
    //ostringstream basefactor;
    //basefactor << "Files." << nbkg+3 << "." << "Factor";
    //TString timesfactor(basefactor.str().c_str()); 
    //Double_t nprod = params->GetValue(timesfactor,1.000);
    //printf("Data Yield = %5.2f ; SumBkg = %5.2f ; SumBkg+Sig = %5.2f ; Data-SumBkg diff = %5.2f%% \n",
    //        h0->Integral(),hbkg2->Integral,(hbkg2->Integral()+(signalhistos[0]->Integral()/nprod),
    //        (h0->Integral()-hbkg2->Integral)*100./h0->Integral()));

    //
    // Print D0 and lumi:
    //
    TText *t1 = new TText();
    t1->SetTextFont(62);
    t1->SetTextColor(1);   
    t1->SetNDC();
    t1->SetTextAlign(12);
    t1->SetTextSize(textSize);
    TString prelim="D\328 Preliminary";
    if(oFileName.EndsWith(".eps")) {
	prelim="D\349 Preliminary L=3.7 fb^-1#";
    }
    else if(oFileName.EndsWith(".gif")) {
	prelim="D\328 Preliminary L=3.7 fb^-1#";
    }
    t1->DrawTextNDC(0.13,0.965,prelim.Data());

    // a counter of how much text we have added from the top
    int nAddTextLines=0;
    
    // any additional text?
    for(int iText=1;iText<20;iText++) {
	ostringstream baseTextName;
	baseTextName << "Histo.AddText." << iText;
	TString bTextName(baseTextName.str().c_str());
	if(params->Defined(bTextName)) {
	    // we are adding a line of text
	    TLatex *t2 = new TLatex();
	    t2->SetTextFont(62);
	    t2->SetTextColor(13);   
	    t2->SetTextAlign(32);
	    t2->SetNDC();
	    t2->SetTextSize(textSize);
	    TString addText(params->GetValue(bTextName,"."));
	    float x0=0.94;
	    float y0=0.96-(nAddTextLines)*0.05;
	    
	    // check if the user specified an alternative location for the text
	    if(params->Defined(bTextName+".X0")) x0=params->GetValue(bTextName+".X0",0.94);
	    if(params->Defined(bTextName+".Y0")) y0=params->GetValue(bTextName+".Y0",0.8);
	    if(params->Defined(bTextName+".TextSize")) t2->SetTextSize(params->GetValue(bTextName+".TextSize",textSize));
	    
	    // and increment the counter keeping track of how much we added,
	    // but only if the user didn't move the label around.
	    if(!params->Defined(bTextName+".X0")) nAddTextLines++;
	    printf("AddText %4.2f %4.2f %s\n",x0,y0,addText.Data());
	    
	    t2->DrawLatex(x0,y0,addText.Data()); 
	}
    }// end additional text
    
    // now draw the frame axis again so that we can see the tick marks
    frame->Draw("sameaxis");
    
    // Legend:
    TString showLegend(params->GetValue("Histo.ShowLegend","."));
    if( showLegend != "no" ){ 
	float lgdxmin=.65, lgdxmax=.90, lgdymin=.50, lgdymax=.91;
	if(showLegend=="yes" || showLegend=="right") {
	    
	} else if (showLegend=="left"){
	    lgdxmin=.16;
	    lgdxmax=.42;
	}
	TLegend *lgd = new TLegend(lgdxmin,lgdymin,lgdxmax,lgdymax); 
	// This line makes the legend transparent (not grey, ewwww!): 
	lgd->SetBorderSize(0); lgd->SetTextSize(textSize*0.9);// 10% less size 
	lgd->SetTextFont(62); lgd->SetFillColor(0);
	// Plot the legend in reverse order (but data goes first):
	NiceAddEntry(lgd,h0,params->GetValue("Files.1.Title","Data"),"PL");
	for(Int_t i = nbkg; i>=0; i--){
	    TH1F * h = (TH1F*) addedhistos[i];
	    TString lgd_entry= sampletitles[i]; // sampletitles runs from 0 (firstbkg) to ntot-1
	    NiceAddEntry(lgd,h,lgd_entry.Data(),"F");	
	}
	for(Int_t i = nsig-1; i>=0; i--){
	    TH1F * h = (TH1F*) signalhistos[i];
	    TString lgd_entry = sampletitles[i+nbkg+1]; // sampletitles runs from 0 (firstbkg) to ntot-1
	    ostringstream basefactor;
	    basefactor << "Files." << i+nbkg+3 << "." << "Factor";
	    TString timesfactor(basefactor.str().c_str());
	    Double_t nprod = params->GetValue(timesfactor,1.000);
	    if (nprod != 1.0 ) lgd_entry.Form("%s x%2.0f",lgd_entry.Data(),nprod);
	    //cout << i+nbkg+3 << " " << nprod << " " << lgd_entry.Data() << endl;
	    NiceAddEntry(lgd,h,lgd_entry.Data(),"L"); 
	}
	lgd->Draw("SAME");	
    }// show legend


    // Draw the KS:
    TLatex *ks = new TLatex();
    ks->SetTextFont(62);
    ks->SetTextColor(1);   
    TString ks_val = Form("KS = %3.2f",KS);
    ks->SetTextAlign(11); ks->SetTextSize(0.03); // ks->SetTextAngle(90); 
    ks->DrawTextNDC(0.83,0.93,ks_val.Data());
    TString chi2_val = Form("#chi^{2}/ndf = %3.1f",chi2ndf);
    ks->SetNDC(true); ks->DrawLatex(0.83,0.97,chi2_val.Data());
    //
    // Voila!
    //
}