Exemple #1
0
def normcheckpath(path, checkdir=False):
    """Normalize a path and check that it exists.

    Useful e.g. so that different path specifications that resolve to the same
    location will resolve to the same string.

    Parameters
    ----------
    path : string
        Path to check

    checkdir : bool
        Whether `path` is expected to be a directory

    Returns
    -------
    normpath : string
        Normalized path

    """
    normpath = find_resource(path)
    if checkdir:
        kind = 'dir'
        check = isdir
    else:
        kind = 'file'
        check = isfile

    if not check(normpath):
        raise IOError('Path "%s" which resolves to "%s" is not a %s.' %
                      (path, normpath, kind))
    return normpath
Exemple #2
0
    def read(self, filenames, encoding=None):
        """Override `read` method to interpret `filenames` as PISA resource
        locations, then call overridden `read` method. Also, IOError fails
        here, whereas it is ignored in RawConfigParser.

        For further help on this method and its arguments, see
        :method:`~backports.configparser.configparser.read`

        """
        if isinstance(filenames, str):
            filenames = [filenames]
        resource_locations = []
        for filename in filenames:
            resource_location = find_resource(filename)
            if not isfile(resource_location):
                raise ValueError('"%s" is not a file or could not be located' %
                                 filename)
            resource_locations.append(resource_location)

        filenames = resource_locations

        # NOTE: From here on, most of the `read` method is copied, but
        # ignoring IOError exceptions is removed here. Python copyrights apply.

        if isinstance(filenames, str):
            filenames = [filenames]
        read_ok = []
        for filename in filenames:
            with open(filename, encoding=encoding) as fp:
                self._read(fp, filename)
            read_ok.append(filename)
        return read_ok
Exemple #3
0
    def save(self, fpath, ver=None, **kwargs):
        """Save cross sections (and the energy specification) to a file at
        `fpath`."""
        if ver is None:
            if self._ver is None:
                raise ValueError(
                    'Either a ver must be specified in call to `save` or it '
                    'must have been set prior to the invocation of `save`.'
                )
            ver = self._ver
        else:
            assert ver == self._ver

        try:
            fpath = find_resource(fpath)
        except IOError:
            pass
        fpath = os.path.expandvars(os.path.expanduser(fpath))
        all_xs = {}
        # Get any existing data from file
        if os.path.exists(fpath):
            all_xs = from_file(fpath)
        # Validate existing data by instantiating objects from each
        for v, d in all_xs.items():
            CrossSections(ver=v, energy=d['energy'], xsec=d['xsec'])
        if ver in all_xs:
            logging.warning('Overwriting existing version "' + ver +
                            '" in file ' + fpath)
        all_xs[ver] = {'xsec':self, 'energy':self.energy}
        to_file(all_xs, fpath, **kwargs)
Exemple #4
0
    def __init__(
        self,
        events_file,
        files_per_flavor,
        output_names,
        reco,
        keys,
        cuts,
        track_E_cut=None,
        **std_kwargs,
    ):

        # instantiation args that should not change
        self.events_file = find_resource(events_file)

        # init base class
        super().__init__(
            expected_params=(),
            **std_kwargs,
        )

        self.output_names = output_names
        self.reco = reco
        self.files_per_flavor = split(files_per_flavor)
        self.track_E_cut = track_E_cut
        self.keys = split(keys)
        self.cuts = eval(cuts)
Exemple #5
0
    def setup_function(self):

        # load MCeq tables
        spline_tables_dict = pickle.load(
            BZ2File(find_resource(self.params.table_file.value)))

        self.data.data_specs = self.calc_specs

        for container in self.data:
            container['sys_flux'] = np.empty((container.size, 2), dtype=FTYPE)

        if self.calc_mode == 'binned':
            # speed up calculation by adding links
            # as layers don't care about flavour
            self.data.link_containers('nu', [
                'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc',
                'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc',
                'nuebar_nc', 'numubar_nc', 'nutaubar_nc'
            ])

        for container in self.data:
            # evaluate the splines (flux and deltas) for each E/CZ point
            # at the moment this is done on CPU, therefore we force 'host'
            for key in spline_tables_dict.keys():
                logging.info(
                    'Evaluating MCEq splines for %s for Barr parameter %s' %
                    (container.name, key))
                container['barr_' + key] = np.empty((container.size, 8),
                                                    dtype=FTYPE)
                self.eval_spline(container['true_energy'].get('host'),
                                 container['true_coszen'].get('host'),
                                 spline_tables_dict[key],
                                 out=container['barr_' + key].get('host'))
                container['barr_' + key].mark_changed('host')
        self.data.unlink_containers()
Exemple #6
0
    def setup_function(self):

        # object for oscillation parameters
        self.osc_params = OscParams()

        # setup the layers
        #if self.params.earth_model.value is not None:
        earth_model = find_resource(self.params.earth_model.value)
        YeI = self.params.YeI.value.m_as('dimensionless')
        YeO = self.params.YeO.value.m_as('dimensionless')
        YeM = self.params.YeM.value.m_as('dimensionless')
        prop_height = self.params.prop_height.value.m_as('km')
        detector_depth = self.params.detector_depth.value.m_as('km')
        self.layers = Layers(earth_model, detector_depth, prop_height)
        self.layers.setElecFrac(YeI, YeO, YeM)

        # set the correct data mode
        self.data.data_specs = self.calc_specs

        # --- calculate the layers ---
        if self.calc_mode == 'binned':
            # speed up calculation by adding links
            # as layers don't care about flavour
            self.data.link_containers('nu', [
                'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc',
                'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc',
                'nuebar_nc', 'numubar_nc', 'nutaubar_nc'
            ])

        for container in self.data:
            self.layers.calcLayers(container['true_coszen'].get('host'))
            container['densities'] = self.layers.density.reshape(
                (container.size, self.layers.max_layers))
            container['distances'] = self.layers.distance.reshape(
                (container.size, self.layers.max_layers))

        # don't forget to un-link everything again
        self.data.unlink_containers()

        # --- setup empty arrays ---
        if self.calc_mode == 'binned':
            self.data.link_containers('nu', [
                'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc',
                'nutau_nc'
            ])
            self.data.link_containers('nubar', [
                'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc',
                'numubar_nc', 'nutaubar_nc'
            ])
        for container in self.data:
            container['probability'] = np.empty((container.size, 3, 3),
                                                dtype=FTYPE)
        self.data.unlink_containers()

        # setup more empty arrays
        for container in self.data:
            container['prob_e'] = np.empty((container.size), dtype=FTYPE)
            container['prob_mu'] = np.empty((container.size), dtype=FTYPE)
