Branching array of char in ttree

Hello,
I would like to branch a string in my tree. It works beautiful in c++:

root [1] TTree t(“t”,"")
root [2] char* s = ""
root [8] t.Branch(“s”,s,“s/C”)
root [12] s[0]='a’
root [14] s[1]='b’
root [16] t.Fill()

root [19] s[2]='c’
root [21] t.Fill()

root [23] s[2]=’\0’
root [24] s[1]=’\0’
root [26] t.Fill()
root [27] t.Scan()


  • Row * s *

  •    0 *        ab *
    
  •    1 *       abc *
    
  •    2 *         a *
    

In python I have to use the array module and then I have difficulties since ‘\0’ produces a strange character. If I try the same, then I have:

t=TTree(‘t’, ‘’)
s=array(‘c’,‘ab’)
t.Branch(‘s’,s,‘s/C’)
t.Fill()

s.append(‘c’)
t.Fill()

s.pop()
s.pop()
t.Fill()

t.Scan()


  • Row * s *

  •    0 *      abo *
    
  •    1 *      abc *
    
  •    2 *      abc *
    

Can someone help me please?
Cheers, Gabriel

Gabriel,

not exactly: CINT saves you by allocating a larger buffer for the string variable that you allocate, and probably initializes it to \0, or what you did in the C++ macro would not have worked (try compiling it, and see it crash at runtime in several places: the assignments beyond the empty string bounds as well as in the print/scan).

In python, you get exactly what you asked for: a character array. That is not a string. You can get the same behavior by creating a larger buffer, and then being careful about ‘\0’ as you are in the C++ macro that you posted. Or, you can use a smaller array, but then you will still need to take care that the array address may change when appending (if you don’t allocate enough memory to start with). Thus, you should reset the branch address every time (i.e. t.SetBranchAddress(‘s’,s) ) before calling Fill().

Something like:[code]t=TTree(‘t’, ‘’)
s=array(‘c’, ‘ab\0’)
t.Branch(‘s’,s,‘s/C’)
t.Fill()
s.pop()
s.extend(‘c\0’)
t.SetBranchAddress(‘s’,s)
t.Fill()

remove not last (which is ‘\0’), but one-but last

s.remove(s[-2])
s.remove(s[-2])
t.SetBranchAddress(‘s’,s)
t.Fill()

t.Scan() [/code]
Alternatively, you can work with a pythonize character buffer, that behaves close to CINT-style:[code]gROOT.ProcessLine( “struct MyStringBuf { char s[256]; };” )
s = MyStringBuf();

t=TTree(‘t’, ‘’)
t.Branch(‘s’,AddressOf(s,‘s’),‘s/C’)
s.s = ‘ab’
t.Fill()

append 1

s.s += ‘c’
t.Fill()

pop 2 by slicing

s.s = s.s[:-2]
t.Fill()

t.Scan()[/code]
In PyROOT, the conversions of string to char-array (and vice versa) take care of the ‘\0’ for you.

HTH,
Wim

Thank you very much! I was missing the update on Branch address and also the ‘\0’ in the end of string. One more question, is it possible to branch an array of strings?

Cheers, Gabriel

Gabriel,

any object that comes with a dictionary can be saved. As such, I don’t quite see the need for making things complicated with character arrays etc. Why not simply use an std::vectorstd::string? Something like:

[code]from ROOT import *

f=TFile(‘test.root’,‘recreate’)
t=TTree(‘t’, ‘’)
vs = std.vector(std.string)()
t.Branch(‘vs’,vs)
vs.reserve(3)
vs.push_back( ‘ab’ )
vs.push_back( vs[0] + ‘c’ )
vs.push_back( vs[1][:-2] )
t.Fill()
f.Write()[/code]
for writing and then something similar:

[code]from ROOT import *

f=TFile(‘test.root’)
f.t.GetEntry(0)
print list(t.vs)[/code]
for reading (I used a file in this example to show that it works, as t.Scan() didn’t give me any pretty output).

HTH,
Wim