Esempio n. 1
0
 def rebin(h, name):
     myBinning = []
     if name.startswith("MT"):
         myBinning = systematics.getBinningForPlot("shapeTransverseMass")
     elif name.startswith("INVMASS"):
         myBinning = systematics.getBinningForPlot("shapeInvariantMass")
     else:
         raise Exception("Unknown binning information")
     myArray = array.array("d", myBinning)
     # Rebin and move under/overflow bins to visible bins
     h = h.Rebin(len(myBinning) - 1, "", myArray)
     h.SetBinContent(1, h.GetBinContent(0) + h.GetBinContent(1))
     h.SetBinError(1,
                   math.sqrt(h.GetBinContent(0)**2 + h.GetBinContent(1)**2))
     h.SetBinContent(
         h.GetNbinsX() + 1,
         h.GetBinContent(h.GetNbinsX() + 1) +
         h.GetBinContent(h.GetNbinsX() + 2))
     h.SetBinError(
         h.GetNbinsX() + 1,
         math.sqrt(
             h.GetBinError(h.GetNbinsX() + 1)**2 +
             h.GetBinError(h.GetNbinsX() + 2)**2))
     h.SetBinContent(0, 0.0)
     h.SetBinError(0, 0.0)
     h.SetBinContent(h.GetNbinsX() + 2, 0.0)
     h.SetBinError(h.GetNbinsX() + 2, 0.0)
     return h
ToleranceForLuminosityDifference = 0.05  # Tolerance for throwing error on luminosity difference ("0.01" means that a 1% is required)
ToleranceForMinimumRate = 0.0  # Tolerance for almost zero rate (columns with smaller rate are suppressed)
labelPrefix = ""  # Prefix for the labels of datacard columns, e.g. "Hplus2tb_" #fixme: breaks if not empty string

# Options for tables, figures etc.
OptionBr = 0.01  # Br(t->bH+)
OptionSqrtS = 13  # sqrt(s)

#================================================================================================
# Counter and histogram path definitions
#================================================================================================
SignalRateCounter = "Selected events"  # fixme: what is this for?
FakeRateCounter = "EWKfaketaus:SelectedEvents"  # fixme: what is this for?
shapeHistoName = None  # Path where the shape histogram is located
histoPathInclusive = "ForDataDrivenCtrlPlots"
ShapeHistogramsDimensions = systematics.getBinningForPlot(
    shapeHistoName)  # Get the new binning for the shape histogram
DataCardName += "_" + OptionMassShape

if OptionMassShape == "LdgTetrajetMass":
    shapeHistoName = "LdgTetrajetMass_AfterAllSelections"

#================================================================================================
# Observation definition (how to retrieve number of observed events)
#================================================================================================
from HiggsAnalysis.LimitCalc.InputClasses import ObservationInput
Observation = ObservationInput(datasetDefinition="Data",
                               shapeHistoName=shapeHistoName,
                               histoPath=histoPathInclusive)

