Manipulating array of user defined TObject in python

Hi,

I’m trying to use PyROOT to manipulate data in objects that inherit from TObject. I define two such objects, one of which I would like to contain an array of the second object. When I try to utilize the object array though python complains that the object does not support indexing. How can I use arrays of objects I define?

Here’s the object I’d like to make an array of:

#ifndef TSNCAND_H
#define TSNCAND_H

#include <iostream>

#include "TROOT.h"
#include "TObject.h"

using namespace std;

class TSNCand: public TObject
{
  public:
    Int_t id;
    Double_t ra;
    Double_t dec;
    Int_t nite;
    Int_t run;
    Int_t ccd;
    Int_t ccdx;
    Int_t ccdy;
    Int_t band;
    Double_t dist;         // distance to truth SN
    Int_t truthSNID;       // ID of truth SN matched to

    TSNCand();
    void Clear();
    void Dump();

    ClassDef(TSNCand, 1);
};

#endif

Here’s the object that contains the array of TSNCand:

#ifndef TSNTRUTH_H
#define TSNTRUTH_H

#include <iostream>

#include "TROOT.h"
#include "TObject.h"

#include "TSNCand.h"

#define NMAX 500
#define NFILTER 5
#define MAX_MJD 50

enum eType {
  eTypeUnknown,
  eTypeIa,
  eTypeIbc,
  eTypeIn,
  eTypeIP,
  eTypeIIP,
  eTypeIL,
  eTypeIIL,
  eTypeIIn,
};

enum eFilter {
  eFilterU,
  eFilterG,
  eFilterR,
  eFilterI,
  eFilterZ,
};

using namespace std;

class TSNTruth: public TObject
{
  public:
    Int_t id;
    Double_t ra;
    Double_t dec;
    Double_t z;
    Int_t chip;
    Double_t x;
    Double_t y;
    Int_t type;

    Double_t peakMag[NFILTER];
    Double_t mjd[MAX_MJD];
    Double_t mag[NFILTER][MAX_MJD];

    Int_t nCand;

    TSNCand *snCand;  // array of snCandidates

    TSNTruth();
    void Clear();
    void Dump();

    ClassDef(TSNTruth, 1);
};

#endif

In TSNTruth.cxx I create an array of NMAX TSNCand:

snCand = new TSNCand[NMAX];

I can compile it and access all of it in python except for the snCand array:

Python 2.6.4 (r264:75706, Jun  4 2010, 18:20:16) 
[GCC 4.4.4 20100503 (Red Hat 4.4.4-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ROOT
>>> ROOT.gSystem.Load("libTSNTruth.so")
0
>>> snt = ROOT.TSNTruth()
>>> snt.ra = 355.23
>>> snt.dec = -42.1
>>> snt.Dump()
id: 0, ra: 355.23, dec: -42.1, z: 0
chip: 0, x: 0, y: 0, type: 0
nCand: 0
>>> snt.snCand
<ROOT.TSNCand* object ("TSNCand") at 0x9977c2c>
>>> snt.snCand[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'TSNCand' object does not support indexing
>>> snt.snCand[0].ra
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'TSNCand' object does not support indexing

Also if I make snCand just a single object not an array I can successfully access in python. Has anyone successfully done this sort of thing before?

I thought a little more about it and I guess I can use a getter/setter type of scheme or something that just returns a pointer to an TSNCand object seems to work:

TSNCand *TSNTruth::getSNCand(Int_t n)
{
  if (n > -1 && n < NMAX)
    return &snCand[n];
  else
    return 0;
}

But I’m still curious to know if I can directly access the objects as I asked in my first post. How’s it done?

Hi,

arrays of objects aren’t supported as there is no python equivalent (as opposed to arrays of builtin types, for which there is the buffer interface and module array). It probably is possible to package it into a custom python object, but then I’d probably choose to package the array into an std::vector, so might as well use that directly in the first place.

Cheers,
Wim

Could you please post or point me to an example where this is done? Looking at the older posts here I don’t understand how to do it and they seem to deal with using numpy arrays.

For example, if I changed

TSNCand *snCand;  // array of snCandidates

to

Double_t snCandRA[NMAX];

How do I change the values in this array in python?

Hi,

there was an issue with global arrays like this (now fixed in trunk). As a workaround, put the double array snCandRA in a namespace and it should work.

Cheers,
Wim