///////////////////////////////////////////////////////////////////////// // // SPlot tutorial // author: Kyle Cranmer // date Dec. 2008 // // This tutorial shows an example of using SPlot to unfold two distributions. // The physics context for the example is that we want to know // the isolation distribution for real electrons from Z events // and fake electrons from QCD. Isolation is our 'control' variable // To unfold them, we need a model for an uncorrelated variable that // discriminates between Z and QCD. To do this, we use the invariant // mass of two electrons. We model the Z with a Gaussian and the QCD // with a falling exponential. // // Note, since we don't have real data in this tutorial, we need to generate // toy data. To do that we need a model for the isolation variable for // both Z and QCD. This is only used to generate the toy data, and would // not be needed if we had real data. ///////////////////////////////////////////////////////////////////////// #ifndef __CINT__ #include "RooGlobalFunc.h" #endif #include "RooRealVar.h" #include "RooStats/SPlot.h" #include "RooDataSet.h" #include "RooRealVar.h" #include "RooGaussian.h" #include "RooExponential.h" #include "RooChebychev.h" #include "RooAddPdf.h" #include "RooProdPdf.h" #include "RooAddition.h" #include "RooProduct.h" #include "TCanvas.h" #include "RooAbsPdf.h" #include "RooFit.h" #include "RooFitResult.h" #include "RooWorkspace.h" #include "RooConstVar.h" // use this order for safety on library loading using namespace RooFit ; using namespace RooStats ; // see below for implementation void AddModel(RooWorkspace*); void AddData(RooWorkspace*); void DoSPlot(RooWorkspace*); void MakePlots(RooWorkspace*); void rs301_splot() { // Create a new workspace to manage the project. RooWorkspace* wspace = new RooWorkspace("myWS"); // add the signal and background models to the workspace. // Inside this function you will find a discription our model. AddModel(wspace); // add some toy data to the workspace AddData(wspace); // inspect the workspace if you wish // wspace->Print(); // do sPlot. //This wil make a new dataset with sWeights added for every event. DoSPlot(wspace); // Make some plots showing the discriminating variable and // the control variable after unfolding. MakePlots(wspace); // cleanup delete wspace; } //____________________________________ void AddModel(RooWorkspace* ws){ // Make models for signal (Higgs) and background (Z+jets and QCD) // In real life, this part requires an intellegent modeling // of signal and background -- this is only an example. // set range of observable Double_t lowRange = 00, highRange = 200; // make a RooRealVar for the observables RooRealVar invMass("invMass", "M_{inv}", lowRange, highRange,"GeV"); RooRealVar isolation("isolation", "isolation", 0., 20., "GeV"); ///////////////////////////////////////////// // make 2-d model for Z including the invariant mass // distribution and an isolation distribution which we want to // unfold from QCD. std::cout << "make z model" << std::endl; // mass model for Z RooRealVar mZ("mZ", "Z Mass", 91.2, lowRange, highRange); RooRealVar sigmaZ("sigmaZ", "Width of Gaussian", 2,0,10,"GeV"); RooGaussian mZModel("mZModel", "Z+jets Model", invMass, mZ, sigmaZ); // we know Z mass mZ.setConstant(); // we leave the width of the Z free during the fit in this example. // isolation model for Z. Only used to generate toy MC. // the exponential is of the form exp(c*x). If we want // the isolation to decay an e-fold every R GeV, we use // c = -1/R. RooConstVar zIsolDecayConst("zIsolDecayConst", "z isolation decay constant", -1); RooExponential zIsolationModel("zIsolationModel", "z isolation model", isolation, zIsolDecayConst); // make the combined Z model RooProdPdf zModel("zModel", "4-d model for Z", RooArgSet(mZModel, zIsolationModel)); ////////////////////////////////////////////// // make QCD model std::cout << "make qcd model" << std::endl; // mass model for QCD. // the exponential is of the form exp(c*x). If we want // the mass to decay an e-fold every R GeV, we use // c = -1/R. // We can leave this parameter free during the fit. RooRealVar qcdMassDecayConst("qcdMassDecayConst", "Decay const for QCD mass spectrum", -0.01, -100, 100,"1/GeV"); RooExponential qcdMassModel("qcdMassModel", "qcd Mass Model", invMass, qcdMassDecayConst); // isolation model for QCD. Only used to generate toy MC // the exponential is of the form exp(c*x). If we want // the isolation to decay an e-fold every R GeV, we use // c = -1/R. RooConstVar qcdIsolDecayConst("qcdIsolDecayConst", "Et resolution constant", -.1); RooExponential qcdIsolationModel("qcdIsolationModel", "QCD isolation model", isolation, qcdIsolDecayConst); // make the 2-d model RooProdPdf qcdModel("qcdModel", "2-d model for QCD", RooArgSet(qcdMassModel, qcdIsolationModel)); ////////////////////////////////////////////// // combined model // These variables represent the number of Z or QCD events // They will be fitted. RooRealVar zYield("zYield","fitted yield for Z",50 ,0.,1000) ; RooRealVar qcdYield("qcdYield","fitted yield for QCD", 100 ,0.,1000) ; // now make the combined model std::cout << "make full model" << std::endl; RooAddPdf model("model","z+qcd background models", RooArgList(zModel, qcdModel), RooArgList(zYield,qcdYield)); // interesting for debugging and visualizing the model model.graphVizTree("fullModel.dot"); std::cout << "import model" << std::endl; ws->import(model); } //____________________________________ void AddData(RooWorkspace* ws){ // Add a toy dataset // how many events do we want? Int_t nEvents = 1000; // get what we need out of the workspace to make toy data RooAbsPdf* model = ws->pdf("model"); RooRealVar* invMass = ws->var("invMass"); RooRealVar* isolation = ws->var("isolation"); // make the toy data std::cout << "make data set and import to workspace" << std::endl; RooDataSet* data = model->generate(RooArgSet(*invMass, *isolation),nEvents); // import data into workspace ws->import(*data, Rename("data")); } //____________________________________ void DoSPlot(RooWorkspace* ws){ std::cout << "Calculate sWeights" << std::endl; // get what we need out of the workspace to do the fit RooAbsPdf* model = ws->pdf("model"); RooRealVar* zYield = ws->var("zYield"); RooRealVar* qcdYield = ws->var("qcdYield"); RooDataSet* data = (RooDataSet*) ws->data("data"); // fit the model to the data. model->fitTo(*data, Extended() ); // The sPlot technique requires that we fix the parameters // of the model that are not yields after doing the fit. RooRealVar* sigmaZ = ws->var("sigmaZ"); RooRealVar* qcdMassDecayConst = ws->var("qcdMassDecayConst"); sigmaZ->setConstant(); qcdMassDecayConst->setConstant(); RooMsgService::instance().setSilentMode(true); // Now we use the SPlot class to add SWeights to our data set // based on our model and our yield variables RooStats::SPlot* sData = new RooStats::SPlot("sData","An SPlot", *data, model, RooArgList(*zYield,*qcdYield) ); // Check that our weights have the desired properties std::cout << "Check SWeights:" << std::endl; std::cout << std::endl << "Yield of Z is " << zYield->getVal() << ". From sWeights it is " << sData->GetYieldFromSWeight("zYield") << std::endl; std::cout << "Yield of QCD is " << qcdYield->getVal() << ". From sWeights it is " << sData->GetYieldFromSWeight("qcdYield") << std::endl << std::endl; for(Int_t i=0; i < 10; i++) { std::cout << "z Weight " << sData->GetSWeight(i,"zYield") << " qcd Weight " << sData->GetSWeight(i,"qcdYield") << " Total Weight " << sData->GetSumOfEventSWeight(i) << std::endl; } std::cout << std::endl; // import this new dataset with sWeights std::cout << "import new dataset with sWeights" << std::endl; ws->import(*data, Rename("dataWithSWeights")); } void MakePlots(RooWorkspace* ws){ // Here we make plots of the discriminating variable (invMass) after the fit // and of the control variable (isolation) after unfolding with sPlot. std::cout << "make plots" << std::endl; // make our canvas TCanvas* cdata = new TCanvas("sPlot","sPlot demo", 400, 600); cdata->Divide(1,3); // get what we need out of the workspace RooAbsPdf* model = ws->pdf("model"); RooAbsPdf* zModel = ws->pdf("zModel"); RooAbsPdf* qcdModel = ws->pdf("qcdModel"); RooRealVar* isolation = ws->var("isolation"); RooRealVar* invMass = ws->var("invMass"); // note, we get the dataset with sWeights RooDataSet* data = (RooDataSet*) ws->data("dataWithSWeights"); // this shouldn't be necessary, need to fix something with workspace // do this to set parameters back to their fitted values. model->fitTo(*data, Extended() ); //plot invMass for data with full model and individual componenets overlayed // TCanvas* cdata = new TCanvas(); cdata->cd(1); RooPlot* frame = invMass->frame() ; data->plotOn(frame ) ; model->plotOn(frame) ; model->plotOn(frame,Components(*zModel),LineStyle(kDashed), LineColor(kRed)) ; model->plotOn(frame,Components(*qcdModel),LineStyle(kDashed),LineColor(kGreen)) ; frame->SetTitle("Fit of model to discriminating variable"); frame->Draw() ; // Now use the sWeights to show isolation distribution for Z and QCD. // The SPlot class can make this easier, but here we demonstrait in more // detail how the sWeights are used. The SPlot class should make this // very easy and needs some more development. // Plot isolation for Z component. // Do this by plotting all events weighted by the sWeight for the Z component. // The SPlot class adds a new variable that has the name of the corresponding // yield + "_sw". cdata->cd(2); // create weightfed data set RooDataSet * dataw_z = new RooDataSet(data->GetName(),data->GetTitle(),data,*data->get(),0,"zYield_sw") ; RooPlot* frame2 = isolation->frame() ; dataw_z->plotOn(frame2, DataError(RooAbsData::SumW2) ) ; frame2->SetTitle("isolation distribution for Z"); frame2->Draw() ; // Plot isolation for QCD component. // Eg. plot all events weighted by the sWeight for the QCD component. // The SPlot class adds a new variable that has the name of the corresponding // yield + "_sw". cdata->cd(3); RooDataSet * dataw_qcd = new RooDataSet(data->GetName(),data->GetTitle(),data,*data->get(),0,"qcdYield_sw") ; RooPlot* frame3 = isolation->frame() ; dataw_qcd->plotOn(frame3,DataError(RooAbsData::SumW2) ) ; frame3->SetTitle("isolation distribution for QCD"); frame3->Draw() ; // cdata->SaveAs("SPlot.gif"); }