def prepare_args(self, parser, plotData):
        super(CalculateWJetsOSSSFactor, self).prepare_args(parser, plotData)
        self._plotdict_keys = [
            "wjets_from_mc_os_nicks", "wjets_from_mc_ss_nicks"
        ]
        self.prepare_list_args(plotData, self._plotdict_keys)

        def run(self, plotData=None):
            super(CalculateWJetsOSSSFactor, self).run(plotData)

            # make sure that all necessary histograms are available
            for nicks in zip(
                    *[plotData.plotdict[key] for key in self._plotdict_keys]):
                for nick in nicks:
                    if isinstance(nick, basestring):
                        assert isinstance(
                            plotData.plotdict["root_objects"].get(nick),
                            ROOT.TH1)
                    elif not isinstance(nick, bool):
                        for subnick in nick:
                            assert isinstance(
                                plotData.plotdict["root_objects"].get(subnick),
                                ROOT.TH1)

        for wjets_from_mc_os_nicks, wjets_from_mc_ss_nicks in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):

            yield_wj_mc_os = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_from_mc_os_nicks])()
            yield_wj_mc_ss = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_from_mc_ss_nicks])()
            # make sure we don't have negative yields

            yield_wj_mc_os = uncertainties.ufloat(
                max(0.0, yield_wj_mc_os.nominal_value), yield_wj_mc_os.std_dev)
            yield_wj_mc_ss = uncertainties.ufloat(
                max(0.0, yield_wj_mc_ss.nominal_value), yield_wj_mc_ss.std_dev)
            print(yield_wj_mc_os, yield_wj_mc_ss)
            assert (yield_wj_mc_os != 0.0) or (yield_wj_mc_ss != 0.0)
            # the final yield in the signal region is N_data, WJ^{SR} = N_data, WJ^{CR} * N_MC,WJ^{SR} / N_MC,WJ^{CR}
            os_ss_factor = yield_wj_mc_os / yield_wj_mc_ss

            plotData.metadata[wjets_from_mc_os_nicks] = {
                "os_ss_factor":
                os_ss_factor.nominal_value,
                "os_ss_factor_unc":
                os_ss_factor.std_dev,
                "yield_unc_rel":
                abs(os_ss_factor.std_dev / os_ss_factor.nominal_value
                    if os_ss_factor.nominal_value != 0.0 else 0.0),
            }
            plotData.metadata
            print(plotData.metadata)
	def run(self, plotData=None):
		super(EstimateWjets, self).run(plotData)
		
		# make sure that all necessary histograms are available
		for nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			for nick in nicks:
				if isinstance(nick, basestring):
					assert isinstance(plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
				elif not isinstance(nick, bool):
					for subnick in nick:
						assert isinstance(plotData.plotdict["root_objects"].get(subnick), ROOT.TH1)
		
		for wjets_from_mc, wjets_shape_nick, wjets_data_control_nick, wjets_data_substract_nicks, wjets_mc_signal_nick, wjets_mc_control_nick in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			if not wjets_from_mc: # skips the full estimation of this module and uses MC estimate of WJ instead.
				# Get yield and uncertainity in data in the control region
				yield_data_control = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_data_control_nick])()
				for nick in wjets_data_substract_nicks:
					# subtract yields of all backgrounds
					yield_bkg_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
					if nick in plotData.metadata:
						yield_bkg_control = uncertainties.ufloat(
								plotData.metadata[nick].get("yield", yield_bkg_control.nominal_value),
								plotData.metadata[nick].get("yield_unc", yield_bkg_control.std_dev)
						)
					yield_data_control -= yield_bkg_control
				# make sure we don't have negative yields	
				yield_data_control = uncertainties.ufloat(max(0.0, yield_data_control.nominal_value), yield_data_control.std_dev)
				
				yield_mc_signal = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_mc_signal_nick])()
				yield_mc_control = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_mc_control_nick])()
				
				assert (yield_data_control*yield_mc_signal == 0.0) or (yield_mc_control != 0.0)
				# the final yield in the signal region is N_data, WJ^{SR} = N_data, WJ^{CR} * N_MC,WJ^{SR} / N_MC,WJ^{CR}
				final_yield = yield_data_control * yield_mc_signal
				if final_yield != 0.0:
					final_yield /= yield_mc_control
				log.debug("Relative statistical uncertainty of the yield for process W+jets (nick \"{nick}\") is {unc}.".format(nick=wjets_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
				
				plotData.metadata[wjets_shape_nick] = {
					"yield" : final_yield.nominal_value,
					"yield_unc" : final_yield.std_dev,
					"yield_unc_rel" : abs(final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0),
				}
				plotData.metadata
				# scale the wj file by the ratio of the estimated yield and the yield given by MC.
				integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_shape_nick])()
				if integral_shape != 0.0:
					scale_factor = final_yield / integral_shape
					log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_shape_nick, scale_factor=scale_factor))
					plotData.plotdict["root_objects"][wjets_shape_nick].Scale(scale_factor.nominal_value)
	def run(self, plotData=None):
		super(UnpolarisationScaleFactors, self).run(plotData)
		
		for unpolarisation_nominal_nick, unpolarisation_shift_up_nick, unpolarisation_shift_down_nick, unpolarisation_forced_gen_polarisation in zip(*[plotData.plotdict[key] for key in ["unpolarisation_nominal_nicks", "unpolarisation_shift_up_nicks", "unpolarisation_shift_down_nicks", "unpolarisation_forced_gen_polarisations"]]):
		
			scale_factors = {}
			scale_factors_pos = {}
			scale_factors_neg = {}
			for shift, nick in zip(*[["nominal", "shift up", "shift down"], [unpolarisation_nominal_nick, unpolarisation_shift_up_nick, unpolarisation_shift_down_nick]]):
				neg_gen_norm = uncertainties.ufloat(
						plotData.plotdict["root_objects"][nick].GetBinContent(1),
						plotData.plotdict["root_objects"][nick].GetBinError(1)
				)
				pos_gen_norm = uncertainties.ufloat(
						plotData.plotdict["root_objects"][nick].GetBinContent(2),
						plotData.plotdict["root_objects"][nick].GetBinError(2)
				)
				scale_factors[shift] = polarisationsignalscaling.PolarisationScaleFactors(pos_gen_norm, neg_gen_norm, pos_gen_norm, neg_gen_norm, forced_gen_polarisation=unpolarisation_forced_gen_polarisation)
				
				scale_factors_pos[shift] = scale_factors[shift].get_bias_removal_factor_pospol() if plotData.plotdict["unpolarisation_remove_bias_instead_unpolarisation"] else scale_factors[shift].get_scale_factor_pospol()
				log.debug("Positive helicity of \"{nick}\" to be scaled by a factor of {factor} ({shift}).".format(
						nick=nick,
						factor=scale_factors_pos[shift],
						shift=shift
				))
				
				scale_factors_neg[shift] = scale_factors[shift].get_bias_removal_factor_neg_pol() if plotData.plotdict["unpolarisation_remove_bias_instead_unpolarisation"] else scale_factors[shift].get_scale_factor_negpol()
				log.debug("Negative helicity of \"{nick}\" to be scaled by a factor of {factor} ({shift}).".format(
						nick=nick,
						factor=scale_factors_neg[shift],
						shift=shift
				))
			
			total_uncertainties_pos = [abs((scale_factors_pos["shift up"]-scale_factors_pos["nominal"])/scale_factors_pos["nominal"]),
			                           abs((scale_factors_pos["shift down"]-scale_factors_pos["nominal"])/scale_factors_pos["nominal"])]
			total_uncertainties_neg = [abs((scale_factors_neg["shift up"]-scale_factors_neg["nominal"])/scale_factors_neg["nominal"]),
			                           abs((scale_factors_neg["shift down"]-scale_factors_neg["nominal"])/scale_factors_neg["nominal"])]
			
			log.info("Total uncertainties on scale factor for positive helicity = (+) {tot_pos_plus} / (-) {tot_pos_minus}".format(
					tot_pos_plus=total_uncertainties_pos[0],
					tot_pos_minus=total_uncertainties_pos[1]
			))
			log.info("Total uncertainties on scale factor for negative helicity = (+) {tot_neg_plus} / (-) {tot_neg_minus}".format(
					tot_neg_plus=total_uncertainties_neg[0],
					tot_neg_minus=total_uncertainties_neg[1]
			))
	def run(self, plotData=None):
		super(EstimateQcdTauHadTauHad, self).run(plotData)
		
		# make sure that all necessary histograms are available
		for nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			for nick in nicks:
				if isinstance(nick, basestring):
					assert isinstance(plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
				elif (not isinstance(nick, float) and not isinstance(nick, bool)):
					for subnick in nick:
						assert isinstance(plotData.plotdict["root_objects"].get(subnick), ROOT.TH1)
		
		for qcd_data_shape_nick, qcd_data_signal_control_nick, qcd_data_relaxed_control_nick, qcd_data_subtract_nicks, qcd_control_signal_subtract_nicks, qcd_control_relaxed_subtract_nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			
			for nick in qcd_data_subtract_nicks:
				plotData.plotdict["root_objects"][qcd_data_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1.0)
			
			yield_control_signal = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_data_signal_control_nick])()
			for nick in qcd_control_signal_subtract_nicks:
				yield_bgk_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				yield_control_signal -= yield_bgk_control
			yield_control_signal = uncertainties.ufloat(max(0.0, yield_control_signal.nominal_value), yield_control_signal.std_dev)

			yield_control_relaxed = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_data_relaxed_control_nick])()
			for nick in qcd_control_relaxed_subtract_nicks:
				yield_bgk_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				yield_control_relaxed -= yield_bgk_control
			yield_control_relaxed = uncertainties.ufloat(max(0.0, yield_control_relaxed.nominal_value), yield_control_relaxed.std_dev)

			scale_factor = yield_control_signal
			if yield_control_relaxed != 0.0:
				scale_factor /= yield_control_relaxed
			
			log.debug("Scale factor for process QCD (nick \"{nick}\") is {scale_factor}.".format(nick=qcd_data_shape_nick, scale_factor=scale_factor))
			plotData.plotdict["root_objects"][qcd_data_shape_nick].Scale(scale_factor.nominal_value)

			final_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_data_shape_nick])()
			
			log.debug("Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}.".format(nick=qcd_data_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
			
			plotData.metadata[qcd_data_shape_nick] = {
				"yield" : final_yield.nominal_value,
				"yield_unc" : final_yield.std_dev,
				"yield_unc_rel" : abs(final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0),
			}
Exemplo n.º 5
0
    def run(self, plotData=None):
        super(EstimateWjets, self).run(plotData)

        for wjets_from_mc, wjets_shape_nick, wjets_data_control_nick, wjets_data_substract_nicks, wjets_mc_signal_nick, wjets_mc_control_nick in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            if not wjets_from_mc:
                yield_data_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"]
                    [wjets_data_control_nick])()
                for nick in wjets_data_substract_nicks:
                    yield_bkg_control = tools.PoissonYield(
                        plotData.plotdict["root_objects"][nick])()
                    if nick in plotData.metadata:
                        yield_bkg_control = uncertainties.ufloat(
                            plotData.metadata[nick].get(
                                "yield", yield_bkg_control.nominal_value),
                            plotData.metadata[nick].get(
                                "yield_unc", yield_bkg_control.std_dev))
                    yield_data_control -= yield_bkg_control
                yield_data_control = max(0.0, yield_data_control)

                yield_mc_signal = tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_mc_signal_nick])()
                yield_mc_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_mc_control_nick])()

                assert (yield_data_control * yield_mc_signal
                        == 0.0) or (yield_mc_control != 0.0)
                final_yield = yield_data_control * yield_mc_signal
                if final_yield != 0.0:
                    final_yield /= yield_mc_control
                log.debug(
                    "Relative statistical uncertainty of the yield for process W+jets (nick \"{nick}\") is {unc}."
                    .format(nick=wjets_shape_nick,
                            unc=final_yield.std_dev / final_yield.nominal_value
                            if final_yield.nominal_value != 0.0 else 0.0))

                plotData.metadata[wjets_shape_nick] = {
                    "yield":
                    final_yield.nominal_value,
                    "yield_unc":
                    final_yield.std_dev,
                    "yield_unc_rel":
                    abs(final_yield.std_dev / final_yield.nominal_value
                        if final_yield.nominal_value != 0.0 else 0.0),
                }

                integral_shape = tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_shape_nick])()
                if integral_shape != 0.0:
                    scale_factor = final_yield / integral_shape
                    log.debug(
                        "Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}."
                        .format(nick=wjets_shape_nick,
                                scale_factor=scale_factor))
                    plotData.plotdict["root_objects"][wjets_shape_nick].Scale(
                        scale_factor.nominal_value)
