Skip to content
Snippets Groups Projects

ROOT Files

The two main types of ROOT files in KM3NeT are the online and offline files, however, both types can be mixed together as the data is stored in distinct ROOT trees. UnROOT has a single ROOTFile type to represent a KM3NeT ROOT file which can be used to access both the online and offline information. This section describes what kind of data is stored in each tree and how to access them.

Offline Dataformat

The offline dataformat is used to store Monte Carlo (MC) simulations and reconstruction results. The OfflineTree type represents an actual offline file and it is essentially a vector of events (Vector{Evt}) with some fancy caching, lazy access and slicing magic. The offline tree is accessible via the .offline field of the ROOTFile type.

MC Header

The MC header stores metadata related to the simulation chain. The individual entries can be accessed as properties, as shown below.

julia> using KM3io, KM3NeTTestData

julia> f = ROOTFile(datapath("offline", "numucc.root"))
ROOTFile{OnlineTree (0 events, 0 summaryslices), OfflineTree (10 events)}

julia> f.offline
OfflineTree (10 events)

julia> f.offline.header
MCHeader
  DAQ => (livetime = 394,)
  PDF => (i1 = 4, i2 = 58)
  XSecFile => Any[]
  can => (zmin = 0, zmax = 1027, r = 888.4)
  can_user => [0.0, 1027.0, 888.4]
  coord_origin => (x = 0, y = 0, z = 0)
  cut_in => (Emin = 0, Emax = 0, cosTmin = 0, cosTmax = 0)
  cut_nu => (Emin = 100, Emax = 1.0e8, cosTmin = -1, cosTmax = 1)
  cut_primary => (Emin = 0, Emax = 0, cosTmin = 0, cosTmax = 0)
  cut_seamuon => (Emin = 0, Emax = 0, cosTmin = 0, cosTmax = 0)
  decay => ["doesnt", "happen"]
  detector => NOT
  drawing => Volume
  end_event => Any[]
  genhencut => (gDir = 2000, Emin = 0)
  genvol => (zmin = 0, zmax = 1027, r = 888.4, volume = 2.649e9, numberOfEvents = 100000)
  kcut => 2
  livetime => (numberOfSeconds = 0, errorOfSeconds = 0)
  model => (interaction = 1, muon = 2, scattering = 0, numberOfEnergyBins = 1, field_4 = 12)
  muon_desc_file => Any[]
  ngen => 100000.0
  norma => (primaryFlux = 0, numberOfPrimaries = 0)
  nuflux => Real[0, 3, 0, 0.5, 0.0, 1.0, 3.0]
  physics => (program = "GENHEN", version = "7.2-220514", date = 181116, time = 1138)
  seed => (program = "GENHEN", level = 3, iseed = 305765867, field_3 = 0, field_4 = 0)
  simul => (program = "JSirene", version = 11012, date = "11/17/18", time = 7)
  sourcemode => diffuse
  spectrum => (alpha = -1.4,)
  start_run => 1
  target => isoscalar
  usedetfile => false
  xlat_user => 0.63297
  xparam => OFF
  zed_user => [0.0, 3450.0]


julia> f.offline.header.genvol
(zmin = 0, zmax = 1027, r = 888.4, volume = 2.649e9, numberOfEvents = 100000)

julia> f.offline.header.genvol.volume
2.649e9

Event data

The following REPL session shows how to open a file, access individual events or slices of events, loop through events and access e.g. the tracks which are stored in the events.

julia> using KM3io, KM3NeTTestData

julia> f = ROOTFile(datapath("offline", "km3net_offline.root"))
ROOTFile{OfflineTree (10 events)}

julia> f.offline[5]
KM3io.Evt (83 hits, 0 MC hits, 56 tracks, 0 MC tracks)

