Esempio n. 1
0
def main(return_outputs=False):
    """Main; call as script with `return_outputs=False` or interactively with
    `return_outputs=True`"""
    from pisa.utils.plotter import Plotter
    args = parse_args()
    set_verbosity(args.v)
    plot_formats = []
    if args.pdf:
        plot_formats.append('pdf')
    if args.png:
        plot_formats.append('png')

    distribution_maker = DistributionMaker(pipelines=args.pipeline)  # pylint: disable=redefined-outer-name
    if args.select is not None:
        distribution_maker.select_params(args.select)

    outputs = distribution_maker.get_outputs(return_sum=args.return_sum)  # pylint: disable=redefined-outer-name
    if args.outdir:
        # TODO: unique filename: append hash (or hash per pipeline config)
        fname = 'distribution_maker_outputs.json.bz2'
        mkdir(args.outdir)
        fpath = expand(os.path.join(args.outdir, fname))
        to_file(outputs, fpath)

    if args.outdir and plot_formats:
        my_plotter = Plotter(outdir=args.outdir,
                             fmt=plot_formats,
                             log=False,
                             annotate=False)
        for num, output in enumerate(outputs):
            my_plotter.plot_2d_array(output, fname='dist_output_%d' % num)

    if return_outputs:
        return distribution_maker, outputs
Esempio n. 2
0
def test_parse_pipeline_config():
    """Unit test for function `parse_pipeline_config`"""
    from argparse import ArgumentParser

    parser = ArgumentParser()
    parser.add_argument('-p',
                        '--pipeline',
                        metavar='CONFIGFILE',
                        default='settings/pipeline/example.cfg',
                        help='File containing settings for the pipeline.')
    parser.add_argument(
        '-v',
        action='count',
        default=0,
        help='Set verbosity level. Minimum is forced to level 1 (info)')
    args = parser.parse_args()
    args.v = max(1, args.v)
    set_verbosity(args.v)

    # Load via PISAConfigParser
    config0 = PISAConfigParser()
    config0.read(args.pipeline)
    _ = parse_pipeline_config(config0)

    # Load directly
    config = parse_pipeline_config(args.pipeline)

    logging.debug('Keys and values found in config:')
    for key, vals in config.items():
        logging.debug('%s: %s', key, vals)

    logging.info('<< PASS : test_parse_pipeline_config >>')
Esempio n. 3
0
def main(description=__doc__):
    """Script interface for `test_prob3numba` function"""
    parser = ArgumentParser(description=description)
    parser.add_argument("--ignore-fails", action="store_true")
    parser.add_argument("--define-as-ref", action="store_true")
    parser.add_argument("-v", action="count", default=Levels.WARN)
    kwargs = vars(parser.parse_args())
    set_verbosity(kwargs.pop("v"))
    test_prob3numba(**kwargs)
Esempio n. 4
0
def test_kde_bootstrapping(verbosity=Levels.WARN):
    """Unit test for the kde stage."""

    set_verbosity(verbosity)

    example_cfg = parse_pipeline_config("settings/pipeline/example.cfg")

    # We have to remove containers with too few events, otherwise the KDE fails simply
    # because too few distinct events are in one of the PID channels after bootstrapping.
    example_cfg[("data", "simple_data_loader")]["output_names"] = [
        "numu_cc",
        "numubar_cc",
    ]

    kde_stage_cfg = OrderedDict()
    kde_stage_cfg["apply_mode"] = example_cfg[("utils", "hist")]["apply_mode"]
    kde_stage_cfg["calc_mode"] = "events"
    kde_stage_cfg["bootstrap"] = False
    kde_stage_cfg["bootstrap_seed"] = 0
    kde_stage_cfg["bootstrap_niter"] = 5

    kde_pipe_cfg = deepcopy(example_cfg)

    # Replace histogram stage with KDE stage
    del kde_pipe_cfg[("utils", "hist")]
    kde_pipe_cfg[("utils", "kde")] = kde_stage_cfg

    # no errors in baseline since there is no bootstrapping enabled
    kde_pipe_cfg["pipeline"]["output_key"] = "weights"

    # get a baseline
    dmaker = DistributionMaker([kde_pipe_cfg])
    map_baseline = dmaker.get_outputs(return_sum=True)[0]
    logging.debug(f"Baseline KDE'd map:\n{map_baseline}")

    # Make sure that different seeds produce different maps, and that the same seed will
    # produce the same map.
    # We enable bootstrapping now, without re-loading everything, to save time.
    dmaker.pipelines[0].output_key = ("weights", "errors")
    dmaker.pipelines[0].stages[-1].bootstrap = True

    map_seed0 = dmaker.get_outputs(return_sum=True)[0]
    dmaker.pipelines[0].stages[-1].bootstrap_seed = 1
    map_seed1 = dmaker.get_outputs(return_sum=True)[0]

    logging.debug(f"Map with seed 0 is:\n{map_seed0}")
    logging.debug(f"Map with seed 1 is:\n{map_seed1}")

    assert not map_seed0 == map_seed1

    dmaker.pipelines[0].stages[-1].bootstrap_seed = 0
    map_seed0_reprod = dmaker.get_outputs(return_sum=True)[0]

    assert map_seed0 == map_seed0_reprod

    logging.info("<< PASS : kde_bootstrapping >>")
Esempio n. 5
0
def test_kde_bootstrapping(verbosity=Levels.WARN):
    """Unit test for the kde stage."""

    set_verbosity(verbosity)

    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)

    # get map, but without the linearization
    test_cfg[("utils", "kde")]["linearize_log_dims"] = False
    dmaker = DistributionMaker([test_cfg])
    map_baseline_no_linearization = dmaker.get_outputs(return_sum=True)[0]

    # get a baseline (with linearization, which we will use from here on out)
    test_cfg[("utils", "kde")]["linearize_log_dims"] = True
    dmaker = DistributionMaker([test_cfg])
    map_baseline = dmaker.get_outputs(return_sum=True)[0]
    logging.debug(f"Baseline KDE'd map:\n{map_baseline}")

    # assert that linearization make a difference at all
    total_no_lin = np.sum(map_baseline_no_linearization.nominal_values)
    total_with_lin = np.sum(map_baseline.nominal_values)
    assert not (total_no_lin == total_with_lin)
    # but also that the difference isn't huge (< 5% difference in total bin count)
    # --> This will fail if one forgets to *not* take the log when linearization
    #     is turned off, for example. In that case, most bins will be empty, because
    #     the binning would be lin while the KDE would be log.
    assert np.abs(total_no_lin / total_with_lin - 1.0) < 0.05
    # Make sure that different seeds produce different maps, and that the same seed will
    # produce the same map.
    # We enable bootstrapping now, without re-loading everything, to save time.
    dmaker.pipelines[0].output_key = ("weights", "errors")
    dmaker.pipelines[0].stages[-1].bootstrap = True

    map_seed0 = dmaker.get_outputs(return_sum=True)[0]
    dmaker.pipelines[0].stages[-1].bootstrap_seed = 1
    map_seed1 = dmaker.get_outputs(return_sum=True)[0]

    logging.debug(f"Map with seed 0 is:\n{map_seed0}")
    logging.debug(f"Map with seed 1 is:\n{map_seed1}")

    assert not map_seed0 == map_seed1

    dmaker.pipelines[0].stages[-1].bootstrap_seed = 0
    map_seed0_reprod = dmaker.get_outputs(return_sum=True)[0]

    assert map_seed0 == map_seed0_reprod

    logging.info("<< PASS : kde_bootstrapping >>")
Esempio n. 6
0
def main():
    """Run `add_fluxes_to_file` function with arguments from command line"""
    args = parse_args()
    set_verbosity(args.v)

    flux_table = load_2d_table(args.flux_file)
    flux_file_bname, ext = splitext(basename(args.flux_file))

    input_paths = []
    for input_path in args.input:
        if isdir(input_path):
            for filename in listdir(input_path):
                filepath = join(input_path, filename)
                input_paths.append(filepath)

        else:
            input_paths += glob.glob(input_path)

    input_paths = nsort(input_paths)

    paths_to_process = []
    basenames = []
    for input_path in input_paths:
        if isdir(input_path):
            logging.debug('Path "%s" is a directory, skipping', input_path)
            continue

        firstpart, ext = splitext(input_path)
        if ext.lstrip('.') not in HDF5_EXTS:
            logging.debug('Path "%s" is not an HDF5 file, skipping',
                          input_path)
            continue

        bname = basename(firstpart)
        if bname in basenames:
            raise ValueError(
                'Found files with duplicate basename "%s" (despite files'
                ' having different paths); resolve the ambiguous names and'
                ' re-run. Offending files are:\n  "%s"\n  "%s"' %
                (bname, paths_to_process[basenames.index(bname)], input_path))

        basenames.append(bname)
        paths_to_process.append(input_path)

    logging.info('Will process %d input file(s)...', len(paths_to_process))

    for filepath in paths_to_process:
        logging.info('Working on input file "%s"', filepath)
        add_fluxes_to_file(data_file_path=filepath,
                           flux_table=flux_table,
                           flux_name='nominal',
                           outdir=args.outdir,
                           label=flux_file_bname)
