import json
import os
import numpy as np
import logging
from NuRadioReco.detector import detector_base
from NuRadioReco.detector import generic_detector
from NuRadioReco.detector.RNO_G import rnog_detector
logger = logging.getLogger("NuRadioReco.detector")
def _find_path(name):
""" Checks for file relative to local folder and detector.py """
dir_path = os.path.dirname(os.path.realpath(__file__)) # get the directory of this file
filename = os.path.join(dir_path, name)
if os.path.exists(filename):
return filename
else:
# try local folder instead
if not os.path.exists(name):
raise NameError("Can't locate json database file in: {} or {}".format(filename, name))
return name
def _find_reference_entry(station_dict):
"""
Search for the strings "reference_station" or "reference_channel" in the detector description.
This is used to determine whether to use the detector_base or generic_detector class.
"""
for station in station_dict['stations']:
if 'reference_station' in station_dict['stations'][station]:
return True
for channel in station_dict['channels']:
if 'reference_channel' in station_dict['channels'][channel] or 'reference_station' in \
station_dict['channels'][channel]:
return True
return False
def _if_not_None(value, default):
""" Return `value` if `value is not None`, otherwise return `default` """
return value if value is not None else default
[docs]def Detector(*args, **kwargs):
"""
This function returns a detector class object.
It chooses the correct class based on the "source" argument.
The returned object is of one of these classes:
- kwargs["source"] == "rnog_mongo" -> `NuRadioReco.detector.RNO_G.rnog_detector`
- kwargs["source"] == "sql" -> `NuRadioReco.detector.detector_base`
- kwargs["source"] == "json" or "dictionary" -> `NuRadioReco.detector.detector_base` or
`NuRadioReco.detector.generic_detector`
For 'kwargs["source"] == "json"', whether to use "detector_base" or "generic_detector"
depends on whether a reference station / channel is defined in the json file / dictionary
or not.
Parameters
----------
args: Positional arguments (arguments without keyword)
For backwards compatibility, when source is sql | json | dictionary, args are interpreted as follows:
- json_filename = args[0] only when source == "json")
- source = args[1]
- dictionary = args[2]
- assume_inf = args[3]
- antenna_by_depth = args[4]
kwargs: Optional arguments (arguments with keyword)
Keyword arguments passed to detector object. The argument "source" is used to select the
correct class (see description above). If no keyword "source" is passed, the default "json"
is used.
Returns
-------
det: NuRadioReco.detector.* (see options above)
Detector class object
"""
# Interprete positional arguments (args) for backwards compatibility
# when source is sql | json | dictionary
# json_filename = args[0] is used below (when source == 'json').
if len(args) >= 2:
source = args[1].lower()
else:
source = kwargs.pop("source", "json").lower()
if len(args) >= 3:
dictionary = args[2]
else:
dictionary = kwargs.pop("dictionary", None)
if len(args) >= 4:
assume_inf = args[3]
else:
assume_inf = kwargs.pop("assume_inf", None)
if len(args) >= 5:
antenna_by_depth = args[4]
else:
# None because the default argument for GenericDetector and DetectorBase are different
antenna_by_depth = kwargs.pop("antenna_by_depth", None)
if source == "sql":
return detector_base.DetectorBase(
json_filename=None, source=source, dictionary=dictionary,
assume_inf=_if_not_None(assume_inf, True),
antenna_by_depth=_if_not_None(antenna_by_depth, True))
elif source == "rnog_mongo":
return rnog_detector.Detector(*args, **kwargs)
elif source == "dictionary":
if not isinstance(dictionary, dict):
raise ValueError("Argument \"dictionary\" is not correct while source=\"dictionary\" is set.")
station_dict = dictionary
# in this case, `json_filname` not need and should not be passed twice
kwargs.pop("json_filename", None)
filename = ''
elif source == 'json':
if len(args):
json_filename = args[0] # used to be passed as positional argument
elif "json_filename" in kwargs:
json_filename = kwargs.pop("json_filename")
else:
raise ValueError("No possitional arguments and no argument \"json_filename\" "
"was not passed while source=\"json\" (default) is set.")
filename = _find_path(json_filename)
f = open(filename, 'r')
station_dict = json.load(f)
else:
raise ValueError(f'Unknown source specifed (\"{source}\"). '
f'Must be one of \"json\", \"sql\", \"dictionary\", \"mongo\"')
has_reference_entry = _find_reference_entry(station_dict)
if source == 'json':
f.close()
has_default = np.any([arg in kwargs and kwargs[arg] is not None
for arg in ["default_station", "default_channel", "default_device"]])
if has_reference_entry or has_default:
if has_default:
logger.warning(
'Deprecation warning: Passing the default detector station is deprecated. Default stations '
'and default channel should be specified in the detector description directly.'
)
if "default_station" in kwargs:
logger.info('Default detector station provided (station '
f'{kwargs["default_station"]}) -> Using generic detector')
return generic_detector.GenericDetector(
json_filename=filename, source=source, dictionary=dictionary,
assume_inf=_if_not_None(assume_inf, True),
antenna_by_depth=_if_not_None(antenna_by_depth, False), **kwargs)
else:
# Keys might be present (but should be None). Keys are deprecated, keep them for backwards compatibility
for key in ["default_station", "default_channel", "default_device"]:
kwargs.pop(key, "None")
return detector_base.DetectorBase(
json_filename=filename, source=source, dictionary=dictionary,
assume_inf=_if_not_None(assume_inf, True),
antenna_by_depth=_if_not_None(antenna_by_depth, True), **kwargs)