Writing an I3Converter in Python

The converter implementation

It is pretty simple to implement a converter in Python. All you need to do is define a class that inherits from I3Converter and implements two methods, CreateDescription() and FillRows(), and defines a class-level attribute ‘booked’ holding the type the converter expects. Here, for example, is a complete implementation of a converter for I3LineFitParams:

from icecube.linefit import I3LineFitParams
from icecube import tableio

class I3LineFitParamsConverter(tableio.I3Converter):
    booked = I3LineFitParams
    def CreateDescription(self,lfparams):
        desc = tableio.I3TableRowDescription()
        desc.add_field("lf_vel",tableio.types.Float64,"Gm/s","velocity of the fitted track (from LineFit)")
        desc.add_field("lf_vel_x",tableio.types.Float64,"Gm/s","x-component of the velocity of the fitted track")
        desc.add_field("lf_vel_y",tableio.types.Float64,"Gm/s","y-component of the velocity of the fitted track")
        desc.add_field("lf_vel_z",tableio.types.Float64,"Gm/s","z-component of the velocity of the fitted track")
        desc.add_field("n_hits",tableio.types.UInt32,"number","number of reconstructed hits (or reconstructed pulses, depending on how the fit was done) used to calculate the fit")
        return desc
    def FillRows(self,lfparams,rows):
        rows["lf_vel"]   = lfparams.LFVel
        rows["lf_vel_x"] = lfparams.LFVelX
        rows["lf_vel_y"] = lfparams.LFVelY
        rows["lf_vel_z"] = lfparams.LFVelZ
        rows["n_hits"]   = lfparams.NHits
        return 1

tableio.I3ConverterRegistry.register(I3LineFitParamsConverter)

The converter expects a FrameObject of type linefit.I3LineFitParams and produces an I3TableRowDescription with 5 fields. The last line registers the converter so that it can be used automatically when objects of type linefit.I3LineFitParams are encountered in the frame.

Including Python converters in your project

CMakeLists.txt

First, you should add a python directory to your project if it doesn’t already have one:

i3_project(linefit PYTHON_DIR python)

python/__init__.py

You should also create a directory, e.g. linefit/python, containing a file __init__.py with the following contents:

from icecube._linefit import *

try:
    import icecube.tableio
    import converters
except ImportError:
    pass

The line from icecube._linefit import * merges the python bindings for the C++ bits of your project into the script. The try/except block will attempt to import tableio, then the file converters.py, failing gracefully if tableio can not be found. This will make converters available whenever the bindings for LineFit are imported into Python.

python/converters.py

Any converters should be defined in converters.py, including the call to tableio.I3ConverterRegistry.register().

FAQs

How do I create a description for an enumerated type?

You can construct an I3Datatype from a boost-python-wrapped enum like this:

desc = tableio.I3TableRowDescription()
desc.add_field('type', tableio.I3Datatype(dataclasses.I3Particle.ParticleType), '', '')