Example #1
0
def draw_channel(channel,
                 fit=None,
                 no_data=False,
                 ypadding=None,
                 log_ypadding=None,
                 **kwargs):
    """
    Draw a HistFactory::Channel only include OverallSys systematics
    in resulting band as an illustration of the level of uncertainty
    since correlations of the NPs are not known and it is not
    possible to draw the statistically correct error band.
    """
    if fit is not None:
        log.warning("applying snapshot on channel {0}".format(channel.name))
        channel = channel.apply_snapshot(fit)
    if channel.data and channel.data.hist and not no_data:
        data_hist = channel.data.hist
    else:
        data_hist = None
    model_hists = []
    signal_hists = []
    systematics_terms = {}
    for sample in channel.samples:
        nominal_hist = sample.hist.Clone(shallow=True)
        _systematics = {}
        for sys_name, osys, hsys in sample.iter_sys():
            systematics_terms[sys_name] = (sys_name + '_UP',
                                           sys_name + '_DOWN')
            if hsys is not None:
                # include only overallsys component
                norm, shape = split_norm_shape(hsys, nominal_hist)
                if osys is not None:
                    osys.low *= norm.low
                    osys.high *= norm.high
                else:
                    osys = norm
            _systematics[sys_name + '_DOWN'] = nominal_hist * osys.low
            _systematics[sys_name + '_UP'] = nominal_hist * osys.high
            log.debug("sample: {0} overallsys: {1} high: {2} low: {3}".format(
                sample.name, sys_name, osys.high, osys.low))
        nominal_hist.systematics = _systematics
        if sample.GetNormFactor('SigXsecOverSM') is not None:
            signal_hists.append(nominal_hist)
        else:
            model_hists.append(nominal_hist)
    if 'systematics' in kwargs:
        del kwargs['systematics']
    figs = []
    for logy in (False, True):
        figs.append(
            draw(data=data_hist,
                 model=model_hists or None,
                 signal=signal_hists or None,
                 systematics=systematics_terms,
                 logy=logy,
                 ypadding=(log_ypadding or ypadding) if logy else ypadding,
                 **kwargs))
    return figs
Example #2
0
def draw_channel(channel, fit=None, no_data=False,
                 ypadding=None, log_ypadding=None, **kwargs):
    """
    Draw a HistFactory::Channel only include OverallSys systematics
    in resulting band as an illustration of the level of uncertainty
    since correlations of the NPs are not known and it is not
    possible to draw the statistically correct error band.
    """
    if fit is not None:
        log.warning("applying snapshot on channel {0}".format(channel.name))
        channel = channel.apply_snapshot(fit)
    if channel.data and channel.data.hist and not no_data:
        data_hist = channel.data.hist
    else:
        data_hist = None
    model_hists = []
    signal_hists = []
    systematics_terms = {}
    for sample in channel.samples:
        nominal_hist = sample.hist.Clone(shallow=True)
        _systematics = {}
        for sys_name, osys, hsys in sample.iter_sys():
            systematics_terms[sys_name] = (
                sys_name + '_UP',
                sys_name + '_DOWN')
            if hsys is not None:
                # include only overallsys component
                norm, shape = split_norm_shape(hsys, nominal_hist)
                if osys is not None:
                    osys.low *= norm.low
                    osys.high *= norm.high
                else:
                    osys = norm
            _systematics[sys_name + '_DOWN'] = nominal_hist * osys.low
            _systematics[sys_name + '_UP'] = nominal_hist * osys.high
            log.debug("sample: {0} overallsys: {1} high: {2} low: {3}".format(
                sample.name, sys_name, osys.high, osys.low))
        nominal_hist.systematics = _systematics
        if sample.GetNormFactor('SigXsecOverSM') is not None:
            signal_hists.append(nominal_hist)
        else:
            model_hists.append(nominal_hist)
    if 'systematics' in kwargs:
        del kwargs['systematics']
    figs = []
    for logy in (False, True):
        figs.append(draw(
            data=data_hist,
            model=model_hists or None,
            signal=signal_hists or None,
            systematics=systematics_terms,
            logy=logy,
            ypadding=(log_ypadding or ypadding) if logy else ypadding,
            **kwargs))
    return figs
Example #3
0
def apply_split_norm_shape(s):
    from rootpy.stats.histfactory import split_norm_shape
    for histosys in s.histo_sys:
        # skip histosys for which overallsys already exist
        if s.GetOverallSys(histosys.name) is not None:
            continue
        log.info("splitting HistoSys `{0}` in sample `{1}`".format(
            histosys.name, s.name))
        norm, shape = split_norm_shape(histosys, s.hist)
        histosys.high = shape.high
        histosys.low = shape.low
        s.AddOverallSys(norm)
