예제 #1
0
def main(opts, moduleSelector, multipleDirs):
    #Print(CaptionStyle() + "*** Datacard generator ***" + NormalStyle() + "\n")

    # Definitions
    signalLabel = "Signal analysis"
    ewkLabel = "Embedding"
    qcdInvLabel = "QCD inverted"

    #gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS)
    #gc.set_debug(gc.DEBUG_STATS)
    #ROOT.SetMemoryPolicy(ROOT.kMemoryStrict)
    #gc.set_debug(gc.DEBUG_STATS)
    Verbose("Loading datacard \"%s\"" % (opts.datacard))

    # Catch any errors in the input datacard
    os.system("python %s" % opts.datacard)
    config = load_module(opts.datacard)

    # Replace source directory if necessary
    if multipleDirs != None:
        config.Path = multipleDirs
    Verbose("Input directory is \"%s\"" % (config.Path))

    # If user insisted on certain QCD method on command line, produce datacards only for that QCD method
    # Otherwise produce cards for all QCD methods
    myQCDMethods = [
        DataCard.DatacardQCDMethod.INVERTED, DataCard.DatacardQCDMethod.MC
    ]

    # Obtain dataset creators (also check multicrab directory existence)
    Verbose("Checking input multicrab directory presence")
    multicrabPaths = PathFinder.MulticrabPathFinder(config.Path)
    mcrabInfoOutput = []
    mcrabInfoOutput.append("Input directories:")

    signalDsetCreator = getDsetCreator(signalLabel,
                                       multicrabPaths.getSignalPath(),
                                       mcrabInfoOutput)
    embeddingDsetCreator = None
    if not config.OptionGenuineTauBackgroundSource == "DataDriven":
        mcrabInfoOutput.append(
            "- Embedding will be estimated from signal analysis MC")
        Verbose(WarningLabel() +
                "Embedding will be estimated from signal analysis MC" +
                NormalStyle())
    else:
        multicrabPaths.getEWKPath()
        if multicrabPaths.getEWKPath() == "":
            raise Exception(
                ErrorLabel() +
                "You asked for data driven EWK+tt with taus, but no corresponding multicrab was found!"
            )
        embeddingDsetCreator = getDsetCreator(ewkLabel,
                                              multicrabPaths.getEWKPath(),
                                              mcrabInfoOutput)
    qcdInvertedDsetCreator = getDsetCreator(
        qcdInvLabel, multicrabPaths.getQCDInvertedPath(), mcrabInfoOutput,
        DataCard.DatacardQCDMethod.INVERTED in myQCDMethods)

    if qcdInvertedDsetCreator == None:
        myQCDMethods.remove(DataCard.DatacardQCDMethod.INVERTED)
    else:
        myQCDMethods.remove(DataCard.DatacardQCDMethod.MC)

    # Require existence of signal analysis and one QCD measurement
    if signalDsetCreator == None:
        msg = ErrorLabel() + " Signal analysis multicrab directory not found!"
        raise Exception(msg)
    if len(myQCDMethods) == 0:
        msg = " QCD measurement (factorised and/or inverted) not found!"
        Print(WarningLabel() + msg)

    # Check options that are affecting the validity of the results
    if not config.OptionIncludeSystematics:
        msg = " Skipping of shape systematics has been forced (flag OptionIncludeSystematics in the datacard file)"
        Print(WarningLabel() + msg)
    if not config.OptionDoControlPlots:
        msg = " Skipping of data-driven control plot generation been forced (flag OptionDoControlPlots in the datacard file)"
        Print(WarningLabel() + msg)

    # Find list of available eras, search modes, and optimization modes common for all multicrab directories
    Verbose(
        "Find list of available eras, search modes, and optimization modes common for all multicrab directories",
        True)
    moduleSelector.setPrimarySource("Signal analysis", signalDsetCreator)
    if embeddingDsetCreator != None:
        moduleSelector.addOtherSource("Embedding", embeddingDsetCreator)

    #if qcdFactorisedDsetCreator != None:
    #moduleSelector.addOtherSource("QCD factorised", qcdFactorisedDsetCreator)

    if qcdInvertedDsetCreator != None:
        moduleSelector.addOtherSource("QCD inverted", qcdInvertedDsetCreator)

    moduleSelector.doSelect(
        opts, printSelections=opts.verbose
    )  # alex: prints out selected eras, modes, optimisation
    moduleSelector.closeFiles()

    # Separate light and heavy masses if they are not separated
    mySearchModeList = moduleSelector.getSelectedSearchModes()
    if ("Light" not in mySearchModeList and len(config.LightMassPoints) > 0 and len(config.HeavyMassPoints) > 0) or \
       ("Heavy" not in mySearchModeList and len(config.HeavyMassPoints) > 0 and len(config.LightMassPoints) > 0):
        mySearchModeList.append(mySearchModeList[0])

    # Summarise the consequences of the user choises
    nEras = len(moduleSelector.getSelectedEras())
    nModes = len(moduleSelector.getSelectedSearchModes())
    nOptModes = len(moduleSelector.getSelectedOptimizationModes())
    nQCDMethods = len(myQCDMethods)
    nDatacards = nEras * nModes * nOptModes * nQCDMethods
    msg = "Producing %d set(s) of datacards" % (nDatacards)
    msg += " [%d era(s) x %d search mode(s) x %d optimization mode(s) x %d QCD measurement(s)]" % (
        nEras, nModes, nOptModes, nQCDMethods)
    Print(HighlightAltStyle() + msg + NormalStyle())  #NoteStyle()

    # Produce datacards
    myCounter = 0
    myStartTime = time.time()
    myOriginalName = config.DataCardName
    myOutputDirectories = []

    # For-loop: QCD methods
    for qcdMethod in myQCDMethods:

        # For-loop: Data eras
        for era in moduleSelector.getSelectedEras():
            mySearchModeCounter = 0

            # For-loop: Search modes
            for searchMode in mySearchModeList:
                # Separate light and heavy mass points into their own subdirectories
                if len(mySearchModeList) > 1:
                    if mySearchModeList[0] == mySearchModeList[1]:
                        if mySearchModeCounter == 0:
                            config.MassPoints = config.LightMassPoints
                            config.DataCardName = myOriginalName + "_LightHplus"
                        elif mySearchModeCounter == 1:
                            config.MassPoints = config.HeavyMassPoints
                            config.DataCardName = myOriginalName + "_HeavyHplus"

                # print config.MassPoints
                mySearchModeCounter += 1
                # For-loop: Optimization modes
                for optimizationMode in moduleSelector.getSelectedOptimizationModes(
                ):
                    if hasattr(ROOT.gROOT, "CloseFiles"):
                        ROOT.gROOT.CloseFiles()
                    ROOT.gROOT.GetListOfCanvases().Delete()

                    # After these, three histograms are still left in memory
                    # Worst memory leak seems to come from storing and not freeing the main counters
                    # Create the dataset creator managers separately for each module
                    signalDsetCreator = getDsetCreator(
                        signalLabel, multicrabPaths.getSignalPath(),
                        mcrabInfoOutput)
                    embeddingDsetCreator = None
                    if not config.OptionGenuineTauBackgroundSource == "DataDriven":
                        mcrabInfoOutput.append(
                            "- Embedding will be estimated from signal analysis MC"
                        )
                        msg = "Embedding will be estimated from signal analysis MC"
                        Verbose(WarningLabel() +
                                msg)  #fixme: is this obsolete?
                    else:
                        embeddingDsetCreator = getDsetCreator(
                            ewkLabel, multicrabPaths.getEWKPath(),
                            mcrabInfoOutput)
                    myQCDDsetCreator = None

                    # if qcdMethod == DataCard.DatacardQCDMethod.FACTORISED:
                    #     enabled = DataCard.DatacardQCDMethod.FACTORISED in myQCDMethods
                    #     myQCDDsetCreator = getDsetCreator("QCD factorised", multicrabPaths.getQCDFactorisedPath(), mcrabInfoOutput, enabled)
                    #     if myQCDDsetCreator == None:
                    #         raise Exception(ErrorLabel()+"Could not find factorised QCD pseudomulticrab!"+NormalStyle())

                    if qcdMethod == DataCard.DatacardQCDMethod.INVERTED:
                        enabled = DataCard.DatacardQCDMethod.INVERTED in myQCDMethods
                        myQCDDsetCreator = getDsetCreator(
                            qcdInvLabel, multicrabPaths.getQCDInvertedPath(),
                            mcrabInfoOutput, enabled)
                        if myQCDDsetCreator == None:
                            msg = "Could not find inverted QCD pseudomulticrab"
                            raise Exception(ErrorLabel() + msg + NormalStyle())

                    Verbose(
                        "Create the datacard generator & check config file contents"
                    )
                    dcgen = DataCard.DataCardGenerator(opts,
                                                       config,
                                                       qcdMethod,
                                                       verbose=opts.verbose)

                    # Tweak to provide the correct datasetMgrCreator to the generator
                    qcd = "Unset"
                    if qcdMethod == DataCard.DatacardQCDMethod.FACTORISED:
                        qcd = "factorised"
                    elif qcdMethod == DataCard.DatacardQCDMethod.INVERTED:
                        qcd = "inverted"

                    # Print settings to user
                    PrintEraModeOptQCDMethod(era, searchMode, optimizationMode,
                                             qcd)

                    #Print("era=%s, searchMode=%s, optimizationMode=%s, QCD method=%s" % (era, searchMode, optimizationMode, qcd))
                    dcgen.setDsetMgrCreators(signalDsetCreator,
                                             embeddingDsetCreator,
                                             myQCDDsetCreator)

                    # Print progress info
                    myCounter += 1
                    msg = "Producing datacard %d/%d" % (myCounter, nDatacards)
                    Print(HighlightAltStyle() + msg +
                          NormalStyle())  #CaptionStyle

                    # Do the heavy stuff
                    myDir = dcgen.doDatacard(era, searchMode, optimizationMode,
                                             mcrabInfoOutput)
                    myOutputDirectories.append(myDir)

                    # Do tail fit for heavy H+ if asked
                    if opts.dotailfit:
                        Print("Performing tail fit for heavy H+ ...")
                        myHeavyStatus = True
                        for m in config.MassPoints:
                            if m < 175:
                                myHeavyStatus = False
                        if myHeavyStatus:
                            Print("Doing tail fit ...")
                            os.chdir(myDir)
                            os.system(
                                "../dcardTailFitter.py -x ../dcardTailFitSettings.py"
                            )
                            os.chdir("..")

    Verbose("Datacard generator is done!")

    # Timing calculations
    myEndTime = time.time()
    myTotTime = (myEndTime - myStartTime)
    myAvgTime = (myTotTime) / float(nDatacards)
    Verbose(
        "Running took on average %.1f s per datacard (elapsed time = %.1f s,  datacards = %d) "
        % (myAvgTime, myTotTime, nDatacards))

    # Generate plots for systematics
    if opts.systAnalysis:
        for d in myOutputDirectories:
            Print("Generating systematics plots for %s" (d))
            os.chdir(d)
            os.system("../plotShapes.py")
            os.chdir("..")

    # Make tar file
    myTimestamp = time.strftime("%y%m%d_%H%M%S", time.gmtime(time.time()))
    myLimitCode = None
    if opts.lands:
        myLimitCode = "lands"
    elif opts.combine:
        myLimitCode = "combine"
    myFilename = "datacards_%s_archive_%s.tgz" % (myLimitCode, myTimestamp)
    fTar = tarfile.open(myFilename, mode="w:gz")

    # For-loop: All output dirs
    for d in myOutputDirectories:
        fTar.add(d)
    fTar.close()

    msg = "Created archive of results directories to "
    Print(msg + SuccessStyle() + myFilename + NormalStyle())
