Filling asymmetric error of RooRealVar in RooDataSet

I am trying to fill a simple RooDataSet with, among other things, a RooRealVar that has an asymmetric error. I do this within the framework of a CMSSW analyzer. The basic idea is that I declare a pointer to a RooDataSet object, as well as pointers to the variables that define its dimension, as private data members of the CMSSW analyzer class; something like

class ParPlotter : public edm::EDAnalyzer {
public:
ParPlotter(const edm::ParameterSet& pset);
virtual ~ParPlotter();
void fillParDataset();
private:
virtual void analyze(const edm::Event& event, const edm::EventSetup& eventSetup) {};
virtual void endRun(const edm::Run &run, const edm::EventSetup &setup) {};

RooCategory* effVar_;
RooRealVar* binNumber_;
RooCategory* parName_;
RooRealVar* parVal_;
RooDataSet* parData_;

};

In the constructor for ParPlotter, I set up the RooDataSet:

ParPlotter::ParPlotter(const edm::ParameterSet& pset)
{
//define dimensions of RooDataSet
effVar_ = new RooCategory(“effVar”, “”);
for (VSTRING_IT iEffVar = effVars_.begin(); iEffVar != effVars_.end(); ++iEffVar) {
effVar_->defineType((*iEffVar).c_str());
}
binNumber_ = new RooRealVar(“binNumber”, “Bin number”, -1.0);
parName_ = new RooCategory(“parName”, “”);
for (VSTRING_IT iParName = parNames_.begin(); iParName != parNames_.end(); ++iParName) {
parName_->defineType((*iParName).c_str());
}
parVal_ = new RooRealVar(“parVal”, “”, -1.0);
parData_ = new RooDataSet(“parData”, “”, RooArgSet(*effVar_, *binNumber_, *parName_, *parVal_));

//go!
fillParDataset();
makePlots();
}

Then, I call a function called fillParDataset() to fill the RooDataSet with information I extract from a ROOT file. It looks like:

void ParPlotter::fillParDataset()
{
//open file
TFile* file = NULL;
bool fileErr = false;
try { file = new TFile(inputFile_.c_str()); }
catch (cms::Exception& ex) { fileErr = true; }
if (!fileErr && (file != NULL)) {
file->cd();

//loop over efficiency variables                                                                                                         
for (VSTRING_IT iEffVar = effVars_.begin(); iEffVar != effVars_.end(); ++iEffVar) {
  const unsigned int effVarIndex = iEffVar - effVars_.begin();

  //loop over bins
  int iBin = 0;
  while (iBin != -1) {
    file->cd();
    stringstream name1;
    name1 << "PhotonToID/" << *iEffVar << "/" << branchNames_[effVarIndex] << "_bin" << iBin;
    name1 << "__gaussPlusLinear/";

    //get RooFitResult for parameters and their errors                                                                                   
    RooFitResult* fitRes = NULL;
    file->GetObject(plotAux_.name(name1.str(), "fitresults").c_str(), fitRes);

    if (fitRes != NULL) {

      //loop over parameters in the RooFitResult                                                                                         
      RooArgList pars = fitRes->floatParsFinal();
      for (VSTRING_IT iParName = parNames_.begin(); iParName != parNames_.end(); ++iParName) {
        const Int_t parIndex = iParName - parNames_.begin();

        //fill RooDataSet                                                                                                                
        effVar_->setLabel((*iEffVar).c_str());
        *binNumber_ = iBin;
        parName_->setLabel((*iParName).c_str());
        *parVal_ = ((RooRealVar&)pars[parIndex]).getVal();
        parVal_->setAsymError(((RooRealVar&)pars[parIndex]).getErrorLo(),
                              ((RooRealVar&)pars[parIndex]).getErrorHi());

    //debug printout: does the error get set?  answer: yes
        cout << "error: (+" << parVal_->getErrorHi() << ", -" << parVal_->getErrorLo() << ")\n";

    //RooDataSet filled here
        parData_->add(RooArgSet(*effVar_, *binNumber_, *parName_, *parVal_));

    /*********************************/
    //debug printout: see that the error on "parVal" in row 0 is identical to the error on "parVal" in the last added row!
        cout << "Row 0:\n";
        const RooArgSet* row0 = parData_->get(0);
        row0->Print("v");
        cout << "Current row:\n";
        const RooArgSet* row = parData_->get(parData_->numEntries() - 1);
        row->Print("v");
    /*********************************/

      }//for (VSTRING_IT iParName = parNames_.begin(); iParName != parNames_.end(); ++iParName)                                          

      //increment iBin                                                                                                                   
      ++iBin;

    }//if (fitRes != NULL)                                                                                      
    else {
      cout << "Error getting RooFitResult with name ";
      cout << plotAux_.name(name1.str(), "fitresults") << ".\n";
      iBin = -1;

    }//else                                                                                                                              

  }//while (iBin != -1)                                                                                                                  

}//for (VSTRING_IT iEffVar = effVars_.begin(); iEffVar != effVars_.end(); ++iEffVar)                                                     

file->Close();

}//if (!fileErr)
else cerr << "Error opening file " << inputFile_ << “.\n”;
delete file;
}