Example #4
0
def apply_split_norm_shape(s):
    from rootpy.stats.histfactory import split_norm_shape
    for histosys in s.histo_sys:
        # skip histosys for which overallsys already exist
        if s.GetOverallSys(histosys.name) is not None:
            continue
        log.info("splitting HistoSys `{0}` in sample `{1}`".format(
            histosys.name, s.name))
        norm, shape = split_norm_shape(histosys, s.hist)
        histosys.high = shape.high
        histosys.low = shape.low
        s.AddOverallSys(norm)
Example #5
0
    def histfactory(self, sample, category, systematics=False,
                    rec=None, weights=None, mva=False,
                    uniform=False, nominal=None):
        if not systematics:
            return
        if len(self.modes) != 1:
            raise TypeError(
                'histfactory sample only valid for single production mode')
        if len(self.masses) != 1:
            raise TypeError(
                'histfactory sample only valid for single mass point')

        # isolation systematic
        sample.AddOverallSys(
            'ATLAS_ANA_HH_{0:d}_Isolation'.format(self.year),
            1. - 0.06,
            1. + 0.06)

        mode = self.modes[0]

        if mode in ('Z', 'W'):
            _uncert_mode = 'VH'
        else:
            _uncert_mode = self.MODES_WORKSPACE[mode]

        if self.year == 2011:
            energy = 7
        elif self.year == 2012:
            energy = 8
        else:
            raise ValueError(
                "collision energy is unknown for year {0:d}".format(self.year))

        # QCD_SCALE
        for qcd_scale_term, qcd_scale_mode, qcd_scale_category, values in self.QCD_SCALE:
            if qcd_scale_mode == _uncert_mode and qcd_scale_category == category.name:
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(qcd_scale_term, low, high)

        # UE UNCERTAINTY
        for ue_term, ue_mode, ue_category, values in self.UE_UNCERT:
            if ue_mode == _uncert_mode and ue_category == category.name:
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(ue_term, low, high)

        # PDF ACCEPTANCE UNCERTAINTY (OverallSys)
        for pdf_term, pdf_mode, pdf_category, values in self.PDF_ACCEPT_NORM_UNCERT:
            if pdf_mode == _uncert_mode and pdf_category == category.name:
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(pdf_term, low, high)

        sample_nom = sample.hist

        # PDF ACCEPTANCE UNCERTAINTY (HistoSys) ONLY FOR MVA
        if mva:
            for pdf_term, pdf_mode, pdf_category, hist_names in self.PDF_ACCEPT_SHAPE_UNCERT:
                if pdf_mode == _uncert_mode and pdf_category == category.name:
                    high_name, low_name = hist_names.format(energy).split('/')
                    high_shape, low_shape = self.PDF_ACCEPT_file[high_name], self.PDF_ACCEPT_file[low_name]
                    if len(high_shape) != len(sample.hist):
                        log.warning("skipping pdf acceptance shape systematic "
                                    "since histograms are not compatible")
                        continue
                    high = sample_nom.Clone(shallow=True, name=sample_nom.name + '_{0}_UP'.format(pdf_term))
                    low = sample_nom.Clone(shallow=True, name=sample_nom.name + '_{0}_DOWN'.format(pdf_term))
                    high *= high_shape
                    low *= low_shape
                    histsys = histfactory.HistoSys(
                        pdf_term, low=low, high=high)
                    sample.AddHistoSys(histsys)

        #mixing Norms
        if self.SM:
            log.info('adding norm factor')
            sample.AddNormFactor('ATLAS_epsilon', 1., -200., 200., False)
        elif self.BSM:
            log.info('adding norm factor')
            sample.AddNormFactor('ATLAS_epsilon_rejected', 1., -200., 200., False)
        else:
            log.info('no norms for {0}'.format(self.name))



        # BR_tautau
        _, (br_up, br_down) = yellowhiggs.br(
            self.mass, 'tautau', error_type='factor')
        sample.AddOverallSys('ATLAS_BR_tautau', br_down, br_up)

        # <NormFactor Name="mu_BR_tautau" Val="1" Low="0" High="200" />
        sample.AddNormFactor('mu_BR_tautau', 1., 0., 200., True)

        #mu_XS[energy]_[mode]
        #_, (xs_up, xs_down) = yellowhiggs.xs(
        #    energy, self.mass, self.MODES_DICT[self.mode][0],
        #    error_type='factor')
        #sample.AddOverallSys(
        #    'mu_XS{0:d}_{1}'.format(energy, self.MODES_WORKSPACE[self.mode]),
        #    xs_down, xs_up)
        sample.AddNormFactor(
            'mu_XS{0:d}_{1}'.format(energy, self.MODES_WORKSPACE[self.mode]),
            1., 0., 200., True)

        # https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/HSG4Uncertainties
        # pdf uncertainty
        if mode == 'gg':
            if energy == 8:
                sample.AddOverallSys('pdf_Higgs_gg', 0.93, 1.08)
            else: # 7 TeV
                sample.AddOverallSys('pdf_Higgs_gg', 0.92, 1.08)
        else:
            if energy == 8:
                sample.AddOverallSys('pdf_Higgs_qq', 0.97, 1.03)
            else: # 7 TeV
                sample.AddOverallSys('pdf_Higgs_qq', 0.98, 1.03)

        # EWK NLO CORRECTION FOR VBF ONLY
        if mode == 'VBF':
            sample.AddOverallSys('NLO_EW_Higgs', 0.98, 1.02)

        # QCDscale_ggH3in HistoSys ONLY FOR MVA
        # also see ggH3in script
        if mva and mode == 'gg' and category.name == 'vbf':
            Rel_Error_2j = 0.215
            Error_exc = 0.08613046469238815 # Abs error on the exclusive xsec
            xsec_exc = 0.114866523583739 # Exclusive Xsec
            Error_3j = sqrt(Error_exc**2 - (Rel_Error_2j*xsec_exc)**2)
            rel_error = Error_3j / xsec_exc

            dphi = rec['true_dphi_jj_higgs_no_overlap']
            scores = rec['classifier']

            idx_2j = ((pi - dphi) < 0.2) & (dphi >= 0)
            idx_3j = ((pi - dphi) >= 0.2) & (dphi >= 0)

            # get normalization factor
            dphi_2j = weights[idx_2j].sum()
            dphi_3j = weights[idx_3j].sum()

            weight_up = np.ones(len(weights))
            weight_dn = np.ones(len(weights))

            weight_up[idx_2j] -= (dphi_3j / dphi_2j) * rel_error
            weight_dn[idx_2j] += (dphi_3j / dphi_2j) * rel_error

            weight_up[idx_3j] += rel_error
            weight_dn[idx_3j] -= rel_error

            weight_up *= weights
            weight_dn *= weights

            up_hist = nominal.clone(shallow=True, name=sample_nom.name + '_QCDscale_ggH3in_UP')
            up_hist.Reset()
            dn_hist = nominal.clone(shallow=True, name=sample_nom.name + '_QCDscale_ggH3in_DOWN')
            dn_hist.Reset()

            fill_hist(up_hist, scores, weight_up)
            fill_hist(dn_hist, scores, weight_dn)

            if uniform:
                up_hist = uniform_hist(up_hist)
                dn_hist = uniform_hist(dn_hist)

            shape = histfactory.HistoSys('QCDscale_ggH3in',
                low=dn_hist,
                high=up_hist)
            norm, shape = histfactory.split_norm_shape(shape, sample_nom)
            sample.AddHistoSys(shape)