Esempio n. 7
0
def main():
    """Perform a hyperplane fit to discrete systematics sets."""
    args = parse_args()
    set_verbosity(args.v)

    # Read in data and fit hyperplanes to it
    input_data, fit_results = hyperplane(fit_cfg=args.fit_cfg)

    # Save to disk
    save_hyperplane_fits(input_data=input_data,
                         fit_results=fit_results,
                         outdir=args.outdir,
                         tag=args.tag)
Esempio n. 8
0
def main(return_outputs=False):
    """Main; call as script with `return_outputs=False` or interactively with
    `return_outputs=True`"""
    from pisa.utils.plotter import Plotter
    args = parse_args()
    set_verbosity(args.v)
    plot_formats = []
    if args.pdf:
        plot_formats.append('pdf')
    if args.png:
        plot_formats.append('png')
        
    detectors = Detectors(args.pipeline,shared_params=args.shared_params)
    Names = detectors.det_names
    if args.select is not None:
        detectors.select_params(args.select)

    outputs = detectors.get_outputs(return_sum=args.return_sum)

    #outputs = outputs[0].fluctuate(
     #               method='poisson', random_state=get_random_state([0, 0, 0]))

    if args.outdir:
        # TODO: unique filename: append hash (or hash per pipeline config)
        fname = 'detectors_outputs.json.bz2'
        mkdir(args.outdir)
        fpath = expand(os.path.join(args.outdir, fname))
        to_file(outputs, fpath)

    if args.outdir and plot_formats:
        my_plotter = Plotter(
            outdir=args.outdir,
            fmt=plot_formats, log=False,
            annotate=False
        )
        for num, output in enumerate(outputs):
            if args.return_sum:
                my_plotter.plot_2d_array(
                    output,
                    fname=Names[num]
                )
            else:
                for out in output:
                    my_plotter.plot_2d_array(
                        out,
                        fname=Names[num]
                    )

    if return_outputs:
        return detectors, outputs
Esempio n. 9
0
def main():
    """Perform a hypersurface fit to discrete systematics sets."""

    # Get args
    args = parse_args()
    set_verbosity(args.v)

    # Read in data and fit hypersurfaces to it
    hypersurfaces = create_hypersurfaces(fit_cfg=args.fit_cfg)

    # Store as JSON
    mkdir(args.outdir)
    arbitrary_hypersurface = list(hypersurfaces.values())[0]
    output_path = join( args.outdir, get_hypersurface_file_name(arbitrary_hypersurface, args.tag) )
    to_file(hypersurfaces, output_path)
Esempio n. 10
0
def main():
    """Script function to run tests on a cross section file"""
    from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
    set_verbosity(3)

    parser = ArgumentParser(description='Test genie xsec service',
                            formatter_class=ArgumentDefaultsHelpFormatter)
    parser.add_argument('-x', '--xsec_file', type=str, required=True,
                        help='Input GENIE ROOT cross-section file')
    parser.add_argument('-o', '--outdir', type=str, default='./',
                        help='Output directory for plots')
    args = parser.parse_args()

    # TODO(shivesh): tests
    # test_XSec(args.xsec_file)
    test_standard_plots(args.xsec_file, args.outdir+'/standard/')
    test_per_e_plot(args.xsec_file, args.outdir+'/per_e/')
Esempio n. 11
0
def parse_args():
    """Parse command line arguments"""
    parser = ArgumentParser(
        description='Print contents of a parsed config file',
        formatter_class=ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        'pipeline', metavar='CONFIGFILE',
        nargs='?',
        default='settings/pipeline/example.cfg',
        help='Pipeline config file to parse',
    )
    parser.add_argument(
        '-v',
        action='count',
        default=Levels.WARN,
        help='Set verbosity level',
    )
    kwargs = vars(parser.parse_args())
    set_verbosity(kwargs.pop('v'))
    return kwargs
Esempio n. 12
0
def main():
    args = parse_args()
    set_verbosity(args.verbose)

    assert len(args.infiles[0]) == 2
    assert len(args.subtitles) == 2
    logging.info('Loading MapSet from files {0}'.format(args.infiles[0]))
    o_mapset = MapSet.from_json(args.infiles[0][0])
    t_mapset = MapSet.from_json(args.infiles[0][1])
    assert len(o_mapset) == 1 and len(t_mapset) == 1
    o_map = o_mapset.pop()
    t_map = t_mapset.pop()

    outfile = args.outdir + '/' + args.outname
    make_plot(
        maps=(o_map, t_map),
        outfile=outfile,
        logv=args.logv,
        center_zero=args.center_zero,
        vlabel=args.vlabel,
        title=args.title,
        sub_titles=args.subtitles,
    )
Esempio n. 13
0
            mVac[0] -= delta
        if mVac[2] == 0.:
            mVac[2] += delta

        dmVacVac[0, 0] = 0.
        dmVacVac[1, 1] = 0.
        dmVacVac[2, 2] = 0.
        dmVacVac[0, 1] = mVac[0] - mVac[1]
        dmVacVac[1, 0] = -dmVacVac[0, 1]
        dmVacVac[0, 2] = mVac[0] - mVac[2]
        dmVacVac[2, 0] = -dmVacVac[0, 2]
        dmVacVac[1, 2] = mVac[1] - mVac[2]
        dmVacVac[2, 1] = -dmVacVac[1, 2]

        return dmVacVac


def test_pi_osc_params():
    """
    # TODO: implement me!
    """
    pass


if __name__ == '__main__':
    from pisa import TARGET
    from pisa.utils.log import set_verbosity, logging
    assert TARGET == 'cpu', "Cannot test functions on GPU, set PISA_TARGET to 'cpu'"
    set_verbosity(1)
    test_pi_osc_params()
