Пример #1
0
    def load(self):
        # Run default loading
        templates.Templates.load(self)

        mc_channels = set(["mc", ])
        channel.expand(self._channel_config, mc_channels)

        for var in ['pt', 'eta', 'phi']:
            for flavor in ['b', 'c', 'l']:
                key = '%s_%cjet' % (var, flavor)
                input = '/BTagEff_Chi2sel/%s_%cJet' % (var, flavor)
                for channel_, plot_ in self.plots[input].items():
                    if "data" == channel_ or "qcd" == channel_:
                        break
                    elif channel_ in mc_channels:
                        if key in self._btag:
                            self._btag[key].Add(plot_)
                            self._btag[key+'_btag'].Add(self.plots[input+'_bTag'][channel_])
                        else:
                            self._btag[key] = plot_.Clone()
                            self._btag[key+'_btag'] = self.plots[input+'_bTag'][channel_].Clone()
Пример #2
0
    def load(self):
        '''
        Load all channels into memory

        Child classes may explicitly call this function to load plots
        '''

        bg_channels = set(["mc", ])
        channel.expand(self._channel_config, bg_channels)
        for channel_ in self._channels:
            ch_loader = self._channel_loader(self._prefix,
                                             verbose=self._verbose)
            ch_loader.load(self._channel_config, self._plot_config, channel_,
                           plot_patterns=self._plot_patterns)

            channel_scale_ = (self._channel_scale and
                              self._channel_scale.get(channel_, None))

            if self._verbose and channel_scale_:
                print("custom scale", channel_,
                      "x{0:.3f}".format(channel_scale_))

            # Channel plots are loaded. Store plots in the dictionary with
            # keys equal to plot name and values are dictionaries with keys
            # being the channel and values are plots; scale the plots if scale
            # is provided
            #
            for key, hist in ch_loader.plots.items():
                if key not in self.plots:
                    self._plots[key] = {}

                if channel_scale_:
                    hist.Scale(channel_scale_)

                if self._bg_error and channel_ in bg_channels:
                    error.add(hist, self._bg_error)

                self._plots[key][channel_] = hist

            del(ch_loader)
Пример #3
0
    def __init__(self, options, args, config):
        SignalOverBackground.__init__(self, options, args, config)

        self._background_channels = set(["mc", ])
        channel.expand(self._channel_config, self._background_channels)
Пример #4
0
    def __init__(self, options, args, config,
                 channel_loader=loader.ChannelLoader):

        self._verbose = (options.verbose if options.verbose
                         else config["core"]["verbose"])

        self._batch_mode = (options.batch if options.batch
                            else config["core"]["batch"])

        if self._batch_mode and not options.save and self._verbose:
            print("warning: script is run in batch mode but canvases are not "
                  "saved")

        # load channel configuration
        #
        channel_config = (options.channel_config if options.channel_config
                          else config["template"]["channel"])
        if not channel_config:
            raise RuntimeError("channel config is not defined")

        self._channel_config = channel.load(os.path.expanduser(channel_config))

        # load channel scale(s)
        #
        self._channel_scale = (
                scale.load(os.path.expanduser(options.channel_scale),
                           self._channel_config)
                if options.channel_scale
                else None)

        # load plot configuration
        #
        plot_config = (options.plot_config if options.plot_config
                        else config["template"]["plot"])

        if not plot_config:
            raise RuntimeError("plot config is not defined")

        self._plot_config = plot.load(os.path.expanduser(plot_config))

        # Get list of channels to be loaded
        #
        if not options.channels:
            raise RuntimeError("no channels are specified")

        use, ban = split_use_and_ban(ch.strip()
                                     for ch in options.channels.split(','))
        if not use:
            raise RuntimeError("no channels are turned ON")

        use = channel.expand(self._channel_config, use, verbose=self._verbose)

        if ban:
            use -= channel.expand(self._channel_config, ban,
                                  verbose=self._verbose)

        if not use:
            raise RuntimeError("all channels are turned OFF")

        self._channels = use

        # Loaded plots are kept in the structures like:
        # plot_name: {
        #   channel1: hist_obj,
        #   channel2: hist_obj,
        #   etc.
        # }
        #
        self._plots = {}
        self._channel_loader = channel_loader
        self._prefix = options.prefix
        if options.save:
            value = options.save.lower()

            if value not in ["ps", "pdf"]:
                raise RuntimeError("unsupported save format: " + value)

            self._save = value
        else:
            self._save = False

        self._bg_error = options.bg_error
        if self._bg_error:
            self._bg_error = float(self._bg_error)
            if not (0 <= self._bg_error <= 100):
                raise RuntimeError("background error is out of range")
            else:
                self._bg_error /= 100

        self._label = options.label or os.getenv("EXO_PLOT_LABEL", None)
        self._sub_label = options.sub_label or os.getenv("EXO_PLOT_SUBLABEL",
                                                         None)

        if options.plots:
            self._plot_patterns = options.plots.split(':')
        else:
            self._plot_patterns = []

        self._legend_align = "right"
        self._legend_valign = "top"

        self._log = options.log
        self._ratio= options.ratio