Exemple #7
0
    def setup_function(self):

        # setup Earth model
        if self.params.earth_model.value is not None:
            earth_model = find_resource(self.params.earth_model.value)
            YeI = self.params.YeI.value.m_as('dimensionless')
            YeO = self.params.YeO.value.m_as('dimensionless')
            YeM = self.params.YeM.value.m_as('dimensionless')
        else:
            earth_model = None

        # setup the layers
        prop_height = self.params.prop_height.value.m_as('km')
        detector_depth = self.params.detector_depth.value.m_as('km')
        self.layers = Layers(earth_model, detector_depth, prop_height)
        if earth_model is not None:
            self.layers.setElecFrac(YeI, YeO, YeM)

        # set the correct data mode
        self.data.representation = self.calc_mode

        # --- calculate the layers ---
        if self.data.is_map:
            # speed up calculation by adding links
            # as layers don't care about flavour
            self.data.link_containers('nu', ['nue_cc', 'numu_cc', 'nutau_cc',
                                             'nue_nc', 'numu_nc', 'nutau_nc',
                                             'nuebar_cc', 'numubar_cc', 'nutaubar_cc',
                                             'nuebar_nc', 'numubar_nc', 'nutaubar_nc'])

        for container in self.data:
            if self.params.earth_model.value is not None:
                self.layers.calcLayers(container['true_coszen'])
                container['densities'] = self.layers.density.reshape((container.size, self.layers.max_layers))
                container['distances'] = self.layers.distance.reshape((container.size, self.layers.max_layers))
            else:
                self.layers.calcPathLength(container['true_coszen'])
                container['distances'] = self.layers.distance

        # don't forget to un-link everything again
        self.data.unlink_containers()

        # --- setup empty arrays ---
        if self.data.is_map:
            self.data.link_containers('nu', ['nue_cc', 'numu_cc', 'nutau_cc',
                                             'nue_nc', 'numu_nc', 'nutau_nc'])
            self.data.link_containers('nubar', ['nuebar_cc', 'numubar_cc', 'nutaubar_cc',
                                                'nuebar_nc', 'numubar_nc', 'nutaubar_nc'])
        for container in self.data:
            container['probability'] = np.empty((container.size, 3, 3), dtype=FTYPE)
        self.data.unlink_containers()

        # setup more empty arrays
        for container in self.data:
            container['prob_e'] = np.empty((container.size), dtype=FTYPE)
            container['prob_mu'] = np.empty((container.size), dtype=FTYPE)
Exemple #8
0
 def __load(self, fname):
     fpath = resources.find_resource(fname)
     with h5py.File(fpath, 'r') as open_file:
         meta = dict(open_file.attrs)
         for k, v in meta.items():
             if hasattr(v, 'tolist'):
                 meta[k] = v.tolist()
         data = hdf.from_hdf(open_file)
     self.validate(data)
     return data, meta
Exemple #9
0
def from_file(fname, fmt=None, **kwargs):
    """Dispatch correct file reader based on `fmt` (if specified) or guess
    based on file name's extension.

    Parameters
    ----------
    fname : string
        File path / name from which to load data.

    fmt : None or string
        If string, for interpretation of the file according to this format. If
        None, file format is deduced by an extension found in `fname`.

    **kwargs
        All other arguments are passed to the function dispatched to read the
        file.

    Returns
    -------
    Object instantiated from the file (string, dictionary, ...). Each format
    is interpreted differently.

    Raises
    ------
    ValueError
        If extension is not recognized

    """
    if fmt is None:
        rootname, ext = os.path.splitext(fname)
        ext = ext.replace('.', '').lower()
    else:
        rootname = fname
        ext = fmt.lower()

    if ext in ZIP_EXTS or ext in XOR_EXTS:
        rootname, inner_ext = os.path.splitext(rootname)
        inner_ext = inner_ext.replace('.', '').lower()
        ext = inner_ext

    fname = resources.find_resource(fname)
    if ext in jsons.JSON_EXTS:
        return jsons.from_json(fname, **kwargs)
    if ext in hdf.HDF5_EXTS:
        return hdf.from_hdf(fname, **kwargs)
    if ext in PKL_EXTS:
        return from_pickle(fname, **kwargs)
    if ext in CFG_EXTS:
        return from_cfg(fname, **kwargs)
    if ext in TXT_EXTS:
        return from_txt(fname, **kwargs)
    errmsg = 'File "%s": unrecognized extension "%s"' % (fname, ext)
    log.logging.error(errmsg)
    raise ValueError(errmsg)
Exemple #10
0
    def __init__(self, fp, fpname, fpath=None):
        self._iter_stack = []
        """Stack for storing dicts with 'fp', 'fpname', 'fpath', 'lineno', and
        'line' for keeping track of the hierarchy of master config & included
        configs"""

        # It's ok to not find the fpname / fpname to not be a file for the
        # *master* config, since this could e.g. be a io.StringIO file-like
        # object (`read_string`) which comes from no actual file/resource on
        # disk.
        if not fpname and hasattr(fp, 'name'):
            fpname = fp.name

        if fpath is None:
            try:
                resource = find_resource(fpname)
            except IOError:
                pass
            else:
                if isfile(resource):
                    fpath = abspath(expanduser(expandvars(fpname)))

        if fpath is None:
            try:
                resource = find_resource(fpname)
            except IOError:
                pass
            else:
                if isfile(resource):
                    fpath = resource

        if fpath is None:
            self.fpaths_processed = []
        else:
            self.fpaths_processed = [fpath]

        self.fps_processed = [fp]

        record = dict(fp=fp, fpname=fpname, fpath=fpath, lineno=0, line='')
        self._iter_stack.append(record)
        self.file_hierarchy = OrderedDict([(fpname, OrderedDict())])
Exemple #11
0
    def __init__(self, airs_spline, **std_kwargs):
        _airs_spline_loc = find_resource(airs_spline)
        self.airs_spline = photospline.SplineTable(_airs_spline_loc)

        expected_params = [
            "airs_scale",
        ]

        super().__init__(
            expected_params=expected_params,
            **std_kwargs,
        )
def normcheckpath(path, checkdir=False):
    normpath = find_resource(path)
    if checkdir:
        kind = 'dir'
        check = os.path.isdir
    else:
        kind = 'file'
        check = os.path.isfile

    if not check(normpath):
        raise IOError('Path "%s" which resolves to "%s" is not a %s.'
                      % (path, normpath, kind))
    return normpath
Exemple #13
0
    def __init__(
        self,
        in_files,
        lic_files,
        output_names,
        n_files: int,
        diff_nu_cc_xs="dsdxdy_nu_CC_iso.fits",
        diff_nubar_cc_xs="dsdxdy_nubar_CC_iso.fits",
        diff_nu_nc_xs="dsdxdy_nu_NC_iso.fits",
        diff_nubar_nc_xs="dsdxdy_nubar_NC_iso.fits",
        **std_kwargs
    ):

        if isinstance(lic_files, str):
            self._lic_files_paths = [
                find_resource(lic_files),
            ]
        elif isinstance(lic_files, (list, tuple)):
            self._lic_files_paths = [find_resource(lic_file) for lic_file in lic_files]
        else:
            raise TypeError("Unknown lic_file datatype {}".format(type(lic_files)))

        if isinstance(in_files, str):
            self.in_files = [
                find_resource(in_files),
            ]
        elif isinstance(in_files, (tuple, list)):
            self.in_files = [find_resource(in_file) for in_file in in_files]
        else:
            raise TypeError("Unknown in_files datatype {}".format(type(in_files)))

        # load the lic files!
        self.lic_files = [
            LW.MakeGeneratorsFromLICFile(name) for name in self._lic_files_paths
        ]
        self.xs_obj = LW.CrossSectionFromSpline(
            find_resource(diff_nu_cc_xs),
            find_resource(diff_nubar_cc_xs),
            find_resource(diff_nu_nc_xs),
            find_resource(diff_nubar_nc_xs),
        )

        # the target containers!
        self.output_names = output_names
        # with this, we just need to multiply the weight by the actual flux. Then it'll work!
        self._one_weighter = LW.Weighter(
            LW.ConstantFlux(1.0 / n_files), self.xs_obj, self.lic_files
        )