Esempio n. 14
0
def parse_args(command, description):
    """Parse command line args.

    Returns
    -------
    init_args_d : dict

    """
    assert command in [discrete_hypo_test, inj_param_scan, systematics_tests]

    parser = ArgumentParser(
        description=description,
        formatter_class=ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        '-d',
        '--logdir',
        required=True,
        metavar='DIR',
        type=str,
        help='Directory into which to store results and metadata.')
    parser.add_argument('--min-settings',
                        type=str,
                        metavar='MINIMIZER_CFG',
                        default=None,
                        help='''Minimizer settings config file.''')
    parser.add_argument(
        '--min-method',
        type=str,
        default=None,
        choices=('l-bfgs-b', 'slsqp'),
        help='''Name of minimizer to use. Note that this takes precedence over
        the minimizer method specified via the --min-settings config
        file.''')
    parser.add_argument(
        '--min-opt',
        type=str,
        metavar='OPTION:VALUE',
        nargs='+',
        default=None,
        help='''Minimizer option:value pair(s) (can specify multiple).
        Values specified here override any of the same name in the config file
        specified by --min-settings''')
    parser.add_argument(
        '--no-octant-check',
        action='store_true',
        help='''Disable fitting hypotheses in theta23 octant opposite initial
        octant.''')
    parser.add_argument(
        '--ordering-check',
        action='store_true',
        help='''Fit both ordering hypotheses. This should only be flagged if
        the ordering is NOT the discrete hypothesis being tested''')
    parser.add_argument(
        '--shared-params',
        type=str,
        default=None,
        action='append',
        help='''Shared parameters for multi detector analysis (repeat for 
        multiple). The values of these parameters are kept the same in all 
        detectors that contain the param.''')

    if command == discrete_hypo_test:
        # Data cannot be data for MC studies e.g. injected parameter scans so
        # these arguments are redundant there.
        group = parser.add_mutually_exclusive_group(required=True)
        group.add_argument(
            '--data-is-data',
            action='store_true',
            help='''Data pipeline is based upon actual, measured data. The
            naming scheme for stored results is chosen accordingly.''')
        group.add_argument(
            '--data-is-mc',
            action='store_true',
            help='''Data pipeline is based upon Monte Carlo simulation, and not
            actual data. The naming scheme for stored results is chosen
            accordingly. If this is selected, --fluctuate-data is forced off.'''
        )

        # For the MC tests (injected parameter scan, systematic tests etc.) you
        # must have the same pipeline for h0, h1 and data. So this argument is
        # instead replaced with a generic pipeline argument.
        parser.add_argument(
            '--h0-pipeline',
            required=True,
            type=str,
            action='append',
            metavar='PIPELINE_CFG',
            help='''Settings for the generation of hypothesis h0
            distributions; repeat this argument to specify multiple
            pipelines.''')

    else:
        assert command in [inj_param_scan, systematics_tests]
        parser.add_argument(
            '--pipeline',
            required=True,
            type=str,
            action='append',
            metavar='PIPELINE_CFG',
            help='''Settings for the generation of h0, h1 and data
            distributions; repeat this argument to specify multiple
            pipelines.''')

    parser.add_argument(
        '--h0-param-selections',
        type=str,
        default=None,
        metavar='PARAM_SELECTOR_LIST',
        help='''Comma-separated (no spaces) list of param selectors to apply to
        hypothesis h0's distribution maker's pipelines.''')
    parser.add_argument('--h0-name',
                        type=str,
                        metavar='NAME',
                        default=None,
                        help='''Name for hypothesis h0. E.g., "NO" for normal
        ordering in the neutrino mass ordering analysis. Note that the name
        here has no bearing on the actual process, so it's important that you
        be careful to use a name that appropriately identifies the
        hypothesis.''')
    # For the MC tests (injected parameter scan, systematic tests etc.) you
    # must have the same pipeline for h0, h1 and data. So this argument is
    # hidden.
    if command not in (inj_param_scan, systematics_tests):
        parser.add_argument(
            '--h1-pipeline',
            type=str,
            action='append',
            default=None,
            metavar='PIPELINE_CFG',
            help='''Settings for the generation of hypothesis h1 distributions;
            repeat this argument to specify multiple pipelines. If omitted, the
            same settings as specified for --h0-pipeline are used to generate
            hypothesis h1 distributions (and so you have to use the
            --h1-param-selections argument to generate a hypotheses distinct
            from hypothesis h0 but still use h0's distribution maker).''')
    parser.add_argument(
        '--h1-param-selections',
        type=str,
        default=None,
        metavar='PARAM_SELECTOR_LIST',
        help='''Comma-separated (no spaces) list of param selectors to apply to
        hypothesis h1 distribution maker's pipelines.''')
    parser.add_argument('--h1-name',
                        type=str,
                        metavar='NAME',
                        default=None,
                        help='''Name for hypothesis h1. E.g., "IO" for inverted
        ordering in the neutrino mass ordering analysis. Note that the name
        here has no bearing on the actual process, so it's important that you
        be careful to use a name that appropriately identifies the
        hypothesis.''')
    # For the MC tests (injected parameter scan, systematic tests etc.) you
    # must have the same pipeline for h0, h1 and data. So this argument is
    # hidden.
    if command not in (inj_param_scan, systematics_tests):
        parser.add_argument(
            '--data-pipeline',
            type=str,
            action='append',
            default=None,
            metavar='PIPELINE_CFG',
            help='''Settings for the generation of "data" distributions; repeat
            this argument to specify multiple pipelines. If omitted, the same
            settings as specified for --h0-pipeline are used to generate data
            distributions (i.e., data is assumed to come from hypothesis h0.'''
        )
    parser.add_argument(
        '--data-param-selections',
        type=str,
        default=None,
        metavar='PARAM_SELECTOR_LIST',
        help='''Comma-separated list of param selectors to apply to the data
        distribution maker's pipelines. If neither --data-pipeline nor
        --data-param-selections are specified, *both* are copied from
        --h0-pipeline and --h0-param-selections, respectively. However,
        if --data-pipeline is specified while --data-param-selections is not,
        then the param selections in the pipeline config file(s) specified are
        used to produce data distributions.''')
    parser.add_argument(
        '--data-name',
        type=str,
        metavar='NAME',
        default=None,
        help='''Name for the data. E.g., "NO" for normal ordering in the
        neutrino mass ordering analysis. Note that the name here has no bearing
        on the actual process, so it's important that you be careful to use a
        name that appropriately identifies the hypothesis.''')
    # For the injected parameter scan and systematic studies, only the Asimov
    # analysis should be used, so these arguments are not needed.
    if command not in (inj_param_scan, systematics_tests):
        parser.add_argument(
            '--fluctuate-data',
            action='store_true',
            help='''Apply fluctuations to the data distribution. This should
            *not* be set for analyzing "real" (measured) data, and it is common
            to not use this feature even for Monte Carlo analysis. Note that if
            this is not set, --num-data-trials and --data-start-ind are forced
            to 1 and 0, respectively.''')
        parser.add_argument(
            '--fluctuate-fid',
            action='store_true',
            help='''Apply fluctuations to the fiducaial distributions. If this
            flag is not set, --num-fid-trials and --fid-start-ind are forced to
            1 and 0, respectively.''')
    parser.add_argument(
        '--metric',
        type=str,
        required=True,
        metavar='METRIC',
        action='append',
        choices=sorted(ALL_METRICS),
        help='''Name of metric(s) to use for optimizing the fit. Must be one of
        %s. Repeat this argument if you want to use different metrics for
        different detectors. If only one metric is specified, all detectors will
        use the same. Otherwise you have to specify one metric for each detector
        (even if two use the same) and pay attention to the order.''' %
        (ALL_METRICS, ))
    parser.add_argument(
        '--other-metric',
        type=str,
        default=None,
        metavar='METRIC',
        action='append',
        choices=['all'] + sorted(ALL_METRICS),
        help='''Name of another metric to evaluate at the best-fit point. Must
        be either 'all' or one of %s. Repeat this argument (or use 'all') to
        specify multiple metrics.''' % (ALL_METRICS, ))
    if command not in (inj_param_scan, systematics_tests):
        parser.add_argument(
            '--num-data-trials',
            type=int,
            default=1,
            help='''When performing Monte Carlo analysis, set to > 1 to produce
            multiple pseudodata distributions from the data distribution maker's
            Asimov distribution. This is overridden if --fluctuate-data is not
            set (since each data distribution will be identical if it is not
            fluctuated). This is typically left at 1 (i.e., the Asimov
            distribution is assumed to be representative.''')
        parser.add_argument('--data-start-ind',
                            type=int,
                            default=0,
                            help='''Fluctated data set index.''')
        parser.add_argument(
            '--num-fid-trials',
            type=int,
            default=1,
            help='''Number of fiducial pseudodata trials to run. In our
            experience, it takes ~10^3-10^5 fiducial psuedodata trials to
            achieve low uncertainties on the resulting significance, though
            that exact number will vary based upon the details of an
            analysis.''')
        parser.add_argument('--fid-start-ind',
                            type=int,
                            default=0,
                            help='''Fluctated fiducial data index.''')
    # A blind analysis only makes sense when the possibility of actually
    # analysing data is available.
    if command not in (inj_param_scan, systematics_tests):
        parser.add_argument(
            '--blind',
            action='store_true',
            help='''Blinded analysis. Do not show parameter values or store to
            logfiles.''')
    parser.add_argument(
        '--allow-dirty',
        action='store_true',
        help='''Warning: Use with caution. (Allow for run despite dirty
        repository.)''')
    parser.add_argument(
        '--allow-no-git-info',
        action='store_true',
        help='''*** DANGER! Use with extreme caution! (Allow for run despite
        complete inability to track provenance of code.)''')
    parser.add_argument(
        '--no-min-history',
        action='store_true',
        help='''Do not store minimizer history (steps). This behavior is also
        enforced if --blind is specified.''')
    # Add in the arguments specific to the injected parameter scan.
    if command == inj_param_scan:
        parser.add_argument(
            '--param_name',
            type=str,
            metavar='NAME',
            required=True,
            help='''Name of param to scan over. This must be in the config
            files defined above. One exception is that you can define this as
            `sin2theta23` and it will be interpreted not as theta23 values but
            as the square of the sine of theta23 values instead.''')
        parser.add_argument(
            '--inj_vals',
            type=str,
            required=True,
            help='''List of values to inject as true points in the parameter
            defined above. Must be something that numpy can interpret. In this
            script, numpy is imported as np so please use np in your string. An
            example would be np.linspace(0.35,0.65,31).''')
        parser.add_argument(
            '--inj_units',
            type=str,
            required=True,
            help='''A string to be able to deal with the units in the parameter
            scan and make sure that they match those in the config files. Even
            if the parameter is dimensionless this must be stated.''')
        parser.add_argument(
            '--use-inj-prior',
            action='store_true',
            help='''Generally, one should not use a prior on the parameter of
            interest here since the Asimov analysis breaks down with the use of
            non-central prior i.e. injecting a truth that differs from the
            centre of the prior. Flag this to force the prior to be left on.'''
        )
    # Add in the arguments specific to the systematic tests.
    if command == systematics_tests:
        parser.add_argument(
            '--inject_wrong',
            action='store_true',
            help='''Inject a parameter to some systematically wrong value.
            This will be either +/- 1 sigma or +/- 10%% if such a definition
            is impossible. By default this parameter will be fixed unless
            the fit_wrong argument is also flagged.''')
        parser.add_argument(
            '--fit_wrong',
            action='store_true',
            help='''In the case of injecting a systematically wrong hypothesis
            setting this argument will get the minimiser to try correct for it.
            If inject_wrong is set to false then this must also be set to
            false or else the script will fail.''')
        parser.add_argument(
            '--only_syst',
            default=None,
            type=str,
            action='append',
            metavar='PARAM_NAME',
            help='''Specify the name of one of the systematics in the file to
            run the test for this systematic. Repeat this argument to specify
            multiple systematics. If none are provided, the test will be run
            over all systematics in the pipeline.''')
        parser.add_argument(
            '--skip_baseline',
            action='store_true',
            help='''Skip the baseline systematic test i.e. the one where none
            of them are fixed and/or modified. In most cases you will want this
            for comparison but if you are only interested in the effect of
            shifting certain systematics then this step can be skipped.''')
    parser.add_argument(
        '--pprint',
        action='store_true',
        help='''Live-updating one-line vew of metric and parameter values. (The
        latter are not displayed if --blind is specified.)''')
    parser.add_argument('-v',
                        action='count',
                        default=None,
                        help='set verbosity level')
    args = parser.parse_args(sys.argv[2:])
    assert args.min_settings is not None or args.min_method is not None
    init_args_d = vars(args)

    set_verbosity(init_args_d.pop('v'))

    min_settings_from_file = init_args_d.pop('min_settings')
    minimizer = init_args_d.pop('min_method')
    min_opt = init_args_d.pop('min_opt')

    # TODO: put this datastructure remnant from PISA 2 out of its misery...
    minimizer_settings = dict(method=dict(value='', desc='no desc'),
                              options=dict(value=dict(), desc=dict()))

    if min_settings_from_file is not None:
        minimizer_settings.update(from_file(min_settings_from_file))

    if minimizer is not None:
        minimizer_settings['method'] = dict(value=minimizer, desc='no desc')

    if min_opt is not None:
        for opt_val_str in min_opt:
            opt, val_str = [s.strip() for s in opt_val_str.split(':')]
            try:
                val = int(val_str)
            except ValueError:
                try:
                    val = float(val_str)
                except ValueError:
                    val = val_str
            minimizer_settings['options']['value'][opt] = val
            minimizer_settings['options']['desc'][opt] = 'no desc'
    init_args_d['minimizer_settings'] = minimizer_settings

    init_args_d['check_octant'] = not init_args_d.pop('no_octant_check')
    init_args_d['check_ordering'] = init_args_d.pop('ordering_check')

    if command not in (inj_param_scan, systematics_tests):
        init_args_d['data_is_data'] = not init_args_d.pop('data_is_mc')
    else:
        init_args_d['data_is_data'] = False
        init_args_d['fluctuate_data'] = False
        init_args_d['fluctuate_fid'] = False

    init_args_d['store_minimizer_history'] = (
        not init_args_d.pop('no_min_history'))

    other_metrics = init_args_d.pop('other_metric')
    if other_metrics is not None:
        other_metrics = [s.strip().lower() for s in other_metrics]
        if 'all' in other_metrics:
            other_metrics = sorted(ALL_METRICS)
        for m in init_args_d['metric']:
            if m in other_metrics:
                other_metrics.remove(m)
        if not other_metrics:
            other_metrics = None
        else:
            logging.info('Will evaluate other metrics %s', other_metrics)
        init_args_d['other_metrics'] = other_metrics

    return init_args_d
