root icon indicating copy to clipboard operation
root copied to clipboard

[RF] Strange problems with RooRealVars with names containing slashes

Open cburgard opened this issue 3 years ago • 2 comments

Describe the bug

RooRealVars that have slashes ("/") in their name can cause a whole slew of issues. They should either be disallowed completely (replacing the slash in the name by something during construction) or the code needs to be adjusted to handle them correctly.

Expected behavior

RooRealVars should behave the same regardless of their name.

To Reproduce

Create RooDataHist with an observable that contains a slash in the name, build a RooHistFunc on top of it. Build some type of Pdf on top of this and fit it to the RooDataHist. The fit will treat the "slash" observable as a fit parameter rather than as an observable. Changing the name fixes that.

Additional context

This might seem like an arcane issue, but it can happen very easily because the new RooLagrangianMorphFunc uses the observable name to identify the locations of histograms in the source file, so any histogram that is a subfolder rather than at the toplevel will cause this issue to appear.

cburgard avatar Jul 25 '22 15:07 cburgard

Hi @cburgard, thanks for reporting this! I struggle to reproduce this problem. I have implemented your instructions in the following code:

void repro() {

    using namespace RooFit;

    // Define the observable with slash in the name
    RooRealVar x{"x/1", "x/1", 0.0, -10.0, 10.0};

    // Build a RooDataHist, filled with uniform bin content
    RooDataHist dh{"dh", "dh", x};
    const std::size_t entriesPerBin = 100;
    for(std::size_t i = 0; i < dh.numEntries(); ++i) {
        for(std::size_t j = 0; j < entriesPerBin; ++j) {
            dh.add(*dh.get(i), 1.0);
        }
    }
    x.setVal(0.0);

    // Create a RooHistFunc on top of it
    RooHistFunc histFunc{"histFunc", "histFunc", x, dh};

    // Define a model that uses the RooHistFunc.
    RooRealVar frac{"frac", "frac", 0.5, 0.0, 1.0};
    RooGaussian gaus{"gaus", "gaus", x, RooConst(2.0), RooConst(1.0)};
    RooRealSumPdf model{"model", "model", {gaus, histFunc}, {frac}};

    // Fit the model to the RooDataHist
    std::unique_ptr<RooFitResult> result{model.fitTo(dh, PrintLevel(-1), Save(true))};
    result->Print();
}

However, the fit result is just fine, listing only frac as a parameter as expected:

    Floating Parameter    FinalValue +/-  Error   
  --------------------  --------------------------
                  frac    2.1309e-09 +/-  6.49e-0

How do I need to change this reproducer code to get the problem that you are reporting? And which ROOT version did you use?

guitargeek avatar Jul 31 '22 12:07 guitargeek

Upon closer inspection, I am unable to reproduce this issue myself now. I will investigate further and close the issue if it magically disappeared.

For additional context, I will attach the script where the issue originally occurred, but seems to be gone now.

import ROOT
 
ROOT.gStyle.SetOptStat(0)
ROOT.PyConfig.IgnoreCommandLineOptions = True
ROOT.gROOT.SetBatch(True)

obsname = "CutGGF_TopoDPhill_truth/DPhill_V1_truth"

def makews():

  # Create functions
  # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
  # Setup observable that is to be morphed
  obsvar = ROOT.RooRealVar("DPhill_V1_truth", "\#Delta \#phi_{truth}^{ll} [rad]", 0, 1.8)
   
  cosa   = ROOT.RooRealVar("cosa","cosa",-1.,1.)
  kAww   = ROOT.RooRealVar("kAww","kAww",1.)
  kSM    = ROOT.RooRealVar("kSM","kSM",1.)
  Lambda = ROOT.RooRealVar("Lambda","Lambda",1000.)
  kHww   = ROOT.RooRealVar("kHww","kHww",0.)
  
  gSM  = ROOT.RooFormulaVar("_gSM"  ,"cosa*kSM",                        ROOT.RooArgList(cosa,kSM))
  gHww = ROOT.RooFormulaVar("_gHww" ,"cosa*kHww/Lambda",                ROOT.RooArgList(cosa,kHww,Lambda))
  gAww = ROOT.RooFormulaVar("_gAww" ,"sqrt(1-(cosa*cosa))*kAww/Lambda", ROOT.RooArgList(cosa,kAww,Lambda))
  
  # Inputs to setup config
  # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
  infilename = "samples-analyzed-NonSMggF-250722-o.root"
  
  obsvar.setConstant(True)
  
  par = "cosa"
  samplelist = ["sig_X_ggf_BSM1", "sig_X_ggf_BSM2", "sig_X_ggf_SM"]
   
  # Set Config
  # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
   
  config = ROOT.RooLagrangianMorphFunc.Config()
  config.fileName = infilename
  config.observableName = obsname
  config.folderNames = samplelist
  config.couplings.add(gSM)
  config.couplings.add(gHww)
  config.couplings.add(gAww)
   
  # Create morphing function
  # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
   
  morphfunc = ROOT.RooLagrangianMorphFunc("morphfunc", "morphed dist. of DPhill", config)
  
  # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
  # Extract input templates for plotting
  # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
   
  morphfuncpdf = ROOT.RooWrapperPdf("morphpdf", "morphpdf",morphfunc)
  ws = ROOT.RooWorkspace("workspace")
  ws.Import(morphfuncpdf)
  
  return ws


def plot(ws):
  morphfunc = ws.function("morphfunc")
  morphpdf = ws.pdf("morphpdf")
  obsvar = ws.var(obsname)

  UnfoldedFile = ROOT.TFile.Open("Unfolded.root","READ")
  U1 = UnfoldedFile.Get("DPhill")
  data_hist=ROOT.RooDataHist("dphill","dphill",[obsvar],U1)
  
  morphpdf.fitTo(data_hist,ROOT.RooFit.SumW2Error(True))
  morphfunc.printParameters();


ws = makews()
plot(ws)  

cburgard avatar Aug 09 '22 12:08 cburgard

I'll close this issue. Feel free to open a new one, should the problem pop up again in a reproducible form!

guitargeek avatar Jun 15 '23 00:06 guitargeek