Setting a .C macro global variable from pyroot

Hello,

I have a ROOT macro named “CMS_lumi.C” which defines a global variable named “lumi” using the line:

TString lumi = “19.7 fb^{-1}”;

I wish to run this macro from a python script and change the value assigned to this global variable. In my script, I therefore do:

import ROOT as r
r.gROOT.LoadMacro(“CMS_lumi.C”)
test = r.gROOT.GetGlobal(“lumi”) # Access the global variable
print test # Prints value of global variable.
test = “new_value” # Unfortunately sets only local variable “test”, not global variable “lumi”.
r.CMS_lumi(…) # Run macro. Unforunately, still picks up original value of “lumi”.

This allows me to print the value of the variable and to run to macro. But I can’t find any way of changing the value assigned to the global variable, such that when I run the macro, it will use the new value. Can this be done ?

Thanks,
Ian Tomalin

This is a case where the distinction between C++ objects/variables and Python objects is important. In Python, when you do “foo = bar” it means “the thing bar can now be accessed by the name foo”. In C++ the same statement means “foo is the label for a place in memory where I now store or copy the value of bar”.

In the case of your problem, initially ‘test’ is a Python label referring to a TString. In PyROOT, TStrings print to the terminal similarly to a regular Python string, but they are different types. When you do test = “new_value”, the “new_value” is actually a regular Python string, not a TString, so you just said “ok forget whatever test was before, now it’s a label referring to this Python string.”

You can confirm this by looking at what is returned by type(test) before and after each assignment.

I can think a workaround, but I don’t know if it’s the best/correct way to do it. The PyROOT TString has a assign member. Normally assign takes care of the mechanics of using the “=” operator, but while playing with your example, I found that if I did test.assign(“new_value”), that test stays as a TString, it doesn’t turn into a Python string. So maybe try using assign and see if your macro picks it up.

Jean-François

Ok I tested it myself and this works. I don’t know the reason why assign works, and there might be a better way that doesn’t need __methods, but here it is:

# foo.C
TString lumi = "blabla";
void foo(){
  std::cout << lumi << std::endl;
}
import ROOT
ROOT.gROOT.LoadMacro("foo.C")

ROOT.foo() # prints blabla
test = ROOT.gROOT.GetGlobal("lumi")
print test # prints blabla

test.__assign__("new_value")
ROOT.foo() # prints new_value

Hi,

assign’ maps onto the C++ operator=(). That was done as it wasn’t clear to me whether the C++ assignment operator should simply be hidden, or whether it had some use somewhere (the name ‘assign’ is made-up and has no python meaning).

That said, I would have thought that:ROOT.lumi = "noot noot"; would work as expected. It doesn’t (it would on any other namespace, just not on the global one), so I’ll see whether I can fix that.

Cheers,
Wim

Hi,

figured it out … now in v5-34-00-patches:[code]>>> import ROOT

ROOT.gROOT.LoadMacro(“foo.C”)
0

ROOT.foo()
blabla

ROOT.lumi = “noot noot”;
ROOT.foo()
noot noot

[/code]
Thanks,
Wim

Hello,

this issue is related:

I switched to ROOT6 and it turns out that my python scripts have some problems with gROOT.

For example the old code reads

from ROOT import * ROOT.gROOT.LoadMacro("AtlasStyle.C")

The execution leads to

Root was set up via lsetup.

Hi,

the error is correct: after “from ROOT import *”, gROOT lives in the global space, not the ROOT (C++) namespace. Just fix the code by removing “ROOT.” and it will work in both 5 & 6.

Cheers,
Wim

Hi Wim,

thanks for the answer. It solved the problem.

Ciao

Manuel