Exemple #14
0
    def _compute_nominal_outputs(self):
        '''
        load events, perform sanity check and put them into histograms,
        if alt_bg file is specified, also put these events into separate histograms,
        that are normalized to the nominal ones (we are only interested in the shape difference)
        '''
        # get params
        icc_bg_file = self.params.icc_bg_file.value
        if 'shape' in self.error_method:
            alt_icc_bg_file = self.params.alt_icc_bg_file.value
        else:
            alt_icc_bg_file = None
        sim_ver = self.params.sim_ver.value
        use_def1 = self.params.use_def1.value
        bdt_cut = self.params.bdt_cut.m_as('dimensionless')

        self.bin_names = self.output_binning.names
        self.bin_edges = []
        for name in self.bin_names:
            if 'energy' in  name:
                bin_edges = self.output_binning[name].bin_edges.to('GeV').magnitude
            else:
                bin_edges = self.output_binning[name].bin_edges.magnitude
            self.bin_edges.append(bin_edges)

        # the rest of this function is PISA v2 legacy code...
        logging.info('Initializing BackgroundServiceICC...')
        logging.info('Opening file: %s'%(icc_bg_file))

        try:
            bg_file = h5py.File(find_resource(icc_bg_file),'r')
            if alt_icc_bg_file is not None:
                alt_bg_file = h5py.File(find_resource(alt_icc_bg_file),'r')
        except IOError,e:
            logging.error("Unable to open icc_bg_file %s"%icc_bg_file)
            logging.error(e)
            sys.exit(1)
Exemple #15
0
    def setup_function(self):
        import ROOT
        # setup the layers
        earth_model = find_resource(self.earth_model)
        self.layers = Layers(earth_model, self.detector_depth,
                             self.prop_height)
        # This is a bit hacky, but setting the electron density to 1.
        # gives us the total density of matter, which is what we want.
        self.layers.setElecFrac(1., 1., 1.)

        # setup cross-sections
        self.xsroot = ROOT.TFile(self.xsec_file)
        # set the correct data mode
        self.data.data_specs = self.calc_specs

        # --- calculate the layers ---
        if self.calc_mode == 'binned':
            # layers don't care about flavor
            self.data.link_containers('nu', [
                'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc',
                'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc',
                'nuebar_nc', 'numubar_nc', 'nutaubar_nc'
            ])

        for container in self.data:
            self.layers.calcLayers(container['true_coszen'].get(WHERE))
            container['densities'] = self.layers.density.reshape(
                (container.size, self.layers.max_layers))
            container['distances'] = self.layers.distance.reshape(
                (container.size, self.layers.max_layers))
            container['rho_int'] = np.empty((container.size), dtype=FTYPE)
        # don't forget to un-link everything again
        self.data.unlink_containers()

        # --- setup cross section and survival probability ---
        if self.calc_mode == 'binned':
            # The cross-sections do not depend on nc/cc, so we can at least link those containers
            self.data.link_containers('nue', ['nue_cc', 'nue_nc'])
            self.data.link_containers('nuebar', ['nuebar_cc', 'nuebar_nc'])
            self.data.link_containers('numu', ['numu_cc', 'numu_nc'])
            self.data.link_containers('numubar', ['numubar_cc', 'numubar_nc'])
            self.data.link_containers('nutau', ['nutau_cc', 'nutau_nc'])
            self.data.link_containers('nutaubar',
                                      ['nutaubar_cc', 'nutaubar_nc'])
        for container in self.data:
            container['xsection'] = np.empty((container.size), dtype=FTYPE)
            container['survival_prob'] = np.empty((container.size),
                                                  dtype=FTYPE)
        self.data.unlink_containers()
Exemple #16
0
    def __init__(
        self,
        events_file,
        **std_kwargs,
    ):
        # instantiation args that should not change
        self.events_file = find_resource(events_file)

        expected_params = ('atm_muon_scale', )

        # init base class
        super().__init__(
            expected_params=expected_params,
            **std_kwargs,
        )
Exemple #17
0
    def setup_function(self):
        scale_file = find_resource(self.scale_file)
        logging.info("Loading scaling factors from : %s", scale_file)

        scaling_dict = from_json(scale_file)
        scale_binning = MultiDimBinning(
            **scaling_dict[self.variable]["binning"])

        scale_factors = np.array(scaling_dict[self.variable]["scales"],
                                 dtype=FTYPE)
        logging.info(f"Binning for ad-hoc systematic: \n {str(scale_binning)}")
        logging.info(
            f"scaling factors of ad-hoc systematic:\n {str(scale_factors)}")
        self.data.representation = scale_binning
        for container in self.data:
            container["adhoc_scale_factors"] = scale_factors
Exemple #18
0
    def setup_function(self):
        sys.path.append(self.globes_wrapper)
        import GLoBES
        ### you need to start GLoBES from the folder containing a dummy experiment
        # therefore we go to the folder, load GLoBES and then go back
        curdir = os.getcwd()
        os.chdir(self.globes_wrapper)
        self.globes_calc =  GLoBES.GLoBESCalculator("calc")
        os.chdir(curdir)
        self.globes_calc.InitSteriles(2)
        # object for oscillation parameters
        self.osc_params = OscParams()
        earth_model = find_resource(self.earth_model)
        prop_height = self.prop_height.m_as('km')
        detector_depth = self.detector_depth.m_as('km')
        self.layers = Layers(earth_model, detector_depth, prop_height)
        # The electron fractions are taken into account internally by GLoBES/SNU.
        # See the SNU patch for details. It uses the density to decide
        # whether it is in the core or in the mantle. Therefore, we just multiply by
        # one to give GLoBES the raw densities.
        self.layers.setElecFrac(1., 1., 1.)

        # set the correct data mode
        self.data.data_specs = self.calc_specs

        # --- calculate the layers ---
        if self.calc_mode == 'binned':
            # speed up calculation by adding links
            # as layers don't care about flavour
            self.data.link_containers('nu', ['nue_cc', 'numu_cc', 'nutau_cc',
                                             'nue_nc', 'numu_nc', 'nutau_nc',
                                             'nuebar_cc', 'numubar_cc', 'nutaubar_cc',
                                             'nuebar_nc', 'numubar_nc', 'nutaubar_nc'])

        for container in self.data:
            self.layers.calcLayers(container['true_coszen'].get('host'))
            container['densities'] = self.layers.density.reshape((container.size, self.layers.max_layers))
            container['distances'] = self.layers.distance.reshape((container.size, self.layers.max_layers))

        # don't forget to un-link everything again
        self.data.unlink_containers()

        # setup probability containers
        for container in self.data:
            container['prob_e'] = np.empty((container.size), dtype=FTYPE)
            container['prob_mu'] = np.empty((container.size), dtype=FTYPE)
            container['prob_nonsterile'] = np.empty((container.size), dtype=FTYPE)
Exemple #19
0
    def __init__(
        self,
        events_file,
        output_names,
        **std_kwargs,
    ):

        # instantiation args that should not change
        self.events_file = find_resource(events_file)

        # init base class
        super().__init__(
            expected_params=(),
            **std_kwargs,
        )

        self.output_names = output_names
