def test_tgraph_asymm_errors_correlation(self): """ Check that the uncertainties are calculated correctly with a correlation coefficient different from 0 """ n_graph = get_random_graph(r.TGraphAsymmErrors, 5) d_graph = get_random_graph(r.TGraphAsymmErrors, 5) rho = np.random.uniform(-1, 1, 1) r_graph = gu.divide_graphs(n_graph, d_graph, rho) # Just to be sure that there is no influence on the ratio check it # All checks concerning x-direction are not done here! y_vals = np.array(r_graph.GetY()) yn_vals = np.array(n_graph.GetY()) yd_vals = np.array(d_graph.GetY()) npt.assert_allclose(y_vals, yn_vals / yd_vals) _, _, yle, yhe = gu.get_errors(r_graph) _, _, ydle, ydhe = gu.get_errors(d_graph) _, _, ynle, ynhe = gu.get_errors(n_graph) anl_errs = self._get_analytic_err(yn_vals, yd_vals, ynle, ydle, rho) npt.assert_allclose(yle, anl_errs) anh_errs = self._get_analytic_err(yn_vals, yd_vals, ynhe, ydhe, rho) npt.assert_allclose(yhe, anh_errs)
def test_tgraph_asymm_errors(self): """Test that TGraphAsymmErrors are handled correctly""" n_vals = 25 x_vals = np.random.uniform(0, 10, n_vals) y_vals = np.random.uniform(0, 10, n_vals) xl_errs = np.random.uniform(0, 1, n_vals) yl_errs = np.random.uniform(0, 1, n_vals) xh_errs = np.random.uniform(0, 1, n_vals) yh_errs = np.random.uniform(0, 1, n_vals) in_graph = r.TGraphAsymmErrors(n_vals, x_vals, y_vals, xl_errs, xh_errs, yl_errs, yh_errs) r_low, r_high = 3, 8 in_range_idcs = (x_vals > r_low) & (x_vals < r_high) r_graph = gu.graph_in_range(in_graph, r_low, r_high) self.assertTrue(isinstance(r_graph, r.TGraphAsymmErrors)) npt.assert_allclose(np.array(r_graph.GetX()), x_vals[in_range_idcs]) npt.assert_allclose(np.array(r_graph.GetY()), y_vals[in_range_idcs]) rlx_errs, rhx_errs, rly_errs, rhy_errs = gu.get_errors(r_graph) npt.assert_allclose(rlx_errs, xl_errs[in_range_idcs]) npt.assert_allclose(rly_errs, yl_errs[in_range_idcs]) npt.assert_allclose(rhx_errs, xh_errs[in_range_idcs]) npt.assert_allclose(rhy_errs, yh_errs[in_range_idcs])
def remove_y_errors(graph): """ Get a (copy) of the passed graph with removed y errors """ x_vals, y_vals = np.array(graph.GetX()), np.array(graph.GetY()) x_lo, x_hi, _, _ = get_errors(graph) return r.TGraphAsymmErrors(len(x_vals), x_vals, y_vals, x_lo, x_hi)
def remove_x_errors(graph): """ Get a (copy) of the passed graph with removed x errors """ x_vals, y_vals = np.array(graph.GetX()), np.array(graph.GetY()) _, _, y_lo, y_hi = get_errors(graph) nbins = len(x_vals) x_err = np.zeros(nbins, dtype=float) return r.TGraphAsymmErrors(nbins, x_vals, y_vals, x_err, x_err, y_lo, y_hi)
def test_tgraph_errors(self): graph = get_random_graph(r.TGraphErrors) xerr, yerr = gu.get_errors(graph) root_x_err, root_y_err = [], [] for i in xrange(graph.GetN()): root_x_err.append(graph.GetErrorX(i)) root_y_err.append(graph.GetErrorY(i)) npt.assert_allclose(np.array(root_x_err), xerr) npt.assert_allclose(np.array(root_y_err), yerr)
def test_tgraph_errors(self): """Check that the TGraphErrors are handled correctly""" n_graph = get_random_graph(r.TGraphErrors, 5) d_graph = get_random_graph(r.TGraphErrors, 5) r_graph = gu.divide_graphs(n_graph, d_graph) npt.assert_allclose( np.array(r_graph.GetY()), np.array(n_graph.GetY()) / np.array(d_graph.GetY())) npt.assert_allclose(np.array(r_graph.GetX()), np.array(n_graph.GetX())) x_errs, y_errs = gu.get_errors(r_graph) xn_errs, yn_errs = gu.get_errors(n_graph) npt.assert_allclose(x_errs, xn_errs) _, yd_errs = gu.get_errors(d_graph) an_errs = self._get_analytic_err(np.array(n_graph.GetY()), np.array(d_graph.GetY()), yn_errs, yd_errs) npt.assert_allclose(y_errs, an_errs)
def test_tgraph_asymm_errors(self): """Check that TGraphAsymmErrors are handled correctly""" n_graph = get_random_graph(r.TGraphAsymmErrors, 5) d_graph = get_random_graph(r.TGraphAsymmErrors, 5) r_graph = gu.divide_graphs(n_graph, d_graph) xn_vals, yn_vals = np.array(n_graph.GetX()), np.array(n_graph.GetY()) yd_vals = np.array(d_graph.GetY()) x_vals, y_vals = np.array(r_graph.GetX()), np.array(r_graph.GetY()) npt.assert_allclose(y_vals, yn_vals / yd_vals) npt.assert_allclose(x_vals, xn_vals) xle, xhe, yle, yhe = gu.get_errors(r_graph) xnle, xnhe, ynle, ynhe = gu.get_errors(n_graph) _, _, ydle, ydhe = gu.get_errors(d_graph) npt.assert_allclose(xle, xnle) npt.assert_allclose(xhe, xnhe) anl_errs = self._get_analytic_err(yn_vals, yd_vals, ynle, ydle) npt.assert_allclose(yle, anl_errs) anh_errs = self._get_analytic_err(yn_vals, yd_vals, ynhe, ydhe) npt.assert_allclose(yhe, anh_errs)
def get_combined_graph(stat, syst): """ Get the combined graph of the statistical and systematical uncertainties (added in quadrature) """ syst_uncer = np.array(syst.GetY()) # stored in y-values n_bins = len(syst_uncer) xlow, xhigh, ylow, yhigh = get_errors(stat) xcentral, ycentral = np.array(stat.GetX()), np.array(stat.GetY()) ylow = np.sqrt(ylow**2 + syst_uncer**2) yhigh = np.sqrt(yhigh**2 + syst_uncer**2) return r.TGraphAsymmErrors(n_bins, xcentral, ycentral, xlow, xhigh, ylow, yhigh)
def test_tgraph_asymm_errors(self): graph = get_random_graph(r.TGraphAsymmErrors) xlo, xhi, ylo, yhi = gu.get_errors(graph) rxlo, rxhi, rylo, ryhi = [], [], [], [] for i in xrange(graph.GetN()): rxlo.append(graph.GetErrorXlow(i)) rxhi.append(graph.GetErrorXhigh(i)) rylo.append(graph.GetErrorYlow(i)) ryhi.append(graph.GetErrorYhigh(i)) npt.assert_allclose(np.array(rxlo), xlo) npt.assert_allclose(np.array(rxhi), xhi) npt.assert_allclose(np.array(rylo), ylo) npt.assert_allclose(np.array(ryhi), yhi)
def calc_chi2(pred_hist, data_graph): """ Calculate the chi2 between the predictor histogram and the data graph """ # Need to select the bins without over- and underflow bin here pred = np.array([b for b in pred_hist][1:pred_hist.GetNbinsX() + 1]) data_central = np.array(data_graph.GetY()) _, _, data_err, _ = get_errors(data_graph) def chisquare((norm,)): return np.sum((( norm * pred - data_central) / data_err)**2) min_res = minimize(chisquare, np.array(data_central[0]), method='nelder-mead') fit_norm = min_res.x[0] return np.sum(((fit_norm * pred - data_central) / data_err)**2), fit_norm
def setUp(self): self.func = r.TF1('test_func', '[0] * (1 + [1] * x[0] + [2] * x[0]*x[0])', -2, 2) self.func.SetParameters(1, 2.0, -2.0) self.func_x_max = 2 self.func_x_min = -2 self.func_y_min = -11 self.func_y_max = 1.5 # Use TGraphAsymmErrors with random errors self.graph = r.TGraphAsymmErrors(10, np.linspace(0, 4, 10), np.sqrt(np.linspace(4, 16, 10)), np.random.uniform(size=10), np.random.uniform(size=10), np.random.uniform(size=10), np.random.uniform(size=10)) gxlo, gxhi, gylo, gyhi = get_errors(self.graph) graph_x = np.array(self.graph.GetX()) graph_y = np.array(self.graph.GetY()) self.graph_x_max = np.max(graph_x + gxhi) self.graph_x_min = np.min(graph_x - gxlo) self.graph_y_max = np.max(graph_y + gyhi) self.graph_y_min = np.min(graph_y - gylo) self.hist = r.TH1D(create_random_str(8), '', 10, -3, 1) self.hist.Fill(-1) # Fill one event into each bin to have non-trivial results for i in xrange(12): self.hist.Fill(-3.2 + 4.0 / 10 * i) self.hist_x_max = 1 self.hist_x_min = -3 self.hist_y_max = 2 self.hist_y_min = 1 # For 2D histograms we don't need to fill the histogram since the min # and max values do not depend on it self.hist2d = r.TH2D(create_random_str(8), '', 10, -3, 1, 10, 4, 5) self.hist2d_x_max = 1 self.hist2d_x_min = -3 self.hist2d_y_max = 5 self.hist2d_y_min = 4
def get_largest_dev_graph(diff_graphs): """ Get the graph containing in each point the largest deviation from 0 as uncertainties. The uncertainties of the input graphs are ignored for now. """ y_vals = np.array([g.GetY() for g in diff_graphs]) max_dev = np.max(y_vals, axis=0) min_dev = -np.min(y_vals, axis=0) # Clean up negative values so that the graphs can be plotted max_dev *= (max_dev > 0) min_dev *= (min_dev > 0) # Assume that all of them have the same binning elo, ehi, _, _ = get_errors(diff_graphs[0]) xval = np.array(diff_graphs[0].GetX()) return r.TGraphAsymmErrors(len(elo), xval, np.zeros_like(elo), elo, ehi, min_dev, max_dev)
def get_corrected_ratio(data, wsp, model, sym_uncer=False, dbg_file=None): """ Get the corrected ratio in all bins """ logging.info('Getting corrected ratio with {} errors'. format('HESSE' if sym_uncer else 'MINOS')) corr_ratio = [] # NOTE: Assuming here that the bins are ordered correctly AND that the for label, bounds in model.bins.iteritems(): selections = [] for ivar, var in enumerate(model.bin_cut_vars): selections.append(select_bin(var, *bounds[ivar])) bin_data = apply_selections(data, selections) chi1_prob, chi2_prob = get_state_fractions(bin_data, wsp, model, label) print_info('chi1', bin_data, chi1_prob) print_info('chi2', bin_data, chi2_prob) if dbg_file is not None: debug_plots('chi1_{}'.format(label), dbg_file, chi1_prob, bin_data.corr_chi1, bin_data.chicMass) debug_plots('chi2_{}'.format(label), dbg_file, chi2_prob, bin_data.corr_chi2, bin_data.chicMass) chi1_w = bin_data.loc[:, 'corr_chi1'] * chi1_prob chi2_w = bin_data.loc[:, 'corr_chi2'] * chi2_prob chi1_corr = np.sum(chi1_w) chi2_corr = np.sum(chi2_w) corr_ratio.append(chi2_corr / chi1_corr) # Assume that the relative uncertainties are unchanged for the corrected and # the uncorrected graph and use them to determine the uncertainties of the # corrected graph uncorr_graph = get_graph(wsp, model, 'r_chic2_chic1', sym_uncer) xlo, xhi, err_lo, err_hi = get_errors(uncorr_graph) xvals, yvals = np.array(uncorr_graph.GetX()), np.array(uncorr_graph.GetY()) corr_ratio = np.array(corr_ratio) return r.TGraphAsymmErrors(len(corr_ratio), xvals, corr_ratio, xlo, xhi, err_lo / yvals * corr_ratio, err_hi / yvals * corr_ratio)
def calc_chi2(graph, func): """ Calculate the chi2 between the graph and all passed values of norm, lth and dlth (resp. kappa1 and kappa2) """ logging.debug( 'Calculating chi2 for graph \'{}\' and function \'{}\''.format( graph.GetName(), func.__name__)) x_v = np.array(graph.GetX()) ratio_v = np.array(graph.GetY()) _, _, err_lo, err_hi = get_errors(graph) func_vals = func(x_v) # Again let numpy broadcasting to the lifting of getting everything into the # correct shapes. Since ratio_v and the error arrays are only 1 dimensional # this works perfectly diff = ratio_v[:, None] - func_vals err = (diff < 0) * err_hi[:, None] + (diff > 0) * err_lo[:, None] return np.sum((diff**2) / err**2, axis=0)
def dump(graph, direction): """ Dump the graph to a .tex table """ x_vals = np.array(graph.GetX()) y_vals = np.array(graph.GetY()) xlo, xhi, ylo, yhi = get_errors(graph) x_lo, x_hi = x_vals - xlo, x_vals + xhi fmt_str = get_fmt_str(direction) for i, x in enumerate(x_vals): uncer_lo = '{:.4f}'.format(ylo[i]) uncer_hi = '{:.4f}'.format(yhi[i]) if uncer_lo == uncer_hi: uncer = '\pm {}'.format(uncer_lo) else: uncer = '{{}}^{{+{}}}_{{-{}}}'.format(uncer_hi, uncer_lo) print(fmt_str.format(x_lo[i], x_hi[i], x, y_vals[i], uncer))
def make_rel_diff_plot(graph_file, plot_config, variable): """ Make the plot of the relative, scaled differences """ rgraphs = get_variation_graphs(graph_file, '_scaled_rel_diff', plot_config) largest_d_graph = graph_file.Get('largest_dev_r_chic2_chic1') # To have the y-axis in percent rgraphs = [scale_graph(g, 100) for g in rgraphs] largest_d_graph = scale_graph(largest_d_graph, 100) _, _, ylo, yhi = get_errors(largest_d_graph) yran = np.max([np.abs(ylo), np.abs(yhi)]) if yran > YRANGE_REL_DIFF[variable][1]: factor = 1.0 while yran / factor > YRANGE_REL_DIFF[variable][1]: factor *= 2 yran = [v * factor for v in YRANGE_REL_DIFF[variable]] else: yran = YRANGE_REL_DIFF[variable] leg = create_legend(0.675, 0.88, 0.16, plot_config, True) can = mkplot(shift_graphs(rgraphs, HORIZONTAL_SHIFT[variable], 0), drawOpt='PLEX0', yRange=yran, yLabel='scaled relative difference w.r.t. nominal [%]', leg=leg, legEntries=[v[1] for v in plot_config['variations']], **VAR_PLOT[variable]) mkplot(largest_d_graph, can=can, drawOpt='sameE2', attr=LARGE_DEV_ATTR, leg=leg, legEntries=['largest deviation'], legOpt='F') x_range = VAR_PLOT[variable]['xRange'] mkplot(r.TLine(0, 0, x_range[1], 0), can=can, drawOpt='same', attr=LINE_ATTR) return can
def convert_graph(graph, direction): """ Convert the TGraphAsymmErrors to the hepdata expected format See: https://hepdata-submission.readthedocs.io/en/latest/data_yaml.html """ x_vals = np.array(graph.GetX()) x_lo, x_hi, y_lo, y_hi = get_errors(graph) # number of digits after comma for bin-borders and bin-centers depends # on the angle under consideration fmt_bin = lambda x: int(round(x)) fmt_cent = lambda x: round(x, 2) fmt_dep = lambda x: round(x, 4) if direction == 'costh': fmt_bin = lambda x: round(x, 4) fmt_cent = fmt_bin # Create the independent variable table in the format that hepdata expectes table = {} table['independent_variables'] = [{ 'header': { 'name': direction, 'units': '' }, 'values': [] }] for cent, lo, hi in zip(x_vals, x_lo, x_hi): table['independent_variables'][0]['values'].append({ 'low': fmt_bin(cent - lo), 'high': fmt_bin(cent + hi), 'value': fmt_cent(cent) }) # Create the dependent variable table table['dependent_variables'] = [{ 'header': { 'name': 'chi_c2 over chi_c1 ratio' }, 'values': [] }] y_vals = np.array(graph.GetY()) for cent, lo, hi in zip(y_vals, y_lo, y_hi): table['dependent_variables'][0]['values'].append({ 'value': fmt_dep(cent), 'errors': [ # hepdata wants the minus sign in front of the lower errors { 'asymerror': { 'minus': -fmt_dep(lo), 'plus': fmt_dep(hi) }, 'label': 'stat' } ] }) return table