From 1cce06d3e6eb4906608b29d5c2cf61f23beaeff7 Mon Sep 17 00:00:00 2001 From: Fabio Monti Date: Wed, 23 Apr 2025 17:19:01 +0200 Subject: [PATCH 1/2] select bins to plot in PostFitShapesFromWorkspace --- CombineTools/bin/PostFitShapesFromWorkspace.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CombineTools/bin/PostFitShapesFromWorkspace.cpp b/CombineTools/bin/PostFitShapesFromWorkspace.cpp index a7b626d1a25..0f3c39a2d88 100644 --- a/CombineTools/bin/PostFitShapesFromWorkspace.cpp +++ b/CombineTools/bin/PostFitShapesFromWorkspace.cpp @@ -47,6 +47,7 @@ int main(int argc, char* argv[]) { bool skip_proc_errs = false; bool total_shapes = false; std::vector reverse_bins_; + std::string selected_bins_=""; po::options_description help_config("Help"); help_config.add_options() @@ -103,6 +104,7 @@ int main(int argc, char* argv[]) { ("total-shapes", po::value(&total_shapes)->default_value(total_shapes)->implicit_value(true), "Save signal- and background shapes added for all channels/categories") + ("selected-bins", po::value(&selected_bins_)->default_value(selected_bins_), "List of bins to consider") ("reverse-bins", po::value>(&reverse_bins_)->multitoken(), "List of bins to reverse the order for"); @@ -186,7 +188,12 @@ int main(int argc, char* argv[]) { return no_shape; }); - auto bins = cmb.cp().bin_set(); + auto bins = cmb.cp().bin_set(); + if(selected_bins_!="") { + vector selected_bins_vec; + boost::split(selected_bins_vec, selected_bins_, boost::is_any_of(",")); + bins = cmb.cp().bin(selected_bins_vec).bin_set(); + } TFile outfile(output.c_str(), "RECREATE"); TH1::AddDirectory(false); From a66e7f5afa7eaa3c188011022ab0449defdd3c37 Mon Sep 17 00:00:00 2001 From: Fabio Monti Date: Tue, 6 May 2025 11:47:54 +0200 Subject: [PATCH 2/2] workflow to split PostFitShapesFromWorkspace by bin with combineTool --- .../combine/PostFitShapesFromWorkspace.py | 68 +++++++++++++++++++ CombineTools/scripts/combineTool.py | 2 + 2 files changed, 70 insertions(+) create mode 100644 CombineTools/python/combine/PostFitShapesFromWorkspace.py diff --git a/CombineTools/python/combine/PostFitShapesFromWorkspace.py b/CombineTools/python/combine/PostFitShapesFromWorkspace.py new file mode 100644 index 00000000000..1b2af5ad616 --- /dev/null +++ b/CombineTools/python/combine/PostFitShapesFromWorkspace.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +from __future__ import absolute_import +from __future__ import print_function +import sys +import re +import json +import ROOT +import CombineHarvester.CombineTools.combine.utils as utils + +from CombineHarvester.CombineTools.combine.CombineToolBase import CombineToolBase +from six.moves import map + + +class PostFitShapesFromWorkspace(CombineToolBase): + description = 'Calculate nuisance parameter impacts' + requires_root = True + + def __init__(self): + CombineToolBase.__init__(self) + + def attach_intercept_args(self, group): + CombineToolBase.attach_intercept_args(self, group) + group.add_argument('-w', '--workspace', required=True) + group.add_argument('-f', '--fitresult', required=True) + group.add_argument('-d','--datacard', default="") + group.add_argument('--freeze', default="") + group.add_argument('-m', '--mass') + group.add_argument('--samples', default="") + group.add_argument('--covariance', action='store_true') + group.add_argument('--skip-proc-errs', action='store_true') + group.add_argument('--total-shapes', action='store_true') + group.add_argument('--postfit', action='store_true') + + def attach_args(self, group): + CombineToolBase.attach_args(self, group) + group.add_argument('--outdir', '-o', help="""output directory for root files""") + + def run_method(self): + wsFile = ROOT.TFile(self.args.workspace) + w = wsFile.Get('w') + pass_str = ' '.join(self.passthru) + bins = [ nameIdx.first for nameIdx in w.allCats()["CMS_channel"] ] + print("bins",bins) + + extra_args_str = " --workspace %s --fitresult %s "%(self.args.workspace,self.args.fitresult) + if self.args.skip_proc_errs: + extra_args_str += " --skip-proc-errs " + if self.args.total_shapes: + extra_args_str += " --total-shapes " + if self.args.postfit: + extra_args_str += " --postfit " + if self.args.covariance: + extra_args_str += " --covariance " + if self.args.freeze!="": + extra_args_str += " --freeze %s "%(self.args.freeze) + if self.args.datacard!="": + extra_args_str += " --datacard %s "%(self.args.datacard) + if self.args.samples!="": + extra_args_str += " --samples %s "%(self.args.samples) + + for b in bins: + outfile="%s/shapes_%s.root"%(self.args.outdir, b) + self.job_queue.append( + 'PostFitShapesFromWorkspace %s --selected-bins %s --output %s'%(extra_args_str,b,outfile)) + self.flush_queue() + sys.exit(0) + diff --git a/CombineTools/scripts/combineTool.py b/CombineTools/scripts/combineTool.py index ffe94796bbd..72b7eb4ccb1 100755 --- a/CombineTools/scripts/combineTool.py +++ b/CombineTools/scripts/combineTool.py @@ -14,6 +14,7 @@ from CombineHarvester.CombineTools.combine.T2W import T2W from CombineHarvester.CombineTools.combine.FastScan import FastScan from CombineHarvester.CombineTools.combine.TaylorExpand import TaylorExpand +from CombineHarvester.CombineTools.combine.PostFitShapesFromWorkspace import PostFitShapesFromWorkspace ROOT.PyConfig.IgnoreCommandLineOptions = True ROOT.gROOT.SetBatch(ROOT.kTRUE) @@ -37,6 +38,7 @@ def register_method(parser, method_dict, method_class): register_method(parser, methods, PrintWorkspace) register_method(parser, methods, ModifyDataSet) register_method(parser, methods, Impacts) +register_method(parser, methods, PostFitShapesFromWorkspace) register_method(parser, methods, ImpactsFromScans) register_method(parser, methods, CollectLimits) register_method(parser, methods, CollectGoodnessOfFit)