Exemple #20
0
    def read(self, filenames, encoding=None):
        """Override `read` method to interpret `filenames` as PISA resource
        locations, then call overridden `read` method. Also, IOError fails
        here, whereas it is ignored in RawConfigParser.

        For further help on this method and its arguments, see
        :method:`~backports.configparser.configparser.read`

        """
        if isinstance(filenames, basestring):
            filenames = [filenames]
        resource_locations = []
        for filename in filenames:
            resource_location = find_resource(filename)
            if not isfile(resource_location):
                raise ValueError('"%s" is not a file or could not be located' %
                                 filename)
            resource_locations.append(resource_location)

        filenames = resource_locations

        # NOTE: From here on, most of the `read` method is copied, but
        # ignoring IOError exceptions is removed here. Python copyrights apply.

        if PY2 and isinstance(filenames, bytes):
            # we allow for a little unholy magic for Python 2 so that
            # people not using unicode_literals can still use the library
            # conveniently
            warnings.warn(
                "You passed a bytestring as `filenames`. This will not work"
                " on Python 3. Use `cp.read_file()` or switch to using Unicode"
                " strings across the board.",
                DeprecationWarning,
                stacklevel=2,
            )
            filenames = [filenames]
        elif isinstance(filenames, str):
            filenames = [filenames]
        read_ok = []
        for filename in filenames:
            with c_open(filename, encoding=encoding) as fp:
                self._read(fp, filename)
            read_ok.append(filename)
        return read_ok
Exemple #21
0
    def __init__(self, run_settings, detector=None):
        super().__init__()
        if isinstance(run_settings, str):
            rsd = fileio.from_file(resources.find_resource(run_settings))
        elif isinstance(run_settings, dict):
            rsd = run_settings
        else:
            raise TypeError('Unhandled run_settings type passed in arg: ' +
                            type(run_settings))

        if detector:
            detector = str(detector).strip()
        self.detector = detector

        # Determine how deeply nested runs are in the dict to allow for
        # user to specify a dict that has multiple detectors in it OR
        # a dict with just a single detector in it
        if 'flavints' in rsd.values()[0]:
            runs_d = rsd
        elif 'flavints' in rsd.values()[0].values()[0]:
            if self.detector is None:
                if len(rsd) == 1:
                    runs_d = rsd.values()[0]
                else:
                    raise ValueError('Must specify which detector; detectors '
                                     'found: ' + str(rsd.keys()))
            else:
                runs_d = rsd[self.detector.strip()]
        else:
            raise Exception('dict must either be 3 levels: '
                            '{DET:{RUN:{...}}}; or 2 levels: {RUN:{...}}')

        # Force run numbers to be strings (JSON files cannot have an int as
        # a key, so it is a string upon import, and it's safest to keep it as
        # a string considering how non-standardized naming is in IceCube) and
        # convert actual run settings dict to MCSimRunSettings instances
        runs_d = {str(k): MCSimRunSettings(v) for k, v in runs_d.items()}

        # Save the runs_d to this object instance, which behaves like a dict
        self.update(runs_d)
Exemple #22
0
    def __init__(self,
                 detector,
                 geom,
                 proc_ver,
                 pid_spec_ver=1,
                 pid_specs=None):
        geom = str(geom)
        proc_ver = str(proc_ver)
        pid_spec_ver = str(pid_spec_ver)

        if pid_specs is None:
            pid_specs = 'pid/pid_specifications.json'
        if isinstance(pid_specs, str):
            pid_specs = from_json(resources.find_resource(pid_specs))
        elif isinstance(pid_specs, collections.Mapping):
            pass
        else:
            raise TypeError('Unhandled `pid_specs` type: "%s"' %
                            type(data_proc_params))
        self.detector = detector
        self.proc_ver = proc_ver
        self.pid_spec_ver = str(pid_spec_ver)
        d = pid_specs
        all_k = []
        for wanted_key in [detector, geom, proc_ver, pid_spec_ver]:
            wanted_key = wanted_key.replace("'", "").lower()
            for orig_dict_key, subdict in d.items():
                dict_key = orig_dict_key.replace("'", "").lower()
                if (dict_key == wanted_key):
                    d = subdict
                    all_k.append(orig_dict_key)
        if len(all_k) != 4:
            raise ValueError('Could not find %s' %
                             str([detector, geom, proc_ver, pid_spec_ver]))
        self.pid_spec = pid_specs[all_k[0]][all_k[1]][all_k[2]][all_k[3]]

        # Enforce rules on PID spec:
        self.validatePIDSpec(self.pid_spec)
Exemple #23
0
    def load_events(self, events):
        """Load events from path given by `events`. Stored as `self.events`.

        Parameters
        ----------
        events : string or Events object
            If string, load events from that location. If Events object,
            deepcopy to obtain `self.events`

        """
        if isinstance(events, Param):
            events = events.value
        elif isinstance(events, basestring):
            events = find_resource(events)
        this_hash = hash_obj(events, full_hash=self.full_hash)
        if self._events_hash is not None and this_hash == self._events_hash:
            return
        logging.debug("Extracting events from Events obj or file: %s", events)
        events_obj = Events(events)
        events_hash = this_hash

        self.events = events_obj
        self._events_hash = events_hash