Esempio n. 15
0
            log.tprofile.debug('module %s, function %s: %.4f ms',
                               func.__module__, func.__name__,
                               (end_t - start_t) * 1000)

    return profiled_func


def test_profile():
    """Unit tests for `profile` functional (decorator)"""
    @profile
    def get_number():
        log.logging.trace('hello, i am get_number')
        for x in xrange(500000):
            yield x

    @profile
    def expensive_function():
        log.logging.trace('hello, i am expensive fun')
        for x in get_number():
            _ = x ^ x ^ x
        return 'some result!'

    _ = expensive_function()
    log.logging.info('<< ??? : test_profile >> inspect above outputs')


if __name__ == '__main__':
    log.set_verbosity(2)
    test_line_profile()
    test_profile()
Esempio n. 16
0
def main():
    """Main"""
    args = parse_args()
    args_d = vars(args)
    set_verbosity(args_d.pop('v'))
    make_toy_events(**args_d)
Esempio n. 17
0
def run_unit_tests(path=PISA_PATH,
                   allow_missing=OPTIONAL_MODULES,
                   verbosity=Levels.WARN):
    """Run all tests found at `path` (or recursively below if `path` is a
    directory).

    Each module is imported and each test function is run initially with
    `set_verbosity(verbosity)`, but if an exception is caught, the module is
    re-imported or the test function is re-run with
    `set_verbosity(Levels.TRACE)`, then the traceback from the (original)
    exception emitted is displayed.

    Parameters
    ----------
    path : str
        Path to file or directory

    allow_missing : None or sequence of str

    verbosity : int in pisa.utils.log.Levels

    Raises
    ------
    Exception
        If any import or test fails not in `allow_missing`

    """
    set_verbosity(verbosity)
    logging.info("%sPlatform information:", PFX)
    logging.info("%s  HOSTNAME = %s", PFX, socket.gethostname())
    logging.info("%s  FQDN = %s", PFX, socket.getfqdn())
    logging.info("%s  OS = %s %s", PFX, platform.system(), platform.release())
    for key, val in cpuinfo.get_cpu_info().items():
        logging.info("%s  %s = %s", PFX, key, val)
    logging.info(PFX)
    logging.info("%sModule versions:", PFX)
    for module_name in REQUIRED_MODULES + OPTIONAL_MODULES:
        try:
            module = import_module(module_name)
        except ImportError:
            if module_name in REQUIRED_MODULES:
                raise
            ver = "optional module not installed or not import-able"
        else:
            if hasattr(module, "__version__"):
                ver = module.__version__
            else:
                ver = "?"
        logging.info("%s  %s : %s", PFX, module_name, ver)
    logging.info(PFX)

    path = expand(path, absolute=True, resolve_symlinks=True)
    if allow_missing is None:
        allow_missing = []
    elif isinstance(allow_missing, str):
        allow_missing = [allow_missing]

    tests = find_unit_tests(path)

    module_pypaths_succeeded = []
    module_pypaths_failed = []
    module_pypaths_failed_ignored = []
    test_pypaths_succeeded = []
    test_pypaths_failed = []
    test_pypaths_failed_ignored = []

    for rel_file_path, test_func_names in tests.items():
        pypath = ["pisa"] + rel_file_path[:-3].split("/")
        parent_pypath = ".".join(pypath[:-1])
        module_name = pypath[-1].replace(".", "_")
        module_pypath = f"{parent_pypath}.{module_name}"

        try:
            set_verbosity(verbosity)
            logging.info(PFX + f"importing {module_pypath}")

            set_verbosity(Levels.WARN)
            module = import_module(module_pypath, package=parent_pypath)

        except Exception as err:
            if (isinstance(err, ImportError) and hasattr(err, "name")
                    and err.name in allow_missing  # pylint: disable=no-member
                ):
                err_name = err.name  # pylint: disable=no-member
                module_pypaths_failed_ignored.append(module_pypath)
                logging.warning(
                    f"{PFX}module {err_name} failed to import wile importing"
                    f" {module_pypath}, but ok to ignore")
                continue

            module_pypaths_failed.append(module_pypath)

            set_verbosity(verbosity)
            msg = f"<< FAILURE IMPORTING : {module_pypath} >>"
            logging.error(PFX + "=" * len(msg))
            logging.error(PFX + msg)
            logging.error(PFX + "=" * len(msg))

            # Reproduce the failure with full output
            set_verbosity(Levels.TRACE)
            try:
                import_module(module_name, package=parent_pypath)
            except Exception:
                pass

            set_verbosity(Levels.TRACE)
            logging.exception(err)

            set_verbosity(verbosity)
            logging.error(PFX + "#" * len(msg))

            continue

        else:
            module_pypaths_succeeded.append(module_pypath)

        for test_func_name in test_func_names:
            test_pypath = f"{module_pypath}.{test_func_name}"
            try:
                set_verbosity(verbosity)
                logging.debug(PFX + f"getattr({module}, {test_func_name})")

                set_verbosity(Levels.WARN)
                test_func = getattr(module, test_func_name)

                # Run the test function
                set_verbosity(verbosity)
                logging.info(PFX + f"{test_pypath}()")

                set_verbosity(Levels.WARN)
                test_func()

            except Exception as err:
                if (isinstance(err, ImportError) and hasattr(err, "name")
                        and err.name in allow_missing  # pylint: disable=no-member
                    ):
                    err_name = err.name  # pylint: disable=no-member
                    test_pypaths_failed_ignored.append(module_pypath)
                    logging.warning(
                        PFX +
                        f"{test_pypath} failed because module {err_name} failed to"
                        + f" load, but ok to ignore")

                    continue

                test_pypaths_failed.append(test_pypath)
                set_verbosity(verbosity)
                msg = f"<< FAILURE RUNNING : {test_pypath} >>"
                logging.error(PFX + "=" * len(msg))
                logging.error(PFX + msg)
                logging.error(PFX + "=" * len(msg))

                # Reproduce the error with full output

                set_verbosity(Levels.TRACE)
                try:
                    test_func = getattr(module, test_func_name)
                    with np.printoptions(
                            precision=np.finfo(pisa.FTYPE).precision + 2,
                            floatmode="fixed",
                            sign=" ",
                            linewidth=200,
                    ):
                        test_func()
                except Exception:
                    pass

                set_verbosity(Levels.TRACE)
                logging.exception(err)

                set_verbosity(verbosity)
                logging.error(PFX + "#" * len(msg))

            else:
                test_pypaths_succeeded.append(test_pypath)

            finally:
                # remove references to the test function, e.g. to remove refs
                # to pycuda / numba.cuda contexts so these can be closed
                try:
                    del test_func
                except NameError:
                    pass

        # NOTE: Until we get all GPU code into Numba, need to unload pycuda
        # and/or numba.cuda contexts before a module requiring the other one is
        # to be imported.
        # NOTE: the following causes a traceback to be emitted at the very end
        # of the script, regardless of the exception catching here.
        if (pisa.TARGET == "cuda" and pycuda is not None
                and hasattr(pycuda, "autoinit")
                and hasattr(pycuda.autoinit, "context")):
            try:
                pycuda.autoinit.context.detach()
            except Exception:
                pass

        # Attempt to unload the imported module
        # TODO: pipeline, etc. fail as isinstance(service, (Stage, PiStage)) is False
        #if module_pypath in sys.modules and module_pypath != "pisa":
        #    del sys.modules[module_pypath]
        #del module

        # TODO: crashes program; subseqeunt calls in same shell crash(!?!?)
        # if pisa.TARGET == 'cuda' and nbcuda is not None:
        #    try:
        #        nbcuda.close()
        #    except Exception:
        #        pass

    # Summarize results

    n_import_successes = len(module_pypaths_succeeded)
    n_import_failures = len(module_pypaths_failed)
    n_import_failures_ignored = len(module_pypaths_failed_ignored)
    n_test_successes = len(test_pypaths_succeeded)
    n_test_failures = len(test_pypaths_failed)
    n_test_failures_ignored = len(test_pypaths_failed_ignored)

    set_verbosity(verbosity)
    logging.info(
        PFX + f"<< IMPORT TESTS : {n_import_successes} imported,"
        f" {n_import_failures} failed,"
        f" {n_import_failures_ignored} failed to import but ok to ignore >>")
    logging.info(PFX + f"<< UNIT TESTS : {n_test_successes} succeeded,"
                 f" {n_test_failures} failed,"
                 f" {n_test_failures_ignored} failed but ok to ignore >>")

    # Exit with error if any failures (import or unit test)

    if module_pypaths_failed or test_pypaths_failed:
        msgs = []
        if module_pypaths_failed:
            msgs.append(
                f"{n_import_failures} module(s) failed to import:\n  " +
                ", ".join(module_pypaths_failed))
        if test_pypaths_failed:
            msgs.append(f"{n_test_failures} unit test(s) failed:\n  " +
                        ", ".join(test_pypaths_failed))

        # Note the extra newlines before the exception to make it stand out;
        # and newlines after the exception are due to the pycuda error message
        # that is emitted when we call pycuda.autoinit.context.detach()
        sys.stdout.flush()
        sys.stderr.write("\n\n\n")
        raise Exception("\n".join(msgs) + "\n\n\n")