예제 #2
0
def main(opts, moduleSelector, multipleDirs):

    # Fixme: Is this used/needed?
    if 0:
        gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS)
        gc.set_debug(gc.DEBUG_STATS)
        ROOT.SetMemoryPolicy(ROOT.kMemoryStrict)
        gc.set_debug(gc.DEBUG_STATS)

    # Catch any errors in the input datacard (options added to avoid double printouts from the template card; if there are any!)
    if opts.pyValidate:
        Verbose("Validating datacard \"%s\"" % (opts.datacard))
        os.system("python %s" % opts.datacard)

    # Load the datacard
    Verbose("Loading datacard \"%s\"" % (opts.datacard))
    config = aux.load_module(opts.datacard)

    # Replace source directory if necessary
    if multipleDirs != None:
        config.Path = multipleDirs
    Verbose("Input directory is \"%s\"" % (config.Path))

    # Obtain dataset creators (also check multicrab directory existence)
    Verbose("Checking input multicrab directory presence")
    multicrabPaths = PathFinder.MulticrabPathFinder(config.Path, opts.h2tb,
                                                    opts.verbose)
    mcrabInfoOutput = []
    mcrabInfoOutput.append("Input directories:")
    if opts.verbose:
        multicrabPaths.PrintInfo()

    # Determine dataset labels. Fixme: adopt global names (e.g. fakes, genuine)
    if opts.h2tb:
        fakesFromData = (config.OptionFakeBMeasurementSource == "DataDriven")
    else:
        fakesFromData = (
            config.OptionGenuineTauBackgroundSource == "DataDriven")
    signalLabel, bkg1Label, bkg2Label = GetDatasetLabels(
        config, fakesFromData, opts)

    # Create signal/bkg datasets creator
    Verbose("Creating signal & bkg datasets")
    signalDsetCreator = getSignalDsetCreator(multicrabPaths, signalLabel,
                                             mcrabInfoOutput)
    bkg1DsetCreator, bkg2DsetCreator = getBkgDsetCreators(
        multicrabPaths, bkg1Label, bkg2Label, fakesFromData, mcrabInfoOutput)
    # Set signal/bkg datasets creator labels
    signalDsetCreator.setLabel(signalLabel)
    bkg1DsetCreator.setLabel(bkg1Label)
    bkg2DsetCreator.setLabel(bkg2Label)

    PrintDsetInfo(
        [signalDsetCreator, bkg1DsetCreator, bkg2DsetCreator], True
    )  #opts.verbose) #bkg1 = EWK MC, bkg2 = FakeB if (data-driven==True)

    # Check options that are affecting the validity of the results
    CheckOptions(config)

    # Find list of available eras, search modes, and optimization modes common for all multicrab directories
    Verbose(
        "Find list of available eras, search modes, and optimization modes common for all multicrab directories",
        True)
    SetModuleSelectorSources(
        moduleSelector, signalLabel, signalDsetCreator, bkg1Label,
        bkg1DsetCreator, bkg2Label, bkg2DsetCreator,
        opts)  #fixme: santeri check. bkg1=Genuine, bkg2=Fake

    # Summarise the consequences of the user choises
    PrintOptions(moduleSelector)

    # Produce datacards
    myCounter = 0
    myStartTime = time.time()
    myOriginalName = config.DataCardName
    myOutputDirectories = []
    nDatacards = 0
    nEras = len(moduleSelector.getSelectedEras())
    nModes = len(moduleSelector.getSelectedSearchModes())
    nOpts = len(moduleSelector.getSelectedOptimizationModes())

    # For-loop: Data eras
    for i, era in enumerate(moduleSelector.getSelectedEras(), 1):
        msg = "{:<9} {:>3} {:<1} {:<3} {:<50}".format("Era", "%i" % i, "/",
                                                      "%s:" % (nEras), era)
        Print(HighlightAltStyle() + msg + NormalStyle(), i == 1)

        # For-loop: Search modes
        for j, searchMode in enumerate(moduleSelector.getSelectedSearchModes(),
                                       1):
            msg = "{:<9} {:>3} {:<1} {:<3} {:<50}".format(
                "Mode", "%i" % j, "/", "%s:" % (nModes), searchMode)
            Print(HighlightAltStyle() + msg + NormalStyle(), False)

            # For-loop: Optimization modes
            for k, optimizationMode in enumerate(
                    moduleSelector.getSelectedOptimizationModes(), 1):
                nDatacards += 1

                msg = "{:<9} {:>3} {:<1} {:<3} {:<50}".format(
                    "Opt", "%i" % k, "/", "%s:" % (nOpts), optimizationMode)
                Print(HighlightAltStyle() + msg + NormalStyle(), False)

                # FIXME: Crashes!
                #if hasattr(ROOT.gROOT, "CloseFiles"):
                #    ROOT.gROOT.CloseFiles()
                #ROOT.gROOT.GetListOfCanvases().Delete()

                Verbose(
                    "Create the datacard generator & check config file contents"
                )
                dcgen = DataCard.DataCardGenerator(opts,
                                                   config,
                                                   verbose=opts.verbose,
                                                   h2tb=opts.h2tb)
                dcgen.setDsetMgrCreators(signalDsetCreator, bkg1DsetCreator,
                                         bkg2DsetCreator)

                # Do the heavy stuff
                myDir = dcgen.doDatacard(era, searchMode, optimizationMode,
                                         mcrabInfoOutput)
                myOutputDirectories.append(myDir)

                # Do tail fit for heavy H+ if asked
                if opts.dotailfit:
                    Print("Performing tail fit for heavy H+ ...")
                    myHeavyStatus = True
                    for m in config.MassPoints:
                        if m < 161:
                            myHeavyStatus = False
                    if myHeavyStatus:
                        Print("Doing tail fit ...")
                        os.chdir(myDir)
                        os.system(
                            "../dcardTailFitter.py -x ../dcardTailFitSettings.py"
                        )
                        os.chdir("..")

    # Timing calculations
    myEndTime = time.time()
    myTotTime = (myEndTime - myStartTime)
    myAvgTime = (myTotTime) / float(nDatacards)
    Verbose(
        "Running took on average %.1f s per datacard (elapsed time = %.1f s,  datacards = %d) "
        % (myAvgTime, myTotTime, nDatacards))

    # Generate plots for systematics
    if opts.systAnalysis:
        for d in myOutputDirectories:
            Print("Generating systematics plots for %s" (d))
            os.chdir(d)
            os.system("../plotShapes.py")
            os.chdir("..")

    # Inform user
    for d in myOutputDirectories:
        msg = "Created results dir %s" % (SuccessStyle() + d + NormalStyle())
        Print(msg)

    # Optionally, create a tarball with all the results
    CreateTarball(myOutputDirectories, opts)

    if 0:
        gc.collect()
        ROOT.SetMemoryPolicy(ROOT.kMemoryHeuristics)
        memoryDump()
    return