#================================================================================================
# Define systematics lists commmon to datasets
Esempio n. 3
0
    def doDataMining(self, config, dsetMgr, luminosity, mainCounterTable, extractors, controlPlotExtractors):
        print "... processing column: "+ShellStyles.HighlightStyle()+self._label+ShellStyles.NormalStyle()
        #print "begin files =",ROOT.gROOT.GetListOfFiles().GetSize()
        #print "DBG: list at beginning of data mining:",ROOT.gDirectory.GetList().GetSize()
        #for i in range(0,ROOT.gDirectory.GetListOfKeys().GetSize()):
        #    print "keys %d = %s"%(i,ROOT.gDirectory.GetListOfKeys().At(i).GetTitle())
        # Construct list of shape variables used by the column
        myShapeVariationList = []
        for nid in self._nuisanceIds:
            for e in extractors:
                if e.getId() == nid:
                    if (e.getDistribution() == "shapeQ" and not isinstance(e, ConstantExtractor)) or isinstance(e, ShapeVariationToConstantExtractor):
                        myShapeVariationList.append(e._systVariation)
        # Obtain root histogram with uncertainties for shape and cache it
        hRateWithFineBinning = None
        if not (self.typeIsEmptyColumn() or dsetMgr == None):
            mySystematics = dataset.Systematics(allShapes=True) #,verbose=True)
            if not dsetMgr.hasDataset(self.getDatasetMgrColumn()):
                raise Exception(ShellStyles.ErrorLabel()+"Cannot find merged dataset by key '%s' in multicrab dir! Did you forget to merge the root files with hplusMergeHistograms.py?"%self.getDatasetMgrColumn())
            myDatasetRootHisto = dsetMgr.getDataset(self.getDatasetMgrColumn()).getDatasetRootHisto(mySystematics.histogram(self.getFullShapeHistoName()))
            if myDatasetRootHisto.isMC():
                # Set signal xsection
                # for heavy H+
                if config.OptionLimitOnSigmaBr:
                    if self._landsProcess <= 0:
                        # Set cross section of sample to 1 pb in order to obtain limit on sigma x Br
                        #myDatasetRootHisto.Delete()
                        dsetMgr.getDataset(self.getDatasetMgrColumn()).setCrossSection(1)
                        myDatasetRootHisto = dsetMgr.getDataset(self.getDatasetMgrColumn()).getDatasetRootHisto(mySystematics.histogram(self.getFullShapeHistoName()))
                        print "..... Assuming this is signal -> set cross section to 1 pb for limit calculation"
                # for light H+, use 13 TeV ttbar xsect from https://twiki.cern.ch/twiki/bin/view/LHCPhysics/TtbarNNLO
                elif (not config.OptionLimitOnSigmaBr and (self._label[:2] == "HW" or self._label[:2] == "HH" or self._label[:2] == "WH")):
                     ttbarxsect = xsect.backgroundCrossSections.crossSection("TTJets", energy="13")
                     if abs(dsetMgr.getDataset(self.getDatasetMgrColumn()).getCrossSection() - ttbarxsect) > 0.0001:
                         print ShellStyles.WarningLabel()+"Forcing light H+ xsection to 13 TeV ttbar cross section %f in DatacardColumn.py"%ttbarxsect
                         dsetMgr.getDataset(self.getDatasetMgrColumn()).setCrossSection(ttbarxsect)
                         myDatasetRootHisto = dsetMgr.getDataset(self.getDatasetMgrColumn()).getDatasetRootHisto(mySystematics.histogram(self.getFullShapeHistoName()))


                # Normalize to luminosity
                myDatasetRootHisto.normalizeToLuminosity(luminosity)
            self._cachedShapeRootHistogramWithUncertainties = myDatasetRootHisto.getHistogramWithUncertainties().Clone()
            # Remove any variations not active for the column
            self._cachedShapeRootHistogramWithUncertainties.keepOnlySpecifiedShapeUncertainties(myShapeVariationList)
            # Apply additional normalization
            # Note: this applies the normalizatoin also to the syst. uncertainties
            if abs(self._additionalNormalisationFactor - 1.0) > 0.00001:
                print ShellStyles.WarningLabel()+"Applying normalization factor %f to sample '%s'!"%(self._additionalNormalisationFactor, self.getLabel())
                self._cachedShapeRootHistogramWithUncertainties.Scale(self._additionalNormalisationFactor)
            # Leave histograms with the original binning at this stage, but do move under/overflow into first/last bin
            self._cachedShapeRootHistogramWithUncertainties.makeFlowBinsVisible()
	    if not self.typeIsObservation():
		print "..... event yield: %f +- %f (stat.)"%(self._cachedShapeRootHistogramWithUncertainties.getRate(),self._cachedShapeRootHistogramWithUncertainties.getRateStatUncertainty())
        # Obtain rate histogram
        myRateHistograms = []
        if self.typeIsEmptyColumn() or dsetMgr == None:
            if self._opts.verbose:
                print "  - Creating empty rate shape"
            #myArray = array("d",config.ShapeHistogramsDimensions)
            #h = TH1F(self.getLabel(),self.getLabel(),len(myArray)-1,myArray)
            # Use here just one bin to speed up LandS (yes, one needs a histogram for the empty columns even if ShapeStat is off)
            h = ROOT.TH1F(self.getLabel(),self.getLabel(),1,0,1)
            ROOT.SetOwnership(h, True)
            myRateHistograms.append(h)
        else:
            if self._opts.verbose:
                print "  - Extracting rate histogram"
            myShapeExtractor = None
            if self.typeIsObservation():
                myShapeExtractor = ShapeExtractor(ExtractorMode.OBSERVATION)
            else:
                myShapeExtractor = ShapeExtractor(ExtractorMode.RATE)
            myShapeHistograms = myShapeExtractor.extractHistograms(self, dsetMgr, mainCounterTable, luminosity, self._additionalNormalisationFactor)
            myRateHistograms.extend(myShapeHistograms)
        # Cache result
        self._rateResult = ExtractorResult("rate", "rate",
                               myRateHistograms[0].Integral(), # Take only visible part
                               myRateHistograms)
        if self._opts.verbose:
            print "  - Rate: integral = ", myRateHistograms[0].Integral()
            if (self.typeIsEWK()) or self.typeIsEWKfake():
                if isinstance(dsetMgr.getDataset(self.getDatasetMgrColumn()), dataset.DatasetMerged):
                    for dset in dsetMgr.getDataset(self.getDatasetMgrColumn()).datasets:
                        print "  - normalization coefficient for %s: %g"%(dset.getName(),dset.getNormFactor())
                print "  - normalization coefficient = ", dsetMgr.getDataset(self.getDatasetMgrColumn()).getNormFactor()
        if abs(myRateHistograms[0].Integral() - myRateHistograms[0].Integral(0,myRateHistograms[0].GetNbinsX()+2)) > 0.00001:
            raise Exception("Error: under/overflow bins contain data!")
        if self.typeIsEmptyColumn() or dsetMgr == None:
            return

        # Obtain overall purity for QCD
        self._purityForFinalShape = None
        myAveragePurity = None
        try:
            if self.typeIsQCDinverted():
                myDsetRootHisto = myShapeExtractor.extractQCDPurityHistogram(self, dsetMgr, self.getFullShapeHistoName())
                self._rateResult.setPurityHistogram(myDsetRootHisto.getHistogram())
                myAveragePurity = myShapeExtractor.extractQCDPurityAsValue(myRateHistograms[0], self.getPurityHistogram())
                #print "*** Average QCD purity", myAveragePurity
        except:
            print "ERROR: It looks like the purity histogram does not exist!"
            raise

        # Obtain results for nuisances
        # Add the scalar uncertainties to the cached RootHistoWithUncertainties object
        for nid in self._nuisanceIds:
            if self._opts.verbose:
                print "  - Extracting nuisance by id=%s"%nid
            myFoundStatus = False
            for e in extractors:
                if e.getId() == nid:
                    myFoundStatus = True
                    # Obtain result
                    myResult = 0.0
                    myAdditionalResult = None
                    if dsetMgr != None:
                        myResult = e.extractResult(self, dsetMgr, mainCounterTable, luminosity, self._additionalNormalisationFactor)
                        myAdditionalResult = e.extractAdditionalResult(self, dsetMgr, mainCounterTable, luminosity, self._additionalNormalisationFactor)
                    # Obtain histograms
                    myHistograms = []
                    if e.isShapeNuisance():
                        if isinstance(e, ConstantExtractor):
                            # Create up and down histograms out of the constant values
                            myHistograms.extend(_createShapeNuisanceFromConstant(myRateHistograms[0], myResult.getUncertaintyUp(), myResult.getUncertaintyDown()))
                            # Add also to the uncertainties as normalization uncertainty
                            self._cachedShapeRootHistogramWithUncertainties.addNormalizationUncertaintyRelative(e.getId(), myResult.getUncertaintyUp(), myResult.getUncertaintyDown())
                        else:
                            myHistograms = []
                            if not isinstance(e,QCDShapeVariationExtractor):
                                # Apply any further scaling (only necessary for the uncertainties from variation)
                                if e.getDistribution() == "shapeQ" and abs(e.getScaleFactor() - 1.0) > 0.0:
                                    self._cachedShapeRootHistogramWithUncertainties.ScaleVariationUncertainty(e._systVariation, e.getScaleFactor())
                            # Obtain histograms
                            if isinstance(e, QCDShapeVariationExtractor) or isinstance(e, ShapeVariationFromJsonExtractor):
                                myHistograms.extend(e.extractHistograms(self, dsetMgr, mainCounterTable, luminosity, self._additionalNormalisationFactor))
                            else:
                                myHistograms.extend(self._getShapeNuisanceHistogramsFromRHWU(self._cachedShapeRootHistogramWithUncertainties, e._systVariation, e.getMasterId()))
                    else:
                        # For QCD, scale the QCD type constants by the purity
                        if self.typeIsQCDinverted() and e.isQCDNuisance():
                            if isinstance(myResult, ScalarUncertaintyItem):
                                myResult.scale(1.0-myAveragePurity)
                            elif isinstance(myResult, list):
                                for i in range(0,len(myResult)):
                                    myResult[i] *= 1.0-myAveragePurity
                            else:
                                myResult *= 1.0-myAveragePurity
                        # Add scalar uncertainties
                        if self._opts.verbose:
                            print "Adding scalar uncert. ",e.getId()
                        if isinstance(myResult, ScalarUncertaintyItem):
                            self._cachedShapeRootHistogramWithUncertainties.addNormalizationUncertaintyRelative(e.getId(), myResult.getUncertaintyUp(), myResult.getUncertaintyDown())
                        elif isinstance(myResult, list):
                            self._cachedShapeRootHistogramWithUncertainties.addNormalizationUncertaintyRelative(e.getId(), myResult[1], myResult[0])
                        else:
                            self._cachedShapeRootHistogramWithUncertainties.addNormalizationUncertaintyRelative(e.getId(), myResult, myResult)
                    # Cache result
                    self._nuisanceResults.append(ExtractorResult(e.getId(),
                                                                 e.getMasterId(),
                                                                 myResult,
                                                                 myHistograms,
                                                                 "Stat." in e.getDescription() or "stat." in e.getDescription() or e.getDistribution()=="shapeStat",
                                                                 additionalResult=myAdditionalResult))
            if not myFoundStatus:
                raise Exception("\n"+ShellStyles.ErrorLabel()+"(data group ='"+self._label+"'): Cannot find nuisance with id '"+nid+"'!")
        # Print list of uncertainties
        if self._opts.verbose and dsetMgr != None and not self.typeIsEmptyColumn():
            print "  - Has shape variation syst. uncertainties: %s"%(", ".join(map(str,self._cachedShapeRootHistogramWithUncertainties.getShapeUncertainties().keys())))
        #self._cachedShapeRootHistogramWithUncertainties.Debug()

        # Obtain results for control plots
        if config.OptionDoControlPlots:
            for c in controlPlotExtractors:
                if dsetMgr != None and not self.typeIsEmptyColumn():
                    if self._opts.verbose:
                        print "  - Extracting data-driven control plot %s"%c._histoTitle
                    myCtrlDsetRootHisto = c.extractHistograms(self, dsetMgr, mainCounterTable, luminosity, self._additionalNormalisationFactor)
                    if myCtrlDsetRootHisto == None:
                        print ShellStyles.WarningLabel()+"Could not find control plot '%s', skipping..."%c._histoTitle
                        self._controlPlots.append(None)
                    else:
                        # Obtain overall purity for QCD
                        myAverageCtrlPlotPurity = None
                        hCtrlPlotPurity = None
                        if self.typeIsQCDinverted(): #and False: #FIXME switch on when purity exists
                            myDsetHisto = c.extractQCDPurityHistogram(self, dsetMgr)
                            hCtrlPlotPurity = aux.Clone(myDsetHisto.getHistogram())
                            myAverageCtrlPlotPurity = c.extractQCDPurityAsValue(myRateHistograms[0], hCtrlPlotPurity)
                        # Now normalize
                        if myDatasetRootHisto.isMC():# and myCtrlDsetRootHisto.getHistogramWithUncertainties().getRootHisto().GetName() != self._cachedShapeRootHistogramWithUncertainties.getRootHisto().GetName():
                            myCtrlDsetRootHisto.normalizeToLuminosity(luminosity)
                        h = myCtrlDsetRootHisto.getHistogramWithUncertainties()
                        # Remove any variations not active for the column
                        h.keepOnlySpecifiedShapeUncertainties(myShapeVariationList)
                        # Rebin and move under/overflow bins to visible bins
                        if not isinstance(h.getRootHisto(), ROOT.TH2):
                            if getBinningForPlot(c._histoTitle) != None:
                                myArray = array("d",getBinningForPlot(c._histoTitle))
                                h.Rebin(len(myArray)-1,"",myArray)
                            h.makeFlowBinsVisible()
                        # Apply any further scaling (only necessary for the unceratainties from variation)
                        for nid in self._nuisanceIds:
                            for e in extractors:
                                if e.getId() == nid:
                                    if e.getDistribution() == "shapeQ" and abs(e.getScaleFactor() - 1.0) > 0.0:
                                        if not isinstance(h.getRootHisto(),ROOT.TH2):
                                            h.ScaleVariationUncertainty(e._systVariation, e.getScaleFactor())
                        # Add to RootHistogramWithUncertainties non-shape uncertainties
                        for n in self._nuisanceResults:
                            if not n.resultIsStatUncertainty() and len(n.getHistograms()) == 0: # systematic uncert., but not shapeQ
                                if self._opts.verbose:
                                    print "    - Adding norm. uncertainty: %s"%n.getMasterId()
                                myResult = n.getResult()
                                if self.typeIsQCDinverted():
                                    # Scale QCD nuisance by impurity (and unscale by shape impurity already applied to nuisance)
                                    for e in extractors:
                                        if e.getId() == n.getId():
                                            if e.isQCDNuisance():
                                                myResult = n.getResult().Clone()
                                                myResult.scale((1.0-myAverageCtrlPlotPurity) / (1.0 - myAveragePurity))
                                                #print n._exId, n.getResult().getUncertaintyUp(), myAverageCtrlPlotPurity, myResult.getUncertaintyUp()
                                if not isinstance(h.getRootHisto(),ROOT.TH2):
                                    if isinstance(myResult, ScalarUncertaintyItem):
                                        h.addNormalizationUncertaintyRelative(n.getId(), myResult.getUncertaintyUp(), myResult.getUncertaintyDown())
                                    elif isinstance(myResult, list):
                                        h.addNormalizationUncertaintyRelative(n.getId(), myResult[1], myResult[0])
                                    else:
                                        h.addNormalizationUncertaintyRelative(n.getId(), myResult, myResult)
                            elif not n.resultIsStatUncertainty() and len(n.getHistograms()) > 0:
                                if isinstance(n.getResult(), ScalarUncertaintyItem): # constantToShape
                                    if self._opts.verbose:
                                        print "    - Adding norm. uncertainty: %s"%n.getId()
                                    if not isinstance(h.getRootHisto(),ROOT.TH2):
                                        h.addNormalizationUncertaintyRelative(n.getMasterId(), myResult.getUncertaintyUp(), myResult.getUncertaintyDown())
                                for e in extractors:
                                    if e.getId() == n.getId():
                                        if isinstance(e,QCDShapeVariationExtractor):
                                            # Calculate and add QCD shape uncertainty to h
                                            if not isinstance(h.getRootHisto(),ROOT.TH2):
                                                e.extractHistograms(self, dsetMgr, mainCounterTable, luminosity, self._additionalNormalisationFactor, rootHistoWithUncertainties=h)
                        # Scale if asked
                        if self._landsProcess > 0 and config.OptionLimitOnSigmaBr:
                            h.Scale(self._additionalNormalisationFactor)
                        # Store RootHistogramWithUncertainties
                        myDictionary = {}
                        myDictionary["shape"] = h
                        myDictionary["purity"] = hCtrlPlotPurity
                        myDictionary["averagePurity"] = myAverageCtrlPlotPurity
                        for item in dir(self):
                            if item.startswith("typeIs"):
                                try:
                                    myStatus = getattr(self, item)()
                                    myDictionary[item] = myStatus
                                except TypeError:
                                    pass
                        self._controlPlots.append(myDictionary)
    def createSystHistograms(self, hRate, hSystUp, hSystDown, hSystUpFromVar, hSystDownFromVar, quietMode=True):
        '''
        Uses the histogram "hSystUpFromVar" and "hSystDownFromVar" to account the systematic uncertainties 
        related to the Transfer Factors (TF) from the Control (or Verification) 
        Region (VR) to the Signal Region (SR). This sys. uncertainty should have both a Rate + Shape impact
        on final invariant mass distribution. 

        The two aforementioned histograms correspond to the invariant massdistrubutions
        ("ForDataDrivenCtrlPlots/LdgTetrajetMass_AfterAllSelections") obtained by using applying
        the transfer factors (TF) of the FakeB measurement to shapes from the VR. Instead of the nominal TF 
        however, the TF+TF_Error and TF-TF_Error are used instead, where TF_Error is the statistical error of
        the TF, calculated by using error propagation:
        TF = CR1/CR2
        TF_Error = ErrorPropagationForDivision(TF) = sqrt((sigmaA/b)**2 + (a/(b**2)*sigmaB)**2)
        where:
        A = Integral of CR1 histogram  (from ROOT)
        sigmaA = Integral Error for CR1 histogram (from ROOT)
        These histograms should be already in place (and correctly normalised) for the FakeB pseudodataset, 
        after running the ./makePseudoMulticrab.py -m <FakeB-dir> script.

        The error is symmetric and it is basically defined as:
        hSystUp   = Rate + 1sigma
        hSystDown = Rate - 1sigma
        where the rate is obtained from the filled histogram provided ("hRate")
        and sigma is the TF_Error as discussed above (error propagation on the division of CR1 and CR2)

        In this function we don't need to calculate the error propagation. The function assumes that the histograms provided
        already have the final variations in place (i.e. up = rate+error, down = rate-error)
        ''' 
        # Get the (clean) histogram name 
        fullName  = hRate.GetName()
        cleanName = fullName.replace("_cloned", "")
        cleanName = cleanName.replace("_FakeBMeasurementTrijetMass", "")
        rebinX    = systematics.getBinningForPlot(cleanName)
        
        # if hRate.GetNbinsX() != hSystUpFromVar.GetNbinsX():

        if rebinX != None:
            self.Verbose("Rebinning histogram \"%s\" (\"%s\")" % (cleanName, fullName), True)
            hRate            = hRate.Rebin(len(rebinX)-1, hRate.GetName(), array.array("d", rebinX))
            hSystUpFromVar   = hSystUpFromVar.Rebin(len(rebinX)-1, hSystUpFromVar.GetName(), array.array("d", rebinX))
            hSystDownFromVar = hSystDownFromVar.Rebin(len(rebinX)-1, hSystDownFromVar.GetName(), array.array("d", rebinX))
            ### hSystUp      = hSystUp.Rebin(len(rebinX)-1, hSystUp.GetName(), array.array("d", rebinX))     #don't !
            ### hSystDown    = hSystDown.Rebin(len(rebinX)-1, hSystDown.GetName(), array.array("d", rebinX)) #don't !

        # Constuct a summary table
        table   = []
        align  = "{:>7} {:>15} {:>10} {:>12} {:>12} {:>12} {:>10}"
        header = align.format("Bin #", "Bin Centre", "Rate (Nom)", "Rate (Up)", "Rate (Down)", "% Up", "% Down")
        hLine  = "="*85
        table.append( "{:^85}".format(cleanName))
        table.append(hLine)
        table.append(header)
        table.append(hLine)

        # For-loop: All histogram bins for given data-driven control plot
        nBinsX = hRate.GetNbinsX()
        for i in range(1, nBinsX+1):
            self.Verbose("Calculating systematic for bin \"%d\" in histogram \"%s\"" % (i, hRate.GetName()), i==1)

            # Calculate the systematics 
            rateNominal      = hRate.GetBinContent(i)
            rateSystUp       = hSystUpFromVar.GetBinContent(i)
            rateSystDown     = hSystDownFromVar.GetBinContent(i)
            binCentre        = hRate.GetBinCenter(i)

            # Calculate percentage difference wrt nominal
            if rateNominal > 0.0:
                rateSystUpPerc   = (rateSystUp-rateNominal)/(rateNominal)*100
                rateSystDownPerc = (rateSystDown-rateNominal)/(rateNominal)*100
            else:
                rateSystUpPerc   = 0
                rateSystDownPerc = 0
                
            # Fill summary table for given bin
            row = align.format(i, binCentre, "%.1f" % rateNominal, "%.1f" % rateSystUp, "%.1f" % rateSystDown, "%.1f" % rateSystUpPerc, "%.1f" % rateSystDownPerc)
            table.append(row)
            self.Verbose(ShellStyles.ErrorStyle() + row + ShellStyles.NormalStyle(), i==1)

            # Fill the up/down systematics histograms
            self.Verbose("Setting the systematics values in the histograms SystUp and SystDown", False)
            hSystUp.SetBinContent(i, rateSystUp)
            hSystDown.SetBinContent(i, rateSystDown)

        # Append total uncertainty info
        table.extend(self.GetTotalUncertainyTable(hRate, hSystUpFromVar, hSystDownFromVar, hLine, align))
        
        # Print summary table
        if  quietMode == False or self._verbose == True:
            for i, row in enumerate(table, 1):
                self.Print(row, i==1)
        return