Esempio n. 18
0
        pathlength = np.asarray(pathlength)

        self._distance = pathlength


def test_Layers():

    logging.info('Test layers calculation:')
    layer = Layers('osc/PREM_4layer.dat')
    layer.setElecFrac(0.4656, 0.4656, 0.4957)
    cz = np.linspace(-1, 1, 1e5, dtype=FTYPE)
    layer.calcLayers(cz)
    logging.info('n_layers = %s' % layer.n_layers)
    logging.info('density  = %s' % layer.density)
    logging.info('distance = %s' % layer.distance)

    logging.info('Test path length calculation:')
    layer = Layers(None)
    cz = np.array([1., 0., -1.])
    layer.calcPathLength(cz)
    logging.info('coszen = %s' % cz)
    logging.info('pathlengths = %s' % layer.distance)

    logging.info('<< PASS : test_Layers >>')


if __name__ == '__main__':
    set_verbosity(3)
    test_Layers()
Esempio n. 19
0
def main(return_outputs=False):
    """Run unit tests if `pipeline.py` is called as a script."""
    from pisa.utils.plotter import Plotter

    args = parse_args()
    set_verbosity(args.v)

    # Even if user specifies an integer on command line, it comes in as a
    # string. Try to convert to int (e.g. if `'1'` is passed to indicate the
    # second stage), and -- if successful -- use this as `args.only_stage`.
    # Otherwise, the string value passed will be used (e.g. `'osc'` could be
    # passed).
    try:
        only_stage_int = int(args.only_stage)
    except (ValueError, TypeError):
        pass
    else:
        args.only_stage = only_stage_int

    if args.outdir:
        mkdir(args.outdir)
    else:
        if args.pdf or args.png:
            raise ValueError("No --outdir provided, so cannot save images.")

    # Most basic parsing of the pipeline config (parsing only to this level
    # allows for simple strings to be specified as args for updating)
    bcp = PISAConfigParser()
    bcp.read(args.pipeline)

    # Update the config with any args specified on command line
    if args.arg is not None:
        for arg_list in args.arg:
            if len(arg_list) < 2:
                raise ValueError(
                    'Args must be formatted as: "section arg=val". Got "%s"'
                    " instead." % " ".join(arg_list))
            section = arg_list[0]
            remainder = " ".join(arg_list[1:])
            eq_split = remainder.split("=")
            newarg = eq_split[0].strip()
            value = ("=".join(eq_split[1:])).strip()
            logging.debug('Setting config section "%s" arg "%s" = "%s"',
                          section, newarg, value)
            try:
                bcp.set(section, newarg, value)
            except NoSectionError:
                logging.error(
                    'Invalid section "%s" specified. Must be one of %s',
                    section,
                    bcp.sections(),
                )
                raise

    # Instantiate the pipeline
    pipeline = Pipeline(bcp)  # pylint: disable=redefined-outer-name

    if args.select is not None:
        pipeline.select_params(args.select, error_on_missing=True)

    if args.only_stage is None:
        stop_idx = args.stop_after_stage
        try:
            stop_idx = int(stop_idx)
        except (TypeError, ValueError):
            pass
        if isinstance(stop_idx, str):
            stop_idx = pipeline.index(stop_idx)
        outputs = pipeline.get_outputs(idx=stop_idx)  # pylint: disable=redefined-outer-name
        if stop_idx is not None:
            stop_idx += 1
        indices = slice(0, stop_idx)
    else:
        assert args.stop_after_stage is None
        idx = pipeline.index(args.only_stage)
        stage = pipeline[idx]
        indices = slice(idx, idx + 1)

        # Create dummy inputs if necessary
        inputs = None
        if hasattr(stage, "input_binning"):
            logging.warning(
                "Stage requires input, so building dummy"
                " inputs of random numbers, with random state set to the input"
                " index according to alphabetical ordering of input names and"
                " filled in alphabetical ordering of dimension names.")
            input_maps = []
            tmp = deepcopy(stage.input_binning)
            alphabetical_binning = tmp.reorder_dimensions(sorted(tmp.names))
            for input_num, input_name in enumerate(sorted(stage.input_names)):
                # Create a new map with all 3's; name according to the input
                hist = np.full(shape=alphabetical_binning.shape,
                               fill_value=3.0)
                input_map = Map(name=input_name,
                                binning=alphabetical_binning,
                                hist=hist)

                # Apply Poisson fluctuations to randomize the values in the map
                input_map.fluctuate(method="poisson", random_state=input_num)

                # Reorder dimensions according to user's original binning spec
                input_map.reorder_dimensions(stage.input_binning)
                input_maps.append(input_map)
            inputs = MapSet(maps=input_maps, name="ones", hash=1)

        outputs = stage.run(inputs=inputs)

    for stage in pipeline[indices]:
        if not args.outdir:
            break
        stg_svc = stage.stage_name + "__" + stage.service_name
        fbase = os.path.join(args.outdir, stg_svc)
        if args.intermediate or stage == pipeline[indices][-1]:
            stage.outputs.to_json(fbase + "__output.json.bz2")

        # also only plot if args intermediate or last stage
        if args.intermediate or stage == pipeline[indices][-1]:
            formats = OrderedDict(png=args.png, pdf=args.pdf)
            if isinstance(stage.outputs, Data):
                # TODO(shivesh): plots made here will use the most recent
                # "pisa_weight" column and so all stages will have identical plots
                # (one workaround is to turn on "memcache_deepcopy")
                # TODO(shivesh): intermediate stages have no output binning
                if stage.output_binning is None:
                    logging.debug("Skipping plot of intermediate stage %s",
                                  stage)
                    continue
                outputs = stage.outputs.histogram_set(
                    binning=stage.output_binning,
                    nu_weights_col="pisa_weight",
                    mu_weights_col="pisa_weight",
                    noise_weights_col="pisa_weight",
                    mapset_name=stg_svc,
                    errors=True,
                )

            try:
                for fmt, enabled in formats.items():
                    if not enabled:
                        continue
                    my_plotter = Plotter(
                        stamp="Event rate",
                        outdir=args.outdir,
                        fmt=fmt,
                        log=False,
                        annotate=args.annotate,
                    )
                    my_plotter.ratio = True
                    my_plotter.plot_2d_array(outputs,
                                             fname=stg_svc + "__output",
                                             cmap="RdBu")
            except ValueError as exc:
                logging.error(
                    "Failed to save plot to format %s. See exception"
                    " message below",
                    fmt,
                )
                traceback.format_exc()
                logging.exception(exc)
                logging.warning("I can't go on, I'll go on.")

    if return_outputs:
        return pipeline, outputs