julia> f.offline[3:5]
3-element Vector{KM3io.Evt}:
 KM3io.Evt (318 hits, 0 MC hits, 56 tracks, 0 MC tracks)
 KM3io.Evt (157 hits, 0 MC hits, 56 tracks, 0 MC tracks)
 KM3io.Evt (83 hits, 0 MC hits, 56 tracks, 0 MC tracks)

julia> event = f.offline[1]
KM3io.Evt (176 hits, 0 MC hits, 56 tracks, 0 MC tracks)

julia> event.trks[1:4]
4-element Vector{KM3io.Trk}:
 KM3io.Trk(1, [445.835395997812, ... , 294.6407542676734, 4000)
 KM3io.Trk(2, [445.835395997812, ... , 294.6407542676734, 4000)
 KM3io.Trk(3, [448.136188112227, ... , 294.6407542676734, 4000)
 KM3io.Trk(4, [448.258348900570, ... , 291.64653112688273, 4000)

julia> for event in f.offline
           @show event
       end
event = KM3io.Evt (176 hits, 0 MC hits, 56 tracks, 0 MC tracks)
event = KM3io.Evt (125 hits, 0 MC hits, 55 tracks, 0 MC tracks)
event = KM3io.Evt (318 hits, 0 MC hits, 56 tracks, 0 MC tracks)
event = KM3io.Evt (157 hits, 0 MC hits, 56 tracks, 0 MC tracks)
event = KM3io.Evt (83 hits, 0 MC hits, 56 tracks, 0 MC tracks)
event = KM3io.Evt (60 hits, 0 MC hits, 56 tracks, 0 MC tracks)
event = KM3io.Evt (71 hits, 0 MC hits, 56 tracks, 0 MC tracks)
event = KM3io.Evt (84 hits, 0 MC hits, 56 tracks, 0 MC tracks)
event = KM3io.Evt (255 hits, 0 MC hits, 54 tracks, 0 MC tracks)
event = KM3io.Evt (105 hits, 0 MC hits, 56 tracks, 0 MC tracks)

Online Dataformat

The online dataformat refers to the dataformat which is written by the data acquisition system (DAQ) of the KM3NeT detectors, more precisely, the ROOT files produced by the JDataFilter which is part of the Jpp framework. The very same format is used in run-by-run (RBR) Monte Carlo (MC) productions, which mimic the detector response and therefore produce similarly structured data. The online data can be accessed via the .online field of the ROOTFile type.

Event data

The events are accessible via ROOTFile(filename).online.events which supports indexing, slicing and iteration, just like the we have seen above, in case of the offline events. Notice however that the online format also contains other types of trees, that's why the explicit .events field is needed. Everything is lazily loaded so that the data is only occupying memory when it's actually accessed, similar to the offline access. In the examples below, we use KM3NeTTestdata to get access to small sample files.

julia> using KM3io, KM3NeTTestData

julia> f = ROOTFile(datapath("online", "km3net_online.root"))
ROOTFile{OnlineTree (3 events, 3 summaryslices), OfflineTree (0 events)}

julia> event = f.online.events[1]
KM3io.DAQEvent with 96 snapshot and 18 triggered hits

julia> event.triggered_hits[4:8]
5-element Vector{KM3io.TriggeredHit}:
 KM3io.TriggeredHit(808447186, 0x00, 30733214, 0x19, 0x0000000000000016)
 KM3io.TriggeredHit(808447186, 0x01, 30733214, 0x15, 0x0000000000000016)
 KM3io.TriggeredHit(808447186, 0x02, 30733215, 0x15, 0x0000000000000016)
 KM3io.TriggeredHit(808447186, 0x03, 30733214, 0x1c, 0x0000000000000016)
 KM3io.TriggeredHit(808451907, 0x07, 30733441, 0x1e, 0x0000000000000004)

julia> for event  f.online.events
           @show event.header.frame_index length(event.snapshot_hits)
       end
event.header.frame_index = 127
length(event.snapshot_hits) = 96
event.header.frame_index = 127
length(event.snapshot_hits) = 124
event.header.frame_index = 129
length(event.snapshot_hits) = 78

Summaryslices and Summary Frames

Summaryslices are generated from timeslices (raw hit data) and are produced by the DataFilter. A slice contains the data of 100ms and is divided into so-called frames, each corresponding to the data of a single optical module. Due to the high amount of data, the storage of timeslices is usually reduced by a factor of 10-100 after the event triggering stage. However, summaryslices are covering the full data taking period. They however do not contain hit data but only the rates of the PMTs encoded into a single byte, which therefore is only capable to store 256 different values. The actual rate is calcuated by the helper functions pmtrate() and pmtrates() which take a SummaryFrame and optionally a PMT channel ID as arguments.

The summaryslices are accessible using the .summaryslices attribute of the OnlineTree instance, which again is hidden behind the .online field of a ROOTFile:

julia> using KM3io, KM3NeTTestData

julia> f = ROOTFile(datapath("online", "km3net_online.root"))
ROOTFile{OnlineTree (3 events, 3 summaryslices), OfflineTree (0 events)}

julia> f.online.summaryslices
KM3io.SummarysliceContainer with 3 summaryslices

julia> for s  f.online.summaryslices
           @show s.header
       end
s.header = KM3io.SummarysliceHeader(44, 6633, 126, KM3io.UTCExtended(0x5dc6018c, 0x23c34600, false))
s.header = KM3io.SummarysliceHeader(44, 6633, 127, KM3io.UTCExtended(0x5dc6018c, 0x29b92700, false))
s.header = KM3io.SummarysliceHeader(44, 6633, 128, KM3io.UTCExtended(0x5dc6018c, 0x2faf0800, false))

Each summaryslice consists of multiple frames, one for every optical module which has sent data during the recording time of the corresponding timeslice.

!!! note

During run transistions, the number of summaryframes in a summaryslice is fluctuating a lot until
it eventually saturates, usually within a few seconds or minutes. Therefore, it is expected that the
number of summaryframes (i.e. active DOMs) is low at the beginning of the file and stabilises after
a few summaryslices.

To access the actual PMT rates and flags (e.g. for high-rate veto or FIFO status) of a summaryframe, several helper functions exist. Let's grab a summaryslice:

using KM3io, KM3NeTTestData

f = ROOTFile(datapath("online", "km3net_online.root"))

s = f.online.summaryslices[1]

and have a look at one of the frames, the 23rd of the first summaryslice:

frame = s.frames[23]

The White Rabbit status:

wrstatus(frame)

Checking if any of the PMTs is in high rate veto:

hrvstatus(frame)

The number of PMTs in high rate veto:

count_hrvstatus(frame)

Checking if any of the TDC FIFOs were almost full:

fifostatus(frame)

Counting the number of TDCs which had FIFO almost full:

count_fifostatus(frame)

The rates of each individual PMT channel ordered by increasing channel ID:

pmtrates(frame)

Individual PMT parameters can be accessed as well, by passing the summaryframe and the PMT ID (DAQ channel ID):

pmtrate(frame, 3)

Here is an example of a simple summary output:

for pmt in 0:30
    println("PMT $(pmt): HRV($(hrvstatus(frame, pmt))) FIFO($(fifostatus(frame, pmt)))")
end

xrootd access

You can access files directly via xrootd by providing the URL on e.g. HPSS. Be aware that URL has to be typed correctly, / instead of // results in an error!), so it should always start with something like root://ccxroot:1999//hpss/....

julia> using KM3io

julia> f = ROOTFile("root://ccxroot:1999//hpss/in2p3.fr/group/km3net/data/raw/sea/KM3NeT_00000132/14/KM3NeT_00000132_00014481.root")
ROOTFile{OnlineTree (136335 events, 107632 summaryslices)}

Now you can use it as if it was on your local filesystem. UnROOT.jl will take care of loading only the needed data from the server.