예제 #3
0
def main(opts, moduleSelector, multipleDirs):
    print CaptionStyle()+"*** Datacard generator ***"+NormalStyle()+"\n"
    #gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS)
    #gc.set_debug(gc.DEBUG_STATS)
    #ROOT.SetMemoryPolicy(ROOT.kMemoryStrict)
    #gc.set_debug(gc.DEBUG_STATS)
    print "Loading datacard:",opts.datacard
    os.system("python %s"%opts.datacard) # Catch any errors in the input datacard
    config = load_module(opts.datacard)
    # Replace source directory if necessary
    if multipleDirs != None:
        config.Path = multipleDirs
    print "Input directory:",config.Path

    # If user insisted on certain QCD method on command line, produce datacards only for that QCD method
    # Otherwise produce cards for all QCD methods
    myQCDMethods = [DataCard.DatacardQCDMethod.INVERTED, DataCard.DatacardQCDMethod.MC]

    # Obtain dataset creators (also check multicrab directory existence)
    print "\nChecking input multicrab directory presence:"
    multicrabPaths = PathFinder.MulticrabPathFinder(config.Path)
    mcrabInfoOutput = []
    mcrabInfoOutput.append("Input directories:")

    signalDsetCreator = getDsetCreator("Signal analysis", multicrabPaths.getSignalPath(), mcrabInfoOutput)
    embeddingDsetCreator = None
    if not config.OptionGenuineTauBackgroundSource == "DataDriven":
        mcrabInfoOutput.append("- Embedding: estimated from signal analysis MC")
        print "- %sWarning:%s Embedding: estimated from signal analysis MC"%(WarningStyle(),NormalStyle())
    else:
        multicrabPaths.getEWKPath()
        if multicrabPaths.getEWKPath() == "":
            raise Exception(ErrorLabel()+"You asked for data driven EWK+tt with taus, but no corresponding multicrab was found!")
        embeddingDsetCreator = getDsetCreator("Embedding", multicrabPaths.getEWKPath(), mcrabInfoOutput)
    qcdInvertedDsetCreator = getDsetCreator("QCD inverted", multicrabPaths.getQCDInvertedPath(), mcrabInfoOutput, DataCard.DatacardQCDMethod.INVERTED in myQCDMethods)
    if qcdInvertedDsetCreator == None:
        myQCDMethods.remove(DataCard.DatacardQCDMethod.INVERTED)
    else:
        myQCDMethods.remove(DataCard.DatacardQCDMethod.MC)

    # Require existence of signal analysis and one QCD measurement
    if signalDsetCreator == None:
        raise Exception(ErrorStyle()+"Error:"+NormalStyle()+" Signal analysis multicrab directory not found!")
    if len(myQCDMethods) == 0:
        print (WarningLabel()+" QCD measurement (factorised and/or inverted) not found!")

    # Check options that are affecting the validity of the results
    if not config.OptionIncludeSystematics:
        print "\n%sWarning%s: skipping of shape systematics has been forced (flag OptionIncludeSystematics in the datacard file)"%(WarningStyle(),NormalStyle())
    if not config.OptionDoControlPlots:
        print "\n%sWarning%s: skipping of data driven control plot generation been forced (flag OptionDoControlPlots in the datacard file)"%(WarningStyle(),NormalStyle())

    # Find list of available eras, search modes, and optimization modes common for all multicrab directories
    moduleSelector.setPrimarySource("Signal analysis", signalDsetCreator)
    if embeddingDsetCreator != None:
        moduleSelector.addOtherSource("Embedding", embeddingDsetCreator)
    #if qcdFactorisedDsetCreator != None:
        #moduleSelector.addOtherSource("QCD factorised", qcdFactorisedDsetCreator)
    if qcdInvertedDsetCreator != None:
        moduleSelector.addOtherSource("QCD inverted", qcdInvertedDsetCreator)
    moduleSelector.doSelect(opts)
    moduleSelector.closeFiles()

    # Separate light and heavy masses if they are not separated
    mySearchModeList = moduleSelector.getSelectedSearchModes()
    if ("Light" not in mySearchModeList and len(config.LightMassPoints) > 0 and len(config.HeavyMassPoints) > 0) or \
       ("Heavy" not in mySearchModeList and len(config.HeavyMassPoints) > 0 and len(config.LightMassPoints) > 0):
        mySearchModeList.append(mySearchModeList[0])

    # Summarise the consequences of the user choises
    myDatacardCount = len(moduleSelector.getSelectedEras())*len(moduleSelector.getSelectedSearchModes())*len(moduleSelector.getSelectedOptimizationModes())*len(myQCDMethods)
    print "\nProducing %s%d sets of datacards%s (%d era(s) x %d search mode(s) x %d optimization mode(s) x %d QCD measurement(s))\n"%(HighlightStyle(),myDatacardCount,NormalStyle(),len(moduleSelector.getSelectedEras()),len(moduleSelector.getSelectedSearchModes()),len(moduleSelector.getSelectedOptimizationModes()),len(myQCDMethods))
    # Produce datacards
    myCounter = 0
    myStartTime = time.time()
    myOriginalName = config.DataCardName
    myOutputDirectories = []
    for qcdMethod in myQCDMethods:
        for era in moduleSelector.getSelectedEras():
            mySearchModeCounter = 0
            for searchMode in mySearchModeList:
                # Separate light and heavy mass points into their own subdirectories
                if len(mySearchModeList) > 1:
                    if mySearchModeList[0] == mySearchModeList[1]:
                        if mySearchModeCounter == 0:
                            config.MassPoints = config.LightMassPoints
                            config.DataCardName = myOriginalName + "_LightHplus"
                        elif mySearchModeCounter == 1:
                            config.MassPoints = config.HeavyMassPoints
                            config.DataCardName = myOriginalName + "_HeavyHplus"
                mySearchModeCounter += 1
                for optimizationMode in moduleSelector.getSelectedOptimizationModes():
                    if hasattr(ROOT.gROOT, "CloseFiles"):
                        ROOT.gROOT.CloseFiles()
                    ROOT.gROOT.GetListOfCanvases().Delete()
                    # After these, three histograms are still left in memory
                    # Worst memory leak seems to come from storing and not freeing the main counters
                    # Create the dataset creator managers separately for each module
                    signalDsetCreator = getDsetCreator("Signal analysis", multicrabPaths.getSignalPath(), mcrabInfoOutput)
                    embeddingDsetCreator = None
                    if not config.OptionGenuineTauBackgroundSource == "DataDriven":
                        mcrabInfoOutput.append("- Embedding: estimated from signal analysis MC")
                        print "- %sWarning:%s Embedding: estimated from signal analysis MC"%(WarningStyle(),NormalStyle())
                    else:
                        embeddingDsetCreator = getDsetCreator("Embedding", multicrabPaths.getEWKPath(), mcrabInfoOutput)
                    myQCDDsetCreator = None
                    #if qcdMethod == DataCard.DatacardQCDMethod.FACTORISED:
                        #myQCDDsetCreator = getDsetCreator("QCD factorised", multicrabPaths.getQCDFactorisedPath(), mcrabInfoOutput, DataCard.DatacardQCDMethod.FACTORISED in myQCDMethods)
                        #if myQCDDsetCreator == None:
                            #raise Exception(ErrorLabel()+"Could not find factorised QCD pseudomulticrab!"+NormalStyle())
                    if qcdMethod == DataCard.DatacardQCDMethod.INVERTED:
                        myQCDDsetCreator = getDsetCreator("QCD inverted", multicrabPaths.getQCDInvertedPath(), mcrabInfoOutput, DataCard.DatacardQCDMethod.INVERTED in myQCDMethods)
                        if myQCDDsetCreator == None:
                            raise Exception(ErrorLabel()+"Could not find inverted QCD pseudomulticrab!"+NormalStyle())
                    # Print progress info
                    myCounter += 1
                    print "%sProducing datacard %d/%d ...%s\n"%(CaptionStyle(),myCounter,myDatacardCount,NormalStyle())
                    # Create the generator, check config file contents
                    dcgen = DataCard.DataCardGenerator(opts, config, qcdMethod)
                    # Tweak to provide the correct datasetMgrCreator to the generator
                    if qcdMethod == DataCard.DatacardQCDMethod.FACTORISED:
                        print "era=%s%s%s, searchMode=%s%s%s, optimizationMode=%s%s%s, QCD method=%sfactorised%s\n"%(HighlightStyle(),era,NormalStyle(),HighlightStyle(),searchMode,NormalStyle(),HighlightStyle(),optimizationMode,NormalStyle(),HighlightStyle(),NormalStyle())
                    elif qcdMethod == DataCard.DatacardQCDMethod.INVERTED:
                        print "era=%s%s%s, searchMode=%s%s%s, optimizationMode=%s%s%s, QCD method=%sinverted%s\n"%(HighlightStyle(),era,NormalStyle(),HighlightStyle(),searchMode,NormalStyle(),HighlightStyle(),optimizationMode,NormalStyle(),HighlightStyle(),NormalStyle())
                    dcgen.setDsetMgrCreators(signalDsetCreator,embeddingDsetCreator,myQCDDsetCreator)
                    # Do the heavy stuff
                    myDir = dcgen.doDatacard(era,searchMode,optimizationMode,mcrabInfoOutput)
                    myOutputDirectories.append(myDir)
                    # Do tail fit for heavy H+ if asked
                    if opts.dotailfit:
                        myHeavyStatus = True
                        for m in config.MassPoints:
                            if m < 175:
                                myHeavyStatus = False
                        if myHeavyStatus:
                            print "Doing tail fit ..."
                            os.chdir(myDir)
                            os.system("../dcardTailFitter.py -x ../dcardTailFitSettings.py")
                            os.chdir("..")
    print "\nDatacard generator is done."
    myEndTime = time.time()
    print "Running took on average %.1f s / datacard (total elapsed time: %.1f s)"%((myEndTime-myStartTime)/float(myDatacardCount), (myEndTime-myStartTime))
    # Generate plots for systematics
    if opts.systAnalysis:
        for d in myOutputDirectories:
            print "\nGenerating systematics plots for",d
            os.chdir(d)
            os.system("../plotShapes.py")
            os.chdir("..")

    # Make tar file
    myTimestamp = time.strftime("%y%m%d_%H%M%S", time.gmtime(time.time()))
    myLimitCode = None
    if opts.lands:
        myLimitCode = "lands"
    elif opts.combine:
        myLimitCode = "combine"
    myFilename = "datacards_%s_archive_%s.tgz"%(myLimitCode,myTimestamp)
    fTar = tarfile.open(myFilename, mode="w:gz")
    for d in myOutputDirectories:
        fTar.add(d)
    fTar.close()
    print "Created archive of results directories to: %s%s%s"%(HighlightStyle(),myFilename,NormalStyle())