def test_get_limit(self): """ Test main limit setting code """ numpy.random.seed() mu = 5.0 sigma = 1.0 for energy, radius, time in zip( numpy.random.normal(mu, sigma, self._n_events), numpy.random.uniform(self._signal._radial_low, self._signal._radial_high, self._n_events), numpy.random.uniform(self._signal._time_low, self._signal._time_high, self._n_events)): self._signal.fill(energy, radius, time) for background in self._backgrounds: background.fill(energy, radius, time) # Configure signal signal_counts = numpy.arange(1.0, 55.0, 1.0, dtype=float) signal_prior = 18.0 signal_config = limit_config.LimitConfig(signal_prior, signal_counts) # Configure bkg_1 # No penalty term to start with so just an array containing one value bkg_1_counts = numpy.arange(100.0, 101.0, 1.0, dtype=float) bkg_1_prior = 100.0 bkg_1_config = limit_config.LimitConfig(bkg_1_prior, bkg_1_counts) # set chi squared calculator calculator = chi_squared.ChiSquared() # Test 1: test Exceptions limit_setter_1 = limit_setting.LimitSetting( self._signal, floating_backgrounds=self._backgrounds[:1]) self.assertRaises(TypeError, limit_setter_1.get_limit) limit_setter_1.configure_signal(signal_config) self.assertRaises(KeyError, limit_setter_1.get_limit) limit_setter_1.configure_background("bkg_1", bkg_1_config) self.assertRaises(TypeError, limit_setter_1.get_limit) limit_setter_1.set_calculator(calculator) # Test 2: different limits with and without penalty term # Define ROI roi = (mu - sigma, mu + sigma) limit_setter_2 = limit_setting.LimitSetting( self._signal, floating_backgrounds=self._backgrounds[:1], roi=roi, pre_shrink=True) limit_setter_2.configure_signal(signal_config) limit_setter_2.configure_background("bkg_1", bkg_1_config) limit_setter_2.set_calculator(calculator) limit_2 = limit_setter_2.get_limit() # Now try with a penalty term # set new config this time with more background counts to cycle through bkg_1_penalty_counts = numpy.arange(75.0, 125.0, 0.5, dtype=float) bkg_1_sigma = 25.0 # To use in penalty term bkg_1_penalty_config = limit_config.LimitConfig( bkg_1_prior, bkg_1_penalty_counts, bkg_1_sigma) limit_setter_2.configure_background("bkg_1", bkg_1_penalty_config) limit_2_penalty = limit_setter_2.get_limit() self.assertNotEqual(limit_2, limit_2_penalty) # Test 3: Try with a second background # Configure bkg_2 # No penalty term so just an array containing one value bkg_2_counts = numpy.arange(10.0, 11.0, 1.0, dtype=float) bkg_2_prior = 10.0 bkg_2_config = limit_config.LimitConfig(bkg_2_prior, bkg_2_counts) limit_setter_3 = limit_setting.LimitSetting( self._signal, floating_backgrounds=self._backgrounds, roi=roi, pre_shrink=True) limit_setter_3.configure_signal(signal_config) limit_setter_3.configure_background("bkg_1", bkg_1_config) limit_setter_3.configure_background("bkg_2", bkg_2_config) limit_setter_3.set_calculator(calculator) limit_3 = limit_setter_3.get_limit() self.assertNotEqual(limit_2, limit_3) # Check chi squareds have been recorded for each background for config in limit_setter_3._background_configs.values(): chi_squareds = config._chi_squareds self.assertTrue(chi_squareds.shape[1] > 0)
# Shrink spectra to 5 years - livetime used by Andy # And make 3.5m fiducial volume cut Te130_0n2b.shrink(0.0, 10.0, 0.0, 3500.0, 0.0, 5.0) Te130_2n2b.shrink(0.0, 10.0, 0.0, 3500.0, 0.0, 5.0) B8_Solar.shrink(0.0, 10.0, 0.0, 3500.0, 0.0, 5.0) # Create list of backgrounds backgrounds = [] backgrounds.append(Te130_2n2b) backgrounds.append(B8_Solar) # Initialise limit setting class roi = (2.46, 2.68) # Define ROI - as used by Andy set_limit = limit_setting.LimitSetting(Te130_0n2b, backgrounds, roi=roi, pre_shrink=True, verbose=args.verbose) # Configure Te130_0n2b Te130_0n2b_counts = numpy.arange(5.0, 500.0, 5.0, dtype=float) Te130_0n2b_prior = 262.0143 # Based on T_1/2 = 9.94e25 y @ 90% CL # (SNO+-doc-2593-v8) for 5 year livetime # Note extrapolating here to 10 years Te130_0n2b_config = limit_config.LimitConfig(Te130_0n2b_prior, Te130_0n2b_counts) set_limit.configure_signal(Te130_0n2b_config) # Configure Te130_2n2b Te130_2n2b_counts = numpy.arange(11.323579e6, 11.323580e6,
def main(args): """ Script to set 90% CL on all four Majoron-emitting modes. """ # Load signal spectra signals = [] for signal_hdf5 in args.signals: spectrum = store.load(signal_hdf5) print spectrum._name print "Num decays:", spectrum._num_decays print "events:", spectrum.sum() signals.append(spectrum) # Load background spectra floating_backgrounds = [] Te130_2n2b = store.load(args.two_nu) print Te130_2n2b._name Te130_2n2b._num_decays = Te130_2n2b.sum() # Sum not raw events print "Num decays:", Te130_2n2b._num_decays print "events:", Te130_2n2b.sum() floating_backgrounds.append(Te130_2n2b) B8_Solar = store.load(args.b8_solar) print B8_Solar._name B8_Solar._num_decays = B8_Solar.sum() # Sum not raw events print "Num decays:", B8_Solar._num_decays print "events:", B8_Solar.sum() floating_backgrounds.append(B8_Solar) # Apply FV and livetime cuts fv_radius = constants._fv_radius livetime = 1.0 for spectrum in signals: spectrum.cut(time_low=0.0, time_high=livetime) # cut to livetime spectrum.shrink(radial_low=0.0, radial_high=fv_radius) # shrink to FV spectrum.shrink_to_roi(0.5, 3.0, 0) # shrink to ROI for spectrum in floating_backgrounds: spectrum.cut(time_low=0.0, time_high=livetime) # cut to livelime spectrum.shrink(radial_low=0.0, radial_high=fv_radius) # shrink to FV spectrum.shrink_to_roi(0.5, 3.0, 0) # shrink to ROI # Signal configuration signal_configs_np = [] # no penalty term signal_configs = [] prior = 0.0 Te130_0n2b_n1_counts = numpy.linspace(signals[0]._num_decays, 0.0, 100, False) # endpoint=False in linspace arrays Te130_0n2b_n1_config_np = limit_config.LimitConfig(prior, Te130_0n2b_n1_counts) Te130_0n2b_n1_config = limit_config.LimitConfig(prior, Te130_0n2b_n1_counts) signal_configs_np.append(Te130_0n2b_n1_config_np) signal_configs.append(Te130_0n2b_n1_config) Te130_0n2b_n2_counts = numpy.linspace(signals[1]._num_decays, 0.0, 100, False) Te130_0n2b_n2_config_np = limit_config.LimitConfig(prior, Te130_0n2b_n2_counts) Te130_0n2b_n2_config = limit_config.LimitConfig(prior, Te130_0n2b_n2_counts) signal_configs_np.append(Te130_0n2b_n2_config_np) signal_configs.append(Te130_0n2b_n2_config) Te130_0n2b_n3_counts = numpy.linspace(signals[2]._num_decays, 0.0, 100, False) Te130_0n2b_n3_config_np = limit_config.LimitConfig(prior, Te130_0n2b_n3_counts) Te130_0n2b_n3_config = limit_config.LimitConfig(prior, Te130_0n2b_n3_counts) signal_configs_np.append(Te130_0n2b_n3_config_np) signal_configs.append(Te130_0n2b_n3_config) Te130_0n2b_n7_counts = numpy.linspace(signals[3]._num_decays, 0.0, 100, False) Te130_0n2b_n7_config_np = limit_config.LimitConfig(prior, Te130_0n2b_n7_counts) Te130_0n2b_n7_config = limit_config.LimitConfig(prior, Te130_0n2b_n7_counts) signal_configs_np.append(Te130_0n2b_n7_config_np) signal_configs.append(Te130_0n2b_n7_config) # Background configuration # Te130_2n2b Te130_2n2b_prior = 3.7396e6 # Based on NEMO-3 T_1/2, for 1 year livetime # Since we used cut method to cut to livetime # No penalty term Te130_2n2b_counts_np = numpy.array([Te130_2n2b_prior]) Te130_2n2b_config_np = limit_config.LimitConfig(Te130_2n2b_prior, Te130_2n2b_counts_np) # With penalty term Te130_2n2b_counts = numpy.linspace(0.8 * Te130_2n2b_prior, 1.2 * Te130_2n2b_prior, 51) # 51 bins to make sure midpoint (no variation from prior) is included # to use in penalty term (20%, Andy's document on systematics) sigma = 0.2 * Te130_2n2b_prior Te130_2n2b_config = limit_config.LimitConfig(Te130_2n2b_prior, Te130_2n2b_counts, sigma) # B8_Solar # from integrating whole spectrum scaled to Valentina's number B8_Solar_prior = 1252.99691 # No penalty term B8_Solar_counts_np = numpy.array([B8_Solar_prior]) B8_Solar_config_np = limit_config.LimitConfig(B8_Solar_prior, B8_Solar_counts_np) # With penalty term B8_Solar_counts = numpy.linspace(0.96 * B8_Solar_prior, 1.04 * B8_Solar_prior, 11) # 11 bins to make sure midpoint (no variation from prior) is included sigma = 0.04 * B8_Solar_prior # 4% To use in penalty term B8_Solar_config = limit_config.LimitConfig(B8_Solar_prior, B8_Solar_counts, sigma) # DBIsotope converter information - constant across modes isotope_name = "Te130" atm_weight_iso = 129.906229 atm_weight_nat = 127.6 abundance = 0.3408 # Make a list of associated nuclear physics info nuclear_params = [] # n=1: phase_space = 5.94e-16 matrix_element = 3.97 # Averaged nuclear_params.append((phase_space, matrix_element)) # n=2: phase_space = None matrix_element = None nuclear_params.append((phase_space, matrix_element)) # n=1: phase_space = 1.06e-17 # Assuming two Majorons emitted matrix_element = 1.e-3 nuclear_params.append((phase_space, matrix_element)) # n=1: phase_space = 4.83e-17 matrix_element = 1.e-3 nuclear_params.append((phase_space, matrix_element)) # chi squared calculator calculator = chi_squared.ChiSquared() # Set output location output_dir = echidna.__echidna_base__ + "/results/snoplus/" for signal, signal_config_np, nuclear_param in zip(signals, signal_configs_np, nuclear_params): print signal._name # Create no penalty limit setter set_limit_np = limit_setting.LimitSetting( signal, floating_backgrounds=floating_backgrounds) # Configure signal set_limit_np.configure_signal(signal_config_np) # Configure 2n2b set_limit_np.configure_background(Te130_2n2b._name, Te130_2n2b_config_np) # Configure B8 set_limit_np.configure_background(B8_Solar._name, B8_Solar_config_np) # Set converter phase_space, matrix_element = nuclear_param roi_efficiency = signal.get_roi(0).get("efficiency") converter = decay.DBIsotope(isotope_name, atm_weight_iso, atm_weight_nat, abundance, phase_space, matrix_element, roi_efficiency=roi_efficiency) # Set chi squared calculator set_limit_np.set_calculator(calculator) # Get limit try: limit = set_limit_np.get_limit() print "-----------------------------------" print "90% CL at " + str(limit) + " counts" half_life = converter.counts_to_half_life(limit, livetime=livetime) print "90% CL at " + str(half_life) + " yr" print "-----------------------------------" except IndexError as detail: print "-----------------------------------" print detail print "-----------------------------------" for i, signal_config_np in enumerate(signal_configs_np): store.dump_ndarray(output_dir + signals[i]._name + "_np.hdf5", signal_config_np) raw_input("RETURN to continue") signal_num = 0 for signal, signal_config, nuclear_param in zip(signals, signal_configs, nuclear_params): print signal._name # Create limit setter set_limit = limit_setting.LimitSetting( signal, floating_backgrounds=floating_backgrounds) # Configure signal set_limit.configure_signal(signal_config) # Configure 2n2b set_limit.configure_background(Te130_2n2b._name, Te130_2n2b_config, plot_systematic=True) # Configure B8 set_limit.configure_background(B8_Solar._name, B8_Solar_config, plot_systematic=True) # Set converter phase_space, matrix_element = nuclear_param roi_efficiency = signal.get_roi(0).get("efficiency") converter = decay.DBIsotope(isotope_name, atm_weight_iso, atm_weight_nat, abundance, phase_space, matrix_element, roi_efficiency=roi_efficiency) # Set chi squared calculator set_limit.set_calculator(calculator) # Get limit try: limit = set_limit.get_limit() print "-----------------------------------" print "90% CL at " + str(limit) + " counts" half_life = converter.counts_to_half_life(limit, livetime=livetime) print "90% CL at " + str(half_life) + " yr" print "-----------------------------------" except IndexError as detail: print "-----------------------------------" print detail print "-----------------------------------" # Dump SystAnalysers to hdf5 for syst_analyser in set_limit._syst_analysers.values(): store.dump_ndarray( output_dir + syst_analyser._name + str(signal_num) + ".hdf5", syst_analyser) signal_num += 1 # Dump configs to hdf5 for i, signal_config in enumerate(signal_configs): store.dump_ndarray(output_dir + signals[i]._name + ".hdf5", signal_config) store.dump_ndarray(output_dir + "Te130_2n2b_config.hdf5", Te130_2n2b_config) store.dump_ndarray(output_dir + "B8_Solar_config.hdf5", B8_Solar_config)
# from integrating whole spectrum scaled to Valentina's number B8_Solar_prior = 12529.9691 fixed_backgrounds = { Te130_2n2b._name: [Te130_2n2b, Te130_2n2b_prior], B8_Solar._name: [B8_Solar, B8_Solar_prior] } # Create fixed spectrum. Pre-shrink here if pre-shrinking in LimitSetting roi = (2.46, 2.68) # Define ROI - as used by Andy fixed = limit_setting.make_fixed_background(fixed_backgrounds, pre_shrink=True, roi=roi) # Initialise limit setting class set_limit = limit_setting.LimitSetting(Te130_0n2b, fixed_background=fixed, roi=roi, pre_shrink=True, verbose=args.verbose) # Configure Te130_0n2b Te130_0n2b_counts = numpy.arange(5.0, 1000.0, 5.0, dtype=float) Te130_0n2b_prior = 0. # Setting a 90% CL so no signal in observed Te130_0n2b_config = limit_config.LimitConfig(Te130_0n2b_prior, Te130_0n2b_counts) set_limit.configure_signal(Te130_0n2b_config) # Set chi squared calculator calculator = chi_squared.ChiSquared() set_limit.set_calculator(calculator) # Calculate confidence limit