Exemplo n.º 6
0
    def run(self, plotData=None):
        super(EstimateTtbar, self).run(plotData)

        for ttbar_shape_nick, ttbar_data_control_nick, ttbar_data_subtract_nicks, ttbar_mc_signal_nick, ttbar_mc_control_nick in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            yield_data_control = tools.PoissonYield(
                plotData.plotdict["root_objects"][ttbar_data_control_nick])()
            #print "data_control_yield from nick " + ttbar_data_control_nick + " : " + str(yield_data_control)
            for nick in ttbar_data_subtract_nicks:
                yield_bkg_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                #print "\t minus " + nick + " : " + str(yield_bkg_control)
                if nick in plotData.metadata:
                    yield_bkg_control = uncertainties.ufloat(
                        plotData.metadata[nick].get(
                            "yield", yield_bkg_control.nominal_value),
                        plotData.metadata[nick].get("yield_unc",
                                                    yield_bkg_control.std_dev))
                yield_data_control -= yield_bkg_control
            #print "data_control_yield final "  + str(yield_data_control)
            yield_data_control = max(0.0, yield_data_control)

            yield_mc_signal = tools.PoissonYield(
                plotData.plotdict["root_objects"][ttbar_mc_signal_nick])()
            yield_mc_control = tools.PoissonYield(
                plotData.plotdict["root_objects"][ttbar_mc_control_nick])()

            #print "data_mc_signal "  + str(yield_mc_signal)
            #print "data_mc_control "  + str(yield_mc_control)
            integral_shape = plotData.plotdict["root_objects"][
                ttbar_shape_nick].Integral()
            final_yield = yield_mc_control / yield_data_control * integral_shape
            log.debug(
                "Relative statistical uncertainty of the yield for process ttbar+jets (nick \"{nick}\") is {unc}."
                .format(nick=ttbar_shape_nick,
                        unc=final_yield.std_dev / final_yield.nominal_value
                        if final_yield.nominal_value != 0.0 else 0.0))

            plotData.metadata[ttbar_shape_nick] = {
                "yield":
                final_yield.nominal_value,
                "yield_unc":
                final_yield.std_dev,
                "yield_unc_rel":
                abs(final_yield.std_dev / final_yield.nominal_value
                    if final_yield.nominal_value != 0.0 else 0.0),
            }

            if integral_shape != 0.0:
                scale_factor = integral_shape / final_yield
                #print "scale factor: " + str(scale_factor)
                log.debug(
                    "Scale factor for process ttbar+jets (nick \"{nick}\") is {scale_factor}."
                    .format(nick=ttbar_shape_nick, scale_factor=scale_factor))
                plotData.plotdict["root_objects"][ttbar_shape_nick].Scale(
                    scale_factor.nominal_value)
	def run(self, plotData=None):
		super(EstimateQcdPrefit, self).run(plotData)
		
		# make sure that all necessary histograms are available
		for nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			for nick in nicks:
				if isinstance(nick, basestring):
					assert isinstance(plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
				elif (not isinstance(nick, float) and not isinstance(nick, bool)):
					for subnick in nick:
						assert isinstance(plotData.plotdict["root_objects"].get(subnick), ROOT.TH1)
		
		for qcd_shape_nick, qcd_yield_nick, qcd_yield_subtract_nicks, qcd_shape_subtract_nicks, qcd_extrapolation_factor_ss_os in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			######################
			# ------- Step 1 -----
			# 1. Get Yield in Control region and subtract all backgrounds.
			yield_qcd = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_yield_nick])()
			# estimate the QCD yield
			for nick in qcd_yield_subtract_nicks:
				yield_bkg = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				yield_qcd -= yield_bkg
			yield_qcd = uncertainties.ufloat(max(0.0, yield_qcd.nominal_value), yield_qcd.std_dev)
			if(yield_qcd.nominal_value == 0.0):
				log.warning("QCD yield is 0!")
			
			######################
			# ------- Step 2 -----	
			#  QCD shape
			# 1. Subtract the shapes of all backgrounds from data in the control region. 
			# 2. Scale the qcd by the qcd_os_ss_extrapolation_factor to get the prefit estimate. 
			# Sidemark: In this script the factor is supposed to be 1.0 because we want to determine the	
			# factor with this first estimate.
					
			for nick in qcd_shape_subtract_nicks:
				plotData.plotdict["root_objects"][qcd_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1.0/plotData.plotdict["qcd_scale_factor"])
			
			shape_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_shape_nick])()
			if shape_yield != 0.0:
				qcd_extrapolation_factor_ss_os = 1.0
				scale_factor = yield_qcd / shape_yield * qcd_extrapolation_factor_ss_os
				plotData.plotdict["root_objects"][qcd_shape_nick].Scale(scale_factor.nominal_value)
				
			#log.debug("Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}.".format(nick=qcd_data_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
			final_yield_qcd = yield_qcd * qcd_extrapolation_factor_ss_os
			
			# save to be picked up
			plotData.metadata[qcd_shape_nick] = {
				"yield" : final_yield_qcd.nominal_value,
				"yield_unc" : final_yield_qcd.std_dev,
				"yield_unc_rel" : abs(final_yield_qcd.std_dev/final_yield_qcd.nominal_value if final_yield_qcd.nominal_value != 0.0 else 0.0),
			}
	def run(self, plotData=None):
		super(EstimateQcd, self).run(plotData)
		
		# make sure that all necessary histograms are available
		for nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			for nick in nicks:
				if isinstance(nick, basestring):
					assert isinstance(plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
				elif (not isinstance(nick, float) and not isinstance(nick, bool)):
					for subnick in nick:
						assert isinstance(plotData.plotdict["root_objects"].get(subnick), ROOT.TH1)
		
		for qcd_shape_nick, qcd_yield_nick, qcd_yield_subtract_nicks, qcd_shape_subtract_nicks, qcd_extrapolation_factor_ss_os in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			
			yield_qcd = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_yield_nick])()
			# estimate the QCD yield
			# print "yield qcd total: " + str(yield_qcd)
			for nick in qcd_yield_subtract_nicks:
				yield_bkg = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				#print "minus " + nick + "  " + str(yield_bkg)	
				yield_qcd -= yield_bkg
			yield_qcd = uncertainties.ufloat(max(0.0, yield_qcd.nominal_value), yield_qcd.std_dev)
			if(yield_qcd.nominal_value == 0.0):
				log.warning("QCD yield is 0!")
			#  QCD shape
			
			#print "shape total: " + str(tools.PoissonYield(plotData.plotdict["root_objects"][qcd_shape_nick])())
			for nick in qcd_shape_subtract_nicks:
				#print "\t minus " + nick + " " + str(tools.PoissonYield(plotData.plotdict["root_objects"][nick])())
				plotData.plotdict["root_objects"][qcd_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1.0/plotData.plotdict["qcd_scale_factor"])
			
			shape_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_shape_nick])()
			if shape_yield != 0.0:
				scale_factor = yield_qcd / shape_yield * qcd_extrapolation_factor_ss_os
				plotData.plotdict["root_objects"][qcd_shape_nick].Scale(scale_factor.nominal_value)
				
			#log.debug("Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}.".format(nick=qcd_data_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
			final_yield_qcd = yield_qcd * qcd_extrapolation_factor_ss_os
			#print "QCD em estimation summary"
			#print "scale factor : " + str(scale_factor)
			#print "shape_yield :"  + str(shape_yield)
			#print "yield_qcd :" + str(yield_qcd)
			# save to be picked up
			plotData.metadata[qcd_shape_nick] = {
				"yield" : final_yield_qcd.nominal_value,
				"yield_unc" : final_yield_qcd.std_dev,
				"yield_unc_rel" : abs(final_yield_qcd.std_dev/final_yield_qcd.nominal_value if final_yield_qcd.nominal_value != 0.0 else 0.0),
			}
	def run(self, plotData=None):
		super(EstimateTtbar, self).run(plotData)
		
		# make sure that all necessary histograms are available
		for nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			for nick in nicks:
				if isinstance(nick, basestring):
					assert isinstance(plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
				elif not isinstance(nick, bool):
					for subnick in nick:
						assert isinstance(plotData.plotdict["root_objects"].get(subnick), ROOT.TH1)
		
		for ttbar_shape_nick, ttbar_data_control_nick, ttbar_data_subtract_nicks, ttbar_mc_signal_nick, ttbar_mc_control_nick in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
				yield_data_control = tools.PoissonYield(plotData.plotdict["root_objects"][ttbar_data_control_nick])()
				#print "data_control_yield from nick " + ttbar_data_control_nick + " : " + str(yield_data_control)
				for nick in ttbar_data_subtract_nicks:
					yield_bkg_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
					#print "\t minus " + nick + " : " + str(yield_bkg_control)
					if nick in plotData.metadata:
						yield_bkg_control = uncertainties.ufloat(
								plotData.metadata[nick].get("yield", yield_bkg_control.nominal_value),
								plotData.metadata[nick].get("yield_unc", yield_bkg_control.std_dev)
						)
					yield_data_control -= yield_bkg_control
				#print "data_control_yield final "  + str(yield_data_control)
				yield_data_control = max(0.0, yield_data_control)
				
				yield_mc_signal = tools.PoissonYield(plotData.plotdict["root_objects"][ttbar_mc_signal_nick])()
				yield_mc_control = tools.PoissonYield(plotData.plotdict["root_objects"][ttbar_mc_control_nick])()
				
				#print "data_mc_signal "  + str(yield_mc_signal)
				#print "data_mc_control "  + str(yield_mc_control)
				integral_shape = plotData.plotdict["root_objects"][ttbar_shape_nick].Integral()
				final_yield = yield_mc_control / yield_data_control * integral_shape
				log.debug("Relative statistical uncertainty of the yield for process ttbar+jets (nick \"{nick}\") is {unc}.".format(nick=ttbar_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
					
				plotData.metadata[ttbar_shape_nick] = {
					"yield" : final_yield.nominal_value,
					"yield_unc" : final_yield.std_dev,
					"yield_unc_rel" : abs(final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0),
				}
				
				if integral_shape != 0.0:
					scale_factor = integral_shape / final_yield
					#print "scale factor: " + str(scale_factor)
					log.debug("Scale factor for process ttbar+jets (nick \"{nick}\") is {scale_factor}.".format(nick=ttbar_shape_nick, scale_factor=scale_factor))
					plotData.plotdict["root_objects"][ttbar_shape_nick].Scale(scale_factor.nominal_value)
	def __init__(self, root_histogram):
		error = array.array("d", [0.0])
		dims = root_histogram.GetDimension()
		integral_ranges=[]
		for dim in range(dims):
			if dim==0:
				integral_ranges.append(0)
				integral_ranges.append(root_histogram.GetNbinsX()+1)
			elif dim==1:
				integral_ranges.append(0)
				integral_ranges.append(root_histogram.GetNbinsY()+1)
			elif dim==2:
				integral_ranges.append(0)
				integral_ranges.append(root_histogram.GetNbinsZ()+1)
		integral_ranges.append(error)
		integral = root_histogram.IntegralAndError(*integral_ranges)
		error = error[0]
		#self.poisson_yield = uncertainties.ufloat(integral, error)
		self.poisson_yield = uncertainties.ufloat(integral, math.sqrt(abs(integral)))
 def __init__(self, root_histogram):
     error = array.array("d", [0.0])
     dims = root_histogram.GetDimension()
     integral_ranges = []
     for dim in range(dims):
         if dim == 0:
             integral_ranges.append(0)
             integral_ranges.append(root_histogram.GetNbinsX() + 1)
         elif dim == 1:
             integral_ranges.append(0)
             integral_ranges.append(root_histogram.GetNbinsY() + 1)
         elif dim == 2:
             integral_ranges.append(0)
             integral_ranges.append(root_histogram.GetNbinsZ() + 1)
     integral_ranges.append(error)
     integral = root_histogram.IntegralAndError(*integral_ranges)
     error = error[0]
     #self.poisson_yield = uncertainties.ufloat(integral, error)
     self.poisson_yield = uncertainties.ufloat(integral,
                                               math.sqrt(abs(integral)))
	def run(self, plotData=None):
		super(EstimateQcd, self).run(plotData)
		
		for qcd_data_shape_nick, qcd_data_yield_nick, qcd_data_control_nick, qcd_data_substract_nicks, qcd_extrapolation_factor_ss_os, qcd_subtract_shape in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			
			if qcd_subtract_shape:
				for nick in qcd_data_substract_nicks:
					plotData.plotdict["root_objects"][qcd_data_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1.0/plotData.plotdict["qcd_scale_factor"])
				plotData.plotdict["root_objects"][qcd_data_shape_nick].Scale(qcd_extrapolation_factor_ss_os)
			else:
				yield_data_control = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_data_control_nick])()
				yield_qcd_control = yield_data_control
				for nick in qcd_data_substract_nicks:
					yield_bkg_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
					if nick in plotData.metadata:
						yield_bkg_control = uncertainties.ufloat(
								plotData.metadata[nick].get("yield", yield_bkg_control.nominal_value),
								plotData.metadata[nick].get("yield_unc", yield_bkg_control.std_dev)
						)
					yield_qcd_control -= yield_bkg_control
				yield_qcd_control = max(0.0, yield_qcd_control)
			
				scale_factor = yield_qcd_control * qcd_extrapolation_factor_ss_os
				if yield_data_control != 0.0:
					scale_factor /= yield_data_control
			
				final_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_data_yield_nick])() * scale_factor
				log.debug("Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}.".format(nick=qcd_data_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
			
				plotData.metadata[qcd_data_shape_nick] = {
					"yield" : final_yield.nominal_value,
					"yield_unc" : final_yield.std_dev,
					"yield_unc_rel" : abs(final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0),
				}
			
				integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_data_shape_nick])()
				if integral_shape != 0.0:
					scale_factor = final_yield / integral_shape
					log.debug("Scale factor for process QCD (nick \"{nick}\") is {scale_factor}.".format(nick=qcd_data_shape_nick, scale_factor=scale_factor))
					plotData.plotdict["root_objects"][qcd_data_shape_nick].Scale(scale_factor.nominal_value)
	def run(self, plotData=None):
		super(EstimateWjets, self).run(plotData)
		
		for wjets_from_mc, wjets_shape_nick, wjets_data_control_nick, wjets_data_substract_nicks, wjets_mc_signal_nick, wjets_mc_control_nick in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			if not wjets_from_mc:
				yield_data_control = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_data_control_nick])()
				for nick in wjets_data_substract_nicks:
					yield_bkg_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
					if nick in plotData.metadata:
						yield_bkg_control = uncertainties.ufloat(
								plotData.metadata[nick].get("yield", yield_bkg_control.nominal_value),
								plotData.metadata[nick].get("yield_unc", yield_bkg_control.std_dev)
						)
					yield_data_control -= yield_bkg_control
				yield_data_control = max(0.0, yield_data_control)
				
				yield_mc_signal = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_mc_signal_nick])()
				yield_mc_control = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_mc_control_nick])()
				
				assert (yield_data_control*yield_mc_signal == 0.0) or (yield_mc_control != 0.0)
				final_yield = yield_data_control * yield_mc_signal
				if final_yield != 0.0:
					final_yield /= yield_mc_control
				log.debug("Relative statistical uncertainty of the yield for process W+jets (nick \"{nick}\") is {unc}.".format(nick=wjets_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
				
				plotData.metadata[wjets_shape_nick] = {
					"yield" : final_yield.nominal_value,
					"yield_unc" : final_yield.std_dev,
					"yield_unc_rel" : abs(final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0),
				}
				
				integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_shape_nick])()
				if integral_shape != 0.0:
					scale_factor = final_yield / integral_shape
					log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_shape_nick, scale_factor=scale_factor))
					plotData.plotdict["root_objects"][wjets_shape_nick].Scale(scale_factor.nominal_value)
		))
	
        
	plot_configs = []
	datacards_workspaces = {}
	efficiency = {}

	for datacard, cb in datacards_cbs.iteritems():
		for channel in cb.cp().analysis(["ztt"]).era(["13TeV"]).channel_set():
			nPassPre = 0
			nFailPre = 0
			sig_process = cb.cp().bin([category]).signals().process_set()
			
			for category in cb.cp().analysis(["ztt"]).era(["13TeV"]).channel([channel]).bin_set():
				if "pass" in category:
					nPassPre = uncertainties.ufloat(cb.cp().bin([category]).process(sig_process).GetRate(),
									cb.cp().bin([category]).process(sig_process).GetUncertainty())
				elif "fail" in category:
					nFailPre = uncertainties.ufloat(cb.cp().bin([category]).process(sig_process).GetRate(),
									cb.cp().bin([category]).process(sig_process).GetUncertainty())
			efficiency[channel] = nPassPre / (nPassPre + nFailPre)
                      
			command = ["text2workspace.py -m {MASS} -P {MODEL} --PO \"eff={EFF}\" {DATACARD} -o {OUTPUT}".format(
				MASS=[mass for mass in cb.mass_set() if mass != "*"][0],
				MODEL=model_settings["P"],
				EFF=efficiency[channel].nominal_value,
				DATACARD=datacard,
				OUTPUT=os.path.splitext(datacard)[0]+".root")]
			
			print "command -->", command
			tools.parallelize(_call_command, command, n_processes=args.n_processes)