Пример #5
0
    def plot(self):
        '''
        Process loaded histograms and draw them

        The plot() method is responsible for processing loaded channels, e.g.
        put data into Stack, conbine signals, etc.
        '''

        canvases = []
        bg_channels = set(["mc", "qcd"])
        channel.expand(self._channel_config, bg_channels)

        for plot_, channels in self.plots.items():
            # Prepare stacks for data, background and signal
            signal = ROOT.THStack()
            background = ROOT.THStack()
            data = None
            legend = ROOT.TLegend(0, 0, 0, 0) # coordinates will be adjusted

            # prepare channels order and append any missing channels to the
            # end in random order
            order = self._channel_config["order"]
            order.extend(set(channels.keys()) - set(order))

            # process channels in order
            backgrounds = [] # backgrounds should be added to THStack in
                             # reverse order to match legend order
            for channel_ in order:
                if channel_ not in channels:
                    continue

                hist = channels[channel_]
                if channel_ in bg_channels:
                    backgrounds.append(hist)
                    label = "fe"

                elif (channel_.startswith("zp") or
                      channel_.startswith("rsg")):
                    # Signal order does not matter
                    signal.Add(hist)
                    label = "l"

                elif channel_ == "data":
                    data = hist
                    label = "lpe"

                legend.AddEntry(hist,
                                self._channel_config["channel"][channel_]
                                                    ["legend"],
                                label)

            # Add backgrounds to the Stack
            if backgrounds:
                map(background.Add, reversed(backgrounds))

            canvas = self.draw_canvas(plot_,
                                      signal=signal, background=background,
                                      data=data, legend=legend)
            if canvas:
                canvases.append(canvas)

        return canvases
Пример #6
0
    def load(self):
        # Run default loading
        templates.Templates.load(self)

        # Run TFraction Fitter to get MC and QCD scales
        try:
            if self._verbose:
                print("{0:-<80}".format("-- TFractionFitter "))

            if self._tff_input not in self.plots:
                raise RuntimeError("load plot " + self._tff_input)

            # Extract met DATA, QCD and MC
            met = {}
            mc_channels = set(["mc"])
            channel.expand(self._channel_config, mc_channels)
            for channel_, plot_ in self.plots[self._tff_input].items():
                if "data" == channel_:
                    met["data"] = plot_
                elif "qcd" == channel_:
                    met["qcd"] = plot_
                elif channel_ in mc_channels:
                    if "mc" in met:
                        met["mc"].Add(plot_)
                    else:
                        met["mc"] = plot_.Clone()

            print(met.keys())

            missing_channels = set(["data", "qcd", "mc"]) - set(met.keys())
            if missing_channels:
                raise RuntimeError("channels {0!r} are not loaded".format(missing_channels))

            # prepare variable tempaltes for TFractionFitter
            templates_ = ROOT.TObjArray(2)
            templates_.Add(met["mc"])
            templates_.Add(met["qcd"])

            # Setup TFractionFitter
            fitter = ROOT.TFractionFitter(met["data"], templates_)

            # Run TFRactionFitter
            fit_status = fitter.Fit()
            if fit_status:
                raise RuntimeError("fitter error {0}".format(fit_status))

            # Extract MC and QCD scales from TFractionFitter and keep
            # only central values (drop errors)
            fraction = ROOT.Double(0)
            fraction_error = ROOT.Double(0)
            fractions = {}
            fraction_errors = {}
            scales = {}
            scale_errors = {}

            data_integral_ = met["data"].Integral(0, met["data"].GetNbinsX() + 1)
            qcd_integral_ = met["qcd"].Integral(0, met["qcd"].GetNbinsX() + 1)
            mc_integral_ = met["mc"].Integral(0, met["mc"].GetNbinsX() + 1)

            mc_integral_error_ = 0.0
            for i in range(0, met["mc"].GetNbinsX() + 2):
                mc_integral_error_ = mc_integral_error_ + met["mc"].GetBinError(i) ** 2
            mc_integral_error_ = math.sqrt(mc_integral_error_) / mc_integral_

            fitter.GetResult(0, fraction, fraction_error)
            fractions["mc"] = float(fraction)
            fraction_errors["mc"] = float(fraction_error) / float(fraction)
            scales["mc"] = float(fraction) * data_integral_ / mc_integral_
            scale_errors["mc"] = math.sqrt((1 / data_integral_) + mc_integral_error_ ** 2 + fraction_errors["mc"] ** 2)

            fitter.GetResult(1, fraction, fraction_error)
            fractions["qcd"] = float(fraction)
            fraction_errors["qcd"] = float(fraction_error) / float(fraction)
            scales["qcd"] = float(fraction) * data_integral_ / qcd_integral_
            scale_errors["qcd"] = math.sqrt(
                (1 / data_integral_) + mc_integral_error_ ** 2 + fraction_errors["qcd"] ** 2
            )

            # Print found fractions
            if self._verbose:
                print(
                    "\n".join(
                        "{0:>3} fraction: {1:.3f} +- {2:.1f}%".format(key.upper(), value, 100 * fraction_errors[key])
                        for key, value in fractions.items()
                    )
                )
                print(
                    "\n".join(
                        "{0:>3} scale: {1:.3f} +- {2:.1f}%".format(key.upper(), value, 100 * scale_errors[key])
                        for key, value in scales.items()
                    )
                )

            # Scale all MC and QCD samples with fractions
            for plot_, channels_ in self.plots.items():
                # Skip normalization if one of the channels is missing
                if "data" not in channels_ or "qcd" not in channels_:
                    continue

                # Get MC sum
                mc_sum_ = None
                for channel_, hist_ in channels_.items():
                    if channel_ in mc_channels:
                        if mc_sum_:
                            mc_sum_.Add(hist_)
                        else:
                            mc_sum_ = hist_.Clone()

                if not mc_sum_:
                    continue

                data_integral_ = channels_["data"].Integral()
                for channel_, hist_ in channels_.items():
                    if channel_ in mc_channels:
                        hist_.Scale(scales["mc"])
                    elif "qcd" == channel_:
                        hist_.Scale(scales["qcd"])

        except RuntimeError as error:
            if self._verbose:
                print("failed to use TFractionFitter - {0}".format(error), file=sys.stderr)

        finally:
            if self._verbose:
                print()