Exemple #24
0
    def _compute_nominal_outputs(self):
        '''
        load events, perform sanity check and put them into histograms,
        if alt_bg file is specified, also put these events into separate histograms,
        that are normalized to the nominal ones (we are only interested in the shape difference)
        '''
        # get params
        icc_bg_file = self.params.icc_bg_file.value
        if 'shape' in self.error_method:
            alt_icc_bg_file = self.params.alt_icc_bg_file.value
        else:
            alt_icc_bg_file = None
        sim_ver = self.params.sim_ver.value
        use_def1 = self.params.use_def1.value
        bdt_cut = self.params.bdt_cut.m_as('dimensionless')

        self.bin_names = self.output_binning.names
        self.bin_edges = []
        for name in self.bin_names:
            if 'energy' in name:
                bin_edges = self.output_binning[name].bin_edges.to(
                    'GeV').magnitude
            else:
                bin_edges = self.output_binning[name].bin_edges.magnitude
            self.bin_edges.append(bin_edges)

        # the rest of this function is PISA v2 legacy code...
        logging.info('Initializing BackgroundServiceICC...')
        logging.info('Opening file: %s', icc_bg_file)

        try:
            bg_file = h5py.File(find_resource(icc_bg_file), 'r')
            if alt_icc_bg_file is not None:
                alt_bg_file = h5py.File(find_resource(alt_icc_bg_file), 'r')
        except IOError as e:
            logging.error("Unable to open icc_bg_file %s", icc_bg_file)
            logging.error(e)
            sys.exit(1)

        # sanity check
        santa_doms = bg_file['IC86_Dunkman_L6_SANTA_DirectDOMs']['value']
        l3 = bg_file['IC86_Dunkman_L3']['value']
        l4 = bg_file['IC86_Dunkman_L4']['result']
        l5 = bg_file['IC86_Dunkman_L5']['bdt_score']
        l6 = bg_file['IC86_Dunkman_L6']
        if use_def1:
            l4_pass = np.all(l4 == 1)
        else:
            if sim_ver in ['5digit', 'dima']:
                l4_invVICH = bg_file['IC86_Dunkman_L4']['result_invertedVICH']
                l4_pass = np.all(np.logical_or(l4 == 1, l4_invVICH == 1))
            else:
                logging.info(
                    'For the old simulation, def.2 background not done yet,'
                    ' so still use def1 for it.')
                l4_pass = np.all(l4 == 1)
        assert (np.all(santa_doms >= 3) and np.all(l3 == 1) and l4_pass
                and np.all(l5 >= 0.1))
        corridor_doms_over_threshold = l6['corridor_doms_over_threshold']

        inverted_corridor_cut = corridor_doms_over_threshold > 1
        assert (np.all(inverted_corridor_cut)
                and np.all(l6['santa_direct_doms'] >= 3)
                and np.all(l6['mn_start_contained'] == 1.)
                and np.all(l6['mn_stop_contained'] == 1.))

        #load events
        if sim_ver == '4digit':
            variable = 'IC86_Dunkman_L6_MultiNest8D_PDG_Neutrino'
        elif sim_ver in ['5digit', 'dima']:
            variable = 'IC86_Dunkman_L6_PegLeg_MultiNest8D_NumuCC'
        else:
            raise ValueError('Only allow sim_ver  4digit, 5 digit or dima!')
        reco_energy_all = np.array(bg_file[variable]['energy'])
        reco_coszen_all = np.array(np.cos(bg_file[variable]['zenith']))
        pid_all = np.array(bg_file['IC86_Dunkman_L6']['delta_LLH'])
        if alt_icc_bg_file is not None:
            alt_reco_energy_all = np.array(alt_bg_file[variable]['energy'])
            alt_reco_coszen_all = np.array(
                np.cos(alt_bg_file[variable]['zenith']))
            alt_pid_all = np.array(alt_bg_file['IC86_Dunkman_L6']['delta_LLH'])
            alt_l5 = alt_bg_file['IC86_Dunkman_L5']['bdt_score']

        # Cut: Only keep bdt score >= 0.2 (from MSU latest result, make data/MC
        # agree much better)
        cut_events = {}
        cut = l5 >= bdt_cut
        cut_events['reco_energy'] = reco_energy_all[cut]
        cut_events['reco_coszen'] = reco_coszen_all[cut]
        cut_events['pid'] = pid_all[cut]

        if alt_icc_bg_file is not None:
            # Cut: Only keep bdt score >= 0.2 (from MSU latest result, make
            # data/MC agree much better)
            alt_cut_events = {}
            alt_cut = alt_l5 >= bdt_cut
            alt_cut_events['reco_energy'] = alt_reco_energy_all[alt_cut]
            alt_cut_events['reco_coszen'] = alt_reco_coszen_all[alt_cut]
            alt_cut_events['pid'] = alt_pid_all[alt_cut]

        logging.info("Creating a ICC background hists...")
        # make histo
        if self.params.kde_hist.value:
            self.icc_bg_hist = self.kde_histogramdd(
                np.array([cut_events[bin_name]
                          for bin_name in self.bin_names]).T,
                binning=self.output_binning,
                coszen_name='reco_coszen',
                use_cuda=True,
                bw_method='silverman',
                alpha=0.3,
                oversample=10,
                coszen_reflection=0.5,
                adaptive=True)
        else:
            self.icc_bg_hist, _ = np.histogramdd(sample=np.array(
                [cut_events[bin_name] for bin_name in self.bin_names]).T,
                                                 bins=self.bin_edges)

        conversion = self.params.atm_muon_scale.value.m_as(
            'dimensionless') / ureg('common_year').to('seconds').m
        logging.info('nominal ICC rate at %.6E Hz',
                     self.icc_bg_hist.sum() * conversion)

        if alt_icc_bg_file is not None:
            if self.params.kde_hist.value:
                self.alt_icc_bg_hist = self.kde_histogramdd(
                    np.array([
                        alt_cut_events[bin_name] for bin_name in self.bin_names
                    ]).T,
                    binning=self.output_binning,
                    coszen_name='reco_coszen',
                    use_cuda=True,
                    bw_method='silverman',
                    alpha=0.3,
                    oversample=10,
                    coszen_reflection=0.5,
                    adaptive=True)
            else:
                self.alt_icc_bg_hist, _ = np.histogramdd(sample=np.array([
                    alt_cut_events[bin_name] for bin_name in self.bin_names
                ]).T,
                                                         bins=self.bin_edges)
            # only interested in shape difference, not rate
            scale = self.icc_bg_hist.sum() / self.alt_icc_bg_hist.sum()
            self.alt_icc_bg_hist *= scale
Exemple #25
0
    def switch_to_file(self, fp=None, fpname=None):
        """Switch iterator to a new resource location to continue processing.

        Parameters
        ----------
        fp : None or file-like object
            If `fp` is specified, this takes precedence over `fpname`.

        fpname : None or string
            Path of the file or resource to read from. This resource will be
            located and opened if `fp` is None.

        encoding
            Argument is passed to the builtin ``open`` function for opening
            the file.

        """
        fpath = None
        if fp is None:
            assert fpname
            resource = find_resource(fpname)
            if isfile(resource):
                fpath = abspath(expanduser(expandvars(resource)))
                if fpath in self.fpaths_processed:
                    self._cleanup()
                    raise ValueError(
                        'Circular reference; already processed "%s" at path'
                        ' "%s"' % (fpname, fpath))
            else:
                self._cleanup()
                raise ValueError('`fpname` "%s" is not a file')
            fp_ = c_open(fpath, encoding=None)
        else:
            fp_ = fp
            if fpname is None:
                if hasattr(fp_, 'name'):
                    fpname = fp_.name
                else:
                    fpname = ''
            try:
                resource = find_resource(fpname)
            except IOError:
                pass
            else:
                if isfile(resource):
                    fpath = resource
            if fp in self.fps_processed:
                self._cleanup()
                raise ValueError(
                    'Circular reference; already processed file pointer "%s"'
                    ' at path "%s"' % (fp_, fpname))

        if fpath is not None:
            if fpath in self.fpaths_processed:
                self._cleanup()
                raise ValueError(
                    'Circular reference; already processed "%s" at path'
                    ' "%s"' % (fpname, fpath))
            self.fpaths_processed.append(fpath)

        self.fps_processed.append(fp)
        if fpath is not None:
            self.fpaths_processed.append(fpath)

        logging.trace('Switching to "%s" at path "%s"' % (fpname, fpath))

        record = dict(fp=fp_, fpname=fpname, fpath=fpath, lineno=0, line='')
        self._iter_stack.append(record)