Exemplo n.º 15
0
    def run(self, plotData=None):
        super(EstimateQcd, self).run(plotData)

        # make sure that all necessary histograms are available
        for nicks in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            for nick in nicks:
                if isinstance(nick, basestring):
                    assert isinstance(
                        plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
                elif (not isinstance(nick, float)
                      and not isinstance(nick, bool)):
                    for subnick in nick:
                        assert isinstance(
                            plotData.plotdict["root_objects"].get(subnick),
                            ROOT.TH1)

        for qcd_shape_nick, qcd_yield_nick, qcd_yield_subtract_nicks, qcd_shape_subtract_nicks, qcd_extrapolation_factor_ss_os in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):

            yield_qcd = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_yield_nick])()
            # estimate the QCD yield
            # print "yield qcd total: " + str(yield_qcd)
            for nick in qcd_yield_subtract_nicks:
                yield_bkg = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                #print "minus " + nick + "  " + str(yield_bkg)
                yield_qcd -= yield_bkg
            yield_qcd = uncertainties.ufloat(max(0.0, yield_qcd.nominal_value),
                                             yield_qcd.std_dev)
            if (yield_qcd.nominal_value == 0.0):
                log.warning("QCD yield is 0!")
            #  QCD shape

            #print "shape total: " + str(tools.PoissonYield(plotData.plotdict["root_objects"][qcd_shape_nick])())
            for nick in qcd_shape_subtract_nicks:
                #print "\t minus " + nick + " " + str(tools.PoissonYield(plotData.plotdict["root_objects"][nick])())
                plotData.plotdict["root_objects"][qcd_shape_nick].Add(
                    plotData.plotdict["root_objects"][nick],
                    -1.0 / plotData.plotdict["qcd_scale_factor"])

            shape_yield = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_shape_nick])()
            if shape_yield != 0.0:
                scale_factor = yield_qcd / shape_yield * qcd_extrapolation_factor_ss_os
                plotData.plotdict["root_objects"][qcd_shape_nick].Scale(
                    scale_factor.nominal_value)

            #log.debug("Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}.".format(nick=qcd_data_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
            final_yield_qcd = yield_qcd * qcd_extrapolation_factor_ss_os
            #print "QCD em estimation summary"
            #print "scale factor : " + str(scale_factor)
            #print "shape_yield :"  + str(shape_yield)
            #print "yield_qcd :" + str(yield_qcd)
            # save to be picked up
            plotData.metadata[qcd_shape_nick] = {
                "yield":
                final_yield_qcd.nominal_value,
                "yield_unc":
                final_yield_qcd.std_dev,
                "yield_unc_rel":
                abs(final_yield_qcd.std_dev / final_yield_qcd.nominal_value
                    if final_yield_qcd.nominal_value != 0.0 else 0.0),
            }
	def run(self, plotData=None):
		super(EstimateWjetsAndQCD, self).run(plotData)

		for qcd_extrapolation_factor_ss_os, qcd_shape_nick, qcd_ss_lowmt_nick, qcd_ss_highmt_shape_nick, qcd_os_highmt_nick, qcd_shape_highmt_substract_nick, qcd_yield_nick, qcd_shape_substract_nick, qcd_yield_substract_nick, wjets_os_highmt_mc_nick, wjets_ss_highmt_mc_nick, wjets_ss_substract_nick, wjets_ss_data_nick, wjets_os_substract_nick, wjets_os_data_nick, wjets_shape_nick, wjets_relaxed_os_highmt_nick, wjets_relaxed_os_lowmt_nick, wjets_scale_factor_shift, wjets_final_selection in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			########################################
			# estimate QCD for the highmT region
			
			# get qcd ss high mt shape
			for nick in qcd_shape_highmt_substract_nick+[wjets_ss_highmt_mc_nick]:
				plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1)
			
			# get qcd yield in ss high mt region
			yield_qcd_ss_highmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_ss_data_nick])()
			for nick in wjets_ss_substract_nick+[wjets_ss_highmt_mc_nick]:
				yield_qcd_ss_highmt -= tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
			yield_qcd_ss_highmt = max(uncertainties.ufloat(0.0, yield_qcd_ss_highmt.std_dev), yield_qcd_ss_highmt)
			
			# scale qcd ss high mt shape by qcd yield found in data
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_qcd_ss_highmt / integral_shape
				plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick].Scale(scale_factor.nominal_value)
			
			# scale qcd os high mt shape by qcd yield found in ss data and ss->os extrapolation factor
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_os_highmt_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_qcd_ss_highmt * qcd_extrapolation_factor_ss_os / integral_shape
				plotData.plotdict["root_objects"][qcd_os_highmt_nick].Scale(scale_factor.nominal_value)
			
			########################################
			# estimate W+jets
			
			# get w+jets yield in os high mt region
			yield_wjets_os_highmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_data_nick])()
			for nick in wjets_os_substract_nick:
				yield_wjets_os_highmt -= tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
			yield_wjets_os_highmt -= qcd_extrapolation_factor_ss_os*yield_qcd_ss_highmt
			yield_wjets_os_highmt = max(uncertainties.ufloat(0.0, yield_wjets_os_highmt.std_dev), yield_wjets_os_highmt)
			if yield_wjets_os_highmt.nominal_value == 0.0:
				log.warning("W+jets & QCD estimation: data yield in high mT region after background subtraction is 0!")
			
			# get high mt -> low mt extrapolation factor from MC
			if tools.PoissonYield(plotData.plotdict["root_objects"][wjets_relaxed_os_highmt_nick])() != 0.0:
				wjets_extrapolation_factor_mt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_relaxed_os_lowmt_nick])()/tools.PoissonYield(plotData.plotdict["root_objects"][wjets_relaxed_os_highmt_nick])()
			else:
				log.warning("W+jets & QCD estimation: W+jets high mT region in MC has no entries. High->low mT extrapolation factor is set to 1.0!")
				wjets_extrapolation_factor_mt = 1.0
			
			# get w+jets yield in low mt region
			wjets_yield = yield_wjets_os_highmt*wjets_extrapolation_factor_mt
			
			# extrapolate to final selection
			if wjets_final_selection != None:
				wjets_yield = wjets_yield * tools.PoissonYield(plotData.plotdict["root_objects"][wjets_final_selection])() / tools.PoissonYield(plotData.plotdict["root_objects"][wjets_relaxed_os_lowmt_nick])()
			
			# scale signal region histograms
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = wjets_yield / integral_shape
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_shape_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_shape_nick].Scale(scale_factor.nominal_value)
			
			plotData.metadata[wjets_shape_nick] = {
				"yield" : wjets_yield.nominal_value,
				"yield_unc" : wjets_yield.std_dev,
				"yield_unc_rel" : abs(wjets_yield.std_dev/wjets_yield.nominal_value if wjets_yield.nominal_value != 0.0 else 0.0),
			}
			
			########################################
			# estimate QCD for the lowmT
			
			# define w+jets scale factor for qcd estimation
			if tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_highmt_mc_nick])() != 0.0:
				wjets_scale_factor = yield_wjets_os_highmt/tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_highmt_mc_nick])()
			else:
				log.warning("W+jets & QCD estimation: W+jets high mT region in MC has no entries. Scale factor for W+jets in QCD estimation is set to 1.0!")
				wjets_scale_factor = uncertainties.ufloat(1.0, 0.0)
			
			for nick in qcd_shape_substract_nick:
				if "wj" in nick:
					scale_factor = wjets_scale_factor * wjets_scale_factor_shift
					plotData.plotdict["root_objects"][nick].Scale(scale_factor.nominal_value)
				plotData.plotdict["root_objects"][qcd_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1)
			
			yield_qcd_ss_lowmt = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_yield_nick])()
			for nick in qcd_yield_substract_nick:
				if "wj" in nick and tools.PoissonYield(plotData.plotdict["root_objects"][nick])() != 0.0:
					scale_factor = wjets_scale_factor * wjets_scale_factor_shift
					plotData.plotdict["root_objects"][nick].Scale(scale_factor.nominal_value)
				yield_qcd_ss_lowmt -= tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
			yield_qcd_ss_lowmt = max(uncertainties.ufloat(0.0, yield_qcd_ss_lowmt.std_dev), yield_qcd_ss_lowmt)
			if yield_qcd_ss_lowmt.nominal_value == 0.0:
				log.warning("W+jets & QCD estimation: data yield in low mT SS region after background subtraction is 0!")
			
			# get qcd yield in low mt region
			qcd_yield = yield_qcd_ss_lowmt * qcd_extrapolation_factor_ss_os
			
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = qcd_yield / integral_shape
				plotData.plotdict["root_objects"][qcd_shape_nick].Scale(scale_factor.nominal_value)
			
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_ss_lowmt_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_qcd_ss_lowmt / integral_shape
				plotData.plotdict["root_objects"][qcd_ss_lowmt_nick].Scale(scale_factor.nominal_value)
			
			# write relative uncertainties to metadata to pick them up with combine
			plotData.metadata[qcd_shape_nick] = {
				"yield" : qcd_yield.nominal_value,
				"yield_unc" : qcd_yield.std_dev,
				"yield_unc_rel" : abs(qcd_yield.std_dev/qcd_yield.nominal_value if qcd_yield.nominal_value != 0.0 else 0.0),
			}
    def run(self, plotData=None):
        super(EstimateWjetsAndQCD, self).run(plotData)

        for qcd_extrapolation_factor_ss_os, qcd_shape_nick, qcd_ss_lowmt_nick, qcd_ss_highmt_shape_nick, qcd_os_highmt_nick, qcd_shape_highmt_substract_nick, qcd_yield_nick, qcd_shape_substract_nick, qcd_yield_substract_nick, wjets_ss_mc_nick, wjets_os_mc_nick, wjets_os_highmt_mc_nick, wjets_os_lowmt_mc_nick, wjets_ss_highmt_mc_nick, wjets_ss_substract_nick, wjets_ss_data_nick, wjets_os_substract_nick, wjets_os_data_nick, wjets_shape_nick in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            # estimate QCD for the lowmT
            for nick in qcd_shape_substract_nick:
                plotData.plotdict["root_objects"][qcd_shape_nick].Add(
                    plotData.plotdict["root_objects"][nick], -1)
            yield_qcd_control = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_yield_nick])()
            for nick in qcd_yield_substract_nick:
                yield_bkg_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                if nick in plotData.metadata:
                    yield_bkg_control = uncertainties.ufloat(
                        plotData.metadata[nick].get(
                            "yield", yield_bkg_control.nominal_value),
                        plotData.metadata[nick].get("yield_unc",
                                                    yield_bkg_control.std_dev))
                yield_qcd_control -= yield_bkg_control
            yield_qcd_control = max(0.0, yield_qcd_control)

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_shape_nick])()
            if integral_shape != 0.0:
                scale_factor = yield_qcd_control * qcd_extrapolation_factor_ss_os / integral_shape
                plotData.plotdict["root_objects"][qcd_shape_nick].Scale(
                    scale_factor.nominal_value)

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_ss_lowmt_nick])()
            if integral_shape != 0.0:
                scale_factor = yield_qcd_control / integral_shape
                plotData.plotdict["root_objects"][qcd_ss_lowmt_nick].Scale(
                    scale_factor.nominal_value)

            # estimate W+jets
            yield_ss_control = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_ss_data_nick])()
            for nick in wjets_ss_substract_nick:
                yield_bkg_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                yield_ss_control -= yield_bkg_control
            yield_os_control = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_os_data_nick])()
            for nick in wjets_os_substract_nick:
                yield_bkg_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                yield_os_control -= yield_bkg_control

            wjets_extrapolation_factor_ss_os = tools.PoissonYield(
                plotData.plotdict["root_objects"]
                [wjets_os_mc_nick])() / tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_ss_mc_nick])()
            wjets_extrapolation_factor_mt = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_os_lowmt_mc_nick]
            )() / tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_os_highmt_mc_nick])()

            wjets_yield = (
                yield_os_control -
                qcd_extrapolation_factor_ss_os * yield_ss_control
            ) * wjets_extrapolation_factor_ss_os / (
                wjets_extrapolation_factor_ss_os -
                qcd_extrapolation_factor_ss_os) * wjets_extrapolation_factor_mt

            # scale signal region histograms
            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_shape_nick])()
            if integral_shape != 0.0:
                scale_factor = wjets_yield / integral_shape
                log.debug(
                    "Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}."
                    .format(nick=wjets_shape_nick, scale_factor=scale_factor))
                plotData.plotdict["root_objects"][wjets_shape_nick].Scale(
                    scale_factor.nominal_value)

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_os_highmt_mc_nick])()
            if integral_shape != 0.0:
                scale_factor = wjets_yield / (integral_shape *
                                              wjets_extrapolation_factor_mt)
                log.debug(
                    "Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}."
                    .format(nick=wjets_os_highmt_mc_nick,
                            scale_factor=scale_factor))
                plotData.plotdict["root_objects"][
                    wjets_os_highmt_mc_nick].Scale(scale_factor.nominal_value)

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_ss_highmt_mc_nick])()
            if integral_shape != 0.0:
                scale_factor = wjets_yield / (integral_shape *
                                              wjets_extrapolation_factor_mt *
                                              wjets_extrapolation_factor_ss_os)
                log.debug(
                    "Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}."
                    .format(nick=wjets_ss_highmt_mc_nick,
                            scale_factor=scale_factor))
                plotData.plotdict["root_objects"][
                    wjets_ss_highmt_mc_nick].Scale(scale_factor.nominal_value)

