Python deepcopy and RooFit

I use a RooChebychev pdf. I transfer it to another function and can also make a copy of that.
I wrote a demo based on that suggestion by @jonas to take care of ownership (so that variables of RooAbsPdf do not get destroyed):

import copy

import ROOT


def demo_init():
    x = ROOT.RooRealVar("x", "x", -1, 1)
    x.setBins(10)

    a1 = ROOT.RooRealVar("a1", "a1", 0.5, 0., 1.)
    a2 = ROOT.RooRealVar("a2", "a2", 0.0, 0., 1.)

    cheb = ROOT.RooChebychev("cheb", "Background", x, ROOT.RooArgSet(a1, a2))
    ROOT.SetOwnership(x, False)
    ROOT.SetOwnership(a1, False)
    ROOT.SetOwnership(a2, False)
    cheb.addOwnedComponents([x, a1, a2])

    ## Choose a copy method here ##
    # cheb2 = cheb
    cheb2 = copy.deepcopy(cheb)
    return (cheb, cheb2) 


def demo():
    cheb, cheb2 = demo_init()
    cheb.Print()
    del cheb
    cheb2.Print()


demo()

The results depend on whether I use a simple copy or a widely used copy.deepcopy:

A simple copy (everything works fine):

RooChebychev::cheb[ x=x coefficients=(a1,a2) ] = 1
RooChebychev::cheb[ x=x coefficients=(a1,a2) ] = 1

A deep copy (the second function fails with after the first one is destroyed) (the same holds for copy.copy):

RooChebychev::cheb[ x=x coefficients=(a1,a2) ] = 1
RooChebychev::cheb = 1

I believe that in the worst case copy.deepcopy for a PyROOT object should resort to a simple copy. I tried to store parameters of the pdf in an unrelated RooArgList, but surprisingly it had no effect on the cloned function (its parameters got destroyed with the destruction of cheb).

I have to use ROOT 6.30/06 with Python 2 because of some unknown bugs. Feel free to check that with a recent version.

An interesting note: it looks like pickling does not work properly with copied functions. I think it uses some kind of deepcopy internally.

Let’s see what @jonas can tell about this

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

Hi! Please don’t use copy.deepcopy for RooFit objects. This is unsupported. If you want to do a deep or shallow copy in RooFit, these are your options:

    # A deep copy, cloning the object iself and all the input recursively:
    cheb2 = cheb.cloneTree()

    # A shallow copy of only "cheb", taking the same inputs as the original:
    # The original name would not have to be passed as of this PR:
    # https://github.com/root-project/root/pull/18283
    cheb2 = cheb.clone(cheb.GetName())

Note that cheb2 = cheb doesn’t do any copy at all. It simply creates a new Python reference with a different name that points to the same object.

Hi @jonas, thanks for the reply!

Is there any reference to that? Are you going to add it somewhere into the documentation?

How are you going to deal with deep copies? I believe that many Python programmers use it automatically (also for heaps of heterogeneous data). It would be error-prone to leave that only in the documentation. Do you consider implementing some logic for deep copy, raising an error or at least a warning?
I can’t see it explicitly from your commit (and also how RooAbsArg::clone() is connected with deep copying).

Yes, at the moment I don’t do any deep copies of RooFit objects.

Thanks for your good work again.

Cheers,
Yaroslav