How to Weight Without Using TableIO

Although simweights was designed to be used with hdf5 files created byt tableio, it is possible to skip this step. The trick is to create python objects with the same structure as the file objects that simweights expects.

The following is an example of how to do that

#!/usr/bin/env python3

# SPDX-FileCopyrightText: © 2022 the SimWeights contributors
#
# SPDX-License-Identifier: BSD-2-Clause

from pathlib import Path

import pylab as plt
from icecube import dataio, simclasses

import simweights

FILE_DIR = Path("/data/sim/IceCube/2016/filtered/level2/CORSIKA-in-ice/21889/0000000-0000999")
filelist = sorted(str(f) for f in FILE_DIR.glob("Level2_IC86.2016_corsika.021889.00000*.i3.zst"))

# create a dictionary that mimics the structure of a pandas/h5py table
I3PrimaryInjectorInfo = {k: [] for k in dir(simclasses.I3PrimaryInjectorInfo) if k[0] != "_"}

# Same for I3CorsikaWeight but we only need a few columns
I3CorsikaWeight: dict = {"energy": [], "type": [], "zenith": [], "weight": []}

# loop over all the files we want to read
for filename in filelist:
    # open the i3 files with the dataio interface
    infile = dataio.I3File(filename)
    print("Reading " + filename)

    # loop over the frames in the file
    while infile.more():
        # get the frame
        frame = infile.pop_frame()

        # if this is an S-Frame
        if frame.Stop == frame.Simulation:
            # get the info from the frame
            info = frame["I3PrimaryInjectorInfo"]

            for k in I3PrimaryInjectorInfo:
                I3PrimaryInjectorInfo[k].append(getattr(info, k))

        # if this is a physics event in the right sub-event stream
        elif frame.Stop == frame.Physics and frame["I3EventHeader"].sub_event_stream == "InIceSplit":
            # get the weighting object
            w = frame["I3CorsikaWeight"]

            # for each of the columns we need get it from the frame object
            # and put it in the correct column
            I3CorsikaWeight["energy"].append(w.primary.energy)
            I3CorsikaWeight["type"].append(w.primary.type)
            I3CorsikaWeight["zenith"].append(w.primary.dir.zenith)
            I3CorsikaWeight["weight"].append(w.weight)

# make a dictionary object to mimic the file structure of a pandas file
fileobj = {"I3PrimaryInjectorInfo": I3PrimaryInjectorInfo, "I3CorsikaWeight": I3CorsikaWeight}

# create the weighter object
weighter = simweights.CorsikaWeighter(fileobj)

# create an object to represent our cosmic-ray primary flux model
flux = simweights.GaisserH4a()

# get the weights by passing the flux to the weighter
weights = weighter.get_weights(flux)

# print some info about the weighting object
print(weighter.tostring(flux))

# create equal spaced bins in log space
bins = plt.geomspace(3e4, 1e6, 50)

# get energy of the primary cosmic-ray from `PolyplopiaPrimary`
primary_energy = weighter.get_weight_column("energy")

# histogram the primary energy with the weights
plt.hist(primary_energy, weights=weights, bins=bins)

# make the plot look good
plt.xlabel("Primary Energy [GeV]")
plt.ylabel("Event Rate [Hz]")
plt.xlim(bins[0], bins[-1])
plt.ylim(0.1, 10)
plt.loglog()
plt.savefig("without_tableio.svg")
plt.show()
_images/without_tableio.svg