# estimate QCD for the highmT region
            for nick in qcd_shape_highmt_substract_nick + [
                    wjets_ss_highmt_mc_nick
            ]:
                plotData.plotdict["root_objects"][
                    qcd_ss_highmt_shape_nick].Add(
                        plotData.plotdict["root_objects"][nick], -1)

            yield_qcd_ss_highmt = yield_ss_control - tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_ss_highmt_mc_nick])()
            yield_qcd_ss_highmt = max(0.0, yield_qcd_ss_highmt)

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick])()
            if integral_shape != 0.0:
                scale_factor = yield_qcd_ss_highmt / integral_shape
                plotData.plotdict["root_objects"][
                    qcd_ss_highmt_shape_nick].Scale(scale_factor.nominal_value)

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_os_highmt_nick])()
            if integral_shape != 0.0:
                scale_factor = yield_qcd_ss_highmt * qcd_extrapolation_factor_ss_os / integral_shape
                plotData.plotdict["root_objects"][qcd_os_highmt_nick].Scale(
                    scale_factor.nominal_value)
	def run(self, plotData=None):
		super(EstimateWjetsAndQCDSimEquationMethod, self).run(plotData)
		
		# make sure that all necessary histograms are available
		for nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys[:-1]]):
			for nick in nicks:
				print(nick)
				if isinstance(nick, basestring):
					assert isinstance(plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
				elif (not isinstance(nick, float) and not isinstance(nick, bool)):
					for subnick in nick:
						print(subnick)
						assert isinstance(plotData.plotdict["root_objects"].get(subnick), ROOT.TH1)

		for use_inclusive_wjets_mc, wjets_ss_mc_nick, wjets_os_mc_nick, wjets_D_mc_nick, wjets_A_mc_nick, wjets_C_mc_nick, wjets_B_mc_nick, wjets_C_data_nick, C_subtract_nicks, wjets_D_data_nick, D_subtract_nicks, wjets_C_shape_nick,  wjets_B_shape_nick,  wjets_A_shape_nick, wjets_D_shape_nick, qcd_extrapolation_factor_ss_os, qcd_os_highmt_nick, qcd_ss_highmt_nick, qcd_ss_lowmt_nick, qcd_ss_data_nick, qcd_shape_nick, B_subtract_nicks in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			########################################
			# ------------ Step 1 ------------------
			# Measure W OS/SS factor from MonteCarlo
			# 1. Needs inclusive wj_mc for OS and SS 
			# 2. Therefore the scale factor is the same in the high mt control region (mT>70) and the low mt signal like region.
			
			yield_wj_mc_os = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_mc_nick])()
			yield_wj_mc_ss = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_ss_mc_nick])()
			
			# correct negative yields
			yield_wj_mc_os = uncertainties.ufloat(max(0.0, yield_wj_mc_os.nominal_value), yield_wj_mc_os.std_dev)
			yield_wj_mc_ss = uncertainties.ufloat(max(0.0, yield_wj_mc_ss.nominal_value), yield_wj_mc_ss.std_dev)
			
			yield_wj_mc_os_highmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_D_mc_nick])()
			yield_wj_mc_ss_highmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_C_mc_nick])()

			assert (yield_wj_mc_os_highmt != 0.0) or (yield_wj_mc_ss_highmt != 0.0), "Yield of MC in opposite-sign or same-sign region is zero."
			
			# calculate w_os_ss factor and store it in the metadata
			if use_inclusive_wjets_mc:
				w_os_ss_extrapolation_factor = yield_wj_mc_os / yield_wj_mc_ss
			else:
				w_os_ss_extrapolation_factor = yield_wj_mc_os_highmt / yield_wj_mc_ss_highmt
				
			log.debug("W+jets Opposite sign Same-sign factor is \"{FACTOR}\".".format(FACTOR = w_os_ss_extrapolation_factor))	

			
			########################################
			# ------------ Step 2 ------------------
			# Measure opposite-sign extrapolation factor from high Mt Control region (mT>70) to low Mt (mt<50)
			# 1. Needs wj_mc in opposite region for both mT regions.
			yield_wj_mc_os_highmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_D_mc_nick])()
			yield_wj_mc_os_lowmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_A_mc_nick])()
			
			
			assert (yield_wj_mc_os_highmt != 0.0) or (yield_wj_mc_os_lowmt != 0.0), "Yield of MC in opposite-sign lowmt or opposite-sign highmt region is zero."
			
			# calculate w_highmt_lowmt factor and store it in the metadata
			w_os_highmt_lowmt_extrapolation_factor = yield_wj_mc_os_lowmt/yield_wj_mc_os_highmt
			log.debug("W+jets Opposite-sign High mT to low mT factor is \"{FACTOR}\".".format(FACTOR = w_os_highmt_lowmt_extrapolation_factor))	
			
			########################################
			# ------------ Step 3 ------------------
			# Measure same-sign extrapolation factor from high Mt Control region (mT>70) to low Mt (mt<50)
			# This is needed to get the first estimate for Qcd in the same-sign region.
			# 1. Needs wj_mc in opposite region for both mT regions.

						
			# calculate w_highmt_lowmt factor and store it in the metadata
			if tools.PoissonYield(plotData.plotdict["root_objects"][wjets_C_mc_nick])() != 0.0:
				w_ss_highmt_lowmt_extrapolation_factor = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_B_mc_nick])()/tools.PoissonYield(plotData.plotdict["root_objects"][wjets_C_mc_nick])()
			else: 
				log.warning("W+jets & QCD estimation: W+jets high mT region in MC has no entries. High->low mT extrapolation factor is set to 1.0!")
				w_ss_highmt_lowmt_extrapolation_factor = 1.0
			log.debug("W+jets Same-sign High mT to low mT factor is \"{FACTOR}\".".format(FACTOR = w_ss_highmt_lowmt_extrapolation_factor))	

			
			########################################		
			# ------------ Step 4 ------------------
			# Estimate same-sign lowMt QCD with inverted isolation 
			# 1. Get the QCD OS/SS extrapolation factor which is measured using the makePlots_datacardsQCDfactors script. 
			
			# qcd_extrapolation_factor_ss_os
						
			########################################
			# ------------ Step 5 ------------------
			# Estimate highmt same-sign W+jets yield 
			# 1. Get data yield in same-sign highmt region	
			# 2. Subtract all MC backgrounds from same-sign highmt region from it. 
			# 3. Scale it by the qcd_ss_os_extrapolation_factor
			# 4. Get data yield in opposite sign high mt region
			# 5. Subtract all MC backgrounds from opposite-sign highmt region from it.
			# 6. Subtract the estimate for the yield for same-sign highmt from it.
			# 7. Scale it by the differene between the W+jets and QCD extrapolation factor.
			# 8. Scale the shape according to the scale factor.
					
			yield_wjets_ss_highmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_C_data_nick])()	
			for nick in C_subtract_nicks:
				yield_wjets_ss_highmt -= tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				
			log.debug("W+jets Same-sign High mT before estimation yield is \"{YIELD}\".".format(YIELD = yield_wjets_ss_highmt))				
			yield_wjets_ss_highmt = uncertainties.ufloat(max(0.0, yield_wjets_ss_highmt.nominal_value), yield_wjets_ss_highmt.std_dev)
			yield_qcd_ss_highmt = yield_wjets_ss_highmt	
			yield_wjets_os_highmt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_D_data_nick])()
			for nick in D_subtract_nicks:
				yield_wjets_os_highmt -= tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
			yield_wjets_os_highmt = uncertainties.ufloat(max(0.0, yield_wjets_os_highmt.nominal_value), yield_wjets_os_highmt.std_dev)	
				
			log.debug("W+jets Same-sign High mT before estimation yield is \"{YIELD}\".".format(YIELD = yield_wjets_ss_highmt))	
			log.debug("W+jets opposite-sign High mT before estimation yield is \"{YIELD}\".".format(YIELD = yield_wjets_os_highmt))	
			print(qcd_extrapolation_factor_ss_os * yield_wjets_ss_highmt)
			yield_wjets_ss_highmt = yield_wjets_os_highmt - qcd_extrapolation_factor_ss_os * yield_wjets_ss_highmt
			
			# yield_wjets_ss_highmt = uncertainties.ufloat(max(0.0, yield_wjets_ss_highmt.nominal_value), yield_wjets_ss_highmt.std_dev)
			yield_wjets_ss_highmt = yield_wjets_ss_highmt / (w_os_ss_extrapolation_factor - qcd_extrapolation_factor_ss_os)
			
			log.debug("W+jets Same-sign High mT after estimation yield is \"{YIELD}\".".format(YIELD = yield_wjets_ss_highmt))	
			yield_wjets_ss_highmt = uncertainties.ufloat(max(0.0, yield_wjets_ss_highmt.nominal_value), yield_wjets_ss_highmt.std_dev)
			log.debug("W+jets Same-sign High mT after estimation yield is \"{YIELD}\".".format(YIELD = yield_wjets_ss_highmt))
			# store the eyield that might be expected for QCD after having determined Wjets in the highmt ss region
			yield_qcd_ss_highmt -= yield_wjets_ss_highmt
			if yield_wjets_ss_highmt.nominal_value == 0.0:
				log.warning("W+jets & QCD estimation: data yield in high mT same-sign region after background subtraction is 0!")	
			
			# scale same-sign highmt Wjets histograms for controlplots.
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_C_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_wjets_ss_highmt / integral_shape
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_C_shape_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_C_shape_nick].Scale(scale_factor.nominal_value)
				plotData.plotdict["root_objects"][wjets_C_shape_nick].Print()			
			
			########################################
			# ------------ Step 6 a ------------------
			# Estimate final opposite-sign  lowmT W+jets yield 
			# 1. Multiply yield from before the Wjets OS/SS and the low-highmt factor.
			# 2. Scale the shape nicks by the resulting scale factor. 
			
			final_yield_wjets_os_lowmt = w_os_highmt_lowmt_extrapolation_factor * w_os_ss_extrapolation_factor * yield_wjets_ss_highmt
			
			log.debug("W+jets Opposite-sign low mT yield is \"{YIELD}\".".format(YIELD = final_yield_wjets_os_lowmt))	
			if final_yield_wjets_os_lowmt.nominal_value == 0.0:
				log.warning("W+jets estimation: Final yield in low mT opposite-sign is 0!")	
			
			# scale same-sign highmt Wjets histograms for controlplots.
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_A_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = final_yield_wjets_os_lowmt/integral_shape
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_A_shape_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_A_shape_nick].Scale(scale_factor.nominal_value)	
				plotData.plotdict["root_objects"][wjets_A_shape_nick].Print()			
			
			########################################
			# ------------ Step 6 b ------------------
			# Estimate final same-sign  lowmT W+jets yield 
			# 1. Multiply yield from before the Wjets OS/SS and the low-highmt factor.
			# 2. Scale the shape nicks by the resulting scale factor. 				
			
			final_yield_wjets_ss_lowmt = w_ss_highmt_lowmt_extrapolation_factor * yield_wjets_ss_highmt
			log.debug("W+jets Same-sign low mT yield is \"{YIELD}\".".format(YIELD = final_yield_wjets_ss_lowmt))	

			if final_yield_wjets_ss_lowmt.nominal_value == 0.0:
			 	log.warning("W+jets estimation: Final yield in low mT same-sign is 0!")	
			
			# scale same-sign highmt Wjets histograms for controlplots.
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_B_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = final_yield_wjets_ss_lowmt / integral_shape				
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_B_shape_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_B_shape_nick].Scale(scale_factor.nominal_value)	
				plotData.plotdict["root_objects"][wjets_B_shape_nick].Print()			

			########################################
			# ------------ Step 6 c ------------------
			# Estimate final opposite-sign  highmT W+jets yield 
			# 1. Multiply yield from before the Wjets OS/SS factor.
			# 2. Scale the shape nicks by the resulting scale factor. 				
			
			final_yield_wjets_os_highmt = w_os_ss_extrapolation_factor * yield_wjets_ss_highmt
			log.debug("W+jets opposite-sign high mT yield is \"{YIELD}\".".format(YIELD = final_yield_wjets_os_highmt))	

			if final_yield_wjets_os_highmt.nominal_value == 0.0:
			 	log.warning("W+jets estimation: Final yield in low mT same-sign is 0!")	
			
			# scale same-sign highmt Wjets histograms for controlplots.
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_D_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = final_yield_wjets_os_highmt / integral_shape				
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_D_shape_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_D_shape_nick].Scale(scale_factor.nominal_value)	
				plotData.plotdict["root_objects"][wjets_D_shape_nick].Print()
					
			plotData.metadata[wjets_A_shape_nick] = {
				"w_os_ss_factor" : w_os_ss_extrapolation_factor.nominal_value,
				"w_os_ss_factor_unc" : w_os_ss_extrapolation_factor.std_dev,
				"w_os_ss_factor_unc_rel" : abs(w_os_ss_extrapolation_factor.std_dev/w_os_ss_extrapolation_factor.nominal_value if w_os_ss_extrapolation_factor.nominal_value != 0.0 else 0.0),			
				"w_os_highmt_lowmt_factor" : w_os_highmt_lowmt_extrapolation_factor.nominal_value,
				"w_os_highmt_lowmt_factor_unc" : w_os_highmt_lowmt_extrapolation_factor.std_dev,
				"w_os_highmt_lowmt_factor_unc_rel" : abs(w_os_highmt_lowmt_extrapolation_factor.std_dev/w_os_highmt_lowmt_extrapolation_factor.nominal_value if w_os_highmt_lowmt_extrapolation_factor.nominal_value != 0.0 else 0.0),	
				"w_ss_highmt_lowmt_factor" : w_ss_highmt_lowmt_extrapolation_factor.nominal_value,
				"w_ss_highmt_lowmt_factor_unc" : w_ss_highmt_lowmt_extrapolation_factor.std_dev,
				"w_ss_highmt_lowmt_factor_unc_rel" : abs(w_ss_highmt_lowmt_extrapolation_factor.std_dev/w_ss_highmt_lowmt_extrapolation_factor.nominal_value if w_ss_highmt_lowmt_extrapolation_factor.nominal_value != 0.0 else 0.0),
				"w_ss_highmt_yield" : yield_wjets_ss_highmt.nominal_value,
				"w_ss_highmt_yield_unc" : yield_wjets_ss_highmt.std_dev,
				"w_ss_highmt_yield_unc_rel" : abs(yield_wjets_ss_highmt.std_dev/yield_wjets_ss_highmt.nominal_value if yield_wjets_ss_highmt.nominal_value != 0.0 else 0.0),
				"w_os_lowmt_yield" : final_yield_wjets_os_lowmt.nominal_value,
				"w_os_lowmt_yield_unc" : final_yield_wjets_os_lowmt.std_dev,
				"w_os_lowmt_yield_unc_rel" : abs(final_yield_wjets_os_lowmt.std_dev/final_yield_wjets_os_lowmt.nominal_value if final_yield_wjets_os_lowmt.nominal_value != 0.0 else 0.0),
				"w_ss_lowmt_yield" : final_yield_wjets_ss_lowmt.nominal_value,
				"w_ss_lowmt_yield_unc" : final_yield_wjets_ss_lowmt.std_dev,
				"w_ss_lowmt_yield_unc_rel" : abs(final_yield_wjets_ss_lowmt.std_dev/final_yield_wjets_ss_lowmt.nominal_value if final_yield_wjets_ss_lowmt.nominal_value != 0.0 else 0.0),
			}
			log.debug(plotData.metadata)	
						
			########################################
			# ------------ Step 7 ------------------
			# Get a opposite-sign region QCD estimate
			# 1. Get same-sign low-mt data yield.
			# 2. Subtract all background except for Wjets from it.
			# 3. Calculate same-sign lowmt Wjets estimate using the highMt estimte from step 5.
			# 4. Subtract also Wjets to get the same-sign QCD yield.
			# 5. Get the shapes for all histograms and background and get a QCD shape estimate
			
							
			yield_qcd_ss = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_ss_data_nick])()
			for nick in B_subtract_nicks:			
				yield_qcd_ss -= tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
			yield_qcd_ss -= tools.PoissonYield(plotData.plotdict["root_objects"][wjets_B_shape_nick])()
			yield_qcd_ss = uncertainties.ufloat(max(0.0, yield_qcd_ss.nominal_value), yield_qcd_ss.std_dev)

			log.debug("QCD Same-sign yield is \"{YIELD}\".".format(YIELD = yield_qcd_ss))				
			if yield_qcd_ss.nominal_value == 0.0: 
				log.warning("QCD estimation: yield in low mT same-sign is 0!")	
			
			for nick in B_subtract_nicks:
				plotData.plotdict["root_objects"][qcd_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1)
			
			plotData.plotdict["root_objects"][qcd_shape_nick].Add(plotData.plotdict["root_objects"][wjets_B_shape_nick], -1)
			
			qcd_shape_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_shape_nick])()
			qcd_shape_yield = uncertainties.ufloat(max(0.0, qcd_shape_yield.nominal_value), qcd_shape_yield.std_dev)

			yield_qcd_os = yield_qcd_ss * qcd_extrapolation_factor_ss_os
			if qcd_shape_yield.nominal_value != 0:
				scale_factor = yield_qcd_os / qcd_shape_yield 
				log.debug("Scale factor for process QCD (nick \"{nick}\") is {scale_factor}.".format(nick=qcd_shape_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][qcd_shape_nick].Scale(scale_factor.nominal_value)	
				plotData.plotdict["root_objects"][qcd_shape_nick].Print()			
				

			plotData.metadata[qcd_shape_nick] = {
				"QCD SS/OS factor" : qcd_extrapolation_factor_ss_os,
				"QCD Opposite-sign yield" : yield_qcd_os.nominal_value,
				"QCD Opposite-sign yield_unc" : yield_qcd_os.std_dev,
				"QCD Opposite-sign yield_unc_rel" : abs(yield_qcd_os.std_dev/yield_qcd_os.nominal_value if yield_qcd_os.nominal_value != 0.0 else 0.0),
			}

			qcd_shape_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_ss_lowmt_nick])()
			qcd_shape_yield = uncertainties.ufloat(max(0.0, qcd_shape_yield.nominal_value), qcd_shape_yield.std_dev)
			if qcd_shape_yield.nominal_value != 0:
				scale_factor = yield_qcd_ss / qcd_shape_yield
				log.debug("Scale factor for process QCD (nick \"{nick}\") is {scale_factor}.".format(nick=qcd_ss_lowmt_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][qcd_ss_lowmt_nick].Scale(scale_factor.nominal_value)	
				plotData.plotdict["root_objects"][qcd_ss_lowmt_nick].Print()			

			plotData.metadata[qcd_shape_nick] = {
				"QCD Same-sign yield" : yield_qcd_ss.nominal_value,
				"QCD Same-sign yield_unc" : yield_qcd_ss.std_dev,
				"QCD Same-sign yield_unc_rel" : abs(yield_qcd_ss.std_dev/yield_qcd_ss.nominal_value if yield_qcd_ss.nominal_value != 0.0 else 0.0),
			}
			
			qcd_shape_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_ss_highmt_nick])()
			qcd_shape_yield = uncertainties.ufloat(max(0.0, qcd_shape_yield.nominal_value), qcd_shape_yield.std_dev)		
			if qcd_shape_yield.nominal_value != 0:
				scale_factor = yield_qcd_ss_highmt / qcd_shape_yield
				log.debug("Scale factor for process QCD (nick \"{nick}\") is {scale_factor}.".format(nick=qcd_ss_highmt_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][qcd_ss_highmt_nick].Scale(scale_factor.nominal_value)	
				plotData.plotdict["root_objects"][qcd_ss_highmt_nick].Print()			

			plotData.metadata[qcd_shape_nick] = {
				"QCD Same-sign highmt yield" : yield_qcd_ss_highmt.nominal_value,
				"QCD Same-sign highmt yield_unc" : yield_qcd_ss_highmt.std_dev,
				"QCD Same-sign highmt yield_unc_rel" : abs(yield_qcd_ss_highmt.std_dev/yield_qcd_ss_highmt.nominal_value if yield_qcd_ss_highmt.nominal_value != 0.0 else 0.0),
			}
			
			
			qcd_shape_yield = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_os_highmt_nick])()
			qcd_shape_yield = uncertainties.ufloat(max(0.0, qcd_shape_yield.nominal_value), qcd_shape_yield.std_dev)		
			if qcd_shape_yield.nominal_value != 0:
				scale_factor = yield_qcd_ss_highmt * qcd_extrapolation_factor_ss_os / qcd_shape_yield
				log.debug("Scale factor for process QCD (nick \"{nick}\") is {scale_factor}.".format(nick=qcd_os_highmt_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][qcd_os_highmt_nick].Scale(scale_factor.nominal_value)	
				plotData.plotdict["root_objects"][qcd_os_highmt_nick].Print()			

			plotData.metadata[qcd_shape_nick] = {
				"QCD opposite-sign highmt yield" : yield_qcd_ss_highmt.nominal_value,
				"QCD opposite-sign highmt yield_unc" : yield_qcd_ss_highmt.std_dev,
				"QCD opposite-sign highmt yield_unc_rel" : abs(yield_qcd_ss_highmt.std_dev/yield_qcd_ss_highmt.nominal_value if yield_qcd_ss_highmt.nominal_value != 0.0 else 0.0),
			}
Exemplo n.º 19
0
    def run(self, plotData=None):
        super(UnpolarisationScaleFactors, self).run(plotData)

        for unpolarisation_nominal_nick, unpolarisation_shift_up_nick, unpolarisation_shift_down_nick, unpolarisation_forced_gen_polarisation in zip(
                *[
                    plotData.plotdict[key] for key in [
                        "unpolarisation_nominal_nicks",
                        "unpolarisation_shift_up_nicks",
                        "unpolarisation_shift_down_nicks",
                        "unpolarisation_forced_gen_polarisations"
                    ]
                ]):

            scale_factors = {}
            scale_factors_pos = {}
            scale_factors_neg = {}
            for shift, nick in zip(*[["nominal", "shift up", "shift down"],
                                     [
                                         unpolarisation_nominal_nick,
                                         unpolarisation_shift_up_nick,
                                         unpolarisation_shift_down_nick
                                     ]]):
                neg_gen_norm = uncertainties.ufloat(
                    plotData.plotdict["root_objects"][nick].GetBinContent(1),
                    plotData.plotdict["root_objects"][nick].GetBinError(1))
                pos_gen_norm = uncertainties.ufloat(
                    plotData.plotdict["root_objects"][nick].GetBinContent(2),
                    plotData.plotdict["root_objects"][nick].GetBinError(2))
                scale_factors[
                    shift] = polarisationsignalscaling.PolarisationScaleFactors(
                        pos_gen_norm,
                        neg_gen_norm,
                        pos_gen_norm,
                        neg_gen_norm,
                        forced_gen_polarisation=
                        unpolarisation_forced_gen_polarisation)

                scale_factors_pos[shift] = scale_factors[
                    shift].get_bias_removal_factor_pospol(
                    ) if plotData.plotdict[
                        "unpolarisation_remove_bias_instead_unpolarisation"] else scale_factors[
                            shift].get_scale_factor_pospol()
                log.debug(
                    "Positive helicity of \"{nick}\" to be scaled by a factor of {factor} ({shift})."
                    .format(nick=nick,
                            factor=scale_factors_pos[shift],
                            shift=shift))

                scale_factors_neg[shift] = scale_factors[
                    shift].get_bias_removal_factor_neg_pol(
                    ) if plotData.plotdict[
                        "unpolarisation_remove_bias_instead_unpolarisation"] else scale_factors[
                            shift].get_scale_factor_negpol()
                log.debug(
                    "Negative helicity of \"{nick}\" to be scaled by a factor of {factor} ({shift})."
                    .format(nick=nick,
                            factor=scale_factors_neg[shift],
                            shift=shift))

            total_uncertainties_pos = [
                abs((scale_factors_pos["shift up"] -
                     scale_factors_pos["nominal"]) /
                    scale_factors_pos["nominal"]),
                abs((scale_factors_pos["shift down"] -
                     scale_factors_pos["nominal"]) /
                    scale_factors_pos["nominal"])
            ]
            total_uncertainties_neg = [
                abs((scale_factors_neg["shift up"] -
                     scale_factors_neg["nominal"]) /
                    scale_factors_neg["nominal"]),
                abs((scale_factors_neg["shift down"] -
                     scale_factors_neg["nominal"]) /
                    scale_factors_neg["nominal"])
            ]

            log.info(
                "Total uncertainties on scale factor for positive helicity = (+) {tot_pos_plus} / (-) {tot_pos_minus}"
                .format(tot_pos_plus=total_uncertainties_pos[0],
                        tot_pos_minus=total_uncertainties_pos[1]))
            log.info(
                "Total uncertainties on scale factor for negative helicity = (+) {tot_neg_plus} / (-) {tot_neg_minus}"
                .format(tot_neg_plus=total_uncertainties_neg[0],
                        tot_neg_minus=total_uncertainties_neg[1]))
Exemplo n.º 20
0
    def run(self, plotData=None):
        super(EstimateQcdTauHadTauHad, self).run(plotData)

        # make sure that all necessary histograms are available
        for nicks in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            for nick in nicks:
                if isinstance(nick, basestring):
                    assert isinstance(
                        plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
                elif (not isinstance(nick, float)
                      and not isinstance(nick, bool)):
                    for subnick in nick:
                        assert isinstance(
                            plotData.plotdict["root_objects"].get(subnick),
                            ROOT.TH1)

        for qcd_data_shape_nick, qcd_data_signal_control_nick, qcd_data_relaxed_control_nick, qcd_data_subtract_nicks, qcd_control_signal_subtract_nicks, qcd_control_relaxed_subtract_nicks in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):

            for nick in qcd_data_subtract_nicks:
                plotData.plotdict["root_objects"][qcd_data_shape_nick].Add(
                    plotData.plotdict["root_objects"][nick], -1.0)

            yield_control_signal = tools.PoissonYield(
                plotData.plotdict["root_objects"]
                [qcd_data_signal_control_nick])()
            for nick in qcd_control_signal_subtract_nicks:
                yield_bgk_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                yield_control_signal -= yield_bgk_control
            yield_control_signal = uncertainties.ufloat(
                max(0.0, yield_control_signal.nominal_value),
                yield_control_signal.std_dev)

            yield_control_relaxed = tools.PoissonYield(
                plotData.plotdict["root_objects"]
                [qcd_data_relaxed_control_nick])()
            for nick in qcd_control_relaxed_subtract_nicks:
                yield_bgk_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                yield_control_relaxed -= yield_bgk_control
            yield_control_relaxed = uncertainties.ufloat(
                max(0.0, yield_control_relaxed.nominal_value),
                yield_control_relaxed.std_dev)

            scale_factor = yield_control_signal
            if yield_control_relaxed != 0.0:
                scale_factor /= yield_control_relaxed

            log.debug(
                "Scale factor for process QCD (nick \"{nick}\") is {scale_factor}."
                .format(nick=qcd_data_shape_nick, scale_factor=scale_factor))
            plotData.plotdict["root_objects"][qcd_data_shape_nick].Scale(
                scale_factor.nominal_value)

            final_yield = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_data_shape_nick])()

            log.debug(
                "Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}."
                .format(nick=qcd_data_shape_nick,
                        unc=final_yield.std_dev / final_yield.nominal_value
                        if final_yield.nominal_value != 0.0 else 0.0))

            plotData.metadata[qcd_data_shape_nick] = {
                "yield":
                final_yield.nominal_value,
                "yield_unc":
                final_yield.std_dev,
                "yield_unc_rel":
                abs(final_yield.std_dev / final_yield.nominal_value
                    if final_yield.nominal_value != 0.0 else 0.0),
            }
    def run(self, plotData=None):
        super(EstimateWjetsAndQCD, self).run(plotData)

        for qcd_extrapolation_factor_ss_os, qcd_shape_nick, qcd_ss_lowmt_nick, qcd_ss_highmt_shape_nick, qcd_os_highmt_nick, qcd_shape_highmt_substract_nick, qcd_yield_nick, qcd_shape_substract_nick, qcd_yield_substract_nick, wjets_os_highmt_mc_nick, wjets_ss_highmt_mc_nick, wjets_ss_substract_nick, wjets_ss_data_nick, wjets_os_substract_nick, wjets_os_data_nick, wjets_shape_nick, wjets_relaxed_os_highmt_nick, wjets_relaxed_os_lowmt_nick, wjets_scale_factor_shift, wjets_final_selection in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            ########################################
            # estimate QCD for the highmT region

            # get qcd ss high mt shape
            for nick in qcd_shape_highmt_substract_nick + [
                    wjets_ss_highmt_mc_nick
            ]:
                plotData.plotdict["root_objects"][
                    qcd_ss_highmt_shape_nick].Add(
                        plotData.plotdict["root_objects"][nick], -1)

            # get qcd yield in ss high mt region
            yield_qcd_ss_highmt = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_ss_data_nick])()
            for nick in wjets_ss_substract_nick + [wjets_ss_highmt_mc_nick]:
                yield_qcd_ss_highmt -= tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
            yield_qcd_ss_highmt = max(
                uncertainties.ufloat(0.0, yield_qcd_ss_highmt.std_dev),
                yield_qcd_ss_highmt)

            # scale qcd ss high mt shape by qcd yield found in data
            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick])()
            if integral_shape != 0.0:
                scale_factor = yield_qcd_ss_highmt / integral_shape
                plotData.plotdict["root_objects"][
                    qcd_ss_highmt_shape_nick].Scale(scale_factor.nominal_value)

            # scale qcd os high mt shape by qcd yield found in ss data and ss->os extrapolation factor
            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_os_highmt_nick])()
            if integral_shape != 0.0:
                scale_factor = yield_qcd_ss_highmt * qcd_extrapolation_factor_ss_os / integral_shape
                plotData.plotdict["root_objects"][qcd_os_highmt_nick].Scale(
                    scale_factor.nominal_value)

            ########################################
            # estimate W+jets

            # get w+jets yield in os high mt region
            yield_wjets_os_highmt = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_os_data_nick])()
            for nick in wjets_os_substract_nick:
                yield_wjets_os_highmt -= tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
            yield_wjets_os_highmt -= qcd_extrapolation_factor_ss_os * yield_qcd_ss_highmt
            yield_wjets_os_highmt = max(
                uncertainties.ufloat(0.0, yield_wjets_os_highmt.std_dev),
                yield_wjets_os_highmt)
            if yield_wjets_os_highmt.nominal_value == 0.0:
                log.warning(
                    "W+jets & QCD estimation: data yield in high mT region after background subtraction is 0!"
                )

            # get high mt -> low mt extrapolation factor from MC
            if tools.PoissonYield(plotData.plotdict["root_objects"]
                                  [wjets_relaxed_os_highmt_nick])() != 0.0:
                wjets_extrapolation_factor_mt = tools.PoissonYield(
                    plotData.plotdict["root_objects"]
                    [wjets_relaxed_os_lowmt_nick])() / tools.PoissonYield(
                        plotData.plotdict["root_objects"]
                        [wjets_relaxed_os_highmt_nick])()
            else:
                log.warning(
                    "W+jets & QCD estimation: W+jets high mT region in MC has no entries. High->low mT extrapolation factor is set to 1.0!"
                )
                wjets_extrapolation_factor_mt = 1.0

            # get w+jets yield in low mt region
            wjets_yield = yield_wjets_os_highmt * wjets_extrapolation_factor_mt

            # extrapolate to final selection
            if wjets_final_selection != None:
                wjets_yield = wjets_yield * tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_final_selection])(
                    ) / tools.PoissonYield(plotData.plotdict["root_objects"]
                                           [wjets_relaxed_os_lowmt_nick])()

            # scale signal region histograms
            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][wjets_shape_nick])()
            if integral_shape != 0.0:
                scale_factor = wjets_yield / integral_shape
                log.debug(
                    "Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}."
                    .format(nick=wjets_shape_nick, scale_factor=scale_factor))
                plotData.plotdict["root_objects"][wjets_shape_nick].Scale(
                    scale_factor.nominal_value)

            plotData.metadata[wjets_shape_nick] = {
                "yield":
                wjets_yield.nominal_value,
                "yield_unc":
                wjets_yield.std_dev,
                "yield_unc_rel":
                abs(wjets_yield.std_dev / wjets_yield.nominal_value
                    if wjets_yield.nominal_value != 0.0 else 0.0),
            }

            ########################################
            # estimate QCD for the lowmT

            # define w+jets scale factor for qcd estimation
            if tools.PoissonYield(plotData.plotdict["root_objects"]
                                  [wjets_os_highmt_mc_nick])() != 0.0:
                wjets_scale_factor = yield_wjets_os_highmt / tools.PoissonYield(
                    plotData.plotdict["root_objects"]
                    [wjets_os_highmt_mc_nick])()
            else:
                log.warning(
                    "W+jets & QCD estimation: W+jets high mT region in MC has no entries. Scale factor for W+jets in QCD estimation is set to 1.0!"
                )
                wjets_scale_factor = uncertainties.ufloat(1.0, 0.0)

            for nick in qcd_shape_substract_nick:
                if "wj" in nick:
                    scale_factor = wjets_scale_factor * wjets_scale_factor_shift
                    plotData.plotdict["root_objects"][nick].Scale(
                        scale_factor.nominal_value)
                plotData.plotdict["root_objects"][qcd_shape_nick].Add(
                    plotData.plotdict["root_objects"][nick], -1)

            yield_qcd_ss_lowmt = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_yield_nick])()
            for nick in qcd_yield_substract_nick:
                if "wj" in nick and tools.PoissonYield(
                        plotData.plotdict["root_objects"][nick])() != 0.0:
                    scale_factor = wjets_scale_factor * wjets_scale_factor_shift
                    plotData.plotdict["root_objects"][nick].Scale(
                        scale_factor.nominal_value)
                yield_qcd_ss_lowmt -= tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
            yield_qcd_ss_lowmt = max(
                uncertainties.ufloat(0.0, yield_qcd_ss_lowmt.std_dev),
                yield_qcd_ss_lowmt)
            if yield_qcd_ss_lowmt.nominal_value == 0.0:
                log.warning(
                    "W+jets & QCD estimation: data yield in low mT SS region after background subtraction is 0!"
                )

            # get qcd yield in low mt region
            qcd_yield = yield_qcd_ss_lowmt * qcd_extrapolation_factor_ss_os

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_shape_nick])()
            if integral_shape != 0.0:
                scale_factor = qcd_yield / integral_shape
                plotData.plotdict["root_objects"][qcd_shape_nick].Scale(
                    scale_factor.nominal_value)

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_ss_lowmt_nick])()
            if integral_shape != 0.0:
                scale_factor = yield_qcd_ss_lowmt / integral_shape
                plotData.plotdict["root_objects"][qcd_ss_lowmt_nick].Scale(
                    scale_factor.nominal_value)

            # write relative uncertainties to metadata to pick them up with combine
            plotData.metadata[qcd_shape_nick] = {
                "yield":
                qcd_yield.nominal_value,
                "yield_unc":
                qcd_yield.std_dev,
                "yield_unc_rel":
                abs(qcd_yield.std_dev / qcd_yield.nominal_value
                    if qcd_yield.nominal_value != 0.0 else 0.0),
            }
    def run(self, plotData=None):
        super(EstimateQcd, self).run(plotData)

        for qcd_data_shape_nick, qcd_data_yield_nick, qcd_data_control_nick, qcd_data_substract_nicks, qcd_extrapolation_factor_ss_os, qcd_subtract_shape in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):

            yield_data_control = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_data_control_nick])()
            yield_qcd_control = yield_data_control
            for nick in qcd_data_substract_nicks:
                yield_bkg_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                if nick in plotData.metadata:
                    yield_bkg_control = uncertainties.ufloat(
                        plotData.metadata[nick].get(
                            "yield", yield_bkg_control.nominal_value),
                        plotData.metadata[nick].get("yield_unc",
                                                    yield_bkg_control.std_dev))
                yield_qcd_control -= yield_bkg_control

                if qcd_subtract_shape:
                    plotData.plotdict["root_objects"][
                        qcd_data_control_nick].Add(
                            plotData.plotdict["root_objects"][nick],
                            -1.0 / plotData.plotdict["qcd_scale_factor"])

            if qcd_subtract_shape:
                plotData.plotdict["root_objects"][
                    qcd_data_shape_nick] = plotData.plotdict["root_objects"][
                        qcd_data_control_nick]

            yield_qcd_control = max(0.0, yield_qcd_control)

            scale_factor = yield_qcd_control * qcd_extrapolation_factor_ss_os
            if yield_data_control != 0.0:
                scale_factor /= yield_data_control

            final_yield = tools.PoissonYield(
                plotData.plotdict["root_objects"]
                [qcd_data_yield_nick])() * scale_factor
            log.debug(
                "Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}."
                .format(nick=qcd_data_shape_nick,
                        unc=final_yield.std_dev / final_yield.nominal_value
                        if final_yield.nominal_value != 0.0 else 0.0))

            plotData.metadata[qcd_data_shape_nick] = {
                "yield":
                final_yield.nominal_value,
                "yield_unc":
                final_yield.std_dev,
                "yield_unc_rel":
                abs(final_yield.std_dev / final_yield.nominal_value
                    if final_yield.nominal_value != 0.0 else 0.0),
            }

            integral_shape = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_data_shape_nick])()
            if integral_shape != 0.0:
                scale_factor = final_yield / integral_shape
                log.debug(
                    "Scale factor for process QCD (nick \"{nick}\") is {scale_factor}."
                    .format(nick=qcd_data_shape_nick,
                            scale_factor=scale_factor))
                plotData.plotdict["root_objects"][qcd_data_shape_nick].Scale(
                    scale_factor.nominal_value)
	def __init__(self, root_histogram):
		error = array.array("d", [0.0])
		integral = root_histogram.IntegralAndError(1, root_histogram.GetNbinsX(), error)
		error = error[0]
		#self.poisson_yield = uncertainties.ufloat(integral, error)
		self.poisson_yield = uncertainties.ufloat(integral, math.sqrt(abs(integral)))
	def run(self, plotData=None):
		super(EstimateWjetsAndQCD, self).run(plotData)

		for qcd_extrapolation_factor_ss_os, qcd_shape_nick, qcd_ss_lowmt_nick, qcd_ss_highmt_shape_nick, qcd_os_highmt_nick, qcd_shape_highmt_substract_nick, qcd_yield_nick, qcd_shape_substract_nick, qcd_yield_substract_nick, wjets_ss_mc_nick, wjets_os_mc_nick, wjets_os_highmt_mc_nick, wjets_os_lowmt_mc_nick, wjets_ss_highmt_mc_nick, wjets_ss_substract_nick, wjets_ss_data_nick, wjets_os_substract_nick, wjets_os_data_nick, wjets_shape_nick, wjets_final_selection in zip(*[plotData.plotdict[key] for key in self._plotdict_keys]):
			# estimate QCD for the lowmT
			for nick in qcd_shape_substract_nick:
				plotData.plotdict["root_objects"][qcd_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1)
			yield_qcd_control = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_yield_nick])()
			for nick in qcd_yield_substract_nick:
				yield_bkg_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				if nick in plotData.metadata:
					yield_bkg_control = uncertainties.ufloat(
							plotData.metadata[nick].get("yield", yield_bkg_control.nominal_value),
							plotData.metadata[nick].get("yield_unc", yield_bkg_control.std_dev)
					)
				yield_qcd_control -= yield_bkg_control
			yield_qcd_control = max(0.0, yield_qcd_control)

			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_qcd_control * qcd_extrapolation_factor_ss_os / integral_shape
				final_qcd_yield = yield_qcd_control * qcd_extrapolation_factor_ss_os
				plotData.plotdict["root_objects"][qcd_shape_nick].Scale(scale_factor.nominal_value)

			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_ss_lowmt_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_qcd_control / integral_shape
				plotData.plotdict["root_objects"][qcd_ss_lowmt_nick].Scale(scale_factor.nominal_value)

			# write relative uncertainties to metadata to pick them up with combine
			plotData.metadata[qcd_shape_nick] = {
				"yield" : final_qcd_yield.nominal_value,
				"yield_unc" : final_qcd_yield.std_dev,
				"yield_unc_rel" : abs(final_qcd_yield.std_dev/final_qcd_yield.nominal_value if final_qcd_yield.nominal_value != 0.0 else 0.0),
			}

			# estimate W+jets
			yield_ss_control = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_ss_data_nick])()
			for nick in wjets_ss_substract_nick:
				yield_bkg_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				yield_ss_control -= yield_bkg_control
			yield_os_control = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_data_nick])()
			for nick in wjets_os_substract_nick:
				yield_bkg_control = tools.PoissonYield(plotData.plotdict["root_objects"][nick])()
				yield_os_control -= yield_bkg_control

			wjets_extrapolation_factor_ss_os = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_mc_nick])()/tools.PoissonYield(plotData.plotdict["root_objects"][wjets_ss_mc_nick])()
			wjets_extrapolation_factor_mt = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_lowmt_mc_nick])()/tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_highmt_mc_nick])()

			wjets_yield = (yield_os_control-qcd_extrapolation_factor_ss_os*yield_ss_control)*wjets_extrapolation_factor_ss_os/(wjets_extrapolation_factor_ss_os-qcd_extrapolation_factor_ss_os)*wjets_extrapolation_factor_mt
			# extrapolate to final selection
			if wjets_final_selection != None:
				wjets_yield = wjets_yield * tools.PoissonYield(plotData.plotdict["root_objects"][wjets_final_selection])() / tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_lowmt_mc_nick])()



			#print "scale factor inclusive to categorized"
			#print str(tools.PoissonYield(plotData.plotdict["root_objects"][wjets_final_selection])() / tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_lowmt_mc_nick])())
			#print "final selection " + str(tools.PoissonYield(plotData.plotdict["root_objects"][wjets_final_selection])())
			#print "inclusive " + str(tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_lowmt_mc_nick])())
			# scale signal region histograms
			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_shape_nick])()
			#print "QCD/WJets estimation summary"
			#print "Extrapolation factors"
			#print "\t QCD OS/SS: " + str(qcd_extrapolation_factor_ss_os)
			#print "\t WJets OS/SS: " + str(wjets_extrapolation_factor_ss_os)
			#print "\t WJets high-low mT: " + str(wjets_extrapolation_factor_mt)
			#print "WJets yield"
			#print "\t before: " + str(integral_shape)
			#print "\t after: " + str(wjets_yield)
			#print "Scale factor: " + str(wjets_yield / integral_shape)

			if integral_shape != 0.0:
				scale_factor = wjets_yield / integral_shape
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_shape_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_shape_nick].Scale(scale_factor.nominal_value)

			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_os_highmt_mc_nick])()
			if integral_shape != 0.0:
				scale_factor = wjets_yield / (integral_shape * wjets_extrapolation_factor_mt)
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_os_highmt_mc_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_os_highmt_mc_nick].Scale(scale_factor.nominal_value)

			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][wjets_ss_highmt_mc_nick])()
			if integral_shape != 0.0:
				scale_factor = wjets_yield / (integral_shape * wjets_extrapolation_factor_mt * wjets_extrapolation_factor_ss_os)
				log.debug("Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}.".format(nick=wjets_ss_highmt_mc_nick, scale_factor=scale_factor))
				plotData.plotdict["root_objects"][wjets_ss_highmt_mc_nick].Scale(scale_factor.nominal_value)


			# estimate QCD for the highmT region
			for nick in qcd_shape_highmt_substract_nick+[wjets_ss_highmt_mc_nick]:
				plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick].Add(plotData.plotdict["root_objects"][nick], -1)

			yield_qcd_ss_highmt = yield_ss_control - tools.PoissonYield(plotData.plotdict["root_objects"][wjets_ss_highmt_mc_nick])()
			yield_qcd_ss_highmt = max(0.0, yield_qcd_ss_highmt)

			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_qcd_ss_highmt / integral_shape
				plotData.plotdict["root_objects"][qcd_ss_highmt_shape_nick].Scale(scale_factor.nominal_value)

			integral_shape = tools.PoissonYield(plotData.plotdict["root_objects"][qcd_os_highmt_nick])()
			if integral_shape != 0.0:
				scale_factor = yield_qcd_ss_highmt * qcd_extrapolation_factor_ss_os / integral_shape
				plotData.plotdict["root_objects"][qcd_os_highmt_nick].Scale(scale_factor.nominal_value)

			plotData.metadata[wjets_shape_nick] = {
				"yield" : wjets_yield.nominal_value,
				"yield_unc" : wjets_yield.std_dev,
				"yield_unc_rel" : abs(wjets_yield.std_dev/wjets_yield.nominal_value if wjets_yield.nominal_value != 0.0 else 0.0),
			}
	def run(self, plotData=None):
		super(Unpolarisation, self).run(plotData)
		
		remove_bias_instead_unpolarisation = plotData.plotdict["unpolarisation_remove_bias_instead_unpolarisation"]
		
		for index, (nominal_pos_pol_nick, shift_up_pos_pol_nicks, shift_down_pos_pol_nicks, nominal_neg_pol_nick, shift_up_neg_pol_nicks, shift_down_neg_pol_nicks, forced_gen_polarisation, scale_factor_pos_pol_nick, scale_factor_neg_pol_nick, polarisation_before_nick, polarisation_after_nick) in enumerate(zip(*[plotData.plotdict[key] for key in ["unpolarisation_nominal_pos_pol_nicks", "unpolarisation_shift_up_pos_pol_nicks", "unpolarisation_shift_down_pos_pol_nicks", "unpolarisation_nominal_neg_pol_nicks", "unpolarisation_shift_up_neg_pol_nicks", "unpolarisation_shift_down_neg_pol_nicks", "unpolarisation_forced_gen_polarisations", "unpolarisation_scale_factor_pos_pol_nicks", "unpolarisation_scale_factor_neg_pol_nicks", "unpolarisation_polarisation_before_nicks", "unpolarisation_polarisation_after_nicks"]])):
			
			nominal_pos_pol_hist = plotData.plotdict["root_objects"][nominal_pos_pol_nick]
			shift_up_pos_pol_hists = [plotData.plotdict["root_objects"][nick] for nick in shift_up_pos_pol_nicks]
			shift_down_pos_pol_hists = [plotData.plotdict["root_objects"][nick] for nick in shift_down_pos_pol_nicks]
			
			nominal_neg_pol_hist = plotData.plotdict["root_objects"][nominal_neg_pol_nick]
			shift_up_neg_pol_hists = [plotData.plotdict["root_objects"][nick] for nick in shift_up_neg_pol_nicks]
			shift_down_neg_pol_hists = [plotData.plotdict["root_objects"][nick] for nick in shift_down_neg_pol_nicks]
			
			name = hashlib.md5("_".join(map(str, [nominal_pos_pol_nick, shift_up_pos_pol_nicks, shift_down_pos_pol_nicks, nominal_neg_pol_nick, shift_up_neg_pol_nicks, shift_down_neg_pol_nicks, forced_gen_polarisation, scale_factor_pos_pol_nick, scale_factor_neg_pol_nick]))).hexdigest()
			
			scale_factor_pos_pol_hist = nominal_pos_pol_hist.Clone("unpol_pos_"+name)
			scale_factor_pos_pol_hist.Reset()
			scale_factor_neg_pol_hist = nominal_neg_pol_hist.Clone("unpol_neg_"+name)
			scale_factor_neg_pol_hist.Reset()
			
			polarisation_before_hist = nominal_pos_pol_hist.Clone("unpol_pol_before_"+name)
			polarisation_before_hist.Reset()
			polarisation_after_hist = nominal_pos_pol_hist.Clone("unpol_pol_after_"+name)
			polarisation_after_hist.Reset()
			
			# assume same binning for all histograms
			for x_bin in xrange(1, nominal_pos_pol_hist.GetNbinsX()+1):
				for y_bin in xrange(1, nominal_pos_pol_hist.GetNbinsY()+1):
					for z_bin in xrange(1, nominal_pos_pol_hist.GetNbinsZ()+1):
						global_bin = nominal_pos_pol_hist.GetBin(x_bin, y_bin, z_bin)
						
						n_pos_pol = uncertainties.ufloat(
								nominal_pos_pol_hist.GetBinContent(global_bin),
								nominal_pos_pol_hist.GetBinError(global_bin)
						)
						
						unc_up = pow(n_pos_pol.std_dev, 2)
						for shift_hist in shift_up_pos_pol_hists:
							n_shift = uncertainties.ufloat(shift_hist.GetBinContent(global_bin), shift_hist.GetBinError(global_bin))
							unc_up += pow(n_shift-n_pos_pol, 2).nominal_value
						unc_up = math.sqrt(unc_up)
						
						unc_down = pow(n_pos_pol.std_dev, 2)
						for shift_hist in shift_down_pos_pol_hists:
							n_shift = uncertainties.ufloat(shift_hist.GetBinContent(global_bin), shift_hist.GetBinError(global_bin))
							unc_down += pow(n_shift-n_pos_pol, 2).nominal_value
						unc_down = math.sqrt(unc_down)
						
						n_pos_pol.std_dev = max(unc_up, unc_down)
						
						n_neg_pol = uncertainties.ufloat(
								nominal_neg_pol_hist.GetBinContent(global_bin),
								nominal_neg_pol_hist.GetBinError(global_bin)
						)
						
						unc_up = pow(n_neg_pol.std_dev, 2)
						for shift_hist in shift_up_neg_pol_hists:
							n_shift = uncertainties.ufloat(shift_hist.GetBinContent(global_bin), shift_hist.GetBinError(global_bin))
							unc_up += pow(n_shift-n_neg_pol, 2).nominal_value
						unc_up = math.sqrt(unc_up)
						
						unc_down = pow(n_neg_pol.std_dev, 2)
						for shift_hist in shift_down_neg_pol_hists:
							n_shift = uncertainties.ufloat(shift_hist.GetBinContent(global_bin), shift_hist.GetBinError(global_bin))
							unc_down += pow(n_shift-n_neg_pol, 2).nominal_value
						unc_down = math.sqrt(unc_down)
						
						n_neg_pol.std_dev = max(unc_up, unc_down)
						
						scale_factors = polarisationsignalscaling.PolarisationScaleFactors(
								n_pos_pol, n_neg_pol,
								n_pos_pol, n_neg_pol,
								forced_gen_polarisation=forced_gen_polarisation
						)
						
						scale_factor_pos_pol = scale_factors.get_bias_removal_factor_pospol() if remove_bias_instead_unpolarisation else scale_factors.get_scale_factor_pospol()
						scale_factor_pos_pol_hist.SetBinContent(global_bin, scale_factor_pos_pol.nominal_value)
						scale_factor_pos_pol_hist.SetBinError(global_bin, scale_factor_pos_pol.std_dev)
						
						scale_factor_neg_pol = scale_factors.get_bias_removal_factor_negpol() if remove_bias_instead_unpolarisation else scale_factors.get_scale_factor_negpol()
						scale_factor_neg_pol_hist.SetBinContent(global_bin, scale_factor_neg_pol.nominal_value)
						scale_factor_neg_pol_hist.SetBinError(global_bin, scale_factor_neg_pol.std_dev)
						
						polarisation_before = scale_factors.get_gen_polarisation()
						polarisation_before_hist.SetBinContent(global_bin, polarisation_before.nominal_value)
						polarisation_before_hist.SetBinError(global_bin, polarisation_before.std_dev)
						
						# Caution: scale_factors object is modified!
						scale_factors.n_gen_pospol *= scale_factor_pos_pol
						scale_factors.n_gen_negpol *= scale_factor_neg_pol
						polarisation_after = scale_factors.get_gen_polarisation()
						polarisation_after_hist.SetBinContent(global_bin, polarisation_after.nominal_value)
						polarisation_after_hist.SetBinError(global_bin, polarisation_after.std_dev)
						
			plotData.plotdict["root_objects"][scale_factor_pos_pol_nick] = scale_factor_pos_pol_hist
			plotData.plotdict["root_objects"][scale_factor_neg_pol_nick] = scale_factor_neg_pol_hist
			
			plotData.plotdict["root_objects"][polarisation_before_nick] = polarisation_before_hist
			plotData.plotdict["root_objects"][polarisation_after_nick] = polarisation_after_hist
