RooFit Auto-constraining behaviour

Hello,

I have been playing around with constructing a model for a 2-channel analysis where I either make a PDF for my observable and construct an extended model (which I could then use for an unbinned fit), or I make a model where I create a Poisson for each individual bin and my observables are the number of events in each bin. But I’ve found the way RooFit determines what constraint terms to include in the NLL is different depending on how I do it. Below I’ve made a minimal example, where I make a 2-channel model with just a poisson and gaussian constraint for a nuisance parameter, with a single bin in each channel.

In the “binned model” (counting experiment), the attempt to create an NLL without specifying the Constrain option causes RooFit to exclude all the terms from the likelihood. The other method (which I believe is almost the same as the first method) does automatically include the constraint terms. Is this the expected behaviour, or is RooFit trying to tell me there is a something more different about these two models than I am realising?

{
   using namespace RooFit;

   ///Counting experiment model (binned model)
   RooWorkspace w;
   w.factory("PROD::chan1_model(Poisson::chan1(n[0,1000],expr::mean1('bkg1+s',bkg1[30,0,100],s[0,100])),Gaussian::constraint1(gobs_bkg1[30],bkg1,4))");
   w.factory("PROD::chan2_model(Poisson::chan2(n,expr::mean2('bkg2+s',bkg2[40,0,100],s)),Gaussian::constraint2(gobs_bkg2[40],bkg2,7))");
   w.factory("SIMUL::model(chanCat[c1,c2],c1=chan1_model,c2=chan2_model)");
   w.defineSet("obs","chanCat,n");

   RooDataSet data("data","",*w->set("obs"),"n");
   w.cat("chanCat")->setIndex(0);w.var("n")->setVal(35);
   data.add(*w->set("obs"),w.var("n")->getVal());
   w.cat("chanCat")->setIndex(1);w.var("n")->setVal(47);
   data.add(*w->set("obs"),w.var("n")->getVal());

   RooAbsReal* nll = w.pdf("model")->createNLL(data); //needs the "Constrain" option!


   ///PDF-based extended model (unbinned model)
   RooWorkspace w2;
   w2.factory("n[0,1000]");
   w2.factory("dummyObs[0.5,0,1]"); w2.var("dummyObs")->setBins(1); //important that width of bin is 1, so that mean (as a density) is integrated correctly
   w2.factory("expr::mean1('bkg1+s+dummyObs-dummyObs',bkg1[30,0,100],s[0,100],dummyObs)"); //should be a 'density'
   RooRealVar dummy("dummyVar","",1);
   RooRealSumPdf p("chan1","",RooArgList(*w2->function("mean1")),RooArgList(dummy),true);
   p.specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator")  ;
   p.specialIntegratorConfig(kTRUE)->method2D().setLabel("RooBinIntegrator")  ;
   p.specialIntegratorConfig(kTRUE)->methodND().setLabel("RooBinIntegrator")  ;
   p.specialIntegratorConfig(kTRUE)->getConfigSection("RooBinIntegrator").setRealValue("numBins",1);
   p.forceNumInt();
   w2.import(p);
   w2.factory("PROD::chan1_model(chan1,Gaussian::constraint1(gobs_bkg1[30],bkg1,4))");
   
   w2.factory("expr::mean2('bkg2+s+dummyObs-dummyObs',bkg2[40,0,100],s,dummyObs)"); //should be a 'density'. included dummyObs to force dependence
   RooRealSumPdf pdf("chan2","",RooArgList(*w2->function("mean2")),RooArgList(dummy),true);
   w2.import(pdf);
   w2.factory("PROD::chan2_model(chan2,Gaussian::constraint2(gobs_bkg2[30],bkg2,7))");
   w2.factory("SIMUL::model(chanCat[c1,c2],c1=chan1_model,c2=chan2_model)");
   w2.defineSet("obs","chanCat,dummyObs,n");

   RooDataSet data2("data","",*w2->set("obs"),"n");
   w2.cat("chanCat")->setIndex(0);w2.var("n")->setVal(35);
   data2.add(*w2->set("obs"),w2.var("n")->getVal());
   w2.cat("chanCat")->setIndex(1);w2.var("n")->setVal(47);
   data2.add(*w2->set("obs"),w2.var("n")->getVal());
   RooAbsReal* nll2 = w2.pdf("model")->createNLL(data2);

}

Thanks! Will