Data Structure¶
.nur Files and How to Use Them¶
Philosophy and Basic Structure¶
NuRadioReco comes with its own input and output format, called .nur. With the obvious exception of reading in data from other file formats, like CoREAS or the SnowShovel format of the ARIANNA experiment, every processing step in an event reconstruction is done in this format. The big advantage this provides, is that at any point the process can be interrupted and the current state of the event data can be saved. This makes it easy to split a reconstruction into several steps and to check the state of the data structure after every step.
![]()
A NuRadioReco event is organized hierarchical, with an
Eventobject at the top. Elements further down the hierarchy can be accessed via get functions or iterators from their parent object. For example, accessing the traces of a station’s channels would work like this:#get station with ID 42 station = event.get_station(42) # iterate over all channels in station for channel in station.iter_channels(): trace = channel.get_trace()
Reading and Writing .nur Files¶
Reading and writing .nur files is done by dedicated IO modules. Writing events is done by the eventWriter module. To save disc space it offers the option to not store channel and electric field traces, in case only the higher-level parameters are needed. It is also possible to write the detector description onto a *.nur* file.
import NuRadioReco.modules.io.eventWriter event_writer = NuRadioReco.modules.io.eventWriter.eventWriter() event_writer.begin('output_filename.nur') event_writer.run(event, mode='full')To read .nur files, two different modules can be used:
NuRadioRecoiois a general-purpose reader that provides different ways to access events e.g. by ID or by event number. TheeventReaderis a more streamlined wrapper aroundNuRadioRecoiothat provides an iterator over all events. Both modules provide as way to read the detector description from a *.nur* file.import NuRadioReco.modules.io.NuRadioRecoio nuradioreco_io = NuRadioReco.modules.io.NuRadioRecoio.NuRadioRecoio(['path/to/file', '/path/to/other/file']) # get event with run number 0 and event ID 5 event_1 = nuradioreco_io.get_event([0,5]) # get second event in files (counting starts at 0) event_2 = nuradioreco.io.get_event_i(1) # iterate over all events for event in nuradioreco_io.get_event(): station = event.get_station(42) import NuRadioReco.modules.io.eventReader event_reader = NuRadioReco.modules.io.eventReader.eventReader() event_reader.begin(['path/to/file', 'path/to/other/file']) # iterate over events for event in event_reader.run(): station = event.get_station(42)Additionally, .nur files store higher-level parameters in their headers, which makes them easily accessible for all events in a file. For example, if one wanted to make a histogram of the zenith angles in a given file, it would work like this:
import matplotlib.pyplot as plt from NuRadioReco.framework.parameters import stationParameters as stnp from NuRadioReco.utilities import units import NuRadioReco.modules.io.NuRadioRecoio nuradioreco_io = NuRadioReco.modules.io.NuRadioRecoio.NuRadioRecoio(['path/to/file']) header = nuradioreco_io.get_header() station_id = 42 zeniths = header[station_id][stnp.zenith] plt.hist(zeniths/units.deg) plt.show()The way that writing and reading .nur files is handled internally is that every class in the framework has a
serializefunction that writes all information stored in the object into a pickle object and adeserializefunction that writes the data from such a pickle into a class object. To write an event to disk, each object calls theserializefunction on its child objects, stores the pickles they return and then serializes itself. The resulting pickle can then be written to disk. To read a .nur file the same is done in reverse, with each object calling thedeserializefunction on its children. Thanks to this implementation, it is easy to extend the framework, since all that has to be done is to defineserializeanddeserializefunctions and adjust the ones of the parent object.
Parameter Storage¶
NuRadioReco offers a flexible way to store properties in the data structure via the parameter storage. Certain classes (
Station,SimStation,Channel,ElectricField,RadioShowerandHybridShower) provideget_parameterandset_parameterfunctions that allow parameters to be stored in those objects along with their uncertainties and correlation to any other paramters. The parameters are defined in an enumerated type enum, so to add a new parameter, it just needs to be added to the list of parametersImportant
New parameters should always be added to the bottom of the list. Do not re-use old Enums!
Additionally, parameters can be written and accessed via indexing, like one would do to a dictionary:
from NuRadioReco.framework.parameters import stationParameters as stnp from NuRadioReco.utilities import units # both ways to set the parameter are equivalent station.set_parameter(stnp.cr_zenith, 45 * units.deg) station[stnp.cr_zenith] = 45 * units.deg # set parameter uncertainty station.set_parameter_error(stnp.cr_zenith, 2 * units.deg) # 2 ways of accessing parameters: zenith = station.get_parameter(stnp.cr_zenith) zenith = station[stnp.cr_zenith] # get parameter uncertainty zenith_uncertainty = station.get_parameter_error(stnp.cr_zenith)
List of Data Classes¶
Event¶
The Event is the upper-most element of the event structure and holds all simulated and reconstructed showers and stations as well as the event ID and run number.
Radio Shower¶
A Radio Shower is used to hold reconstructed shower parameters via the parameter storage. It should only be used for properties reconstructed from the radio signal, for properties from a simulated shower or reconstructed from another detector, the SimShower or HybridShower should be used, respectrively.
It can be accessed by the
get_showersandget_first_showermethods of the Event class.
SimShower¶
A Sim Shower is used to hold parameters of simulated showers via the parameter storage. They are the same class as
RadioShower, but are stored separately to distinguish between simulated and reconstructed properties.It can be accessed by the
get_sim_showersmethod of the Event class.
Station¶
A Station is used to hold event properties reconstructed at the station level, i.e. reconstructed from the data of a single station.
It can be accessed by the
get_stationandget_stationsmethods of theEventclass
Trigger¶
SimStation¶
A SimStation can hold the same properties as the
Station(and inherits from it), but is used for the MC truth of the simulation. This also implies that events from measured data typically do not have aSimStation.It can be accessed by the
get_sim_stationmethod of theStationclass.
BaseTrace¶
The BaseTrace class is used to store waveforms, both for voltages in the channels and electric fields. While internally traces are stored in the time domain, where they can be accessed via the
get_traceandset_tracemethod, it is also possible access the waveform in the frequency domain via theget_frequency_spectrumandset_frequency_spectrummethod. In that case, a Fourier transformation is done automatically by theTrace. The times and frequencies corresponding to the waveforms returned by theget_traceandget_frequency_spectrummethods can be accessed via theget_timesandget_frequenciesmethods. The times are defined relative to the time of the parentStationand can be changes using theset_trace_start_timemethod, which changes the starting time of the trace.The
Traceclass is not used by itself, but serves as parent class for both theChannelandElectricFieldclasses.
Electric Field¶
The ElectricField is used to store information about electric fields, which can be accessed via the parameter storage and methods inherited from the
BaseTraceclass.Since radio stations for neutrino detection are often so spread out that the electric field is not the same at all channels, each electric field is associated with one or more channels, whose IDs have to be passed to the Constructor function and can be accessed by the
get_channel_idsmethod. Since pulses may reach a channel via different paths through the ice, multipleElectricFieldobjects may be associated with the same channel. Since typically multiple channels are used to reconstruct the electric field, eachElectricFieldcan be associated with multiple channels. To avoid ambiguity, theElectricFieldalso has a position (accessed viaget_position) relative to the station.A
Station´s orSimStation´sElectricFieldobjects can be accessed via theget_electric_fieldsmethod or theget_electric_fields_for_channelsmethod, which allows to filter by channel IDs and ray path types.
Channel¶
The Channel is used to store information about the voltage traces recorded in a channel, which can be accessed via the parameter storage and methods inherited from the
BaseTraceclass.
Hybrid Information¶
As many radio detectors are built as part of a hybrid detector whose data may be used in the radio event reconstruction, a way to make this data accessible in NuRadioReco is needed. The HybridInformation class provides this functionality and sections the information from the other detectors off from the radio part to avoid confusion. Despite its name, it does not hold any data from the other detectors itself, but offers access to
HybridShowerobjects in which this data is stored. For each additional detector (or set of detector data), aHybridSHowerobject can be added via theadd_hybrid_showermethod or accessed via theget_hybrid_showerorget_hybrid_showersmethods.It can be accessed via the
get_hybrid_information'' method of the ``Eventclass.
Hybrid Shower¶
The HybridShower is used to store information about a shower that was reconstructed with a complementary detector, mainly via the parameter storage.
It can be accessed via the
get_hybrid_showerandget_hybrid_showersmethods of theHybridInformationclass.
Hybrid Detector¶
A
HybridDetectorcan be used to store more detailed and experiment-specific information about a complementary detector. The diversity of hybrid radio detectors makes it impractical to provide this functionality inside NuRadioReco itself, but a customHybridDetectorclass can be impemented inside an independent repository. This class can be slotted into the data structure via theset_hybrid_detectormethod of theHybridShowerclass and accessed via itsget_hybrid_detectormethod.A
HybridDetectorclass is required to have a constructor that does not accept any parameters as well as aserializeand adeserializefunction equivalent to the other framework elements.An example for the implementation of a custom
HybridDetectorcan be found in the NuRadioReco/example folder.