Exemplo n.º 26
0
    def run(self, plotData=None):
        super(EstimateQcdPrefit, self).run(plotData)

        # make sure that all necessary histograms are available
        for nicks in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            for nick in nicks:
                if isinstance(nick, basestring):
                    assert isinstance(
                        plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
                elif (not isinstance(nick, float)
                      and not isinstance(nick, bool)):
                    for subnick in nick:
                        assert isinstance(
                            plotData.plotdict["root_objects"].get(subnick),
                            ROOT.TH1)

        for qcd_shape_nick, qcd_yield_nick, qcd_yield_subtract_nicks, qcd_shape_subtract_nicks, qcd_extrapolation_factor_ss_os in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            ######################
            # ------- Step 1 -----
            # 1. Get Yield in Control region and subtract all backgrounds.
            yield_qcd = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_yield_nick])()
            # estimate the QCD yield
            for nick in qcd_yield_subtract_nicks:
                yield_bkg = tools.PoissonYield(
                    plotData.plotdict["root_objects"][nick])()
                yield_qcd -= yield_bkg
            yield_qcd = uncertainties.ufloat(max(0.0, yield_qcd.nominal_value),
                                             yield_qcd.std_dev)
            if (yield_qcd.nominal_value == 0.0):
                log.warning("QCD yield is 0!")

            ######################
            # ------- Step 2 -----
            #  QCD shape
            # 1. Subtract the shapes of all backgrounds from data in the control region.
            # 2. Scale the qcd by the qcd_os_ss_extrapolation_factor to get the prefit estimate.
            # Sidemark: In this script the factor is supposed to be 1.0 because we want to determine the
            # factor with this first estimate.

            for nick in qcd_shape_subtract_nicks:
                plotData.plotdict["root_objects"][qcd_shape_nick].Add(
                    plotData.plotdict["root_objects"][nick],
                    -1.0 / plotData.plotdict["qcd_scale_factor"])

            shape_yield = tools.PoissonYield(
                plotData.plotdict["root_objects"][qcd_shape_nick])()
            if shape_yield != 0.0:
                qcd_extrapolation_factor_ss_os = 1.0
                scale_factor = yield_qcd / shape_yield * qcd_extrapolation_factor_ss_os
                plotData.plotdict["root_objects"][qcd_shape_nick].Scale(
                    scale_factor.nominal_value)

            #log.debug("Relative statistical uncertainty of the yield for process QCD (nick \"{nick}\") is {unc}.".format(nick=qcd_data_shape_nick, unc=final_yield.std_dev/final_yield.nominal_value if final_yield.nominal_value != 0.0 else 0.0))
            final_yield_qcd = yield_qcd * qcd_extrapolation_factor_ss_os

            # save to be picked up
            plotData.metadata[qcd_shape_nick] = {
                "yield":
                final_yield_qcd.nominal_value,
                "yield_unc":
                final_yield_qcd.std_dev,
                "yield_unc_rel":
                abs(final_yield_qcd.std_dev / final_yield_qcd.nominal_value
                    if final_yield_qcd.nominal_value != 0.0 else 0.0),
            }