Example #6
0
    def histfactory(self, sample, category, systematics=True):
        if not systematics:
            return
        if len(self.modes) != 1:
            raise TypeError(
                    'histfactory sample only valid for single production mode')
        if len(self.masses) != 1:
            raise TypeError(
                    'histfactory sample only valid for single mass point')
        mode = self.modes[0]

        if mode in ('Z', 'W'):
            _qcd_scale_mode = 'VH'
        else:
            _qcd_scale_mode = self.MODES_WORKSPACE[mode]

        # QCD_SCALE
        for qcd_scale_term, qcd_scale_mode, qcd_scale_category, values in self.QCD_SCALE:
            if qcd_scale_mode == _qcd_scale_mode and qcd_scale_category.lower() in category.name.lower():
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(qcd_scale_term, low, high)

        # GEN_QMASS
        for qmass_term, qmass_mode, qmass_category, values in self.GEN_QMASS:
            if qmass_mode == _qcd_scale_mode and qmass_category.lower() in category.name.lower():
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(qmass_term, low, high)

        # BR_tautau
        _, (br_up, br_down) = yellowhiggs.br(
            self.mass, 'tautau', error_type='factor')
        sample.AddOverallSys('ATLAS_BR_tautau', br_down, br_up)

        # <NormFactor Name="mu_BR_tautau" Val="1" Low="0" High="200" />
        sample.AddNormFactor('mu_BR_tautau', 1., 0., 200., True)

        if self.year == 2011:
            energy = 7
        elif self.year == 2012:
            energy = 8
        else:
            raise ValueError(
                "collision energy is unknown for year {0:d}".format(self.year))

        #mu_XS[energy]_[mode]
        #_, (xs_up, xs_down) = yellowhiggs.xs(
        #    energy, self.mass, self.MODES_DICT[self.mode][0],
        #    error_type='factor')
        #sample.AddOverallSys(
        #    'mu_XS{0:d}_{1}'.format(energy, self.MODES_WORKSPACE[self.mode]),
        #    xs_down, xs_up)
        sample.AddNormFactor(
            'mu_XS{0:d}_{1}'.format(energy, self.MODES_WORKSPACE[self.mode]),
            1., 0., 200., True)

        # https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/HSG4Uncertainties
        # underlying event uncertainty in the VBF category
        if 'vbf' in category.name.lower():
            if mode == 'gg':
                sample.AddOverallSys('ATLAS_UE_gg', 0.7, 1.3)
            elif mode == 'VBF':
                sample.AddOverallSys('ATLAS_UE_qq', 0.94, 1.06)

        # pdf uncertainty
        if mode == 'gg':
            if energy == 8:
                sample.AddOverallSys('pdf_Higgs_gg', 0.93, 1.08)
            else: # 7 TeV
                sample.AddOverallSys('pdf_Higgs_gg', 0.92, 1.08)
        else:
            if energy == 8:
                sample.AddOverallSys('pdf_Higgs_qq', 0.97, 1.03)
            else: # 7 TeV
                sample.AddOverallSys('pdf_Higgs_qq', 0.98, 1.03)

        # QCDscale_ggH3in MVA only
        if mode == 'gg' and category.name == 'vbf':
            up = self.QCDscale_ggH3in_file.up_fit
            dn = self.QCDscale_ggH3in_file.dn_fit
            nom = sample.hist
            up_hist = nom.clone(shallow=True, name=nom.name + '_QCDscale_ggH3in_UP')
            dn_hist = nom.clone(shallow=True, name=nom.name + '_QCDscale_ggH3in_DOWN')
            up_hist *= up
            dn_hist *= dn
            shape = histfactory.HistoSys('QCDscale_ggH3in',
                low=dn_hist,
                high=up_hist)
            norm, shape = histfactory.split_norm_shape(shape, nom)
            sample.AddHistoSys(shape)