Exemple #26
0
def make_toy_events(outdir, num_events, energy_range, spectral_index,
                    coszen_range, num_sets, first_set, aeff_energy_param,
                    aeff_coszen_param, reco_param, pid_param, pid_dist):
    """Make toy events and store to a file.

    Parameters
    ----------
    outdir : string
    num_events : int
    energy_range : 2-tuple of floats
    spectral_index : float
    coszen_range : 2-tuple of floats
    num_sets : int
    first_set : int
    aeff_energy_param : string
    aeff_coszen_param : string
    reco_param : string
    pid_param : string
    pid_dist : string

    Returns
    -------
    events : :class:`pisa.core.events.Events`

    """
    energy_range = sorted(energy_range)
    coszen_range = sorted(coszen_range)

    # Validation of args
    assert energy_range[0] > 0 and energy_range[1] < 1e9
    assert coszen_range[0] >= -1 and coszen_range[1] <= 1
    assert np.diff(energy_range)[0] > 0, str(energy_range)
    assert np.diff(coszen_range)[0] > 0, str(coszen_range)
    assert spectral_index >= 0, str(spectral_index)
    assert first_set >= 0, str(first_set)
    assert num_sets >= 1, str(first_set)

    # Make sure resources specified actually exist
    for arg in [aeff_energy_param, aeff_coszen_param, reco_param, pid_param]:
        find_resource(arg)

    mkdir(outdir, warn=False)

    set_indices = list(range(first_set, first_set + num_sets))

    # The following loop is for validation only
    for num, index in product(num_events, set_indices):
        mcgen_random_state(num_events=num, set_index=index)

    for num, set_index in product(num_events, set_indices):
        mcevts_fname = FNAME_TEMPLATE.format(
            file_type='events',
            detector='vlvnt',
            e_min=format_num(energy_range[0]),
            e_max=format_num(energy_range[1]),
            spectral_index=format_num(spectral_index,
                                      sigfigs=2,
                                      trailing_zeros=True),
            cz_min=format_num(coszen_range[0]),
            cz_max=format_num(coszen_range[1]),
            num_events=format_num(num, sigfigs=3, sci_thresh=(1, -1)),
            set_index=format_num(set_index, sci_thresh=(10, -10)),
            extension='hdf5')
        mcevts_fpath = os.path.join(outdir, mcevts_fname)
        if os.path.isfile(mcevts_fpath):
            logging.warn('File already exists, skipping: "%s"', mcevts_fpath)
            continue

        logging.info('Working on set "%s"', mcevts_fname)

        # TODO: pass filepaths / resource locations via command line args

        # Create a single random state object to pass from function to function
        random_state = mcgen_random_state(num_events=num, set_index=set_index)

        mc_events = generate_mc_events(
            num_events=num,
            energy_range=energy_range,
            coszen_range=coszen_range,
            spec_ind=spectral_index,
            aeff_energy_param_source=aeff_energy_param,
            aeff_coszen_param_source=aeff_coszen_param,
            random_state=random_state)
        populate_reco_observables(mc_events=mc_events,
                                  param_source=reco_param,
                                  random_state=random_state)
        populate_pid(mc_events=mc_events,
                     param_source=pid_param,
                     random_state=random_state,
                     dist=pid_dist)

        to_file(mc_events, mcevts_fpath)

        return mc_events
Exemple #27
0
    def _compute_nominal_outputs(self):
        """load the evnts from file, perform sanity checks and histogram them
        (into final MapSet)

        """
        # get params
        data_file_name = self.params.data_file.value
        sim_version = self.params.sim_ver.value
        bdt_cut = self.params.bdt_cut.value.m_as('dimensionless')

        self.bin_names = self.output_binning.names

        # TODO: convert units using e.g. `comp_units` in stages/reco/hist.py
        self.bin_edges = []
        for name in self.bin_names:
            if 'energy' in  name:
                bin_edges = self.output_binning[name].bin_edges.to('GeV').magnitude
            else:
                bin_edges = self.output_binning[name].bin_edges.magnitude
            self.bin_edges.append(bin_edges)

        # the rest of this function is PISA v2 legacy code...
        # right now only use burn sample with sim_version = '4digit'
        #print "sim_version == ", sim_version
        if sim_version == "4digit":
            Reco_Neutrino_Name = 'IC86_Dunkman_L6_MultiNest8D_PDG_Neutrino'
            Reco_Track_Name = 'IC86_Dunkman_L6_MultiNest8D_PDG_Track'
        elif sim_version == "5digit" or sim_version=="dima":
            Reco_Neutrino_Name = 'IC86_Dunkman_L6_PegLeg_MultiNest8D_NumuCC'
            Reco_Track_Name = 'IC86_Dunkman_L6_PegLeg_MultiNest8D_Track'
        else:
            raise ValueError(
                'only allow 4digit, 5digit(H2 model for hole ice) or'
                ' dima (dima p1 and p2 for hole ice)!'
            )

        data_file = h5py.File(find_resource(data_file_name), 'r')
        L6_result = np.array(data_file['IC86_Dunkman_L6']['result'])
        dLLH = np.array(data_file['IC86_Dunkman_L6']['delta_LLH'])
        reco_energy_all = np.array(data_file[Reco_Neutrino_Name]['energy'])
        reco_coszen_all = np.array(np.cos(
            data_file[Reco_Neutrino_Name]['zenith']
        ))
        reco_trck_len_all = np.array(data_file[Reco_Track_Name]['length'])
        #print "before L6 cut, no. of burn sample = ", len(reco_coszen_all)

        # sanity check
        santa_doms = data_file['IC86_Dunkman_L6_SANTA_DirectDOMs']['value']
        l3 = data_file['IC86_Dunkman_L3']['value']
        l4 = data_file['IC86_Dunkman_L4']['result']
        l5 = data_file['IC86_Dunkman_L5']['bdt_score']
        assert(np.all(santa_doms>=3) and np.all(l3 == 1) and np.all(l5 >= 0.1))

        # l4==1 was not applied when i3 files were written to hdf5 files, so do
        # it here
        dLLH = dLLH[l4==1]
        reco_energy_all = reco_energy_all[l4==1]
        reco_coszen_all = reco_coszen_all[l4==1]
        l5 = l5[l4==1]
        L6_result = L6_result[l4==1]
        data_file.close()

        dLLH_L6 = dLLH[L6_result==1]
        l5 = l5[L6_result==1]
        reco_energy_L6 = reco_energy_all[L6_result==1]
        reco_coszen_L6 = reco_coszen_all[L6_result==1]
        #print "after L6 cut, no. of burn sample = ", len(reco_coszen_L6)

        # Cut: Only keep bdt score >= 0.2 (from MSU latest result, make data/MC
        # agree much better); if use no such further cut, use bdt_cut = 0.1
        logging.info(
            "Cut2, removing events with bdt_score < %s i.e. only keep bdt > %s"
            %(bdt_cut, bdt_cut)
        )
        cut_events = {}
        cut = l5>=bdt_cut
        cut_events['reco_energy'] = reco_energy_L6[cut]
        cut_events['reco_coszen'] = reco_coszen_L6[cut]
        cut_events['pid'] = dLLH_L6[cut]

        hist, _ = np.histogramdd(sample = np.array(
            [cut_events[bin_name] for bin_name in self.bin_names]
        ).T, bins=self.bin_edges)

        maps = [Map(name=self.output_names[0], hist=hist,
                    binning=self.output_binning)]
        self.template = MapSet(maps, name='data')