Exemplo n.º 27
0
				args.output_dir
		))
	
	plot_configs = []
	datacards_workspaces = {}
	efficiency = {}

	for datacard, cb in datacards_cbs.iteritems():
		for channel in cb.cp().analysis(["ztt"]).era(["13TeV"]).channel_set():
			nPassPre = 0
			nFailPre = 0
			sig_process = cb.cp().bin([category]).signals().process_set()
			
			for category in cb.cp().analysis(["ztt"]).era(["13TeV"]).channel([channel]).bin_set():
				if "pass" in category:
					nPassPre = uncertainties.ufloat(cb.cp().bin([category]).process(sig_process).GetRate(),
									cb.cp().bin([category]).process(sig_process).GetUncertainty())
				elif "fail" in category:
					nFailPre = uncertainties.ufloat(cb.cp().bin([category]).process(sig_process).GetRate(),
									cb.cp().bin([category]).process(sig_process).GetUncertainty())
			efficiency[channel] = nPassPre / (nPassPre + nFailPre)

			command = ["text2workspace.py -m {MASS} -P {MODEL} --PO \"eff={EFF}\" {DATACARD} -o {OUTPUT}".format(
				MASS=[mass for mass in cb.mass_set() if mass != "*"][0],
				MODEL=model_settings["P"],
				EFF=efficiency[channel].nominal_value,
				DATACARD=datacard,
				OUTPUT=os.path.splitext(datacard)[0]+".root")]
			
			print "command -->", command
			tools.parallelize(_call_command, command, n_processes=args.n_processes)