Example #7
0
    def histfactory(self,
                    sample,
                    category,
                    systematics=False,
                    rec=None,
                    weights=None,
                    mva=False,
                    uniform=False,
                    nominal=None):
        if not systematics:
            return
        if len(self.modes) != 1:
            raise TypeError(
                'histfactory sample only valid for single production mode')
        if len(self.masses) != 1:
            raise TypeError(
                'histfactory sample only valid for single mass point')

        # isolation systematic
        sample.AddOverallSys('ATLAS_ANA_HH_{0:d}_Isolation'.format(self.year),
                             1. - 0.06, 1. + 0.06)

        mode = self.modes[0]

        if mode in ('Z', 'W'):
            _uncert_mode = 'VH'
        else:
            _uncert_mode = self.MODES_WORKSPACE[mode]

        if self.year == 2011:
            energy = 7
        elif self.year == 2012:
            energy = 8
        else:
            raise ValueError(
                "collision energy is unknown for year {0:d}".format(self.year))

        # QCD_SCALE
        for qcd_scale_term, qcd_scale_mode, qcd_scale_category, values in self.QCD_SCALE:
            if qcd_scale_mode == _uncert_mode and qcd_scale_category == category.name:
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(qcd_scale_term, low, high)

        # UE UNCERTAINTY
        for ue_term, ue_mode, ue_category, values in self.UE_UNCERT:
            if ue_mode == _uncert_mode and ue_category == category.name:
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(ue_term, low, high)

        # PDF ACCEPTANCE UNCERTAINTY (OverallSys)
        for pdf_term, pdf_mode, pdf_category, values in self.PDF_ACCEPT_NORM_UNCERT:
            if pdf_mode == _uncert_mode and pdf_category == category.name:
                high, low = map(float, values.split('/'))
                sample.AddOverallSys(pdf_term, low, high)

        sample_nom = sample.hist

        # PDF ACCEPTANCE UNCERTAINTY (HistoSys) ONLY FOR MVA
        if mva:
            for pdf_term, pdf_mode, pdf_category, hist_names in self.PDF_ACCEPT_SHAPE_UNCERT:
                if pdf_mode == _uncert_mode and pdf_category == category.name:
                    high_name, low_name = hist_names.format(energy).split('/')
                    high_shape, low_shape = self.PDF_ACCEPT_file[
                        high_name], self.PDF_ACCEPT_file[low_name]
                    if len(high_shape) != len(sample.hist):
                        log.warning("skipping pdf acceptance shape systematic "
                                    "since histograms are not compatible")
                        continue
                    high = sample_nom.Clone(shallow=True,
                                            name=sample_nom.name +
                                            '_{0}_UP'.format(pdf_term))
                    low = sample_nom.Clone(shallow=True,
                                           name=sample_nom.name +
                                           '_{0}_DOWN'.format(pdf_term))
                    high *= high_shape
                    low *= low_shape
                    histsys = histfactory.HistoSys(pdf_term,
                                                   low=low,
                                                   high=high)
                    sample.AddHistoSys(histsys)

        # BR_tautau
        _, (br_up, br_down) = yellowhiggs.br(self.mass,
                                             'tautau',
                                             error_type='factor')
        sample.AddOverallSys('ATLAS_BR_tautau', br_down, br_up)

        # <NormFactor Name="mu_BR_tautau" Val="1" Low="0" High="200" />
        sample.AddNormFactor('mu_BR_tautau', 1., 0., 200., True)

        #mu_XS[energy]_[mode]
        #_, (xs_up, xs_down) = yellowhiggs.xs(
        #    energy, self.mass, self.MODES_DICT[self.mode][0],
        #    error_type='factor')
        #sample.AddOverallSys(
        #    'mu_XS{0:d}_{1}'.format(energy, self.MODES_WORKSPACE[self.mode]),
        #    xs_down, xs_up)
        sample.AddNormFactor(
            'mu_XS{0:d}_{1}'.format(energy, self.MODES_WORKSPACE[self.mode]),
            1., 0., 200., True)

        # https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/HSG4Uncertainties
        # pdf uncertainty
        if mode == 'gg':
            if energy == 8:
                sample.AddOverallSys('pdf_Higgs_gg', 0.93, 1.08)
            else:  # 7 TeV
                sample.AddOverallSys('pdf_Higgs_gg', 0.92, 1.08)
        else:
            if energy == 8:
                sample.AddOverallSys('pdf_Higgs_qq', 0.97, 1.03)
            else:  # 7 TeV
                sample.AddOverallSys('pdf_Higgs_qq', 0.98, 1.03)

        # EWK NLO CORRECTION FOR VBF ONLY
        if mode == 'VBF':
            sample.AddOverallSys('NLO_EW_Higgs', 0.98, 1.02)

        # QCDscale_ggH3in HistoSys ONLY FOR MVA
        # also see ggH3in script
        if mva and mode == 'gg' and category.name == 'vbf':
            Rel_Error_2j = 0.215
            Error_exc = 0.08613046469238815  # Abs error on the exclusive xsec
            xsec_exc = 0.114866523583739  # Exclusive Xsec
            Error_3j = sqrt(Error_exc**2 - (Rel_Error_2j * xsec_exc)**2)
            rel_error = Error_3j / xsec_exc

            dphi = rec['true_dphi_jj_higgs_no_overlap']
            scores = rec['classifier']

            idx_2j = ((pi - dphi) < 0.2) & (dphi >= 0)
            idx_3j = ((pi - dphi) >= 0.2) & (dphi >= 0)

            # get normalization factor
            dphi_2j = weights[idx_2j].sum()
            dphi_3j = weights[idx_3j].sum()

            weight_up = np.ones(len(weights))
            weight_dn = np.ones(len(weights))

            weight_up[idx_2j] -= (dphi_3j / dphi_2j) * rel_error
            weight_dn[idx_2j] += (dphi_3j / dphi_2j) * rel_error

            weight_up[idx_3j] += rel_error
            weight_dn[idx_3j] -= rel_error

            weight_up *= weights
            weight_dn *= weights

            up_hist = nominal.clone(shallow=True,
                                    name=sample_nom.name +
                                    '_QCDscale_ggH3in_UP')
            up_hist.Reset()
            dn_hist = nominal.clone(shallow=True,
                                    name=sample_nom.name +
                                    '_QCDscale_ggH3in_DOWN')
            dn_hist.Reset()

            fill_hist(up_hist, scores, weight_up)
            fill_hist(dn_hist, scores, weight_dn)

            if uniform:
                up_hist = uniform_hist(up_hist)
                dn_hist = uniform_hist(dn_hist)

            shape = histfactory.HistoSys('QCDscale_ggH3in',
                                         low=dn_hist,
                                         high=up_hist)
            norm, shape = histfactory.split_norm_shape(shape, sample_nom)
            sample.AddHistoSys(shape)