Esempio n. 5
0
def main(argv):

    dirs = []
    if len(sys.argv) < 2:
        usage()

    dirs.append(sys.argv[1])

    QCDInvertedNormalization = QCDInvertedNormalizationFactors.QCDInvertedNormalization
    QCDInvertedNormalizationFilteredEWKFakeTaus = QCDInvertedNormalizationFactorsFilteredEWKFakeTaus.QCDInvertedNormalization
    analysis = "signalAnalysisInvertedTau"
    optModes = []
    #optModes.append("OptQCDTailKillerZeroPlus")
    optModes.append("OptQCDTailKillerLoosePlus")
    optModes.append("OptQCDTailKillerMediumPlus")
    optModes.append("OptQCDTailKillerTightPlus")
    #optModes.append("OptQCDTailKillerVeryTightPlus")
    #optModes.append("OnlyGenuineMCTausFalse")
    #optModes.append("OnlyGenuineMCTausTrue")

    #Optimal: 0.8, 0.82, 0.9
    #w1_list = [0.8, 0.82, 0.84, 0.87]
    #w1_list = [0.8, 0.82, 0.9, 1]
    w1_list = [0.9]

    defaultBinning = systematics.getBinningForPlot("shapeTransverseMass")

    diff_opt = []
    for optMode in optModes:
        diff_list = []
        for w1 in w1_list:
            var_values = []
            nom_values = []
            w2 = 1 - w1

            color = 1

            #signal

            dirs_signal = ["../../SignalAnalysis_140605_143702/"]
            datasets_signal = dataset.getDatasetsFromMulticrabDirs(
                dirs_signal,
                dataEra=dataEra,
                searchMode=searchMode,
                analysisName=analysis.replace("InvertedTau", ""),
                optimizationMode=optMode)

            datasets_signal.updateNAllEventsToPUWeighted()
            datasets_signal.loadLuminosities()

            datasets_signal.remove(
                filter(lambda name: "TTToHplus" in name,
                       datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(
                filter(lambda name: "HplusTB" in name,
                       datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(
                filter(lambda name: "Hplus_taunu_t-channel" in name,
                       datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(
                filter(lambda name: "Hplus_taunu_tW-channel" in name,
                       datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(
                filter(lambda name: "TTJets_SemiLept" in name,
                       datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(
                filter(lambda name: "TTJets_FullLept" in name,
                       datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(
                filter(lambda name: "TTJets_Hadronic" in name,
                       datasets_signal.getAllDatasetNames()))

            plots.mergeRenameReorderForDataMC(datasets_signal)

            datasets_signal.merge(
                "EWK",
                ["TTJets", "WJets", "DYJetsToLL", "SingleTop", "Diboson"])

            mtplot_signalfaketaus = plots.DataMCPlot(
                datasets_signal, "shapeEWKFakeTausTransverseMass")
            mt_signalfaketaus = mtplot_signalfaketaus.histoMgr.getHisto(
                "EWK").getRootHisto().Clone("shapeEWKFakeTausTransverseMass")
            mt_signalfaketaus.SetName("BaselineFakeTaus")

            myBinning = [0, 20, 40, 60, 80, 100, 120, 140, 160, 200, 400]
            myArray = array.array("d", myBinning)

            fitBinning = []
            for i in range(0, 45):
                fitBinning.append(i * 10)
            fitArray = array.array("d", fitBinning)

            mt_baseline = mt_signalfaketaus

            #rangeMin = mt_signalfaketaus.GetXaxis().GetXmin()
            #rangeMax = mt_signalfaketaus.GetXaxis().GetXmax()
            #theFit = TF1('theFit',FitFunction(),rangeMin,rangeMax,4)
            #theFit.SetParLimits(0,0.5,10000)
            #theFit.SetParLimits(1,90,10000)
            #theFit.SetParLimits(2,30,10000)
            #theFit.SetParLimits(3,0.001,10000)
            #mt_signalfaketaus.Fit(theFit,"R")
            #theFit.SetRange(mt_signalfaketaus.GetXaxis().GetXmin(),mt_signalfaketaus.GetXaxis().GetXmax())
            #theFit.SetLineStyle(2)
            #theFit.SetLineColor(4)
            #theFit.SetLineWidth(3)
            #theFit.Draw()
            #mt_corr = theFit.GetHistogram()
            #mt_corr = mt_corr.Rebin(len(fitBinning)-1,"",fitArray)
            #mt_corr.Scale(mt_baseline.GetMaximum()/mt_corr.GetMaximum())

            for HISTONAME in histoNameList:
                var = False
                if HISTONAME == "shapeEWKGenuineTausTransverseMass":
                    var = True
                datasets = dataset.getDatasetsFromMulticrabDirs(
                    dirs,
                    dataEra=dataEra,
                    searchMode=searchMode,
                    analysisName=analysis,
                    optimizationMode=optMode)

                datasets.updateNAllEventsToPUWeighted()
                datasets.loadLuminosities()

                plots.mergeRenameReorderForDataMC(datasets)

                datasets.merge(
                    "EWK",
                    ["TTJets", "WJets", "DYJetsToLL", "SingleTop", "Diboson"])

                histonames = datasets.getDataset("Data").getDirectoryContent(
                    HISTONAME)

                bins = []
                for histoname in histonames:
                    binname = histoname.replace(HISTONAME, "")
                    if not binname == "Inclusive":
                        bins.append(binname)

                for i, bin in enumerate(bins):
                    mtplot = plots.DataMCPlot(
                        datasets, HISTONAME + "/" + HISTONAME + bin)

                    if i == 0:
                        mt = mtplot.histoMgr.getHisto(
                            "Data").getRootHisto().Clone(HISTONAME + "/" +
                                                         HISTONAME + bin)
                        mt_ewk = mtplot.histoMgr.getHisto(
                            "EWK").getRootHisto().Clone(HISTONAME + "/" +
                                                        HISTONAME + bin)
                        mtn = mtplot.histoMgr.getHisto(
                            "Data").getRootHisto().Clone(HISTONAME + "/" +
                                                         HISTONAME + bin)
                        mtn_ewk = mtplot.histoMgr.getHisto(
                            "EWK").getRootHisto().Clone(HISTONAME + "/" +
                                                        HISTONAME + bin)

                        if var:
                            legendName = "QCD(Data)+EWK+t#bar{t}(Data, mis-ID. #tau)"
                        else:
                            legendName = "QCD(Data)+EWK+t#bar{t}(MC, mis-ID. #tau)"
                        legendName = legendName.replace("Plus", "")
                        mt.SetName(legendName)
                        mt.SetLineColor(color)
                        mt.Add(mt_ewk, -1)
                        mtn.Add(mtn_ewk, -1)
                        mtn.Scale(QCDInvertedNormalization[str(i)])

                        if var:
                            scale = w1 * QCDInvertedNormalizationFilteredEWKFakeTaus[
                                str(
                                    i
                                )] + w2 * QCDInvertedNormalizationFilteredEWKFakeTaus[
                                    str(i) + "EWK_FakeTaus"]
                            mt.Scale(scale)
                        else:
                            mt.Scale(QCDInvertedNormalization[str(i)])
                        color += 1
                        if color == 5:
                            color += 1
                    else:
                        h = mtplot.histoMgr.getHisto(
                            "Data").getRootHisto().Clone(HISTONAME + "/" +
                                                         HISTONAME + bin)
                        mt_ewk = mtplot.histoMgr.getHisto(
                            "EWK").getRootHisto().Clone(HISTONAME + "/" +
                                                        HISTONAME + bin)
                        hn = mtplot.histoMgr.getHisto(
                            "Data").getRootHisto().Clone(HISTONAME + "/" +
                                                         HISTONAME + bin)
                        mtn_ewk = mtplot.histoMgr.getHisto(
                            "EWK").getRootHisto().Clone(HISTONAME + "/" +
                                                        HISTONAME + bin)

                        h.Add(mt_ewk, -1)
                        hn.Add(mtn_ewk, -1)
                        hn.Scale(QCDInvertedNormalization[str(i)])

                        if var:
                            scale = w1 * QCDInvertedNormalizationFilteredEWKFakeTaus[
                                str(
                                    i
                                )] + w2 * QCDInvertedNormalizationFilteredEWKFakeTaus[
                                    str(i) + "EWK_FakeTaus"]
                            h.Scale(scale)
                        else:
                            h.Scale(QCDInvertedNormalization[str(i)])
                        mt.Add(h)
                        mtn.Add(hn)

                #mt = mt.Rebin(len(myBinning)-1,"",myArray)
                #mt_corr = mt_corr.Rebin(len(myBinning)-1,"",myArray)

                if not var:
                    mt.Add(mt_baseline)
                    #mt.Add(mt_corr)

                #myBinning = []
                #for i in range(0,11):
                #    myBinning.append(20*i)
                #myBinning.append(400)

                #myArray = array.array("d",defaultBinning)
                mt = mt.Rebin(len(myBinning) - 1, "", myArray)

                for i in range(0, mt.GetSize()):
                    if var:
                        var_values.append(mt.GetBinContent(i))
                    else:
                        nom_values.append(mt.GetBinContent(i))

                if var:
                    #mt.SetLineStyle(2)
                    var_hist = mt
                else:
                    #mt.SetLineStyle(2)
                    nom_hist = mt

                style = tdrstyle.TDRStyle()

                #gStyle.SetOptStat(1101)
                #mt_data.SetStats(1)
                #gPad.Update()
                bins = [0, 390, 400]
                arr = array.array("d", bins)
                mtn = mtn.Rebin(len(bins) - 1, "", arr)
                plot_data = plots.PlotBase()
                plot_data.histoMgr.appendHisto(histograms.Histo(mtn, "Data"))
                plot_data.createFrame("Data_" + HISTONAME + "_" + optMode +
                                      "_" + str(w1))
                plot_data.draw()
                plot_data.save()

            plot = plots.ComparisonPlot(nom_hist, var_hist)
            plot.createFrame(optMode.replace(
                "Opt", "Mt_" + "w1=" + str(w1) + "_w2=" + str(w2) +
                "_DataDrivenVsMC_"),
                             createRatio=True)

            moveLegend = {"dx": -0.295, "dy": 0.05}
            plot.setLegend(
                histograms.moveLegend(histograms.createLegend(), **moveLegend))
            histograms.addText(
                0.65, 0.20,
                optMode.replace("OptQCDTailKiller",
                                "R_{BB} ").replace("Plus", ""), 25)
            histograms.addCmsPreliminaryText()
            histograms.addEnergyText()
            lumi = datasets.getDataset("Data").getLuminosity()
            histograms.addLuminosityText(x=None, y=None, lumi=lumi)

            plot.draw()
            plot.save()

            num = 0
            denom = 0
            #print var_values
            for i in range(0, len(nom_values)):
                num += var_values[i] * (var_values[i] - nom_values[i])**2
                denom += var_values[i]
            diff = num / denom
            diff_list.append(diff)
        diff_opt.append(diff_list)

    print w1_list, '\n'
    for i in range(0, len(diff_opt)):
        print diff_opt[i]
        print w1_list[diff_opt[i].index(min(diff_opt[i]))]

    mt_baseline = mt_baseline.Rebin(len(bins) - 1, "", arr)
    plot_bft = plots.PlotBase()
    plot_bft.histoMgr.appendHisto(histograms.Histo(mt_baseline, "baseline"))
    #mt_corr.Scale(2)
    #plot_bft.histoMgr.appendHisto(histograms.Histo(mt_corr,"test"))

    #rangeMin = mt_signalfaketaus.GetXaxis().GetXmin()
    #rangeMax = mt_signalfaketaus.GetXaxis().GetXmax()
    #theFit = TF1('theFit',FitFunction(),rangeMin,rangeMax,4)
    #theFit.SetParLimits(0,0.5,10000)
    #theFit.SetParLimits(1,90,10000)
    #theFit.SetParLimits(2,30,10000)
    #theFit.SetParLimits(3,0.001,10000)
    #mt_signalfaketaus.Fit(theFit,"R")
    #theFit.SetRange(mt_signalfaketaus.GetXaxis().GetXmin(),mt_signalfaketaus.GetXaxis().GetXmax())
    #theFit.SetLineStyle(2)
    #theFit.SetLineColor(4)
    #theFit.SetLineWidth(3)
    #theFit.Draw()

    #mt_corr = theFit.GetHistogram()
    #mt_corr = mt_corr.Rebin(len(fitBinning)-1,"",fitArray)
    #mt_corr.Scale(mt_baseline.GetMaximum()/mt_corr.GetMaximum())
    #plot_bft.histoMgr.appendHisto(histograms.Histo(mt_corr,"test"))
    #plot_bft.histoMgr.appendHisto(histograms.Histo(theFit,"theFit"))

    plot_bft.createFrame('BaselineFakeTaus')
    plot_bft.draw()
    plot_bft.save()
FakeShapeHisto = None
ShapeHistogramsDimensions = None

if OptionMassShape == "TransverseMass":
    SignalShapeHisto = "shapeTransverseMass"
    FakeShapeTTbarHisto = "shapeEWKFakeTausTransverseMass"
    FakeShapeOtherHisto = "shapeProbabilisticBtagEWKFakeTausTransverseMass"
elif OptionMassShape == "FullMass":
    SignalShapeHisto = "shapeInvariantMass"
    FakeShapeOtherHisto = "shapeEWKFakeTausInvariantMass"
    FakeShapeTTbarHisto = FakeShapeOtherHisto
elif OptionMassShape == "TransverseAndFullMass2D": # FIXME: preparing to add support, not yet working
    SignalShapeHisto = "shapetransverseAndFullMass2D" # FIXME: Not yet implemented to signal analysis, etc.
    FakeShapeOtherHisto = "shapeEWKFakeTausTransverseAndFullMass2D" # FIXME: Not yet implemented to signal analysis, etc.
    FakeShapeTTbarHisto = FakeShapeOtherHisto
ShapeHistogramsDimensions = systematics.getBinningForPlot(SignalShapeHisto)

DataCardName += "_"+OptionMassShape.replace("TransverseMass","mT").replace("FullMass","invMass")

##############################################################################
# Observation definition (how to retrieve number of observed events)
#
from HiggsAnalysis.LimitCalc.InputClasses import ObservationInput
Observation = ObservationInput(datasetDefinition="Data",
                               shapeHisto=SignalShapeHisto)
#Observation.setPaths(signalPath,signalDataPaths)

##############################################################################
# Systematics lists
myTrgShapeSystematics = []
if OptionTreatTriggerUncertaintiesAsAsymmetric:
OptionBr=0.01  # Br(t->bH+)
OptionSqrtS=13 # sqrt(s)

##############################################################################
# Counter and histogram path definitions

# Rate counter definitions
SignalRateCounter="Selected events"
FakeRateCounter="EWKfaketaus:SelectedEvents"

# Shape histogram definitions
shapeHistoName=None
if OptionMassShape =="LdgTetrajetMass":
    shapeHistoName="LdgTetrajetMass_AfterAllSelections"
histoPathInclusive="ForDataDrivenCtrlPlots"
ShapeHistogramsDimensions=systematics.getBinningForPlot(shapeHistoName)
DataCardName +="_"+OptionMassShape

##############################################################################
# Observation definition (how to retrieve number of observed events)
#
from HiggsAnalysis.LimitCalc.InputClasses import ObservationInput
Observation=ObservationInput(datasetDefinition="Data", shapeHistoName=shapeHistoName, histoPath=histoPathInclusive)

##############################################################################
# TODO: Define systematics lists commmon to datasets
myTrgSystematics= [] #["CMS_eff_t_trg_data","CMS_eff_t_trg_MC", # Trigger tau part
                     #"CMS_eff_met_trg_data","CMS_eff_met_trg_MC"] # Trigger MET part
myTauIDSystematics=["CMS_eff_t"] #tau ID
#myTauIDSystematics.extend(["CMS_eff_t_highpt"])
#myTauMisIDSystematics=["CMS_fake_eToTau","CMS_fake_muToTau","CMS_fake_jetToTau"] # tau mis-ID
Esempio n. 8
0
def main(argv):

    dirs = []
    if len(sys.argv) < 2:
        usage()

    dirs.append(sys.argv[1])

    dirs_signal = ["../../SignalAnalysis_140605_143702/"]

    QCDInvertedNormalization = QCDInvertedNormalizationFactors.QCDInvertedNormalization
    QCDInvertedNormalizationFilteredEWKFakeTaus = QCDInvertedNormalizationFactorsFilteredEWKFakeTaus.QCDInvertedNormalization
    analysis_inverted = "signalAnalysisInvertedTau"
    analysis = "signalAnalysis"

    optModes = []
    #optModes.append("OptQCDTailKillerZeroPlus")
    optModes.append("OptQCDTailKillerLoosePlus")
    optModes.append("OptQCDTailKillerMediumPlus")
    optModes.append("OptQCDTailKillerTightPlus")

    varHistoName = "shapeEWKGenuineTausTransverseMass"
    nomHistoName = "shapeTransverseMass"
    signalHistoName = "shapeEWKFakeTausTransverseMass"

    #Optimal: 0.8, 0.82, 0.9

    #w_list = [0.65, 0.7, 0.76] #baseline ft
    w_list = [0.66, 0.67, 0.75]

    defaultBinning = systematics.getBinningForPlot("shapeTransverseMass")
    defaultBinning_array = array.array("d", defaultBinning)

    diff_opt = []
    for optMode in optModes:
        diff_list = []
        for w in w_list:
            var_values = []
            nom_values = []

            # baseline fake taus
            mt_baseline_faketaus_data = getDataSets(dirs_signal, dataEra,
                                                    searchMode, analysis,
                                                    optMode)
            mtplot_signalfaketaus = plots.DataMCPlot(mt_baseline_faketaus_data,
                                                     signalHistoName)
            mt_signalfaketaus = mtplot_signalfaketaus.histoMgr.getHisto(
                "EWK").getRootHisto().Clone(signalHistoName)

            # inverted fake taus
            mt_inverted_faketaus_data = getDataSets(dirs, dataEra, searchMode,
                                                    analysis_inverted, optMode)

            histonames_var = mt_inverted_faketaus_data.getDataset(
                "Data").getDirectoryContent(varHistoName)
            histonames_nom = mt_inverted_faketaus_data.getDataset(
                "Data").getDirectoryContent(nomHistoName)

            bins_var = getBins(histonames_var, varHistoName)
            bins_nom = getBins(histonames_nom, nomHistoName)

            normalization_var_qg = getNormalization(
                bins_var, w, QCDInvertedNormalizationFilteredEWKFakeTaus, True)
            normalization_var = getNormalization(
                bins_var, w, QCDInvertedNormalizationFilteredEWKFakeTaus,
                False)
            normalization_nom = getNormalization(bins_nom, w,
                                                 QCDInvertedNormalization,
                                                 False)

            mt_var_qg = getMt(mt_inverted_faketaus_data, bins_var,
                              varHistoName, normalization_var_qg)
            mt_var = getMt(mt_inverted_faketaus_data, bins_var, varHistoName,
                           normalization_var)
            mt_nom = getMt(mt_inverted_faketaus_data, bins_nom, nomHistoName,
                           normalization_nom)

            mt_nom.Add(mt_signalfaketaus)

            mt_var_qg.SetName(
                "QCD(Data)+EWK+t#bar{t}(Data, mis-ID. #tau), q-g bal.")
            mt_var.SetName("QCD(Data)+EWK+t#bar{t}(Data, mis-ID. #tau)")
            mt_nom.SetName("QCD(Data)+EWK+t#bar{t}(MC, mis-ID. #tau)")

            mt_var_qg.SetLineWidth(4)
            mt_var.SetLineColor(14)
            mt_nom.SetLineColor(2)

            #mt_var_qg = mt_var_qg.Rebin(len(defaultBinning)-1,"",defaultBinning_array)
            #mt_var = mt_var.Rebin(len(defaultBinning)-1,"",defaultBinning_array)
            #mt_nom = mt_nom.Rebin(len(defaultBinning)-1,"",defaultBinning_array)

            for i in range(0, mt_nom.GetSize()):
                var_values.append(mt_var_qg.GetBinContent(i))
                nom_values.append(mt_nom.GetBinContent(i))

            style = tdrstyle.TDRStyle()

            varPlots = [mt_var, mt_var_qg]
            plot = plots.ComparisonManyPlot(mt_nom, varPlots)
            plot.createFrame(optMode.replace(
                "Opt", "Mt_DataDrivenVsMC_" + "w=" + str(w) + "_"),
                             createRatio=True)

            moveLegend = {"dx": -0.35, "dy": 0.05}
            plot.setLegend(
                histograms.moveLegend(histograms.createLegend(), **moveLegend))
            histograms.addText(
                0.65, 0.3,
                optMode.replace("OptQCDTailKiller",
                                "R_{BB} ").replace("Plus", ""), 25)
            histograms.addCmsPreliminaryText()
            histograms.addEnergyText()
            lumi = mt_inverted_faketaus_data.getDataset("Data").getLuminosity()
            histograms.addLuminosityText(x=None, y=None, lumi=lumi)

            plot.draw()
            plot.save()

            #mt_var_qg.Delete()
            #mt_var.Delete()
            #mt_nom.Delete()

            #TFile.CurrentFile().Close("R")

            # difference metrics
            num = 0
            denom = 0
            for i in range(0, len(nom_values)):
                num += var_values[i] * (var_values[i] - nom_values[i])**2
                denom += var_values[i]
            diff = num / denom
            diff_list.append(diff)
        diff_opt.append(diff_list)

    os.system("rm MtOptimal/*")
    os.system("mkdir -p MtOptimal")
    print "\nWeights:\t", w_list, '\n'
    optimalWeights = {}
    for i in range(0, len(diff_opt)):
        print optModes[i]
        print "Differences:\t", diff_opt[i], "- Optimal: w =", w_list[
            diff_opt[i].index(min(diff_opt[i]))]
        optimalWeights[optModes[i]] = w_list[diff_opt[i].index(min(
            diff_opt[i]))]
        command = "cp *" + str(w_list[diff_opt[i].index(min(
            diff_opt[i]))]) + "*" + optModes[i].replace("Opt",
                                                        "") + ".eps MtOptimal"
        os.system(command)
    print optimalWeights
    writeWeightsToFile("OptimalWeights.py", optimalWeights)
    writeNormalizationToFile("QCDPlusEWKFakeTauNormalizationFactors.py",
                             normalization_var_qg, bins_var)
Esempio n. 9
0
        p.histoMgr.setHistoLegendLabelMany({rhName: legName})

        # https://root.cern.ch/doc/master/classTHistPainter.html
        if rhName == refName:
            setStyle(i, h.getRootHisto(), False)  #True)
            Verbose("Reference histo is \"%s\"" % (rhName), True)
            p.histoMgr.setHistoDrawStyle(rhName, "CE4")
            p.histoMgr.setHistoLegendStyle(rhName, "LF")
        else:
            setStyle(i, h.getRootHisto(), False)
            p.histoMgr.setHistoDrawStyle(rhName, "P")
            p.histoMgr.setHistoLegendStyle(rhName, "LP")
            #p.histoMgr.setHistoDrawStyle(styles.styles[i]) #styles.generator(False), "P2")

    kwargs = opts._kwargs
    kwargs["rebinX"] = systematics.getBinningForPlot(
        "LdgTetrajetMass_AfterAllSelections")
    kwargs["divideByBinWidth"] = True
    kwargs["stackMCHistograms"] = False
    kwargs["addLuminosityText"] = False
    kwargs["createLegend"] = {"x1": 0.50, "y1": 0.60, "x2": 0.92, "y2": 0.92}
    kwargs["opts"] = {"ymin": 1e-6, "ymaxfactor": 5, "xmax": 3000.0}

    hName = opts.histoKey + "_AllEras"
    dName = aux.getSaveDirPath(opts.mcrab, prefix="", postfix="")
    plots.drawPlot(p, hName, **kwargs)
    SavePlot(p, hName, dName, saveFormats=[".png", ".pdf", ".C"])
    Print(
        "Saving \"%s\" under \"%s\"" %
        (hName, aux.convertToURL(dName, opts.url)), True)

    if not opts.batchMode:
Esempio n. 10
0
FakeShapeHisto = None
ShapeHistogramsDimensions = None

if OptionMassShape == "TransverseMass":
    SignalShapeHisto = "shapeTransverseMass"
    FakeShapeTTbarHisto = "shapeEWKFakeTausTransverseMass"
    FakeShapeOtherHisto = "shapeProbabilisticBtagEWKFakeTausTransverseMass"
elif OptionMassShape == "FullMass":
    SignalShapeHisto = "shapeInvariantMass"
    FakeShapeOtherHisto = "shapeEWKFakeTausInvariantMass"
    FakeShapeTTbarHisto = FakeShapeOtherHisto
elif OptionMassShape == "TransverseAndFullMass2D":  # FIXME: preparing to add support, not yet working
    SignalShapeHisto = "shapetransverseAndFullMass2D"  # FIXME: Not yet implemented to signal analysis, etc.
    FakeShapeOtherHisto = "shapeEWKFakeTausTransverseAndFullMass2D"  # FIXME: Not yet implemented to signal analysis, etc.
    FakeShapeTTbarHisto = FakeShapeOtherHisto
ShapeHistogramsDimensions = systematics.getBinningForPlot(SignalShapeHisto)

DataCardName += "_" + OptionMassShape.replace("TransverseMass", "mT").replace(
    "FullMass", "invMass")

##############################################################################
# Observation definition (how to retrieve number of observed events)
#
from HiggsAnalysis.LimitCalc.InputClasses import ObservationInput
Observation = ObservationInput(datasetDefinition="Data",
                               shapeHisto=SignalShapeHisto)
#Observation.setPaths(signalPath,signalDataPaths)

##############################################################################
# Systematics lists
myTrgShapeSystematics = []
    def createSystHistograms(self,
                             hRate,
                             hSystUp,
                             hSystDown,
                             hSystUpFromVar,
                             hSystDownFromVar,
                             quietMode=True):
        '''
        Uses the histogram "hSystUpFromVar" and "hSystDownFromVar" to account the systematic uncertainties 
        related to the Transfer Factors (TF) from the Control (or Verification) 
        Region (VR) to the Signal Region (SR). This sys. uncertainty should have both a Rate + Shape impact
        on final invariant mass distribution. 

        The two aforementioned histograms correspond to the invariant massdistrubutions
        ("ForDataDrivenCtrlPlots/LdgTetrajetMass_AfterAllSelections") obtained by using applying
        the transfer factors (TF) of the FakeB measurement to shapes from the VR. Instead of the nominal TF 
        however, the TF+TF_Error and TF-TF_Error are used instead, where TF_Error is the statistical error of
        the TF, calculated by using error propagation:
        TF = CR1/CR2
        TF_Error = ErrorPropagationForDivision(TF) = sqrt((sigmaA/b)**2 + (a/(b**2)*sigmaB)**2)
        where:
        A = Integral of CR1 histogram  (from ROOT)
        sigmaA = Integral Error for CR1 histogram (from ROOT)
        These histograms should be already in place (and correctly normalised) for the FakeB pseudodataset, 
        after running the ./makePseudoMulticrab.py -m <FakeB-dir> script.

        The error is symmetric and it is basically defined as:
        hSystUp   = Rate + 1sigma
        hSystDown = Rate - 1sigma
        where the rate is obtained from the filled histogram provided ("hRate")
        and sigma is the TF_Error as discussed above (error propagation on the division of CR1 and CR2)

        In this function we don't need to calculate the error propagation. The function assumes that the histograms provided
        already have the final variations in place (i.e. up = rate+error, down = rate-error)
        '''
        # Get the (clean) histogram name
        fullName = hRate.GetName()
        cleanName = fullName.replace("_cloned", "")
        cleanName = cleanName.replace("_FakeBMeasurementTrijetMass", "")
        rebinX = systematics.getBinningForPlot(cleanName)

        # if hRate.GetNbinsX() != hSystUpFromVar.GetNbinsX():

        if rebinX != None:
            self.Verbose(
                "Rebinning histogram \"%s\" (\"%s\")" % (cleanName, fullName),
                True)
            hRate = hRate.Rebin(
                len(rebinX) - 1, hRate.GetName(), array.array("d", rebinX))
            hSystUpFromVar = hSystUpFromVar.Rebin(
                len(rebinX) - 1, hSystUpFromVar.GetName(),
                array.array("d", rebinX))
            hSystDownFromVar = hSystDownFromVar.Rebin(
                len(rebinX) - 1, hSystDownFromVar.GetName(),
                array.array("d", rebinX))
            ### hSystUp      = hSystUp.Rebin(len(rebinX)-1, hSystUp.GetName(), array.array("d", rebinX))     #don't !
            ### hSystDown    = hSystDown.Rebin(len(rebinX)-1, hSystDown.GetName(), array.array("d", rebinX)) #don't !

        # Constuct a summary table
        table = []
        align = "{:>7} {:>15} {:>10} {:>12} {:>12} {:>12} {:>10}"
        header = align.format("Bin #", "Bin Centre", "Rate (Nom)", "Rate (Up)",
                              "Rate (Down)", "% Up", "% Down")
        hLine = "=" * 85
        table.append("{:^85}".format(cleanName))
        table.append(hLine)
        table.append(header)
        table.append(hLine)

        # For-loop: All histogram bins for given data-driven control plot
        nBinsX = hRate.GetNbinsX()
        for i in range(1, nBinsX + 1):
            self.Verbose(
                "Calculating systematic for bin \"%d\" in histogram \"%s\"" %
                (i, hRate.GetName()), i == 1)

            # Calculate the systematics
            rateNominal = hRate.GetBinContent(i)
            rateSystUp = hSystUpFromVar.GetBinContent(i)
            rateSystDown = hSystDownFromVar.GetBinContent(i)
            binCentre = hRate.GetBinCenter(i)

            # Calculate percentage difference wrt nominal
            if rateNominal > 0.0:
                rateSystUpPerc = (rateSystUp -
                                  rateNominal) / (rateNominal) * 100
                rateSystDownPerc = (rateSystDown -
                                    rateNominal) / (rateNominal) * 100
            else:
                rateSystUpPerc = 0
                rateSystDownPerc = 0

            # Fill summary table for given bin
            row = align.format(i, binCentre, "%.1f" % rateNominal,
                               "%.1f" % rateSystUp, "%.1f" % rateSystDown,
                               "%.1f" % rateSystUpPerc,
                               "%.1f" % rateSystDownPerc)
            table.append(row)
            self.Verbose(
                ShellStyles.ErrorStyle() + row + ShellStyles.NormalStyle(),
                i == 1)

            # Fill the up/down systematics histograms
            self.Verbose(
                "Setting the systematics values in the histograms SystUp and SystDown",
                False)
            hSystUp.SetBinContent(i, rateSystUp)
            hSystDown.SetBinContent(i, rateSystDown)

        # Append total uncertainty info
        table.extend(
            self.GetTotalUncertainyTable(hRate, hSystUpFromVar,
                                         hSystDownFromVar, hLine, align))

        # Print summary table
        if quietMode == False or self._verbose == True:
            for i, row in enumerate(table, 1):
                self.Print(row, i == 1)
        return
def main(argv):

    dirs = []
    if len(sys.argv) < 2:
	usage()

    dirs.append(sys.argv[1])

    QCDInvertedNormalization = QCDInvertedNormalizationFactors.QCDInvertedNormalization
    QCDInvertedNormalizationFilteredEWKFakeTaus = QCDInvertedNormalizationFactorsFilteredEWKFakeTaus.QCDInvertedNormalization
    analysis = "signalAnalysisInvertedTau"
    optModes = []
    #optModes.append("OptQCDTailKillerZeroPlus")
    optModes.append("OptQCDTailKillerLoosePlus") 
    optModes.append("OptQCDTailKillerMediumPlus") 
    optModes.append("OptQCDTailKillerTightPlus") 
    #optModes.append("OptQCDTailKillerVeryTightPlus")
    #optModes.append("OnlyGenuineMCTausFalse")
    #optModes.append("OnlyGenuineMCTausTrue")

    #Optimal: 0.8, 0.82, 0.9
    #w1_list = [0.8, 0.82, 0.84, 0.87]
    #w1_list = [0.8, 0.82, 0.9, 1]
    w1_list = [0.9]

    defaultBinning = systematics.getBinningForPlot("shapeTransverseMass")

    diff_opt = []
    for optMode in optModes:
        diff_list = []
        for w1 in w1_list:
            var_values = []
            nom_values = []
            w2 = 1 - w1
            
            color = 1

            #signal

            dirs_signal = ["../../SignalAnalysis_140605_143702/"]
            datasets_signal = dataset.getDatasetsFromMulticrabDirs(dirs_signal,dataEra=dataEra,  searchMode=searchMode, analysisName=analysis.replace("InvertedTau",""), optimizationMode=optMode)
            
            datasets_signal.updateNAllEventsToPUWeighted()
            datasets_signal.loadLuminosities()
            
            datasets_signal.remove(filter(lambda name: "TTToHplus" in name, datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(filter(lambda name: "HplusTB" in name, datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(filter(lambda name: "Hplus_taunu_t-channel" in name, datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(filter(lambda name: "Hplus_taunu_tW-channel" in name, datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(filter(lambda name: "TTJets_SemiLept" in name, datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(filter(lambda name: "TTJets_FullLept" in name, datasets_signal.getAllDatasetNames()))
            datasets_signal.remove(filter(lambda name: "TTJets_Hadronic" in name, datasets_signal.getAllDatasetNames()))
            
            plots.mergeRenameReorderForDataMC(datasets_signal)
            
            datasets_signal.merge("EWK", [
                "TTJets",
                "WJets",
                "DYJetsToLL",
                "SingleTop",
                "Diboson"
                ])
            
            mtplot_signalfaketaus = plots.DataMCPlot(datasets_signal, "shapeEWKFakeTausTransverseMass")
            mt_signalfaketaus = mtplot_signalfaketaus.histoMgr.getHisto("EWK").getRootHisto().Clone("shapeEWKFakeTausTransverseMass")
            mt_signalfaketaus.SetName("BaselineFakeTaus")

            myBinning = [0, 20, 40, 60, 80, 100, 120, 140, 160, 200, 400]
            myArray = array.array("d",myBinning)

            fitBinning = []
            for i in range(0,45):
               fitBinning.append(i*10) 
            fitArray = array.array("d",fitBinning)

            mt_baseline = mt_signalfaketaus

            #rangeMin = mt_signalfaketaus.GetXaxis().GetXmin()
            #rangeMax = mt_signalfaketaus.GetXaxis().GetXmax()
            #theFit = TF1('theFit',FitFunction(),rangeMin,rangeMax,4)
            #theFit.SetParLimits(0,0.5,10000)
            #theFit.SetParLimits(1,90,10000)
            #theFit.SetParLimits(2,30,10000)
            #theFit.SetParLimits(3,0.001,10000)
            #mt_signalfaketaus.Fit(theFit,"R")
            #theFit.SetRange(mt_signalfaketaus.GetXaxis().GetXmin(),mt_signalfaketaus.GetXaxis().GetXmax())
            #theFit.SetLineStyle(2)
            #theFit.SetLineColor(4)
            #theFit.SetLineWidth(3)
            #theFit.Draw()
            #mt_corr = theFit.GetHistogram()
            #mt_corr = mt_corr.Rebin(len(fitBinning)-1,"",fitArray)
            #mt_corr.Scale(mt_baseline.GetMaximum()/mt_corr.GetMaximum())
            
            for HISTONAME in histoNameList:
                var = False
                if HISTONAME == "shapeEWKGenuineTausTransverseMass":
                    var = True
                datasets = dataset.getDatasetsFromMulticrabDirs(dirs,dataEra=dataEra,  searchMode=searchMode, analysisName=analysis, optimizationMode=optMode)

                datasets.updateNAllEventsToPUWeighted()
                datasets.loadLuminosities()

                plots.mergeRenameReorderForDataMC(datasets)

                datasets.merge("EWK", [
                                "TTJets",
                                "WJets",
                                "DYJetsToLL",
                                "SingleTop",
                                "Diboson"
                              ])

                histonames = datasets.getDataset("Data").getDirectoryContent(HISTONAME)

                bins = []
                for histoname in histonames:
                    binname = histoname.replace(HISTONAME,"")
                    if not binname == "Inclusive":
                        bins.append(binname)

                for i,bin in enumerate(bins):
                    mtplot = plots.DataMCPlot(datasets, HISTONAME+"/"+HISTONAME+bin)

                    if i == 0:
                        mt = mtplot.histoMgr.getHisto("Data").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin)
                        mt_ewk = mtplot.histoMgr.getHisto("EWK").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin)
                        mtn = mtplot.histoMgr.getHisto("Data").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin) 
                        mtn_ewk = mtplot.histoMgr.getHisto("EWK").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin)

                        if var:
                            legendName = "QCD(Data)+EWK+t#bar{t}(Data, mis-ID. #tau)"
                        else:
                            legendName = "QCD(Data)+EWK+t#bar{t}(MC, mis-ID. #tau)"
                        legendName = legendName.replace("Plus","")
                        mt.SetName(legendName)
                        mt.SetLineColor(color)
                        mt.Add(mt_ewk,-1)
                        mtn.Add(mtn_ewk,-1)
                        mtn.Scale(QCDInvertedNormalization[str(i)])

                        if var:
                            scale = w1*QCDInvertedNormalizationFilteredEWKFakeTaus[str(i)] + w2*QCDInvertedNormalizationFilteredEWKFakeTaus[str(i)+"EWK_FakeTaus"]
                            mt.Scale(scale)
                        else:
                            mt.Scale(QCDInvertedNormalization[str(i)])
                        color += 1
                        if color == 5:
                            color += 1
                    else:
                        h = mtplot.histoMgr.getHisto("Data").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin)
                        mt_ewk = mtplot.histoMgr.getHisto("EWK").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin)
                        hn = mtplot.histoMgr.getHisto("Data").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin)
                        mtn_ewk = mtplot.histoMgr.getHisto("EWK").getRootHisto().Clone(HISTONAME+"/"+HISTONAME+bin)

                        h.Add(mt_ewk,-1)
                        hn.Add(mtn_ewk,-1)
                        hn.Scale(QCDInvertedNormalization[str(i)])

                        if var:
                            scale = w1*QCDInvertedNormalizationFilteredEWKFakeTaus[str(i)] + w2*QCDInvertedNormalizationFilteredEWKFakeTaus[str(i)+"EWK_FakeTaus"]
                            h.Scale(scale)
                        else:
                            h.Scale(QCDInvertedNormalization[str(i)])
                        mt.Add(h)
                        mtn.Add(hn)

                #mt = mt.Rebin(len(myBinning)-1,"",myArray)
                #mt_corr = mt_corr.Rebin(len(myBinning)-1,"",myArray)
                
                if not var:
                    mt.Add(mt_baseline)
                    #mt.Add(mt_corr) 
                    
                #myBinning = []    
                #for i in range(0,11):
                #    myBinning.append(20*i)
                #myBinning.append(400)
                
                #myArray = array.array("d",defaultBinning)
                mt = mt.Rebin(len(myBinning)-1,"",myArray)

                for i in range(0,mt.GetSize()):
                    if var:
                        var_values.append(mt.GetBinContent(i))
                    else:
                        nom_values.append(mt.GetBinContent(i))
                
                if var:
                    #mt.SetLineStyle(2)
                    var_hist = mt
                else:
                    #mt.SetLineStyle(2)
                    nom_hist = mt

                style = tdrstyle.TDRStyle()

                #gStyle.SetOptStat(1101)
                #mt_data.SetStats(1)
                #gPad.Update()
                bins = [0, 390, 400]
                arr = array.array("d",bins)
                mtn = mtn.Rebin(len(bins)-1,"",arr)
                plot_data = plots.PlotBase()
                plot_data.histoMgr.appendHisto(histograms.Histo(mtn,"Data"))
                plot_data.createFrame("Data_"+HISTONAME+"_"+optMode+"_"+str(w1))
                plot_data.draw()
                plot_data.save()


            plot = plots.ComparisonPlot(nom_hist,var_hist)
            plot.createFrame(optMode.replace("Opt","Mt_"+"w1="+str(w1)+"_w2="+str(w2)+"_DataDrivenVsMC_"), createRatio=True)

            moveLegend={"dx": -0.295,"dy": 0.05}
            plot.setLegend(histograms.moveLegend(histograms.createLegend(), **moveLegend))
            histograms.addText(0.65, 0.20, optMode.replace("OptQCDTailKiller","R_{BB} ").replace("Plus",""), 25)
            histograms.addCmsPreliminaryText()
            histograms.addEnergyText()
            lumi=datasets.getDataset("Data").getLuminosity()
            histograms.addLuminosityText(x=None, y=None, lumi=lumi)

            plot.draw()
            plot.save()

            num = 0
            denom = 0
            #print var_values
            for i in range(0,len(nom_values)):
                num += var_values[i]*(var_values[i]-nom_values[i])**2
                denom += var_values[i]
            diff = num/denom
            diff_list.append(diff)
        diff_opt.append(diff_list)

    print w1_list,'\n'
    for i in range(0,len(diff_opt)):
        print diff_opt[i]
        print w1_list[diff_opt[i].index(min(diff_opt[i]))]

    mt_baseline = mt_baseline.Rebin(len(bins)-1,"",arr)
    plot_bft = plots.PlotBase()
    plot_bft.histoMgr.appendHisto(histograms.Histo(mt_baseline,"baseline"))
    #mt_corr.Scale(2)
    #plot_bft.histoMgr.appendHisto(histograms.Histo(mt_corr,"test"))


    #rangeMin = mt_signalfaketaus.GetXaxis().GetXmin()
    #rangeMax = mt_signalfaketaus.GetXaxis().GetXmax()
    #theFit = TF1('theFit',FitFunction(),rangeMin,rangeMax,4)
    #theFit.SetParLimits(0,0.5,10000)
    #theFit.SetParLimits(1,90,10000)
    #theFit.SetParLimits(2,30,10000)
    #theFit.SetParLimits(3,0.001,10000)
    #mt_signalfaketaus.Fit(theFit,"R")
    #theFit.SetRange(mt_signalfaketaus.GetXaxis().GetXmin(),mt_signalfaketaus.GetXaxis().GetXmax())
    #theFit.SetLineStyle(2)
    #theFit.SetLineColor(4)
    #theFit.SetLineWidth(3)
    #theFit.Draw()

    #mt_corr = theFit.GetHistogram()
    #mt_corr = mt_corr.Rebin(len(fitBinning)-1,"",fitArray)
    #mt_corr.Scale(mt_baseline.GetMaximum()/mt_corr.GetMaximum())
    #plot_bft.histoMgr.appendHisto(histograms.Histo(mt_corr,"test"))
    #plot_bft.histoMgr.appendHisto(histograms.Histo(theFit,"theFit"))

    plot_bft.createFrame('BaselineFakeTaus')
    plot_bft.draw()
    plot_bft.save()