Esempio n. 20
0
def main():
    args = parse_args()
    set_verbosity(args.v)

    if args.plot:
        import matplotlib as mpl
        mpl.use('pdf')
        import matplotlib.pyplot as plt
        from pisa.utils.plotter import Plotter

    cfg = from_file(args.fit_settings)
    sys_list = cfg.get('general', 'sys_list').replace(' ', '').split(',')
    stop_idx = cfg.getint('general', 'stop_after_stage')


    for sys in sys_list:
        # Parse info for given systematic
        nominal = cfg.getfloat(sys, 'nominal')
        degree = cfg.getint(sys, 'degree')
        force_through_nominal = cfg.getboolean(sys, 'force_through_nominal')
        runs = eval(cfg.get(sys, 'runs'))
        #print "runs ", runs
        smooth = cfg.get(sys, 'smooth')

        x_values = np.array(sorted(runs))

        # Build fit function
        if force_through_nominal:
            function = "lambda x, *p: np.polynomial.polynomial.polyval(x, [1.] + list(p))"
        else:
            function = "lambda x, *p: np.polynomial.polynomial.polyval(x, list(p))"
            # Add free parameter for constant term
            degree += 1
        fit_fun = eval(function)

        # Instantiate template maker
        template_maker = Pipeline(args.template_settings)

        if not args.set_param == '':
            for one_set_param in args.set_param:
                p_name, value = one_set_param.split("=")
                #print "p_name,value= ", p_name, " ", value
                value = parse_quantity(value)
                value = value.n * value.units
                param = template_maker.params[p_name]
                #print "old ", p_name, "value = ", param.value
                param.value = value
                #print "new ", p_name, "value = ", param.value
                template_maker.update_params(param)

        inputs = {}
        map_names = None
        # Get sys templates
        for run in runs:
            for key, val in cfg.items('%s:%s'%(sys, run)):
                if key.startswith('param.'):
                    _, pname = key.split('.')
                    param = template_maker.params[pname]
                    try:
                        value = parse_quantity(val)
                        param.value = value.n * value.units
                    except ValueError:
                        value = parse_string_literal(val)
                        param.value = value
                    param.set_nominal_to_current_value()
                    template_maker.update_params(param)
            # Retreive maps
            template = template_maker.get_outputs(idx=stop_idx)
            if map_names is None: map_names = [m.name for m in template]
            inputs[run] = {}
            for m in template:
                inputs[run][m.name] = m.hist

        # Numpy acrobatics:
        arrays = {}
        for name in map_names:
            arrays[name] = []
            for x in x_values:
                arrays[name].append(
                    inputs[x][name] / unp.nominal_values(inputs[nominal][name])
                )
            a = np.array(arrays[name])
            arrays[name] = np.rollaxis(a, 0, len(a.shape))

        # Shift to get deltas
        x_values -= nominal

        # Binning object (assuming they're all the same)
        binning = template.maps[0].binning

        shape = [d.num_bins for d in binning] + [degree]
        shape_small = [d.num_bins for d in binning]

        outputs = {}
        errors = {}
        for name in map_names:
            # Now actualy perform some fits
            outputs[name] = np.ones(shape)
            errors[name] = np.ones(shape)


            for idx in np.ndindex(*shape_small):
                y_values = unp.nominal_values(arrays[name][idx])
                y_sigma = unp.std_devs(arrays[name][idx])
                if np.any(y_sigma):
                    popt, pcov = curve_fit(fit_fun, x_values, y_values,
                                           sigma=y_sigma, p0=np.ones(degree))
                else:
                    popt, pcov = curve_fit(fit_fun, x_values, y_values,
                                           p0=np.ones(degree))
                perr = np.sqrt(np.diag(pcov))
                for k, p in enumerate(popt):
                    outputs[name][idx][k] = p
                    errors[name][idx][k] = perr[k]

                # TODO(philippeller): the below block of code will fail

                # Maybe plot
                #if args.plot:
                #    fig_num = i + nx * j
                #    if fig_num == 0:
                #        fig = plt.figure(num=1, figsize=( 4*nx, 4*ny))
                #    subplot_idx = nx*(ny-1-j)+ i + 1
                #    plt.subplot(ny, nx, subplot_idx)
                #    #plt.snameter(x_values, y_values, color=plt_colors[name])
                #    plt.gca().errorbar(x_values, y_values, yerr=y_sigma,
                #                       fmt='o', color=plt_colors[name],
                #                       ecolor=plt_colors[name],
                #                       mec=plt_colors[name])
                #    # Plot nominal point again in black
                #    plt.snameter([0.0], [1.0], color='k')
                #    f_values = fit_fun(x_values, *popt)
                #    fun_plot, = plt.plot(x_values, f_values,
                #            color=plt_colors[name])
                #    plt.ylim(np.min(unp.nominal_values(arrays[name]))*0.9,
                #             np.max(unp.nominal_values(arrays[name]))*1.1)
                #    if i > 0:
                #        plt.setp(plt.gca().get_yticklabels(), visible=False)
                #    if j > 0:
                #        plt.setp(plt.gca().get_xticklabels(), visible=False)

        if smooth == 'gauss':
            for name in map_names:
                for d in range(degree):
                    outputs[name][...,d] = gaussian_filter(outputs[name][...,d],sigma=1)

        if smooth == 'gauss_pid':
            for name in map_names:
                split_idx = binning.names.index('pid')
                tot = len(binning)-1
                for d in range(degree):
                    for p in range(len(binning['pid'])):
                        outputs[name][...,p,d] = gaussian_filter(
                            np.swapaxes(outputs[name], split_idx, tot)[...,p,d],
                            sigma=1
                        )
                outputs[name] = np.swapaxes(outputs[name], split_idx, tot)

        # Save the raw ones anyway
        outputs['pname'] = sys
        outputs['nominal'] = nominal
        outputs['function'] = function
        outputs['map_names'] = map_names
        outputs['binning_hash'] = binning.hash
        to_file(outputs, '%s/%s_sysfits_%s_%s.json'%(args.out_dir, sys,
                                                     args.tag, smooth))

        if args.plot:
            for d in range(degree):
                maps = []
                for name in map_names:
                    maps.append(Map(name='%s_raw'%name, hist=outputs[name][...,d],
                                    binning=binning))
                maps = MapSet(maps)
                my_plotter = Plotter(
                    stamp='',
                    outdir=args.out_dir,
                    fmt='pdf',
                    log=False,
                    label=''
                )
                my_plotter.plot_2d_array(
                    maps,
                    fname='%s_%s_%s_%s'%(sys, args.tag, d, smooth),
                )