Пример #7
0
    def plot(self):
        """ Process loaded histograms and draw these """

        # the main executable script should make sure only one plot is loaded:
        # /cutflow or /cutflow_no_weight
        channels = self.plots[self.plots.keys().pop()]

        signal_channels = set(["zp", "zpwide", "kk"])
        channel.expand(self._channel_config, signal_channels)

        background_channels = set(["mc"])
        channel.expand(self._channel_config, background_channels)

        signal_ = {}
        background_ = {}
        total_background_ = None
        data_ = None
        for channel_, hist in channels.items():
            if channel_ in signal_channels:
                signal_[channel_] = cutflow(hist)
            elif channel_ in background_channels:
                background_[channel_] = cutflow(hist)
                if not total_background_:
                    total_background_ = hist.Clone()
                else:
                    total_background_.Add(hist)
            elif channel_ == "data":
                data_ = cutflow(hist)

        total_background_ = cutflow(total_background_)

        channel_names = (
            {
                "zprime_m1000_w10": r"Z' 1 Tev/c\textsuperscript{2}",
                "zprime_m2000_w20": r"Z' 2 Tev/c\textsuperscript{2}",
                "zprime_m3000_w30": r"Z' 3 Tev/c\textsuperscript{2}",
                "stop": r"Single-Top",
                "zjets": r"$Z/\gamma^{\ast}\rightarrow l^{+}l^{-}$",
                # "wjets": r"$W\rightarrow l\nu$",
                "wb": r"$W\rightarrow l\nu$ (bX)",
                "wc": r"$W\rightarrow l\nu$ (cX)",
                "wlight": r"$W\rightarrow l\nu$ (lightX)",
                "ttbar": r"QCD $t\bar{t}$",
            }
            if "text" != self._print_mode
            else {
                "zprime_m1000_w10": r"Z' 1 Tev",
                "zprime_m2000_w20": r"Z' 2 Tev",
                "zprime_m3000_w30": r"Z' 3 Tev",
                "stop": r"Single-Top",
                "zjets": r"Z/gamma -> l+ l-",
                # "wjets": r"W -> l nu",
                "wb": r"W-> l nu (bX)",
                "wc": r"W-> l nu (cX)",
                "wlight": r"W-> l nu (lightX)",
                "ttbar": r"QCD ttbar",
            }
        )

        print_function = print_cutflow_in_text if self._print_mode == "text" else print_cutflow_in_tex

        fields_to_print = [["jets", "electron", "veto_lepton", "twod_cut"], ["jet1", "htlep", "tricut", "met"]]
        if self._non_threshold:
            fields_to_print.append(["chi2", "non_threshold", "eff"])
            for samples_cutflow_ in (signal_, background_):
                if not samples_cutflow_:
                    continue

                for channel_, cutflow_ in samples_cutflow_.items():
                    cutflow_["eff"] = efficiency(cutflow_.get("non_threshold", 0), cutflow_.get("chi2", 0))

            for cutflow_ in (total_background_, data_):
                cutflow_["eff"] = efficiency(cutflow_.get("non_threshold", 0), cutflow_.get("chi2", 0))

        for fields in fields_to_print:
            print_function(None, None, fields)

            for channel_ in self._channel_config["order"]:
                if not channel_.startswith("zprime") or channel_ not in signal_:

                    continue

                print_function(channel_names.get(channel_, channel_), signal_[channel_], fields)

            for channel_ in ["stop", "zjets", "wb", "wc", "wlight", "ttbar"]:
                if channel_ not in background_:
                    continue

                print_function(channel_names.get(channel_, channel_), background_[channel_], fields)

            print_function("Total MC", total_background_, fields)

            if data_:
                print_function("Data 2011", data_, fields)

            print()

        return None