diff --git a/NuRadioReco/modules/RNO_G/channelBlockOffsetFitter.py b/NuRadioReco/modules/RNO_G/channelBlockOffsetFitter.py index e4711e094..d306bba24 100644 --- a/NuRadioReco/modules/RNO_G/channelBlockOffsetFitter.py +++ b/NuRadioReco/modules/RNO_G/channelBlockOffsetFitter.py @@ -217,7 +217,7 @@ def fit_block_offsets( # obtain guesses for block offsets a_guess = np.mean(np.split(filtered_trace, n_blocks), axis=1) if mode == 'approximate': - block_offsets = a_guess + block_offsets = a_guess + np.mean(trace) elif mode == 'fit': # self._offset_guess[channel_id] = a_guess # we can get rid of one parameter through a global shift diff --git a/NuRadioReco/modules/io/RNO_G/readRNOGDataMattak.py b/NuRadioReco/modules/io/RNO_G/readRNOGDataMattak.py index 4d1355026..fa865277e 100644 --- a/NuRadioReco/modules/io/RNO_G/readRNOGDataMattak.py +++ b/NuRadioReco/modules/io/RNO_G/readRNOGDataMattak.py @@ -22,7 +22,7 @@ import random -def create_random_directory_path(prefix="/tmp/", n=7): +def _create_random_directory_path(prefix="/tmp/", n=7): """ Produces a path for a temporary directory with a n letter random suffix @@ -48,7 +48,7 @@ def create_random_directory_path(prefix="/tmp/", n=7): return path -def baseline_correction(wfs, n_bins=128, func=np.median, return_offsets=False): +def _baseline_correction(wfs, n_bins=128, func=np.median, return_offsets=False): """ Simple baseline correction function. @@ -150,7 +150,7 @@ def get_time_offset(trigger_type): raise KeyError(f"Unknown trigger type: {trigger_type}. Known are: {known_trigger_types}. Abort ....") -def all_files_in_directory(mattak_dir): +def _all_files_in_directory(mattak_dir): """ Checks if all Mattak root files are in a directory. Ignoring runinfo.root because (asaik) not all runs have those and information is currently not read by Mattak. @@ -186,11 +186,17 @@ class readRNOGData: def __init__(self, run_table_path=None, load_run_table=True, log_level=logging.INFO): """ + Reader for RNO-G ``.root`` files + + This class provides read access to RNO-G ``.root`` files and converts them + to NuRadioMC :class:`Events `. Requires ``mattak`` + (https://github.com/RNO-G/mattak) to be installed. + Parameters ---------- run_table_path: str | None - Path to a run_table.cvs file. If None, the run table is queried from the DB. (Default: None) + Path to a run_table.csv file. If None, the run table is queried from the DB. (Default: None) load_run_table: bool If True, try to load the run_table from run_table_path. Otherwise, skip this. @@ -198,6 +204,23 @@ def __init__(self, run_table_path=None, load_run_table=True, log_level=logging.I log_level: enum Set verbosity level of logger. If logging.DEBUG, set mattak to verbose (unless specified in mattak_kwargs). (Default: logging.INFO) + + Examples + -------- + + .. code-block:: + + reader = readRNOGDataMattak.readRNOGData() # initialize reader + reader.begin('/path/to/root_file_or_folder') + + evt = reader.get_event_by_index(0) # returns the first event in the file + # OR + evt = reader.get_event(run_nr=1100, event_id=679) # returns the event with run_number 1100 and event_id 679 + # OR + for evt in reader.run(): # loop over all events in file + # perform some analysis + pass + """ self.logger = logging.getLogger('NuRadioReco.readRNOGData') self.logger.setLevel(log_level) @@ -222,6 +245,18 @@ def __init__(self, run_table_path=None, load_run_table=True, log_level=logging.I self.logger.warn("Import of run table failed. Runs can not be filtered.! \n" "You can get the interface from GitHub: git@github.com:RNO-G/rnog-runtable.git") else: + # some users may mistakenly try to pass the .root files to __init__ + # we check for this and raise a (hopefully) helpful error message + user_passed_root_file_msg = ( + "The optional argument run_table_path expects a csv file, " + "but you passed a list of files or a .root file. Note that " + "the .root files to read in should be passed to the `begin` method of this class" + ) + if isinstance(run_table_path, (list, np.ndarray)): + raise TypeError(user_passed_root_file_msg) + elif os.path.isdir(run_table_path) or run_table_path.endswith('.root'): + raise ValueError(user_passed_root_file_msg) + import pandas self.__run_table = pandas.read_csv(run_table_path) @@ -353,14 +388,14 @@ def begin(self, self._datasets = [] self.__n_events_per_dataset = [] + if not isinstance(dirs_files, (list, np.ndarray)): + dirs_files = [dirs_files] + self.logger.info(f"Parse through / read-in {len(dirs_files)} directory(ies) / file(s).") self.__skipped_runs = 0 self.__n_runs = 0 - if not isinstance(dirs_files, (list, np.ndarray)): - dirs_files = [dirs_files] - # Set verbose for mattak if "verbose" in mattak_kwargs: verbose = mattak_kwargs.pop("verbose") @@ -375,7 +410,7 @@ def begin(self, if os.path.isdir(dir_file): - if not all_files_in_directory(dir_file): + if not _all_files_in_directory(dir_file): self.logger.error(f"Incomplete directory: {dir_file}. Skip ...") continue else: @@ -384,7 +419,7 @@ def begin(self, # it is not a combined file). To work around this: Create a tmp directory under `/tmp/`, link the file you want to # read into this directory with the the name `combined.root`, use this path to read the run. - path = create_random_directory_path() + path = _create_random_directory_path() self.logger.debug(f"Create temporary directory: {path}") if os.path.exists(path): raise ValueError(f"Temporary directory {path} already exists.") @@ -393,7 +428,7 @@ def begin(self, self.__temporary_dirs.append(path) # for housekeeping self.logger.debug(f"Create symlink for {dir_file}") - os.symlink(dir_file, os.path.join(path, "combined.root")) + os.symlink(os.path.abspath(dir_file), os.path.join(path, "combined.root")) dir_file = path # set path to e.g. /tmp/NuRadioReco_XXXXXXX/combined.root @@ -721,10 +756,10 @@ def run(self): """ Loop over all events. - Returns - ------- + Yields + ------ - evt: generator(NuRadioReco.framework.event) + evt: `NuRadioReco.framework.event.Event` """ event_idx = -1 for dataset in self._datasets: @@ -774,7 +809,7 @@ def get_event_by_index(self, event_index): Returns ------- - evt: NuRadioReco.framework.event + evt: `NuRadioReco.framework.event.Event` """ self.logger.debug(f"Processing event number {event_index} out of total {self._n_events_total}") @@ -816,7 +851,7 @@ def get_event(self, run_nr, event_id): Returns ------- - evt: NuRadioReco.framework.event + evt: `NuRadioReco.framework.event.Event` """ self.logger.debug(f"Processing event {event_id}") diff --git a/README.md b/README.md index 385697f19..e5c0966f8 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,10 @@ Also please visit https://nu-radio.github.io/NuRadioMC/Introduction/pages/contri ## Publications builing up on NuRadioMC/Reco NuRadioMC is used in an increasing number of studies. To get an overview for what NuRadioMC can be used for, please have a look at the following publications or see [here](https://inspirehep.net/literature?sort=mostrecent&size=25&page=1&q=refersto%3Arecid%3A1738571%20or%20refersto%3Arecid%3A1725583): +* V. Valera, M. Bustamante, O. Mena, "Joint measurement of the ultra-high-energy neutrino spectrum and cross section", [arXiv:2308.07709](https://arxiv.org/abs/2308.07709) * IceCube-Gen2 collaboration, [IceCube-Gen2 Technical Design Report](https://icecube-gen2.wisc.edu/science/publications/TDR) * ARIANNA collaboration (A. Anker et al.), "Developing New Analysis Tools for Near Surface Radio-based Neutrino Detectors", [arXiv:2307.07188](https://arxiv.org/abs/2307.07188) -* L. Pyras, C. Glaser S. Hallmann and A. Nelles, "Atmospheric muons at PeV energies in radio neutrino detectors", [arXiv:2307.04736](https://arxiv.org/abs/2307.04736) +* L. Pyras, C. Glaser S. Hallmann and A. Nelles, "Atmospheric muons at PeV energies in radio neutrino detectors", JCAP 10 (2023) 043, [arXiv:2307.04736](https://arxiv.org/abs/2307.04736) * I. Plaisier, S. Bouma, A. Nelles, "Reconstructing the arrival direction of neutrinos in deep in-ice radio detectors", [arXiv:2302.00054](https://arxiv.org/abs/2302.00054) * S. Bouma, A. Nelles for the IceCube-Gen2 collaboration, "Direction reconstruction performance for IceCube-Gen2 Radio", [PoS(ICRC2023)1045](https://pos.sissa.it/444/1045/pdf) * F. Schlüter and S. Toscano for the IceCube-Gen2 collaboration, "Estimating the coincidence rate between the optical and radio array of IceCube-Gen2", [PoS(ICRC2023)1022](https://pos.sissa.it/444/1022/pdf) diff --git a/changelog.txt b/changelog.txt index 92f29fa23..855407f04 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,10 @@ Changelog - to keep track of all relevant changes please update the categories "new features" and "bugfixes" before a pull request merge! +version 2.2.1 +bugfixes: +- readRNOGDataMattak: fix bug where .root files would not be found if they are passed as relative paths (instead of absolute paths or folder) + version 2.2.0 new features: - expand values stored in SimplePhasedTrigger diff --git a/pyproject.toml b/pyproject.toml index b70d3feca..29091a6fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "NuRadioMC" -version = "2.2.0" +version = "2.2.1" authors = ["Christian Glaser et al."] homepage = "https://github.com/nu-radio/NuRadioMC" documentation = "https://nu-radio.github.io/NuRadioMC/main.html"