The problem is in setting the asymmetric error for the RooRealVar parVal_. The error correctly gets set for whatever the current (i.e. last added) row of the RooDataSet is, but then that same value also overwrites the error values on all previous rows. For example, when I run this code, I get a printout like (this is just a small sample of it)

width
error: (+1.84628, --1.84628)
Row 0:

  1. 0xc82b278 RooCategory:: effVar = pt “”
  2. 0xc82bf20 RooRealVar:: binNumber = 0 C L(-INF - +INF) “Bin number”
  3. 0xc82c510 RooCategory:: parName = cFail “”
  4. 0xc82d500 RooRealVar:: parVal = -0.056243 +/- (-1.84628,1.84628) C L(-INF - +INF) ""
    Current row:
  5. 0xc82b278 RooCategory:: effVar = run “”
  6. 0xc82bf20 RooRealVar:: binNumber = 0 C L(-INF - +INF) “Bin number”
  7. 0xc82c510 RooCategory:: parName = width “”
  8. 0xc82d500 RooRealVar:: parVal = 1 +/- (-1.84628,1.84628) C L(-INF - +INF) “”

cFail
error: (+0.0278142, --0.0278142)
Row 0:

  1. 0xc82b278 RooCategory:: effVar = pt “”
  2. 0xc82bf20 RooRealVar:: binNumber = 0 C L(-INF - +INF) “Bin number”
  3. 0xc82c510 RooCategory:: parName = cFail “”
  4. 0xc82d500 RooRealVar:: parVal = -0.056243 +/- (-0.0278142,0.0278142) C L(-INF - +INF) ""
    Current row:
  5. 0xc82b278 RooCategory:: effVar = run “”
  6. 0xc82bf20 RooRealVar:: binNumber = 1 C L(-INF - +INF) “Bin number”
  7. 0xc82c510 RooCategory:: parName = cFail “”
  8. 0xc82d500 RooRealVar:: parVal = 0.0333502 +/- (-0.0278142,0.0278142) C L(-INF - +INF) “”

The error in item 4 of the “current row” printout always matches the error in item 4 of the “row 0” printout. But the central values are different (as expected), as is the parName_ value. In fact, all of the variables are filled correctly in the RooDataSet, including the central value of parVal_. It’s just the asymmetric error on parVal_.

This is obviously a problem because at the end of filling the dataset, all the data points (rows) have the error of the last data point filled, when I would clearly like all the data points to have different (correct) errors. How can I fix this?

Thanks,
Rachel Yohay

Hi Rachel,

The issue is that a RooDataSet by default only stores the values of a RooRealVar and not the
errors (as this would increase the memory consumption by a factor 3).

If you modify your dataset declaration to request storage of symmetric or asymmetric errors,
your code should be have as you expect:

RooDataSet d(“d”,“d”,MyObservables,StoreAsymError(myObservables))
^^^^^^^^^^^^^^^^^^^^^^^^^^^

This is also documented in the THtml documentation of the RooDataSet constructor.

// StoreError(const RooArgSet&) – Store symmetric error along with value for given subset of observables
// StoreAsymError(const RooArgSet&) – Store asymmetric error along with value for given subset of observables

Wouter

Wouter -

Thank you very much for pointing this out! Of course it works like a charm now.

Best,
Rachel