Esempio n. 21
0
def test_kde_stash(verbosity=Levels.WARN):
    """Unit test for the hist stashing feature.

    Hist stashing can greatly speed up fits as long as the only free parameters
    are in stages that work on the output histograms, rather than the individual
    events. In particular, it should be strictly equivalent to either scale all weights
    by a factor and then running the KDE, or to first calculate the KDE and then scale
    all the bin counts by the same factor. This test ensures that the order of
    operation really doesn't matter.

    This should apply also to the errors, independent of whether the bootstrapping
    method or the utils.set_variance stage was used to produce them.
    """

    import pytest
    from numpy.testing import assert_array_equal, assert_allclose

    set_verbosity(verbosity)

    def assert_correct_scaling(pipeline_cfg, fixed_errors=False):
        """Run the pipeline and assert that scaling by a factor of two is correct."""
        dmaker = DistributionMaker([pipeline_cfg])
        out = dmaker.get_outputs(return_sum="true")[0]
        dmaker.pipelines[0].params.weight_scale = 2.0
        out2 = dmaker.get_outputs(return_sum="true")[0]
        if fixed_errors:
            # this is special: We expect that the nominal counts are multiplied, but
            # that hte errors stay fixed (applies to set_variance errors)
            assert_array_equal(out.nominal_values * 2.0, out2.nominal_values)
            assert_array_equal(out.std_devs, out2.std_devs)
        else:
            assert out * 2.0 == out2

    ## KDE without errors

    # First aeff, then KDE
    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)
    assert_correct_scaling(test_cfg)

    # First KDE, then aeff, with stashing
    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    # turn on stashing
    test_cfg[("utils", "kde")]["stash_hists"] = True
    # Change aeff calculation to binned mode (i.e. multiply bin counts)
    test_cfg[("aeff", "weight")]["calc_mode"] = TEST_BINNING
    test_cfg[("aeff", "weight")]["apply_mode"] = TEST_BINNING
    assert_correct_scaling(test_cfg)

    ## KDE with bootstrap errors

    # First aeff, then KDE with bootstrap
    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)
    # turn OFF stashing
    test_cfg[("utils", "kde")]["stash_hists"] = False
    # turn on bootstrapping
    test_cfg[("utils", "kde")]["bootstrap"] = True
    # return the errors
    test_cfg["pipeline"]["output_key"] = ("weights", "errors")
    assert_correct_scaling(test_cfg)

    # First KDE with stashed hists and bootstrap, then aeff
    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    # turn on stashing
    test_cfg[("utils", "kde")]["stash_hists"] = True
    # turn on bootstrapping
    test_cfg[("utils", "kde")]["bootstrap"] = True
    # return the errors
    test_cfg["pipeline"]["output_key"] = ("weights", "errors")
    # need to change mode to binned
    test_cfg[("aeff", "weight")]["calc_mode"] = TEST_BINNING
    test_cfg[("aeff", "weight")]["apply_mode"] = TEST_BINNING
    assert_correct_scaling(test_cfg)

    ## KDE with errors calculated using set_variance stage

    # first aeff, then KDE and set_variance
    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)
    test_cfg[("utils", "set_variance")] = deepcopy(TEST_CONFIGS.set_variance_cfg)
    # turn on stashing
    test_cfg[("utils", "kde")]["stash_hists"] = False
    # turn OFF bootstrapping
    test_cfg[("utils", "kde")]["bootstrap"] = False
    # return the errors
    test_cfg["pipeline"]["output_key"] = ("weights", "errors")
    # The set_variance stage only calculates errors the first time that the pipeline
    # is evaluated, these errors are stored and re-instated on any sub-sequent
    # evaluations. We expect therefore that only the nominal values scale.
    assert_correct_scaling(test_cfg, fixed_errors=True)

    # first KDE and set_variance, then aeff
    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    # It is still important that the `set_variance` stage is *last*.
    test_cfg[("utils", "set_variance")] = deepcopy(TEST_CONFIGS.set_variance_cfg)
    # turn on stashing
    test_cfg[("utils", "kde")]["stash_hists"] = True
    # turn OFF bootstrapping
    test_cfg[("utils", "kde")]["bootstrap"] = False
    # return the errors
    test_cfg["pipeline"]["output_key"] = ("weights", "errors")
    # need to change mode to binned
    test_cfg[("aeff", "weight")]["calc_mode"] = TEST_BINNING
    test_cfg[("aeff", "weight")]["apply_mode"] = TEST_BINNING
    # We ensure that the behavior is the same as it has been when we were not stashing
    # the histograms and used set_variance.
    assert_correct_scaling(test_cfg, fixed_errors=True)

    # Using the wrong order (not putting set_variance last)
    test_cfg = deepcopy(TEST_CONFIGS.pipe_cfg)
    test_cfg[("data", "toy_event_generator")] = deepcopy(
        TEST_CONFIGS.event_generator_cfg
    )
    test_cfg[("utils", "kde")] = deepcopy(TEST_CONFIGS.kde_cfg)
    # If set_variance is not the last stage, this breaks. The reason is a slightly
    # silly design of set_variance. It should have been constructed such that the
    # total normalization is always divided out, but it wasn't. The way it is
    # constructed now, it is basically tuned by the scaling factor to work for the
    # given livetime and breaks immediately when that changes.
    test_cfg[("utils", "set_variance")] = deepcopy(TEST_CONFIGS.set_variance_cfg)
    test_cfg[("aeff", "weight")] = deepcopy(TEST_CONFIGS.aeff_cfg)
    # turn on stashing
    test_cfg[("utils", "kde")]["stash_hists"] = True
    # turn OFF bootstrapping
    test_cfg[("utils", "kde")]["bootstrap"] = False
    # return the errors
    test_cfg["pipeline"]["output_key"] = ("weights", "errors")
    # need to change mode to binned
    test_cfg[("aeff", "weight")]["calc_mode"] = TEST_BINNING
    test_cfg[("aeff", "weight")]["apply_mode"] = TEST_BINNING
    # With the wrong order, this will fail.
    # FIXME: If someone changes the behavior of set_variance in the future to be
    # more robust, they are welcome to change this unit test.
    with pytest.raises(AssertionError):
        assert_correct_scaling(test_cfg, fixed_errors=True)

    logging.info("<< PASS : kde_stash >>")
Esempio n. 22
0
                    help="Save all the templates used to obtain the gradients.")

  sselect.add_argument('-n','--no-save-templates', action='store_false',
                    default=False, dest='save_templates',
                    help="Do not save the templates for the different test points.")

  parser.add_argument('-o','--outdir',type=str,default=os.getcwd(),metavar='DIR',
                    help="Output directory")

  parser.add_argument('-v', '--verbose', action='count', default=None,
                    help='set verbosity level')

  args = parser.parse_args()

  # Set verbosity level
  set_verbosity(args.verbose)

  # Read the template settings
  template_settings = from_json(args.template_settings)

  # This file only contains the number of test points for each parameter (and perhaps eventually a non-linearity criterion)
  grid_settings  = from_json(args.grid_settings)

  # Get the Fisher matrices for the desired hierarchy and fiducial settings
  fisher_matrices = get_fisher_matrices(template_settings,grid_settings,args.inverted_truth,args.normal_truth,
                                    args.dump_all_stages,args.save_templates,args.outdir)

  
  # Fisher matrices are saved in any case
  for data_tag in fisher_matrices:
    fisher_basename = 'fisher_data_%s'%data_tag
Esempio n. 23
0
#
# pisa tools and objects
#
from pisa.core.binning import OneDimBinning, MultiDimBinning
from pisa.core.map import Map, MapSet
from pisa.core.distribution_maker import DistributionMaker
from pisa.utils.config_parser import parse_pipeline_config
from pisa.core.param import Param, ParamSet
from pisa.analysis.analysis import Analysis

# debug tools
from pisa.utils.log import logging
from pisa.utils.profiler import line_profile
from pisa.utils.log import set_verbosity, Levels
set_verbosity(Levels.TRACE)

##################################################################################

STANDARD_CONFIG = os.environ['PISA'] + \
    '/pisa/stages/data/super_simple_pipeline.cfg'
TRUE_MU = 20.
TRUE_SIGMA = 3.1
NBINS = 51

################################################################################


