Deriving a class from RooAbsPdf

Hi all,

I would like to derive a class from RooAbsPdf. The issue I run into is when I import an instance into RooWorkspace, it crashes. I think this is an issue with the static casts to (TObject*) because when I perform a static or dynamic cast first, I don’t get a crash (but I can’t retrieve the object from the workspace).

I have a complete standalone example here (also attached as zip file, with demo class). Any help as to how I can derive a class that’s comparable with RooWorkspace would be appreciated.

z.zip (1006 Bytes)

void demo(){

    // set up workspace
    RooWorkspace* w = new RooWorkspace("w","w");
    RooRealVar* x = new RooRealVar("x","x",0,0,1);
    RooRealVar* s = new RooRealVar("s","s",0,0,1);
    RooRealVar* m = new RooRealVar("m","m",0,0,1);
    RooGaussian* g = new RooGaussian("gaus","gaus",*x,*m,*s);
    child* childOne = new child("child");
    child* childTwo = new child("child");
    w->import(*x);
    w->import(*s);
    w->import(*m);

    cout<<"import standard PDF (OK)\n";
    w->import(*g);

    cout<<"import child PDF with a static cast (OK)\n";
    w->import(*(TObject*)(childOne));
    cout<<"but object in workspace == zero (Bad): "<<w->obj("child")<<endl;

    cout<<"import child PDF without dynamic_cast (Crash!)\n";                               
    w->import(*childOne);

    cout<<"DONE"<<endl;
}

After some experimentation, I found that things work when I add a copy constructor: morph(const morph* other=0). I’m surprised by this because there also exists the ::Clone() method. Are there other requirements I should be aware of in order to make a class work with RooFit? I would like to make sure this fix is robust. Thanks.

The only thing I can say right now is that Clone() calls TObject::clone(), which is pure virtual. The latter has to be implemented, and should invoke the protected copy constructor that also sets a new name, because RooFit does some bookeeping. Apparently, the default copy constructor does not do the trick.
As to why that is the case: I don’t know yet.

If you want to know what’s the minimum that has to be implemented, I would recommend something simple like RooGaussian. Here we find (some edits concerning public/protected/private by me):

class RooGaussian : public RooAbsPdf {
public:
  RooGaussian() {    } ;
  RooGaussian(const char *name, const char *title,
         RooAbsReal& _x, RooAbsReal& _mean, RooAbsReal& _sigma);
  //Seems to be necessary:
  RooGaussian(const RooGaussian& other, const char* name=0) ;
  virtual TObject* clone(const char* newname) const { return new RooGaussian(*this,newname); }
  inline virtual ~RooGaussian() {  }

  // Optional, if analytical integral known:
  Int_t getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName=0) const ;
  Double_t analyticalIntegral(Int_t code, const char* rangeName=0) const ;
  Int_t getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t staticInitOK=kTRUE) const;
  void generateEvent(Int_t code);

private:

  // The main work
  Double_t evaluate() const ;

  RooRealProxy x ;
  RooRealProxy mean ;
  RooRealProxy sigma ;
  

  ClassDef(RooGaussian,1) // Gaussian PDF
};

Hi @StephanH,

Thanks very much for the minimal example - it will be very helpful! If I can ask one more question, do you know which member functions need to be defined in order to make variables known to RooAbsPdf::fitTo()? I would like to be able to use this class in a fit, but the fit needs to know which variables to modify.

I have tried to implement getComponents, getParameters, and getVariables. I’ve tried functions like:

RooArgSet* morph::getComponents() const {
    RooArgSet* ret = new RooArgSet();
    ret->add(*lambda,kTRUE);
    return ret;
}

Is there a mistake in this sort of implementation? Or is there another function that must be defined? Thanks!

You shouldn’t be implementing any of them. Just use a RooRealProxy as in the RooGaussian implementation, and the rest should be handled by RooFit. You just have to initialise them when the constructor is invoked. It would look similar to this:

RooGaussian::RooGaussian(const char *name, const char *title,
          RooAbsReal& _x, RooAbsReal& _mean,
          RooAbsReal& _sigma) :
  RooAbsPdf(name,title),
  x("x","Observable",this,_x),
  mean("mean","Mean",this,_mean),
  sigma("sigma","Width",this,_sigma)
{
}

Double_t RooGaussian::evaluate() const
{
  double arg = x - mean;
  double sig = sigma;
  double ret = exp(-0.5*arg*arg/(sig*sig));

  return ret ;
}

Thanks! This seems to work. Thanks for explaining.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.