Exemplo n.º 28
0
    def run(self, plotData=None):
        super(Unpolarisation, self).run(plotData)

        remove_bias_instead_unpolarisation = plotData.plotdict[
            "unpolarisation_remove_bias_instead_unpolarisation"]

        for index, (nominal_pos_pol_nick, shift_up_pos_pol_nicks,
                    shift_down_pos_pol_nicks, nominal_neg_pol_nick,
                    shift_up_neg_pol_nicks, shift_down_neg_pol_nicks,
                    forced_gen_polarisation, scale_factor_pos_pol_nick,
                    scale_factor_neg_pol_nick, polarisation_before_nick,
                    polarisation_after_nick) in enumerate(
                        zip(*[
                            plotData.plotdict[key] for key in [
                                "unpolarisation_nominal_pos_pol_nicks",
                                "unpolarisation_shift_up_pos_pol_nicks",
                                "unpolarisation_shift_down_pos_pol_nicks",
                                "unpolarisation_nominal_neg_pol_nicks",
                                "unpolarisation_shift_up_neg_pol_nicks",
                                "unpolarisation_shift_down_neg_pol_nicks",
                                "unpolarisation_forced_gen_polarisations",
                                "unpolarisation_scale_factor_pos_pol_nicks",
                                "unpolarisation_scale_factor_neg_pol_nicks",
                                "unpolarisation_polarisation_before_nicks",
                                "unpolarisation_polarisation_after_nicks"
                            ]
                        ])):

            nominal_pos_pol_hist = plotData.plotdict["root_objects"][
                nominal_pos_pol_nick]
            shift_up_pos_pol_hists = [
                plotData.plotdict["root_objects"][nick]
                for nick in shift_up_pos_pol_nicks if not nick is None
            ]
            shift_down_pos_pol_hists = [
                plotData.plotdict["root_objects"][nick]
                for nick in shift_down_pos_pol_nicks if not nick is None
            ]

            nominal_neg_pol_hist = plotData.plotdict["root_objects"][
                nominal_neg_pol_nick]
            shift_up_neg_pol_hists = [
                plotData.plotdict["root_objects"][nick]
                for nick in shift_up_neg_pol_nicks if not nick is None
            ]
            shift_down_neg_pol_hists = [
                plotData.plotdict["root_objects"][nick]
                for nick in shift_down_neg_pol_nicks if not nick is None
            ]

            name = hashlib.md5("_".join(
                map(str, [
                    nominal_pos_pol_nick, shift_up_pos_pol_nicks,
                    shift_down_pos_pol_nicks, nominal_neg_pol_nick,
                    shift_up_neg_pol_nicks, shift_down_neg_pol_nicks,
                    forced_gen_polarisation, scale_factor_pos_pol_nick,
                    scale_factor_neg_pol_nick
                ]))).hexdigest()

            scale_factor_pos_pol_hist = nominal_pos_pol_hist.Clone(
                "unpol_pos_" + name)
            scale_factor_pos_pol_hist.Reset()
            scale_factor_neg_pol_hist = nominal_neg_pol_hist.Clone(
                "unpol_neg_" + name)
            scale_factor_neg_pol_hist.Reset()

            polarisation_before_hist = nominal_pos_pol_hist.Clone(
                "unpol_pol_before_" + name)
            polarisation_before_hist.Reset()
            polarisation_after_hist = nominal_pos_pol_hist.Clone(
                "unpol_pol_after_" + name)
            polarisation_after_hist.Reset()

            # assume same binning for all histograms
            for x_bin in xrange(1, nominal_pos_pol_hist.GetNbinsX() + 1):
                for y_bin in xrange(1, nominal_pos_pol_hist.GetNbinsY() + 1):
                    for z_bin in xrange(1,
                                        nominal_pos_pol_hist.GetNbinsZ() + 1):
                        global_bin = nominal_pos_pol_hist.GetBin(
                            x_bin, y_bin, z_bin)

                        n_pos_pol = uncertainties.ufloat(
                            nominal_pos_pol_hist.GetBinContent(global_bin),
                            nominal_pos_pol_hist.GetBinError(global_bin))

                        unc_up = pow(n_pos_pol.std_dev, 2)
                        for shift_hist in shift_up_pos_pol_hists:
                            n_shift = uncertainties.ufloat(
                                shift_hist.GetBinContent(global_bin),
                                shift_hist.GetBinError(global_bin))
                            unc_up += pow(n_shift - n_pos_pol, 2).nominal_value
                        unc_up = math.sqrt(unc_up)

                        unc_down = pow(n_pos_pol.std_dev, 2)
                        for shift_hist in shift_down_pos_pol_hists:
                            n_shift = uncertainties.ufloat(
                                shift_hist.GetBinContent(global_bin),
                                shift_hist.GetBinError(global_bin))
                            unc_down += pow(n_shift - n_pos_pol,
                                            2).nominal_value
                        unc_down = math.sqrt(unc_down)

                        n_pos_pol.std_dev = max(unc_up, unc_down)

                        n_neg_pol = uncertainties.ufloat(
                            nominal_neg_pol_hist.GetBinContent(global_bin),
                            nominal_neg_pol_hist.GetBinError(global_bin))

                        unc_up = pow(n_neg_pol.std_dev, 2)
                        for shift_hist in shift_up_neg_pol_hists:
                            n_shift = uncertainties.ufloat(
                                shift_hist.GetBinContent(global_bin),
                                shift_hist.GetBinError(global_bin))
                            unc_up += pow(n_shift - n_neg_pol, 2).nominal_value
                        unc_up = math.sqrt(unc_up)

                        unc_down = pow(n_neg_pol.std_dev, 2)
                        for shift_hist in shift_down_neg_pol_hists:
                            n_shift = uncertainties.ufloat(
                                shift_hist.GetBinContent(global_bin),
                                shift_hist.GetBinError(global_bin))
                            unc_down += pow(n_shift - n_neg_pol,
                                            2).nominal_value
                        unc_down = math.sqrt(unc_down)

                        n_neg_pol.std_dev = max(unc_up, unc_down)

                        if (n_pos_pol * n_neg_pol).nominal_value != 0.0:
                            scale_factors = polarisationsignalscaling.PolarisationScaleFactors(
                                n_pos_pol,
                                n_neg_pol,
                                n_pos_pol,
                                n_neg_pol,
                                forced_gen_polarisation=forced_gen_polarisation
                            )

                            scale_factor_pos_pol = scale_factors.get_bias_removal_factor_pospol(
                            ) if remove_bias_instead_unpolarisation else scale_factors.get_scale_factor_pospol(
                            )
                            scale_factor_pos_pol_hist.SetBinContent(
                                global_bin, scale_factor_pos_pol.nominal_value)
                            scale_factor_pos_pol_hist.SetBinError(
                                global_bin, scale_factor_pos_pol.std_dev)

                            scale_factor_neg_pol = scale_factors.get_bias_removal_factor_negpol(
                            ) if remove_bias_instead_unpolarisation else scale_factors.get_scale_factor_negpol(
                            )
                            scale_factor_neg_pol_hist.SetBinContent(
                                global_bin, scale_factor_neg_pol.nominal_value)
                            scale_factor_neg_pol_hist.SetBinError(
                                global_bin, scale_factor_neg_pol.std_dev)

                            polarisation_before = scale_factors.get_gen_polarisation(
                            )
                            polarisation_before_hist.SetBinContent(
                                global_bin, polarisation_before.nominal_value)
                            polarisation_before_hist.SetBinError(
                                global_bin, polarisation_before.std_dev)

                            # Caution: scale_factors object is modified!
                            scale_factors.n_gen_pospol *= scale_factor_pos_pol
                            scale_factors.n_gen_negpol *= scale_factor_neg_pol
                            polarisation_after = scale_factors.get_gen_polarisation(
                            )
                            polarisation_after_hist.SetBinContent(
                                global_bin, polarisation_after.nominal_value)
                            polarisation_after_hist.SetBinError(
                                global_bin, polarisation_after.std_dev)

                        else:
                            scale_factor_pos_pol_hist.SetBinContent(
                                global_bin, 0.0)
                            scale_factor_pos_pol_hist.SetBinError(
                                global_bin, 0.0)
                            scale_factor_neg_pol_hist.SetBinContent(
                                global_bin, 0.0)
                            scale_factor_neg_pol_hist.SetBinError(
                                global_bin, 0.0)
                            polarisation_before_hist.SetBinContent(
                                global_bin, 0.0)
                            polarisation_before_hist.SetBinError(
                                global_bin, 0.0)
                            polarisation_after_hist.SetBinContent(
                                global_bin, 0.0)
                            polarisation_after_hist.SetBinError(
                                global_bin, 0.0)

            plotData.plotdict["root_objects"][
                scale_factor_pos_pol_nick] = scale_factor_pos_pol_hist
            plotData.plotdict["root_objects"][
                scale_factor_neg_pol_nick] = scale_factor_neg_pol_hist

            plotData.plotdict["root_objects"][
                polarisation_before_nick] = polarisation_before_hist
            plotData.plotdict["root_objects"][
                polarisation_after_nick] = polarisation_after_hist
    def run(self, plotData=None):
        super(EstimateWjets, self).run(plotData)

        # make sure that all necessary histograms are available
        for nicks in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            for nick in nicks:
                if isinstance(nick, basestring):
                    assert isinstance(
                        plotData.plotdict["root_objects"].get(nick), ROOT.TH1)
                elif not isinstance(nick, bool):
                    for subnick in nick:
                        assert isinstance(
                            plotData.plotdict["root_objects"].get(subnick),
                            ROOT.TH1)

        for wjets_from_mc, wjets_shape_nick, wjets_data_control_nick, wjets_data_substract_nicks, wjets_mc_signal_nick, wjets_mc_control_nick in zip(
                *[plotData.plotdict[key] for key in self._plotdict_keys]):
            if not wjets_from_mc:  # skips the full estimation of this module and uses MC estimate of WJ instead.
                # Get yield and uncertainity in data in the control region
                yield_data_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"]
                    [wjets_data_control_nick])()
                for nick in wjets_data_substract_nicks:
                    # subtract yields of all backgrounds
                    yield_bkg_control = tools.PoissonYield(
                        plotData.plotdict["root_objects"][nick])()
                    if nick in plotData.metadata:
                        yield_bkg_control = uncertainties.ufloat(
                            plotData.metadata[nick].get(
                                "yield", yield_bkg_control.nominal_value),
                            plotData.metadata[nick].get(
                                "yield_unc", yield_bkg_control.std_dev))
                    yield_data_control -= yield_bkg_control
                # make sure we don't have negative yields
                yield_data_control = uncertainties.ufloat(
                    max(0.0, yield_data_control.nominal_value),
                    yield_data_control.std_dev)

                yield_mc_signal = tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_mc_signal_nick])()
                yield_mc_control = tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_mc_control_nick])()

                assert (yield_data_control * yield_mc_signal
                        == 0.0) or (yield_mc_control != 0.0)
                # the final yield in the signal region is N_data, WJ^{SR} = N_data, WJ^{CR} * N_MC,WJ^{SR} / N_MC,WJ^{CR}
                final_yield = yield_data_control * yield_mc_signal
                if final_yield != 0.0:
                    final_yield /= yield_mc_control
                log.debug(
                    "Relative statistical uncertainty of the yield for process W+jets (nick \"{nick}\") is {unc}."
                    .format(nick=wjets_shape_nick,
                            unc=final_yield.std_dev / final_yield.nominal_value
                            if final_yield.nominal_value != 0.0 else 0.0))

                plotData.metadata[wjets_shape_nick] = {
                    "yield":
                    final_yield.nominal_value,
                    "yield_unc":
                    final_yield.std_dev,
                    "yield_unc_rel":
                    abs(final_yield.std_dev / final_yield.nominal_value
                        if final_yield.nominal_value != 0.0 else 0.0),
                }
                plotData.metadata
                # scale the wj file by the ratio of the estimated yield and the yield given by MC.
                integral_shape = tools.PoissonYield(
                    plotData.plotdict["root_objects"][wjets_shape_nick])()
                if integral_shape != 0.0:
                    scale_factor = final_yield / integral_shape
                    log.debug(
                        "Scale factor for process W+jets (nick \"{nick}\") is {scale_factor}."
                        .format(nick=wjets_shape_nick,
                                scale_factor=scale_factor))
                    plotData.plotdict["root_objects"][wjets_shape_nick].Scale(
                        scale_factor.nominal_value)