class ToyMCllhParam:
    '''
    Class defining the parameters of the Toy MC
Esempio n. 24
0
def test_kde_histogramdd():
    """Unit tests for kde_histogramdd"""
    from argparse import ArgumentParser
    from shutil import rmtree
    from tempfile import mkdtemp
    from pisa import ureg
    from pisa.core.map import Map, MapSet
    from pisa.utils.log import logging, set_verbosity
    from pisa.utils.plotter import Plotter

    parser = ArgumentParser()
    parser.add_argument("-v",
                        action="count",
                        default=None,
                        help="set verbosity level")
    args = parser.parse_args()
    set_verbosity(args.v)

    temp_dir = mkdtemp()

    try:
        my_plotter = Plotter(
            stamp="",
            outdir=temp_dir,
            fmt="pdf",
            log=False,
            annotate=False,
            symmetric=False,
            ratio=True,
        )

        b1 = OneDimBinning(name="coszen",
                           num_bins=20,
                           is_lin=True,
                           domain=[-1, 1],
                           tex=r"\cos(\theta)")
        b2 = OneDimBinning(name="energy",
                           num_bins=10,
                           is_log=True,
                           domain=[1, 80] * ureg.GeV,
                           tex=r"E")
        b3 = OneDimBinning(name="pid",
                           num_bins=2,
                           bin_edges=[0, 1, 2],
                           tex=r"pid")
        binning = b1 * b2 * b3

        # now let's generate some toy data

        N = 100000
        cz = np.random.normal(1, 1.2, N)
        # cut away coszen outside -1, 1
        cz = cz[(cz >= -1) & (cz <= 1)]
        e = np.random.normal(30, 20, len(cz))
        pid = np.random.uniform(0, 2, len(cz))
        data = np.array([cz, e, pid]).T

        # make numpy histogram for validation
        bins = [unp.nominal_values(b.bin_edges) for b in binning]
        raw_hist, _ = np.histogramdd(data, bins=bins)

        # get KDE'ed histo
        hist = kde_histogramdd(
            data,
            binning,
            bw_method="silverman",
            coszen_name="coszen",
            oversample=10,
            use_cuda=True,
            stack_pid=True,
        )

        # put into mapsets and plot
        m1 = Map(name="KDE", hist=hist, binning=binning)
        m2 = Map(name="raw", hist=raw_hist, binning=binning)
        with np.errstate(divide="ignore", invalid="ignore"):
            m3 = m2 / m1
        m3.name = "hist/KDE"
        m3.tex = m3.name
        m4 = m1 - m2
        m4.name = "KDE - hist"
        m4.tex = m4.name
        ms = MapSet([m1, m2, m3, m4])
        my_plotter.plot_2d_array(ms, fname="test_kde", cmap="summer")
    except:
        rmtree(temp_dir)
        raise
    else:
        logging.warning("Inspect and manually clean up output(s) saved to %s" %
                        temp_dir)
Esempio n. 25
0
def main():
    """main"""
    args = parse_args()
    kwargs = vars(args)
    set_verbosity(kwargs.pop('v'))
    test_example_pipelines(**kwargs)
Esempio n. 26
0
    tmp3 = Umat * tmp2
    Hmat_sympy = Qrel * tmp3
    # subtract constant * id
    Hmat_sympy_minus_mumu = Hmat_sympy - Hmat_sympy[1, 1] * eye(3)
    Hmat_sympy_minus_mumu[0, 0] = Hmat_sympy_minus_mumu[0, 0] - 1
    eps_mat_sympy = Hmat_sympy_minus_mumu
    # simplify
    eps_mat_sympy_simpl = simplify(eps_mat_sympy)
    # evaluate
    eps_mat_sympy_eval = eps_mat_sympy_simpl.subs(
        [(eps_scale, eps_scale_val), (eps_prime, eps_prime_val),
         (phi12, phi12_val), (phi13, phi13_val), (phi23, phi23_val),
         (alpha1, alpha1_val), (alpha2, alpha2_val),
         (deltansi, deltansi_val)]
    )
    # real part
    eps_mat_sympy_eval_re = re(eps_mat_sympy_eval)
    # imaginary part
    eps_mat_sympy_eval_im = im(eps_mat_sympy_eval)

    # complex numpy array
    return (
        np.array(eps_mat_sympy_eval_re) + np.array(eps_mat_sympy_eval_im) * 1.j
    ).astype(CTYPE)


if __name__ == '__main__':
    set_verbosity(Levels.INFO)
    test_nsi_params()
    test_nsi_parameterization()
Esempio n. 27
0
                        choices=['H0', 'scan', 'feldman_cousins'],
                        default='H0',
                        help='''just run significance or whole scan''')
    parser.add_argument('--range',
                        type=str,
                        default='np.linspace(0,2,11)*ureg.dimensionless',
                        help=''' scanning range''')
    parser.add_argument('-f',
                        '--function',
                        type=str,
                        choices=['profile', 'fit'],
                        default='profile',
                        help='''what shpuld be executed''')
    args = parser.parse_args()

    set_verbosity(args.v)

    if os.path.isfile(args.outfile):
        print("Output file ", args.outfile,
              " already existed, delete or remove it.")
    else:
        if args.blind:
            assert (args.function == 'fit')
            assert (args.pseudo_data == 'data')

        if args.data_settings is None:
            data_settings = args.template_settings
        else:
            data_settings = args.data_settings

        data_maker = DistributionMaker(data_settings)
Esempio n. 28
0
                        '--outfile',
                        dest='outfile',
                        metavar='FILE',
                        type=str,
                        action='store',
                        default="event_rate.json",
                        help='''file to store the output''')
    parser.add_argument('-v',
                        '--verbose',
                        action='count',
                        default=None,
                        help='''set verbosity level''')
    args = parser.parse_args()

    #Set verbosity level
    set_verbosity(args.verbose)

    #Check binning
    ebins, czbins = check_binning(args.osc_flux_maps)

    logging.info("Defining aeff_service...")

    if args.mc_mode:
        logging.info("  Using effective area from EVENT DATA...")
        aeff_service = AeffServiceMC(ebins,
                                     czbins,
                                     aeff_weight_file=args.weighted_aeff_file)
    else:
        logging.info("  Using effective area from PARAMETRIZATION...")
        aeff_settings = from_json(find_resource(args.settings_file))
        aeff_service = AeffServicePar(ebins, czbins, **aeff_settings)
Esempio n. 29
0
def parse_args():
    """Parse command line arguments and return as a dict.

    Returns
    -------
    kwargs

    """
    parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        '--template-settings',
        metavar='CONFIGFILE',
        required=True,
        action='append',
        help='''Settings for generating template distributions; repeat
        this option to define multiple pipelines.''')
    parser.add_argument(
        '--steps',
        type=int,
        required=True,
        help='''Provide a number of steps to scan the likelihood space over.'''
    )
    parser.add_argument(
        '--hypo-param-selections',
        type=str,
        nargs='+',
        required=False,
        help='''Selection of params to use in order to generate the
        hypothesised Asimov distributions.''')
    parser.add_argument('--outdir',
                        required=True,
                        metavar='DIR',
                        type=str,
                        help='Directory into which to store results.')
    parser.add_argument(
        '--minimizer-settings',
        type=str,
        metavar='JSONFILE',
        required=True,
        help='''Settings related to the minimizer used in the LLR analysis.''')
    parser.add_argument(
        '--metric',
        type=str,
        choices=['llh', 'chi2', 'conv_llh', 'mod_chi2'],
        required=True,
        help='''Settings related to the minimizer used in the LLR analysis.''')
    parser.add_argument(
        '--debug-mode',
        type=int,
        choices=[0, 1, 2],
        required=False,
        default=1,
        help='''How much information to keep in the output file. 0 for only
        essentials for a physics analysis, 1 for more minimizer history, 2 for
        whatever can be recorded.''')
    parser.add_argument('-v',
                        action='count',
                        default=None,
                        help='set verbosity level')
    kwargs = vars(parser.parse_args())
    set_verbosity(kwargs.pop('v'))
    return kwargs
Esempio n. 30
0
    B = numba.cuda.to_device(np.zeros((3, 3), dtype=FTYPE))

    copy_matrix_guf(A, B)

    test = B.copy_to_host()
    ref = A.copy_to_host()
    assert np.array_equal(test, ref), f"test:\n{test}\n!= ref:\n{ref}"

    logging.info("<< PASS : test_copy_matrix >>")


# --------------------------------------------------------------------------- #


def parse_args():
    """parse command line args"""
    parser = ArgumentParser()
    parser.add_argument("-v", action="count", default=Levels.WARN, help="Verbosity")
    args = parser.parse_args()
    return vars(args)


if __name__ == "__main__":
    set_verbosity(parse_args()["v"])
    test_conjugate_transpose()
    test_conjugate()
    test_matrix_dot_matrix()
    test_matrix_dot_vector()
    test_clear_matrix()
    test_copy_matrix()
Esempio n. 31
0
                    '"%s", max. abs. fract. diff.: %s' %
                    (len(mus), impl, np.max(np.abs((test_unw / ref_unw - 1)))))
            if not recursiveEquality(test_w, ref_w):
                err_msgs.append(
                    'BAD RESULT (weighted), n_gaus=%d, implementation="%s"'
                    ', max. abs. fract. diff.: %s' %
                    (len(mus), impl, np.max(np.abs((test_w / ref_w - 1)))))
            if err_msgs:
                for err_msg in err_msgs:
                    logging.error(err_msg)
                raise ValueError('\n'.join(err_msgs))

    tprofile.debug(
        'gaussians() timings (unweighted) (Note:OMP_NUM_THREADS=%d; evaluated'
        ' at %.0e points)', OMP_NUM_THREADS, n_eval)
    timings_str = '  '.join([format(t, '10d') for t in n_gaus])
    tprofile.debug(' ' * 30 + 'Number of gaussians'.center(59))
    tprofile.debug('         %15s       %s', 'impl.', timings_str)
    timings_str = '  '.join(['-' * 10 for t in n_gaus])
    tprofile.debug('         %15s       %s', '-' * 15, timings_str)
    for impl in GAUS_IMPLEMENTATIONS:
        # only report timings for unweighted case
        timings_str = '  '.join([format(t[0], '10.3f') for t in timings[impl]])
        tprofile.debug('Timings, %15s (ms): %s', impl, timings_str)
    logging.info('<< PASS : test_gaussians >>')


if __name__ == "__main__":
    set_verbosity(2)
    test_gaussians()