Exemple #28
0
def test_CrossSections(outdir=None):
    """Unit tests for CrossSections class"""
    from shutil import rmtree
    from tempfile import mkdtemp

    remove_dir = False
    if outdir is None:
        remove_dir = True
        outdir = mkdtemp()

    try:
        # "Standard" location of cross sections file in PISA; retrieve 2.6.4 for
        # testing purposes
        pisa_xs_file = 'cross_sections/cross_sections.json'
        xs = CrossSections(ver='genie_2.6.4', xsec=pisa_xs_file)

        # Location of the root file to use (not included in PISA at the moment)
        test_dir = expand(os.path.join('/tmp', 'pisa_tests', 'cross_sections'))
        #root_xs_file = os.path.join(test_dir, 'genie_2.6.4_simplified.root')
        root_xs_file = find_resource(os.path.join(
            #'tests', 'data', 'xsec', 'genie_2.6.4_simplified.root'
            'cross_sections', 'genie_xsec_H2O.root'
        ))

        # Make sure that the XS newly-imported from ROOT match those stored in
        # PISA
        if os.path.isfile(root_xs_file):
            xs_from_root = CrossSections.new_from_root(root_xs_file,
                                                       ver='genie_2.6.4')
            logging.info('Found and loaded ROOT source cross sections file %s',
                         root_xs_file)
            #assert xs_from_root.allclose(xs, rtol=1e-7)

        # Check XS ratio for numu_cc to numu_cc + numu_nc (user must inspect)
        kg0 = NuFlavIntGroup('numu_cc')
        kg1 = NuFlavIntGroup('numu_nc')
        logging.info(
            r'\int_1^80 xs(numu_cc) E^{-1} dE = %e',
            xs.get_xs_ratio_integral(kg0, None, e_range=[1, 80], gamma=1)
        )
        logging.info(
            '(int E^{-gamma} * (sigma_numu_cc)/int(sigma_(numu_cc+numu_nc)) dE)'
            ' / (int E^{-gamma} dE) = %e',
            xs.get_xs_ratio_integral(kg0, kg0+kg1, e_range=[1, 80], gamma=1,
                                     average=True)
        )
        # Check that XS ratio for numu_cc+numu_nc to the same is 1.0
        int_val = xs.get_xs_ratio_integral(kg0+kg1, kg0+kg1, e_range=[1, 80],
                                           gamma=1, average=True)
        if not recursiveEquality(int_val, 1):
            raise ValueError('Integral of nc + cc should be 1.0; get %e'
                             ' instead.' % int_val)

        # Check via plot that the

        # Plot all cross sections stored in PISA xs file
        try:
            alldata = from_file(pisa_xs_file)
            xs_versions = alldata.keys()
            for ver in xs_versions:
                xs = CrossSections(ver=ver, xsec=pisa_xs_file)
                xs.plot(save=os.path.join(
                    outdir, 'pisa_' + ver + '_nuxCCNC_H2O_cross_sections.pdf'
                ))
        except ImportError as exc:
            logging.debug('Could not plot; possible that matplotlib not'
                          'installed. ImportError: %s', exc)

    finally:
        if remove_dir:
            rmtree(outdir)
Exemple #29
0
def main():
    """Do the conversion."""
    args = parse_args()
    in_fpath = os.path.expanduser(os.path.expandvars(args.config[0]))
    out_fpath = in_fpath + '.new'

    with open(in_fpath, 'r') as infile:
        orig_contents = infile.readlines()

    osc_stage_header_line = None
    section_names_with_colons = {}
    new_contents = []
    for lineno, orig_line in enumerate(orig_contents, start=1):
        # Remove trailing whitespace, including newline character(s)
        new_line = orig_line.rstrip()

        # Empty (or whitespace-only) line is trivial
        if new_line == '':
            new_contents.append(new_line)
            continue

        # Replace text substitution ("config file variables") syntax
        new_line = OLD_SUB_RE.sub(repl=replace_substitution, string=new_line)

        # Replace stage headers. E.g.
        #     ``  [ stage :stage_name ]``
        # is replaced by
        #     ``  [stage.stage_name]``
        # I.e. retain any whitespace before (and after... though this is
        # already removed) the brackets but swap colon for period and remove
        # whitespace within the brackets.
        new_line = OLD_STAGE_SECTION_RE.sub(
            repl=lambda m: '[stage.%s]' % m.groups(), string=new_line)

        # Replace stage:key variables. E.g. what should now look like
        #     ``  ${ stage : key }  ``
        # should look like
        #     ``  ${stage.key}  ``
        new_line = OLD_STAGE_VARIABLE_RE.sub(
            repl=lambda m: '${stage.%s}' % m.groups(), string=new_line)

        stripped = new_line.strip()

        # Replace order string
        if stripped.startswith('order'):
            new_line = OLD_ORDER_RE.sub(repl=replace_order, string=new_line)
        # Record line on which the [stage.osc] section occurs (if any)
        elif stripped == '[stage.osc]':
            osc_stage_header_line = lineno - 1

        # Convert ``#include x`` to ``#include x as y``, where appropriate
        new_line = PISAConfigParser.INCLUDE_RE.sub(repl=append_include_as,
                                                   string=new_line)

        # Convert JSON filenames to .json.bz2 that are now bzipped
        if '.json' in new_line:
            for json_re in JSON_NO_BZ2_RE_LIST:
                new_line = json_re.sub(repl='.json.bz2', string=new_line)

        # Replace changed names
        for orig_name, new_name in NAMES_CHANGED_MAP.items():
            new_line = new_line.replace(orig_name, new_name)

        # Search for any colons used in section names. This is illegal, as a
        # section name can be used as a variable where the syntax is
        #   ``${section_name:key}``
        # so any colons in section_name will make the parser choke.
        for match in SECTION_NAME_WITH_COLON_RE.finditer(new_line):
            section_name_with_colons = match.groups()[0]
            if NEW_VARIABLE_RE.match(section_name_with_colons):
                if section_name_with_colons.count(':') > 1:
                    raise ValueError(
                        'Multiple colons in new-style variable, line %d:\n'
                        '>> Original line:\n%s\n>> New line:\n%s\n' %
                        (lineno, orig_line, new_line))
                else:
                    continue
            section_name_without_colons = section_name_with_colons.replace(
                ':', OTHER_SECTION_NAME_SEPARATOR)
            section_names_with_colons[section_name_with_colons] = (
                section_name_without_colons)

        new_contents.append(new_line)

    #for item in  section_names_with_colons.items():
    #    print '%s --> %s' % item

    # Go back through and replace colon-sparated section names with
    # ``OTHER_SECTION_NAME_SEPARATOR``-separated section names
    all_names_to_replace = section_names_with_colons.keys()

    def replace_var(match):
        """Closure to replace variable names"""
        whole_string, var_name = match.groups()
        if var_name in all_names_to_replace:
            return '${%s}' % section_names_with_colons[var_name]
        return whole_string

    def replace_section_name(match):
        """Closure to replace section names"""
        whole_string, section_name = match.groups()
        if section_name in all_names_to_replace:
            return whole_string.replace(
                section_name, section_names_with_colons[section_name])
        return whole_string

    for lineno, new_line in enumerate(new_contents, start=1):
        if not new_line:
            continue

        new_line = NEW_VARIABLE_RE.sub(repl=replace_var, string=new_line)
        new_line = NEW_SECTION_RE.sub(repl=replace_section_name,
                                      string=new_line)

        #new_line = NEW_SECTION_RE.sub(repl=replace_colon_names,
        #                              string=new_line)

        #for with_colons, without_colons in section_names_with_colons:
        #    new_line = new_line.replace(with_colons, without_colons)

        # Check for multiple colons in a variable (which is illegal)
        if MULTI_COLON_VAR_RE.findall(new_line):
            raise ValueError(
                'Multiple colons in variable, line %d:\n>> Original'
                ' line:\n%s\n>> New line:\n%s\n' %
                (lineno, orig_contents[lineno - 1], new_line))

        new_contents[lineno - 1] = new_line

    # Parse the new config file with the PISAConfigParser to see if NSI
    # parameters are defined in the `stage.osc` section (if the latter is
    # present). If needed, insert appropriate #include in the section
    pcp = PISAConfigParser()
    missing_section_header = False
    try:
        pcp.read_string(('\n'.join(new_contents) + '\n').decode('utf-8'))
    except MissingSectionHeaderError:
        missing_section_header = True
        pcp.read_string(('\n'.join(['[dummy section header]'] + new_contents) +
                         '\n').decode('utf-8'))

    if 'stage.osc' in pcp:
        keys_containing_eps = [
            k for k in pcp['stage.osc'].keys() if '.eps_'.encode('utf-8') in k
        ]

        nsi_params_present = []
        nsi_params_missing = []
        for nsi_param, nsi_param_re in NSI_PARAM_RE_MAP.items():
            found = None
            for key_idx, key in enumerate(keys_containing_eps):
                if nsi_param_re.match(key):
                    found = key_idx
                    nsi_params_present.append(nsi_param)

            if found is None:
                nsi_params_missing.append(nsi_param)
            else:
                # No need to search this key again
                keys_containing_eps.pop(found)

        if set(nsi_params_present) == set(NSI_PARAM_RE_MAP.keys()):
            all_nsi_params_defined = True
        elif set(nsi_params_missing) == set(NSI_PARAM_RE_MAP.keys()):
            all_nsi_params_defined = False
        else:
            raise ValueError(
                'Found a subset of NSI params defined; missing %s' %
                str(nsi_params_missing))

        # NOTE: since for now the contents of nsi_null.cfg are commented out
        # (until merging NSI branch), the above check will say NSI params are
        # missing if the #include statement was made. So check to see if
        # settings/osc/nsi_null.cfg _has_ been included (we can't tell what
        # section it is in, but we'll have to just accept that).
        #
        # We will probably want to remove this stanza as soon as NSI brnach is
        # merged, since this is imprecise and can introduce other weird corner
        # cases.
        rsrc_loc = find_resource('settings/osc/nsi_null.cfg')
        for file_iter in pcp.file_iterators:
            if rsrc_loc in file_iter.fpaths_processed:
                all_nsi_params_defined = True

        if not all_nsi_params_defined and osc_stage_header_line is None:
            raise ValueError(
                "Found a stage.osc section without NSI params defined (using"
                " PISAConfigParser) but could not find the line of the"
                " `[stage.osc]` header. This could occur if `[stage.osc]` came"
                " from an `#include`'d file. You can manually define the NSI"
                " parameters in this file or in the included file e.g. as"
                " found in `settings/osc/nsi_null.cfg` or simply add the"
                " statement ``#include settings/osc/nsi_null.cfg`` to either"
                " file (so long as that statement it falls within the"
                " stage.osc section).")

        # Add ``#include settings/osc/nsi_null.cfg`` at top of stage.osc
        # section if a stage.osc section is present and no NSI params were
        # specified in that section
        if not all_nsi_params_defined:
            # Add an #include to set all NSI parameters to 0
            new_contents.insert(osc_stage_header_line + 1,
                                '#include settings/osc/nsi_null.cfg')
            # Add an extra blank line after the #include line
            new_contents.insert(osc_stage_header_line + 2, '')

    if not new_contents:
        raise ValueError('Empty file after conversion; quitting.')

    # Note that newlines are added but no join is performed for comparison
    # against `orig_contents`
    new_contents = [line + '\n' for line in new_contents]

    # Now for validation, try to parse the new config file with the
    # PISAConfigParser
    pcp = PISAConfigParser()
    if missing_section_header:
        pcp.read_string((''.join(['[dummy section header]\n'] + new_contents) +
                         '\n').decode('utf-8'))
    else:
        pcp.read_string((''.join(new_contents)).decode('utf-8'))

    if new_contents == orig_contents:
        sys.stdout.write('Nothing modified in the original file (ok!).\n')
        return

    if args.validate_only:
        raise ValueError(
            'Original config file "%s" would be modfied (and so may be'
            ' invalid). Re-run this script without the --validate-only flag to'
            ' produce an appropriately-converted config file.' %
            args.config[0])

    sys.stdout.write('Writing modified config file to "%s"\n' % out_fpath)
    with open(out_fpath, 'w') as outfile:
        outfile.writelines(new_contents)
