Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

PIDSpectrum.cxx

Go to the documentation of this file.
00001 #include "NCUtils/Extrapolation/PIDSpectrum.h"
00002 
00003 #include "NCUtils/Extrapolation/NCBeam.h" // for binning scheme
00004 #include "NCUtils/NCUtility.h"            // for CloneFast
00005 
00006 #include "TCanvas.h"
00007 #include "TLatex.h"
00008 #include "TMath.h"
00009 #include "TPad.h"
00010 #include "TStyle.h"
00011 #include "TLegend.h"
00012 
00013 #include <cmath>
00014 #include <iostream>
00015 #include <algorithm>
00016 
00017 using namespace std;
00018 
00019 ClassImp(PIDSpectrum)
00020 
00021 PIDSpectrum::PIDSpectrum(string _name, string _title,
00022                          int _nPIDBins, double _PIDmin, double _PIDmax,
00023                          int _trueBinFactor, NCBeam::Info _beamInfo,
00024                          double _cutValue)
00025 : TNamed(_name, _title),
00026   fNumPIDBins(_nPIDBins),
00027   fPIDmin(_PIDmin), fPIDmax(_PIDmax),
00028   fTrueBinFactor(_trueBinFactor),
00029   fBeamInfo(_beamInfo),
00030   fCutValue(_cutValue)
00031 {
00032   fEvtTypes.push_back(kNC);
00033   fEvtTypes.push_back(kNumu);
00034   fEvtTypes.push_back(kBeamNue);
00035   fEvtTypes.push_back(kOscNue);
00036   fEvtTypes.push_back(kNutau);
00037 
00038   fDrawColors.resize(fEvtTypes.size());
00039   fDrawColors[kNC]=kRed;
00040   fDrawColors[kNumu]=kBlue;
00041   fDrawColors[kBeamNue]=kGreen+2;
00042   fDrawColors[kOscNue]=kOrange-3;
00043   fDrawColors[kNutau]=kMagenta+2;
00044 
00045   // Set up the binning for true energy axes
00046   Double_t* trueEBins=MultiplyBins(fTrueBinFactor, kNumEnergyBinsFar,
00047                                    kEnergyBinsFar);
00048   int nTrueEBins=kNumEnergyBinsFar*fTrueBinFactor;
00049 
00050   // Gah, have to construct this manually, because ROOT won't let me
00051   // mix-and-match the auto and manual binning for TH3s
00052   if (fNumPIDBins==-1) {
00053     // We're emulating the FarNear method - two bins, separated at the cut value
00054     fPIDBins=new Double_t[3];
00055     fPIDBins[0]=fPIDmin; fPIDBins[2]=fPIDmax;
00056     fPIDBins[1]=fCutValue;
00057     // HACK: we probably shouldn't change this from what was passed
00058     // in, but it makes the rest of the code easier
00059     fNumPIDBins=2;
00060   } else {
00061     fPIDBins=new Double_t[fNumPIDBins+1];
00062     for (int i=0; i<fNumPIDBins+1; ++i)
00063       fPIDBins[i]=fPIDmin+float(i)*(fPIDmax-fPIDmin)/fNumPIDBins;
00064   }
00065 
00066   // This is the one place where we *should* use this variable
00067   fNumBinEdgesDontUseThis=fNumPIDBins+1;
00068 
00069   for (vector<evtType>::iterator it=fEvtTypes.begin(); it!=fEvtTypes.end(); ++it) {
00070     string tmp("hTrue");
00071     tmp+=GetName();
00072     tmp+=EvtTypeAsString(*it);
00073     //cout << "Creating true energy hist" << endl;
00074     fCmpTrue[*it]=new TH2F(tmp.c_str(), "True energy spectrum;True Energy (GeV);PID",
00075                           nTrueEBins, trueEBins,
00076                           fNumPIDBins, fPIDBins);
00077     tmp="t2r_";
00078     tmp+=GetName();
00079     tmp+=EvtTypeAsString(*it);
00080     //cout << "Creating true to reco hist" << endl;
00081     fTrueToReco[*it]=new TH3F(tmp.c_str(), "True-to-reco;Reco Energy;PID;True energy",
00082                              kNumEnergyBinsFar, kEnergyBinsFar,
00083                              fNumPIDBins, fPIDBins,
00084                              nTrueEBins, trueEBins);
00085   }
00086 
00087   delete[] trueEBins;
00088 
00089   string tmp("hData");
00090   tmp+=GetName();
00091   //cout << "Creating data hist" << endl;
00092   fData=new TH2F(tmp.c_str(), "Far Data;Reco Energy;PID",
00093                  kNumEnergyBinsFar, kEnergyBinsFar,
00094                  fNumPIDBins, fPIDBins);
00095 
00096   tmp="hNearMC";
00097   tmp+=GetName();
00098   fNearMC=new TH2F(tmp.c_str(), "Near MC;Reco Energy;PID",
00099                    kNumEnergyBinsFar, kEnergyBinsFar,
00100                    fNumPIDBins, fPIDBins);
00101 
00102   tmp="hNearData";
00103   tmp+=GetName();
00104   fNearData=new TH2F(tmp.c_str(), "Near Data;Reco Energy;PID",
00105                      kNumEnergyBinsFar, kEnergyBinsFar,
00106                      fNumPIDBins, fPIDBins);
00107 
00108 }
00109 
00110 //======================================================================
00111 
00112 Double_t* PIDSpectrum::MultiplyBins(int factor, int nBinsOrig,
00113                                     const Double_t* origBins) const
00114 {
00115   Double_t* newBins=new Double_t[(nBinsOrig+1)*factor+2];
00116 
00117   for (int iOrig=0; iOrig<nBinsOrig+1; ++iOrig) {
00118     for (int j=0; j<factor; ++j) {
00119       newBins[iOrig*factor+j]=origBins[iOrig]+
00120         float(j)/factor*(origBins[iOrig+1]-origBins[iOrig]);
00121     }
00122   }
00123 
00124   return newBins;
00125 }
00126 
00127 //======================================================================
00128 
00129 TH2F* PIDSpectrum::GetPredicted(const NC::OscProb::OscPars* coords,
00130                                 const char* histname,
00131                                 bool doFN,
00132                                 TH1* nearSpectrum) const
00133 {
00134   TH2F* pred=new TH2F(histname, "Predicted total",
00135                       kNumEnergyBinsFar, kEnergyBinsFar,
00136                       fNumPIDBins, fPIDBins);
00137   pred->SetDirectory(0);
00138 
00139   for (vector<evtType>::const_iterator it=fEvtTypes.begin(); it!=fEvtTypes.end(); ++it) {
00140     AddOnePredicted(pred, *it, coords);
00141   }
00142 
00143   // Because we set the bins manually using fArray, the number of
00144   // entries isn't calculated. This results in the histogram not
00145   // drawing properly, so set the number of entries manually to
00146   // something reasonable
00147   pred->SetEntries(int(pred->Integral()));
00148 
00149   // Multiply the predicted spectrum by the ND data/MC ratio
00150   if (doFN)
00151     FarNearCorrect(pred, fNearData, nearSpectrum ? nearSpectrum : fNearMC);
00152 
00153   return pred;
00154 
00155 }
00156 
00157 //======================================================================
00158 
00159 TH2F* PIDSpectrum::GetOnePredicted(evtType t,
00160                                    const NC::OscProb::OscPars* coords,
00161                                    const char* histname) const
00162 {
00163   // This spectrum
00164   string tmp = GetName();
00165   tmp+="_pred";
00166   tmp+=histname ? histname : "";
00167   tmp+=EvtTypeAsString(t);
00168   TH2F* onePred=new TH2F(tmp.c_str(),
00169                          Form("Predicted %s", EvtTypeAsString(t).c_str()),
00170                          kNumEnergyBinsFar, kEnergyBinsFar,
00171                          fNumPIDBins, fPIDBins);
00172 
00173   AddOnePredicted(onePred, t, coords);
00174 
00175   return onePred;
00176 }
00177 
00178 //======================================================================
00179 
00180 void PIDSpectrum::AddOnePredicted(TH2F* onePred, evtType t, const NC::OscProb::OscPars* coords) const
00181 {
00182   // Set up the binning for true energy axes
00183   Double_t* trueEBins=MultiplyBins(fTrueBinFactor, kNumEnergyBinsFar,
00184                                    kEnergyBinsFar);
00185   const int nTrueEBins=kNumEnergyBinsFar*fTrueBinFactor;
00186 
00187   TH1F* oscProb=GetOscWeightHist(t, coords, nTrueEBins, trueEBins);
00188   delete[] trueEBins;
00189 
00190   /*
00191 
00192   // This is some debugging code that might turn out to be useful again one day
00193 
00194   if (oscProb->Integral()==0 && (t==kNumu || t==kNC)) {
00195     cout << "oscprob empty for type " << EvtTypeAsString(t) << endl;
00196     cout << "Coords: ";
00197     for (int i=0; i<(int)coords.size(); ++i) cout << coords[i] << " ";
00198     cout << endl;
00199   }
00200 
00201   static bool doneAlready=false;
00202 
00203   if (t==kNC && !doneAlready) { oscProb->Write(); doneAlready=true; }
00204 
00205   */
00206   // Convolve it all together
00207 
00208   // Need to use find() because map::operator[] isn't const
00209   TH3F* t2r=fTrueToReco.find(t)->second;
00210   TH2F* trueCmp=fCmpTrue.find(t)->second;
00211   /*
00212   if ((t==kNC || t==kNumu) && hit->second->Integral()==0) {
00213     cout << "t2r empty for type " << EvtTypeAsString(t) << endl;
00214     cout << "Coords: ";
00215     for (int i=0; i<(int)coords.size(); ++i) cout << coords[i] << " ";
00216     cout << endl;
00217   }
00218 
00219   if ((t==kNC || t==kNumu) && hit2->second->Integral()==0) {
00220     cout << "fCmpTrue empty for type " << EvtTypeAsString(t) << endl;
00221     cout << "Coords: ";
00222     for (int i=0; i<(int)coords.size(); ++i) cout << coords[i] << " ";
00223     cout << endl;
00224   }
00225   */
00226 
00227   // TH2 and TH3 convert to 1D bin numbers when asked for a bin by 2D
00228   // number. It turns out that this is rather slow (probably since
00229   // it's all implemented by the TH1 base class). Since I know I won't
00230   // be accessing past the end of the range, and I know what dimension
00231   // the histogram has, I can calculate this manually for (hopefully)
00232   // a speedup
00233 
00234   // GetBinContent does bounds-checking, which we don't need,
00235   // since the loop limits ensure that we only access real
00236   // bins. Instead, use the internal array fArray, which for
00237   // some reason is public, to access the bin values without
00238   // incurring the time penalty from bounds-checking
00239   //
00240   // Similarly SetBinContent can be replaced by a direct write to fArray
00241   // The disadvantage here is that bin errors etc won't be set, but we
00242   // don't need them here
00243 
00244   // The arrangement of t2r in memory in fArray is my trueE, PID, recoE
00245   // most significant first. By putting the loops in this same order
00246   // we consider every point in the order they are layed out in memory.
00247   //
00248   // onePred has the same arrangement, except it doesn't have a trueE direction
00249   //
00250   // It is important we loop through every single bin (including underflow
00251   // and overflow) or the counting of the index will go wrong.
00252 
00253   // Begin at the start of the true-to-reco array
00254   float* pt2r = t2r->fArray;
00255 
00256   for(int iTrueE = 0; iTrueE <= nTrueEBins+1; ++iTrueE){
00257     const float oscWeight = oscProb->fArray[iTrueE];
00258 
00259     // For each new true energy go back to the start of the output array
00260     float* pOnePred = onePred->fArray;
00261 
00262     for(int iPID=0; iPID <= fNumPIDBins+1; ++iPID){
00263       // The trueCmp histogram has its axes the wrong way round, so have
00264       // to do this calculation instead of being able to use the same trick
00265       // as for t2r and onePred
00266       const int trueE_PIDBin = iTrueE+(nTrueEBins+2)*iPID;
00267 
00268       const float pidWeight = trueCmp->fArray[trueE_PIDBin];
00269       const float oscPidWeight = oscWeight * pidWeight;
00270 
00271       for(int iRecoE = 0; iRecoE <= kNumEnergyBinsFar+1; ++iRecoE){
00272 
00273         const float fillValue = (*pt2r)*oscPidWeight;
00274 
00275         *pOnePred += fillValue;
00276 
00277         // Advance to the next entry in each array
00278         ++pt2r;
00279         ++pOnePred;
00280 
00281       } // end for iRecoE
00282     } // end for iPID
00283   } // end for iTrueE
00284   /*
00285   if ((t==kNC || t==kNumu) && onePred->Integral()<1e-6) {
00286     cout << "predicted spectrum empty for type " << EvtTypeAsString(t) << endl;
00287     cout << "Coords: ";
00288     for (int i=0; i<(int)coords.size(); ++i) cout << coords[i] << " ";
00289     cout << endl;
00290   }
00291   */
00292   //  delete oscProb;
00293 }
00294 
00295 //==============================================================================
00296 
00297 double PIDSpectrum::GetEventWeight(evtType t, double trueE,
00298                                    const NC::OscProb::OscPars* coords) const
00299 {
00300   switch (t) {
00301   case PIDSpectrum::kNC:
00302     // NCExtrapolationModule only passes NC events from the nominal
00303     // files - NC events from the tau and electron files are
00304     // ignored. The rationale is that there's more stats in the
00305     // nominal files than the others.
00306 
00307     // This is the reason for the bizarre interaction type argument here.
00308     return coords->TransitionProbability(NCType::kNuMuToNuMu,
00309                                          NCType::kNC,
00310                                          NCType::kBaseLineFar,
00311                                          trueE);
00312     break;
00313   case PIDSpectrum::kNumu:
00314     return coords->TransitionProbability(NCType::kNuMuToNuMu,
00315                                          NCType::kCC,
00316                                          NCType::kBaseLineFar,
00317                                          trueE);
00318     break;
00319   case PIDSpectrum::kBeamNue:
00320     // Assume beam nue's don't oscillate.
00321 
00322     // TODO: Do this right
00323     // Apparently this is what's done in other places in NCUtils, so
00324     // maybe it can stay this way
00325     return 1.;
00326     break;
00327   case PIDSpectrum::kOscNue:
00328     return coords->TransitionProbability(NCType::kNuMuToNuE,
00329                                          NCType::kCC,
00330                                          NCType::kBaseLineFar,
00331                                          trueE);
00332     break;
00333   case PIDSpectrum::kNutau:
00334     return coords->TransitionProbability(NCType::kNuMuToNuTau,
00335                                          NCType::kCC,
00336                                          NCType::kBaseLineFar,
00337                                          trueE);
00338     break;
00339   default:
00340       // Something went wrong
00341     cerr << "GetOnePredicted got unknown evtType " << t << endl;
00342     assert(0);
00343   }
00344 }
00345 
00346 //==============================================================================
00347 
00348 TH1F* PIDSpectrum::GetOscWeightHist(evtType t,
00349                                     const NC::OscProb::OscPars* coords,
00350                                     int nBins, Double_t* binEdges) const
00351 {
00352   // Oscillation probabilities for this event type as a fn of energy
00353   static TH1F* oscProb=new TH1F("oscProb", "Oscillation probability", nBins, binEdges);
00354 
00355   //  oscProb->Reset();
00356   //  oscProb->SetDirectory(0);
00357 
00358 
00359   // The "<=" means we include the overflow bin
00360   for (int i=1; i<=oscProb->GetNbinsX()+1; ++i) {
00361     // Poor man's integral over the bin
00362     double Emin=oscProb->GetXaxis()->GetBinLowEdge(i);
00363     double Emax=oscProb->GetXaxis()->GetBinUpEdge(i);
00364     double trueE=0.5*(Emin+Emax);
00365     oscProb->fArray[i] = GetEventWeight(t, trueE, coords);
00366   }
00367 
00368   return oscProb;
00369 }
00370 
00371 //======================================================================
00372 
00373 double PIDSpectrum::PIDWithinRange(double origPID) const
00374 {
00375   if(origPID>fPIDmax) return fPIDmax-1e-3;
00376   if(origPID<fPIDmin) return fPIDmin+1e-3;
00377   return origPID;
00378 }
00379 
00380 //======================================================================
00381 
00382 void PIDSpectrum::FillMC(Detector::Detector_t det,
00383                          const ANtpTruthInfoBeam* t,
00384                          const ANtpRecoInfo* /* r */,
00385                          const ANtpAnalysisInfo* ana,
00386                          double E, double scale)
00387 {
00388   evtType evt(GetEvtType(t));
00389 
00390   double pidVal=PIDWithinRange(ana->separationParameter);
00391 
00392   // Cap energy at 120 GeV
00393   // The -0.01 is to make sure the event goes in the 20-120 GeV
00394   // bin and not the overflow bin above
00395   E=std::min(E,kEnergyBinsFar[kNumEnergyBinsFar]-0.01);
00396 
00397   if (det==Detector::kFar) {
00398     fCmpTrue[evt]->Fill(t->nuEnergy, pidVal, scale);
00399     fTrueToReco[evt]->Fill(E, pidVal, t->nuEnergy, scale);
00400   } else if (det==Detector::kNear) {
00401     fNearMC->Fill(E, pidVal, scale);
00402   } else {
00403     cout << "Unknown detector " << det << ". Bailing" << endl;
00404     exit(1);
00405   }
00406 }
00407 
00408 //======================================================================
00409 
00410 void PIDSpectrum::FillData(Detector::Detector_t det,
00411                            const ANtpTruthInfoBeam* /* t */,
00412                            const ANtpRecoInfo*  /* r */,
00413                            const ANtpAnalysisInfo* ana,
00414                            double E,  double scale)
00415 {
00416 
00417   // Cap energy at 120 GeV
00418   // The -0.01 is to make sure the event goes in the 20-120 GeV
00419   // bin and not the overflow bin above
00420   E=std::min(E,kEnergyBinsFar[kNumEnergyBinsFar]-0.01);
00421 
00422   double pidVal=PIDWithinRange(ana->separationParameter);
00423   if (det==Detector::kFar) fData->Fill(E, pidVal, scale);
00424   else if (det==Detector::kNear) fNearData->Fill(E, pidVal, scale);
00425   else {
00426     cout << "Unknown detector " << det << ". Bailing" << endl;
00427     exit(1);
00428   }
00429 }
00430 
00431 //======================================================================
00432 
00433 void PIDSpectrum::NormalizeTrueToRecos()
00434 {
00435   // The definition of normalized here is that any sum at fixed trueE and PID
00436   // over all the recoE's should come to one.
00437 
00438   for(vector<evtType>::iterator it = fEvtTypes.begin();
00439       it != fEvtTypes.end(); ++it){
00440     TH3F* t2r = fTrueToReco[*it];
00441     const int maxE = t2r->GetNbinsZ()+1;
00442     // The "<=" means we include the overflow bin
00443     for(int iTrueE = 1; iTrueE <= maxE; ++iTrueE){
00444       for(int iPID = 1; iPID <= fNumPIDBins; ++iPID){
00445 
00446         float integral = 0;
00447         for(int iRecoE = 1; iRecoE <= kNumEnergyBinsFar; ++iRecoE){
00448           integral += t2r->GetBinContent(iRecoE, iPID, iTrueE);
00449         }
00450         if(integral == 0) integral = 1; // Don't divide by zero
00451 
00452         for(int iRecoE = 1; iRecoE <= kNumEnergyBinsFar; ++iRecoE){
00453           const float content = t2r->GetBinContent(iRecoE, iPID, iTrueE);
00454           t2r->SetBinContent(iRecoE, iPID, iTrueE, content/integral);
00455         }
00456 
00457       } // end for PID
00458     } // end for trueE
00459   } // end for evtType
00460 }
00461 
00462 //======================================================================
00463 
00464 PIDSpectrum::evtType PIDSpectrum::GetEvtType(const ANtpTruthInfoBeam* t) const
00465 {
00466   if (t->interactionType==0)     return kNC;
00467   else if (abs(t->nuFlavor)==14) return kNumu;
00468   else if (abs(t->nuFlavor)==12 && abs(t->nonOscNuFlavor)==12) return kBeamNue;
00469   else if (abs(t->nuFlavor)==12 && abs(t->nonOscNuFlavor)!=12) return kOscNue;
00470   else if (abs(t->nuFlavor)==16) return kNutau;
00471   else {
00472     cerr << "Unknown particle type " << t->nuFlavor << endl;
00473     assert(0);
00474   }
00475 }
00476 
00477 //======================================================================
00478 
00479 string PIDSpectrum::EvtTypeAsString(evtType t) const
00480 {
00481 
00482   switch (t) {
00483   case kNC:
00484     return "NC";
00485   case kNumu:
00486     return "NuMu";
00487   case kBeamNue:
00488     return "BeamNuE";
00489   case kOscNue:
00490     return "OscNuE";
00491   case kNutau:
00492     return "NuTau";
00493   default:
00494     cerr << "EvtTypeAsString got unknown evtType " << t << endl;
00495     return "Unknown";
00496   }
00497 }
00498 
00499 //======================================================================
00500 
00501 TCanvas* PIDSpectrum::DrawSpectrum(const NC::OscProb::OscPars* coords, 
00502                                    TH1* systratios,
00503                                    string suffix) const
00504 {
00505   TH2F* hPred=GetPredicted(coords, "total", false);
00506 
00507   if (systratios) hPred->Multiply(systratios);
00508   string canName("can_");
00509   canName+=GetName();
00510   canName+=suffix;
00511   TCanvas *c = new TCanvas(canName.c_str(), GetTitle());
00512   c->Divide(2,2);
00513 
00514   c->cd(1);
00515   hPred->DrawCopy("colz");
00516   TLatex* la=new TLatex;
00517   la->SetNDC();
00518   la->DrawLatex(0.2, 0.95, "Predicted");
00519 
00520   c->cd(2);
00521   fData->DrawCopy("colz");
00522   la->DrawLatex(0.2, 0.95, "Data");
00523 
00524   c->cd(3);
00525   TH2F* hRatio=(TH2F*)NC::Utility::CloneFast(fData);
00526   hRatio->SetName("ratio");
00527   hRatio->Divide(hPred);
00528   hRatio->Draw("colz");
00529   la->DrawLatex(0.2, 0.95, "Ratio");
00530 
00531   c->cd(4);
00532   fCmpTrue.find(kNC)->second->DrawCopy("colz");
00533   la->DrawLatex(0.2, 0.95, "True NC true E");
00534 
00535   //  delete hPred;
00536 
00537   return c;
00538 }
00539 
00540 //======================================================================
00541 
00542 vector<TCanvas*> PIDSpectrum::DrawEnergySlices(const NC::OscProb::OscPars* coords,
00543                                                TH1* systratios,
00544                                                string suffix) const
00545 {
00546   return DrawSlices("energy", coords, systratios, suffix);
00547 }
00548 
00549 //======================================================================
00550 
00551 vector<TCanvas*> PIDSpectrum::DrawPIDSlices(const NC::OscProb::OscPars* coords,
00552                                             TH1* systratios,
00553                                             string suffix) const
00554 {
00555   return DrawSlices("pid", coords, systratios, suffix);
00556 }
00557 
00558 //======================================================================
00559 
00560 void PIDSpectrum::ResetMC()
00561 {
00562   typedef map<evtType, TH2F*>::iterator it2;
00563   for(it2 it = fCmpTrue.begin(); it != fCmpTrue.end(); ++it)
00564     it->second->Reset();
00565 
00566   typedef map<evtType, TH3F*>::iterator it3;
00567   for(it3 it = fTrueToReco.begin(); it != fTrueToReco.end(); ++it)
00568     it->second->Reset();
00569 }
00570 
00571 //======================================================================
00572 
00573 vector<TCanvas*> PIDSpectrum::DrawSlices(string variable,
00574                                          const NC::OscProb::OscPars* coords,
00575                                          TH1* systratios,
00576                                          string suffix) const
00577 {
00578   // Are we drawing energy slices? (If not, we're drawing PID slices)
00579   assert(variable == "energy" || variable == "pid");
00580   bool energySlice=(variable=="energy");
00581 
00582   vector<TCanvas*> v;
00583   // Canvas for the energy-integrated-over-PID plot (or vice versa)
00584 
00585   // ROOT is really not happy having more than one canvas with the same name
00586   // Keep a counter so we can keep the canvases from separate calls to this
00587   // function distinct.
00588   static int canvN=0;
00589   TCanvas* cTotal = new TCanvas((variable+"Total_"+suffix+fBeamInfo.GetDescription()+
00590                                  Form("_%d", canvN)));
00591   // Canvas for the actual slices
00592   TCanvas* cSlices = new TCanvas((variable+"Slices_"+suffix+fBeamInfo.GetDescription()+
00593                                   Form("_%d", canvN)));
00594   ++canvN;
00595 
00596   v.push_back(cTotal);   v.push_back(cSlices);
00597 
00598   cSlices->cd();
00599   int nPlots = energySlice ? fNumPIDBins : kNumEnergyBinsFar;
00600   int nDiv = (int)TMath::Ceil(TMath::Sqrt(nPlots));
00601 
00602   // Divide with more rows than columns if possible, so we get wider graphs
00603   if ((nDiv-1)*nDiv>=nPlots)
00604     cSlices->Divide(nDiv-1, nDiv);
00605   else if ((nDiv+1)*(nDiv-1)>=nPlots)
00606     cSlices->Divide(nDiv-1, nDiv+1);
00607   else
00608     cSlices->Divide(nDiv, nDiv);
00609 
00610   TH2F* hTotal=GetPredicted(coords, "total", false);
00611   if (systratios) hTotal->Multiply(systratios);
00612   // In principle we might be being called with parameters that don't
00613   // correspond to the best fit, but this'll do for now
00614   hTotal->SetTitle("Best fit");
00615   NC::OscProb::NoOscillations oscParsNoOsc;
00616   TH2F* hNoOsc=GetPredicted(&oscParsNoOsc, "noosc", false);
00617   hNoOsc->SetTitle("No Oscillations");
00618   // Hold the components in a map
00619   map<evtType, TH2F*> cmpHists;
00620 
00621   for (vector<evtType>::const_iterator it=fEvtTypes.begin(); 
00622        it!=fEvtTypes.end(); ++it) {
00623     // Drawing everything except NC
00624     if (*it==kNC) continue;
00625     cmpHists[*it]=GetOnePredicted(*it, coords, (variable+"Slices_"+suffix).c_str());
00626     cmpHists[*it]->SetLineColor(fDrawColors[*it]);
00627   }
00628 
00629   hTotal->SetLineColor(kRed);
00630   hNoOsc->SetLineColor(kRed);   hNoOsc->SetLineStyle(2);
00631   fData->SetLineColor(kBlack);
00632 
00633   // Stupid ROOT and its stupid global nonsense.
00634   gStyle->SetOptStat(0);
00635 
00636   // Draw the spectrum integrated over the other variable
00637   cTotal->cd();
00638   TH1F* noOsc1D=(TH1F*)ProjectHist(hNoOsc, variable, "NoOsc")->DrawCopy();
00639   noOsc1D->SetLineStyle(2);
00640   if (energySlice) noOsc1D->GetXaxis()->SetRangeUser(0,19.9);
00641   ProjectHist(hTotal, variable, "Total")->DrawCopy("same");
00642 
00643   for (vector<evtType>::const_iterator it=fEvtTypes.begin(); it!=fEvtTypes.end(); ++it) {
00644     // Drawing everything except NC
00645     if (*it==kNC) continue;
00646     ProjectHist(cmpHists[*it], variable,
00647                 string("slice")+EvtTypeAsString(*it))->DrawCopy("same");
00648   }
00649   ProjectHist(fData,  variable, "Data")->DrawCopy("same e");
00650 
00651   ((TPad*)gPad)->BuildLegend()->SetFillColor(kWhite);
00652   if (!energySlice && noOsc1D->GetEntries()) ((TPad*)gPad)->SetLogy();
00653 
00654   // Draw the individual slices
00655   for (int i=1; i<nPlots+1; ++i) {
00656     cSlices->cd(i);
00657 
00658     TH1F* noOsc1DSlice=(TH1F*)ProjectHist(hNoOsc, variable,
00659                                           "NoOsc", i, i)->DrawCopy();
00660     noOsc1DSlice->SetLineStyle(2);
00661     if (energySlice) noOsc1DSlice->GetXaxis()->SetRangeUser(0,19.9);
00662 
00663     ProjectHist(hTotal, variable, "Total", i, i)->DrawCopy("same");
00664 
00665     for(unsigned int n = 0; n < fEvtTypes.size(); ++n){
00666       // Drawing everything except NC
00667       if (fEvtTypes[n]==kNC) continue;
00668 
00669       ProjectHist(cmpHists[fEvtTypes[n]], variable,
00670                   EvtTypeAsString(fEvtTypes[n]),
00671                   i, i)->DrawCopy("same");
00672     }
00673     ProjectHist(fData, variable, "Data", i, i)->DrawCopy("same e");
00674 
00675     if (!energySlice && noOsc1DSlice->GetEntries()) ((TPad*)gPad)->SetLogy();
00676   }
00677 
00678   return v;
00679 }
00680 
00681 //======================================================================
00682 
00683 TH1D* PIDSpectrum::ProjectHist(TH2* h, string axis, string histname,
00684                                int lobin, int hibin) const
00685 {
00686   TH1D* ret;
00687   histname=axis+histname;
00688   if(lobin) histname+=TString::Format("%d", lobin);
00689   else histname+="Integ";
00690 
00691   if (axis=="energy") ret = h->ProjectionX(histname.c_str(), lobin, hibin);
00692   else if (axis=="pid") ret = h->ProjectionY(histname.c_str(), lobin, hibin);
00693   else assert(0 && "unknown projection requested");
00694   ret->SetDirectory(0);
00695   TH1D* clone=(TH1D*)NC::Utility::CloneFast(ret);
00696   clone->SetDirectory(0);
00697   return clone;
00698 }
00699 
00700 //======================================================================
00701 
00702 vector<TCanvas*> PIDSpectrum::DrawNearSpectra(TH1* systratios, string suffix) const
00703 {
00704   vector<TCanvas*> ret;
00705   TString canvName("nearSpectra "+fBeamInfo.GetDescription());
00706   canvName+=suffix.c_str();
00707   TCanvas* c = new TCanvas(canvName, "Near detector spectra");
00708   c->Divide(2,2);
00709   c->cd(1);
00710   TH2F* nearMCShifted=(TH2F*)NC::Utility::CloneFast(fNearMC);
00711   nearMCShifted->SetName("nearMCShifted");
00712   if (systratios) nearMCShifted->Multiply(systratios);
00713   nearMCShifted->Draw("colz");
00714   c->cd(2);
00715   fNearData->Draw("colz");
00716   c->cd(3);
00717   TH2F* hRatio=(TH2F*)NC::Utility::CloneFast(fNearData);
00718   hRatio->SetName("hRatio");
00719   hRatio->Divide(nearMCShifted);
00720   hRatio->Draw("colz");
00721   ret.push_back(c);
00722 
00723   nearMCShifted->SetLineColor(kRed);
00724   fNearData->SetLineColor(kBlack);
00725   // 1D spectra
00726   TCanvas* cE=new TCanvas(canvName+"energy_1D", "Near detector 1D spectra");
00727   cE->cd();
00728   ProjectHist(nearMCShifted, "energy", "nearMC")->DrawCopy();
00729   ProjectHist(fNearData, "energy", "nearData")->DrawCopy("same e");
00730   ret.push_back(cE);
00731 
00732   TCanvas* cPID=new TCanvas(canvName+"pid_1D", "Near detector 1D spectra");
00733   cPID->cd();
00734   ProjectHist(nearMCShifted, "pid", "nearMC")->DrawCopy();
00735   ProjectHist(fNearData, "pid", "nearData")->DrawCopy("same e");
00736   ret.push_back(cPID);
00737 
00738   return ret;
00739 }
00740 
00741 //======================================================================
00742 
00743 void PIDSpectrum::FarNearCorrect(TH2F* fdPred,
00744                                  const TH2F* ndData,
00745                                  const TH1* ndMC1D) const
00746 {
00747   // TODO: Replace the data and MC spectra with just the ratio, which
00748   // we'll only need to calculate once
00749 
00750   // Downcast ndMC - ugh. This should be OK because that histogram came
00751   // from us initially.
00752   TH2F* ndMC = (TH2F*)ndMC1D;
00753 
00754   // Use the now-standard trick of accessing bin contents directly to
00755   // avoid unnecessary bounds-checking
00756   for (int i=0; i<fdPred->fN; ++i) {
00757     // Don't divide by zero. This should really be left to crash, but
00758     // I'm too lazy at the moment
00759     if (ndMC->fArray[i]) fdPred->fArray[i]*=ndData->fArray[i]/ndMC->fArray[i];
00760   }
00761 }
00762 
00763 //======================================================================
00764 
00765 TH1D* PIDSpectrum::GetPseudoNCCCSpectrum(NCType::EEventType nccc,
00766                                          evtType t, 
00767                                          const NC::OscProb::OscPars* coords) const
00768 {
00769   TH2F* spec2d;
00770   if(t==kAll){
00771     // The "true" makes it do far/near correction, so we don't need to do it manually
00772     //NC::OscProb::OscPars* coordsNoOsc=new NC::OscProb::NoOscillations;
00773     spec2d=GetPredicted(coords, "", true);
00774   }
00775   else{
00776     spec2d=GetOnePredicted(t, coords);
00777     spec2d->SetDirectory(0);
00778     // Should make this configurable. Too lazy right now
00779     FarNearCorrect(spec2d, fNearData, fNearMC);
00780   }
00781 
00782   return GetPseudoNCCCComponent(spec2d, nccc);
00783 }
00784 
00785 //======================================================================
00786 
00787 TH1D* PIDSpectrum::GetPseudoNCCCComponent(TH2F* h, NCType::EEventType nccc) const
00788 {
00789   // Find the bin where we should cut to get "NC" one side and "CC" the other
00790   int cutBin=h->GetYaxis()->FindBin(fCutValue);
00791   TH1D* spec1d;
00792   if(nccc==NCType::kNC)
00793     spec1d=h->ProjectionX("pseudonc", 0, cutBin);
00794   else
00795     spec1d=h->ProjectionX("pseudocc", cutBin+1, -1);
00796 
00797   // Need to SetDirectory(0) because of a throughly idiotic behaviour
00798   // of TH2::ProjectionX, which will overwrite an existing histogram
00799   // if the name you request already exists in the current
00800   // directory. Idiots.
00801   spec1d->SetDirectory(0);
00802 
00803   return spec1d;
00804 }

Generated on Mon Feb 15 11:07:22 2010 for loon by  doxygen 1.3.9.1