Exemple #30
0
    def __init__(self, detector, proc_ver, data_proc_params=None):
        super().__init__()
        if data_proc_params is None:
            data_proc_params = 'events/data_proc_params.json'
        if isinstance(data_proc_params, str):
            ps = jsons.from_json(resources.find_resource(data_proc_params))
        elif isinstance(data_proc_params, dict):
            ps = data_proc_params
        else:
            raise TypeError('Unhandled data_proc_params type passed in arg: ' +
                            type(data_proc_params))
        self.detector = detector
        self.proc_ver = str(proc_ver)
        self.det_key = [k for k in ps.keys()
                        if k.lower() == self.detector.lower()][0]
        for key in ps[self.det_key].keys():
            lk = key.lower()
            lpv = self.proc_ver.lower()
            if lk == lpv or ('v'+lk == lpv) or (lk == 'v'+lpv):
                self.procver_key = key
                # This works for PINGU
            elif ('msu_'+lk == lpv) or (lk == 'msu_'+lpv):
                self.procver_key = key
            elif ('nbi_'+lk == lpv) or (lk == 'nbi_'+lpv):
                self.procver_key = key
                # Generalising for DeepCore and different selections
        ps = ps[self.det_key][self.procver_key]
        self.update(ps)

        self.trans_nu_code = False
        if 'nu_code_to_pdg_map' in self:
            self.trans_nu_code = True
            try:
                self.nu_code_to_pdg_map = {
                    int(code): pdg
                    for code, pdg in self['nu_code_to_pdg_map'].items()
                }
            except:
                self.nu_code_to_pdg_map = self['nu_code_to_pdg_map']

        # NOTE: the keys are strings so the particular string formatting is
        # important for indexing into the dict!

        # Add generic cuts
        self['cuts'].update({
            # Cut for particles only (no anti-particles)
            str(NuFlav(12).bar_code).lower():
                {'fields': ['nu_code'], 'pass_if': 'nu_code > 0'},
            # Cut for anti-particles only (no particles)
            str(NuFlav(-12).bar_code).lower():
                {'fields': ['nu_code'], 'pass_if': 'nu_code < 0'},
            # Cut for charged-current interactions only
            str(IntType('cc')).lower():
                {'fields': ['interaction_type'],
                 'pass_if': 'interaction_type == 1'},
            # Cut for neutral-current interactions only
            str(IntType('nc')).lower():
                {'fields': ['interaction_type'],
                 'pass_if': 'interaction_type == 2'},
            # True-upgoing cut usinng the zenith field
            'true_upgoing_zen':
                {'fields': ['true_zenith'], 'pass_if': 'true_zenith > pi/2'},
            # True-upgoing cut usinng the cosine-zenith field
            'true_upgoing_coszen':
                {'fields': ['true_coszen'], 'pass_if': 'true_coszen < 0'},
        })

        # Enforce rules on cuts:
        self.validate_cut_spec(self['cuts'])