diff --git a/analysis/.ipynb_checkpoints/__init__-checkpoint.py b/analysis/.ipynb_checkpoints/__init__-checkpoint.py new file mode 100644 index 000000000..e69de29bb diff --git a/analysis/__init__.py b/analysis/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/analysis/btagMCeff/__init__.py b/analysis/btagMCeff/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/analysis/topEFT/README b/analysis/topEFT/README new file mode 100644 index 000000000..7b7fad2d8 --- /dev/null +++ b/analysis/topEFT/README @@ -0,0 +1,3 @@ +To run analysis on coffea-casa please use: + +`python analysis/topEFT/coffea_casa_run.py --prefix root://xcache// topcoffea/json/TTZToLLNuNu_M10.json` \ No newline at end of file diff --git a/analysis/topEFT/__init__.py b/analysis/topEFT/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/analysis/topEFT/coffea_casa_run.py b/analysis/topEFT/coffea_casa_run.py new file mode 100644 index 000000000..1a05ed568 --- /dev/null +++ b/analysis/topEFT/coffea_casa_run.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +import lz4.frame as lz4f +import pickle +import json +import time +import cloudpickle +import gzip +import os +from optparse import OptionParser + +import uproot +import numpy as np +from coffea import hist, processor +from coffea.util import load, save +from coffea.nanoevents import NanoAODSchema + +#import sys +#sys.path.append('./analysis/topEFT/') +from analysis.topEFT import topeft + +from analysis.topEFT import topeft +from topcoffea.modules import samples +from topcoffea.modules import fileReader + +if __name__ == '__main__': + + import argparse + parser = argparse.ArgumentParser(description='You can customize your run') + parser.add_argument('jsonFiles' , nargs='?', default='' , help = 'Json file(s) containing files and metadata') + parser.add_argument('--prefix', '-r' , nargs='?', default='' , help = 'Prefix or redirector to look for the files') + parser.add_argument('--test','-t' , action='store_true' , help = 'To perform a test, run over a few events in a couple of chunks') + parser.add_argument('--pretend' , action='store_true' , help = 'Read json files but, not execute the analysis') + parser.add_argument('--nworkers','-n' , default=8 , help = 'Number of workers') + parser.add_argument('--chunksize','-s' , default=100000 , help = 'Number of events per chunk') + parser.add_argument('--nchunks','-c' , default=None , help = 'You can choose to run only a number of chunks') + parser.add_argument('--outname','-o' , default='plotsTopEFT', help = 'Name of the output file with histograms') + parser.add_argument('--outpath','-p' , default='histos', help = 'Name of the output directory') + parser.add_argument('--treename' , default='Events', help = 'Name of the tree inside the files') + parser.add_argument('--do-errors', action='store_true', help = 'Save the w**2 coefficients') + parser.add_argument('--do-systs', action='store_true', help = 'Run over systematic samples (takes longer)') + + args = parser.parse_args() + jsonFiles = args.jsonFiles + prefix = args.prefix + dotest = args.test + nworkers = int(args.nworkers) + chunksize = int(args.chunksize) + nchunks = int(args.nchunks) if not args.nchunks is None else args.nchunks + outname = args.outname + outpath = args.outpath + pretend = args.pretend + treename = args.treename + do_errors = args.do_errors + do_systs = args.do_systs + + if dotest: + nchunks = 2 + chunksize = 10000 + nworkers = 1 + print('Running a fast test with %i workers, %i chunks of %i events'%(nworkers, nchunks, chunksize)) + + ### Load samples from json + samplesdict = {} + allInputFiles = [] + + def LoadJsonToSampleName(jsonFile, prefix): + sampleName = jsonFile if not '/' in jsonFile else jsonFile[jsonFile.rfind('/')+1:] + if sampleName.endswith('.json'): sampleName = sampleName[:-5] + with open(jsonFile) as jf: + samplesdict[sampleName] = json.load(jf) + samplesdict[sampleName]['redirector'] = prefix + + if isinstance(jsonFiles, str) and ',' in jsonFiles: jsonFiles = jsonFiles.replace(' ', '').split(',') + elif isinstance(jsonFiles, str) : jsonFiles = [jsonFiles] + for jsonFile in jsonFiles: + if os.path.isdir(jsonFile): + if not jsonFile.endswith('/'): jsonFile+='/' + for f in os.path.listdir(jsonFile): + if f.endswith('.json'): allInputFiles.append(jsonFile+f) + else: + allInputFiles.append(jsonFile) + + # Read from cfg files + for f in allInputFiles: + if not os.path.isfile(f): + print('[WARNING] Input file "%s% not found!'%f) + continue + # This input file is a json file, not a cfg + if f.endswith('.json'): + LoadJsonToSampleName(f, prefix) + # Open cfg files + else: + with open(f) as fin: + print(' >> Reading json from cfg file...') + lines = fin.readlines() + for l in lines: + if '#' in l: l=l[:l.find('#')] + l = l.replace(' ', '').replace('\n', '') + if l == '': continue + if ',' in l: + l = l.split(',') + for nl in l: + if not os.path.isfile(l): prefix = nl + else: LoadJsonToSampleName(nl, prefix) + else: + if not os.path.isfile(l): prefix = l + else: LoadJsonToSampleName(l, prefix) + + flist = {}; + for sname in samplesdict.keys(): + redirector = samplesdict[sname]['redirector'] + flist[sname] = [(redirector+f) for f in samplesdict[sname]['files']] + samplesdict[sname]['year'] = int(samplesdict[sname]['year']) + samplesdict[sname]['xsec'] = float(samplesdict[sname]['xsec']) + samplesdict[sname]['nEvents'] = int(samplesdict[sname]['nEvents']) + samplesdict[sname]['nGenEvents'] = int(samplesdict[sname]['nGenEvents']) + samplesdict[sname]['nSumOfWeights'] = float(samplesdict[sname]['nSumOfWeights']) + + # Print file info + print('>> '+sname) + print(' - isData? : %s' %('YES' if samplesdict[sname]['isData'] else 'NO')) + print(' - year : %i' %samplesdict[sname]['year']) + print(' - xsec : %f' %samplesdict[sname]['xsec']) + print(' - histAxisName : %s' %samplesdict[sname]['histAxisName']) + print(' - options : %s' %samplesdict[sname]['options']) + print(' - tree : %s' %samplesdict[sname]['treeName']) + print(' - nEvents : %i' %samplesdict[sname]['nEvents']) + print(' - nGenEvents : %i' %samplesdict[sname]['nGenEvents']) + print(' - SumWeights : %f' %samplesdict[sname]['nSumOfWeights']) + print(' - Prefix : %s' %samplesdict[sname]['redirector']) + print(' - nFiles : %i' %len(samplesdict[sname]['files'])) + for fname in samplesdict[sname]['files']: print(' %s'%fname) + + if pretend: + print('pretending...') + exit() + + # Check that all datasets have the same list of WCs + for i,k in enumerate(samplesdict.keys()): + if i == 0: + wc_lst = samplesdict[k]['WCnames'] + if wc_lst != samplesdict[k]['WCnames']: + raise Exception("Not all of the datasets have the same list of WCs.") + + processor_instance = topeft.AnalysisProcessor(samplesdict,wc_lst,do_errors,do_systs) + + # Run the processor and get the output + tstart = time.time() + processor_instance = topeft.AnalysisProcessor(samplesdict,wc_lst,do_errors) + + from dask.distributed import Client, Worker, WorkerPlugin + import os, shutil + from typing import List + class DependencyInstaller(WorkerPlugin): + def __init__(self, dependencies: List[str]): + self._depencendies = " ".join(f"'{dep}'" for dep in dependencies) + def setup(self, worker: Worker): + os.system(f"pip install {self._depencendies}") + dependency_installer = DependencyInstaller([ + "git+https://github.com/oshadura/topcoffea.git@coffea-casa-analysis","awkward==1.3.0" + ]) + + client = Client("tls://localhost:8786") + client.register_worker_plugin(dependency_installer) + + shutil.make_archive("analysis", "zip", base_dir="analysis") + client.upload_file("analysis.zip") + + executor_args = { + 'schema': NanoAODSchema, + 'client': client, + 'savemetrics': True + } + + # Run the processor and get the output + tic = time.time() + output = processor.run_uproot_job(flist, + treename=treename, + processor_instance=processor_instance, + executor=processor.dask_executor, + executor_args=executor_args, + chunksize=chunksize, + maxchunks=nchunks + ) + toc = time.time() + + print("Dask client:", client) + print("Total time: %.0f" % (toc - tic)) + print("Events / s / thread: {:,.0f}".format(output[1]['entries'] / output[1]['processtime'])) + print("Events / s: {:,.0f}".format(output[1]['entries'] / (toc - tic))) + + nbins = sum(sum(arr.size for arr in h._sumw.values()) for h in output.values() if isinstance(h, hist.Hist)) + nfilled = sum(sum(np.sum(arr > 0) for arr in h._sumw.values()) for h in output.values() if isinstance(h, hist.Hist)) + print("Filled %.0f bins, nonzero bins: %1.1f %%" % (nbins, 100*nfilled/nbins,)) + + + # This is taken from the DM photon analysis... + # Pickle is not very fast or memory efficient, will be replaced by something better soon + # with lz4f.open("pods/"+options.year+"/"+dataset+".pkl.gz", mode="xb", compression_level=5) as fout: + if not outpath.endswith('/'): outpath += '/' + if not os.path.isdir(outpath): os.system("mkdir -p %s"%outpath) + print('Saving output in %s...'%(outpath + outname + ".pkl.gz")) + with gzip.open(outpath + outname + ".pkl.gz", "wb") as fout: + cloudpickle.dump(output, fout) + print('Done!') diff --git a/analysis/ttTest/__init__.py b/analysis/ttTest/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/setup.py b/setup.py index d987cfe98..da094cd84 100644 --- a/setup.py +++ b/setup.py @@ -18,6 +18,8 @@ "data/btagSF/UL/*.pkl.gz", "data/btagSF/UL/*.csv", "data/btagSF/*.csv", + "json/*.json", + "json/signal_samples/*.json" ], } ) diff --git a/topcoffea/json/TTZToLLNuNu_M10.json b/topcoffea/json/TTZToLLNuNu_M10.json new file mode 100644 index 000000000..1498dc810 --- /dev/null +++ b/topcoffea/json/TTZToLLNuNu_M10.json @@ -0,0 +1,32 @@ +{ + "xsec": 0.2529, + "year": "2018", + "treeName": "Events", + "histAxisName": "", + "options": "", + "WCnames": [], + "files": [ + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_1.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_10.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_11.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_12.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_13.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_14.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_15.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_16.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_17.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_18.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_2.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_3.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_4.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_5.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_6.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_7.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_8.root", + "/store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_9.root" + ], + "nEvents": 14542666, + "nGenEvents": 4876491.715182641, + "nSumOfWeights": 19992000, + "isData": false +} \ No newline at end of file diff --git a/topcoffea/json/__init__.py b/topcoffea/json/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/topeft-coffea-casa.ipynb b/topeft-coffea-casa.ipynb new file mode 100644 index 000000000..36d04a292 --- /dev/null +++ b/topeft-coffea-casa.ipynb @@ -0,0 +1,419 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/bin/bash: /opt/conda/lib/libtinfo.so.6: no version information available (required by /bin/bash)\n", + "Collecting git+https://github.com/oshadura/topcoffea.git@coffea-casa-analysis\n", + " Cloning https://github.com/oshadura/topcoffea.git (to revision coffea-casa-analysis) to /tmp/pip-req-build-e8me1oel\n", + "Building wheels for collected packages: topcoffea\n", + " Building wheel for topcoffea (setup.py) ... \u001b[?25ldone\n", + "\u001b[?25h Created wheel for topcoffea: filename=topcoffea-0.0.0-py3-none-any.whl size=4513687 sha256=50e1a965398095975bcbcd8e54ad498b108779a32b8dac52ff117f8a360d4318\n", + " Stored in directory: /tmp/pip-ephem-wheel-cache-j40zuryw/wheels/3a/95/24/bfbb2d1dc4571114a0106e7d0d6a8124bcd2ad9e72ec9ea14e\n", + "Successfully built topcoffea\n", + "Installing collected packages: topcoffea\n", + "Successfully installed topcoffea-0.0.0\n", + "/bin/bash: /opt/conda/lib/libtinfo.so.6: no version information available (required by /bin/bash)\n", + "Requirement already satisfied: awkward==1.3.0 in /opt/conda/lib/python3.8/site-packages (1.3.0)\n", + "Requirement already satisfied: numpy>=1.13.1 in /opt/conda/lib/python3.8/site-packages (from awkward==1.3.0) (1.21.0)\n", + "Requirement already satisfied: setuptools in /opt/conda/lib/python3.8/site-packages (from awkward==1.3.0) (57.1.0)\n" + ] + } + ], + "source": [ + "!pip install git+https://github.com/oshadura/topcoffea.git@coffea-casa-analysis\n", + "! pip install awkward==1.3.0\n", + "#! pip install -e ." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import lz4.frame as lz4f\n", + "import pickle\n", + "import json\n", + "import time\n", + "import cloudpickle\n", + "import gzip\n", + "import os\n", + "from optparse import OptionParser\n", + "\n", + "import uproot\n", + "import numpy as np\n", + "from coffea import hist, processor\n", + "from coffea.util import load, save\n", + "from coffea.nanoevents import NanoAODSchema\n", + "\n", + "from topcoffea.modules import samples\n", + "from topcoffea.modules import fileReader\n", + "\n", + "import sys\n", + "from analysis.topEFT import topeft\n", + "\n", + "import importlib.resources\n", + "\n", + "if hasattr(__builtins__,'__IPYTHON__'):\n", + " import sys\n", + " sys.argv = ['']" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "jsonFile was selected for UNL /home/cms-jovyan/topcoffea/topcoffea/json/TTZToLLNuNu_M10.json\n" + ] + } + ], + "source": [ + "import argparse\n", + "parser = argparse.ArgumentParser(description='You can customize your run')\n", + "parser.add_argument('jsonFiles' , nargs='?', help = 'Json file(s) containing files and metadata')\n", + "parser.add_argument('--prefix', '-r' , nargs='?', help = 'Prefix or redirector to look for the files')\n", + "parser.add_argument('--test','-t' , action='store_true' , help = 'To perform a test, run over a few events in a couple of chunks')\n", + "parser.add_argument('--pretend' , action='store_true' , help = 'Read json files but, not execute the analysis')\n", + "#parser.add_argument('--nworkers','-n' , default=8 , help = 'Number of workers')\n", + "parser.add_argument('--chunksize','-s' , default=500000 , help = 'Number of events per chunk')\n", + "parser.add_argument('--nchunks','-c' , default=None , help = 'You can choose to run only a number of chunks')\n", + "parser.add_argument('--outname','-o' , default='plotsTopEFT', help = 'Name of the output file with histograms')\n", + "parser.add_argument('--outpath','-p' , default='histos', help = 'Name of the output directory')\n", + "parser.add_argument('--treename' , default='Events', help = 'Name of the tree inside the files')\n", + "parser.add_argument('--do-errors', action='store_true', help = 'Save the w**2 coefficients')\n", + "\n", + "args = parser.parse_args()\n", + "\n", + "if args.jsonFiles is not None:\n", + " jsonFiles = args.jsonFiles\n", + " print('jsonFiles {}'.format(args.jsonFiles))\n", + "else:\n", + " with importlib.resources.path(\"topcoffea.json\", \"TTZToLLNuNu_M10.json\") as path:\n", + " jsonFiles = str(path)\n", + " print('jsonFile was selected for UNL {}'.format(jsonFiles))\n", + " \n", + "if args.prefix is not None:\n", + " prefix = args.prefix\n", + "else:\n", + " prefix = \"root://xcache//\"\n", + "\n", + "dotest = args.test\n", + "#nworkers = int(args.nworkers)\n", + "chunksize = int(args.chunksize)\n", + "nchunks = int(args.nchunks) if not args.nchunks is None else args.nchunks\n", + "outname = args.outname\n", + "outpath = args.outpath\n", + "pretend = args.pretend\n", + "treename = args.treename\n", + "do_errors = args.do_errors\n", + "\n", + "if dotest:\n", + " nchunks = 2\n", + " chunksize = 10000\n", + " nworkers = 1\n", + " print('Running a fast test with %i workers, %i chunks of %i events'%(nworkers, nchunks, chunksize))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['/home/cms-jovyan/topcoffea/topcoffea/json/TTZToLLNuNu_M10.json']\n", + ">> TTZToLLNuNu_M10\n", + " - isData? : NO\n", + " - year : 2018\n", + " - xsec : 0.252900\n", + " - histAxisName : \n", + " - options : \n", + " - tree : Events\n", + " - nEvents : 14542666\n", + " - nGenEvents : 4876491\n", + " - SumWeights : 19992000.000000\n", + " - Prefix : root://xcache//\n", + " - nFiles : 18\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_1.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_10.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_11.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_12.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_13.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_14.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_15.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_16.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_17.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_18.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_2.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_3.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_4.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_5.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_6.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_7.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_8.root\n", + " /store/user/jrgonzal/nanoAODcrab/TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/mc2018_28apr2021_TTZToLLNuNu_M-10_TuneCP5_13TeV-amcatnlo-pythia8/210427_230816/0000/tree_9.root\n" + ] + } + ], + "source": [ + "samplesdict = {}\n", + "allInputFiles = []\n", + "\n", + "def LoadJsonToSampleName(jsonFile, prefix):\n", + " sampleName = jsonFile if not '/' in jsonFile else jsonFile[jsonFile.rfind('/')+1:]\n", + " if sampleName.endswith('.json'): sampleName = sampleName[:-5]\n", + " with open(jsonFile) as jf:\n", + " samplesdict[sampleName] = json.load(jf)\n", + " samplesdict[sampleName]['redirector'] = prefix\n", + "\n", + "if isinstance(jsonFiles, str) and ',' in jsonFiles: jsonFiles = jsonFiles.replace(' ', '').split(',')\n", + "elif isinstance(jsonFiles, str) : jsonFiles = [jsonFiles]\n", + "\n", + "for jsonFile in jsonFiles:\n", + " if os.path.isdir(jsonFile):\n", + " if not jsonFile.endswith('/'): jsonFile+='/'\n", + " for f in os.path.listdir(jsonFile):\n", + " if f.endswith('.json'): allInputFiles.append(jsonFile+f)\n", + " else:\n", + " allInputFiles.append(jsonFile)\n", + "\n", + "print(allInputFiles)\n", + "# Read from cfg files\n", + "for f in allInputFiles:\n", + " if not os.path.isfile(f):\n", + " print('[WARNING] Input file \"%s% not found!'%f)\n", + " continue\n", + " # This input file is a json file, not a cfg\n", + " if f.endswith('.json'): \n", + " LoadJsonToSampleName(f, prefix)\n", + " # Open cfg files\n", + " else:\n", + " with open(f) as fin:\n", + " print(' >> Reading json from cfg file...')\n", + " lines = fin.readlines()\n", + " for l in lines:\n", + " if '#' in l: l=l[:l.find('#')]\n", + " l = l.replace(' ', '').replace('\\n', '')\n", + " if l == '': continue\n", + " if ',' in l:\n", + " l = l.split(',')\n", + " for nl in l:\n", + " if not os.path.isfile(l): prefix = nl\n", + " else: LoadJsonToSampleName(nl, prefix)\n", + " else:\n", + " if not os.path.isfile(l): prefix = l\n", + " else: LoadJsonToSampleName(l, prefix)\n", + "\n", + "flist = {};\n", + "for sname in samplesdict.keys():\n", + " redirector = samplesdict[sname]['redirector']\n", + " flist[sname] = [(redirector+f) for f in samplesdict[sname]['files']]\n", + " samplesdict[sname]['year'] = int(samplesdict[sname]['year'])\n", + " samplesdict[sname]['xsec'] = float(samplesdict[sname]['xsec'])\n", + " samplesdict[sname]['nEvents'] = int(samplesdict[sname]['nEvents'])\n", + " samplesdict[sname]['nGenEvents'] = int(samplesdict[sname]['nGenEvents'])\n", + " samplesdict[sname]['nSumOfWeights'] = float(samplesdict[sname]['nSumOfWeights'])\n", + "\n", + " # Print file info\n", + " print('>> '+sname)\n", + " print(' - isData? : %s' %('YES' if samplesdict[sname]['isData'] else 'NO'))\n", + " print(' - year : %i' %samplesdict[sname]['year'])\n", + " print(' - xsec : %f' %samplesdict[sname]['xsec'])\n", + " print(' - histAxisName : %s' %samplesdict[sname]['histAxisName'])\n", + " print(' - options : %s' %samplesdict[sname]['options'])\n", + " print(' - tree : %s' %samplesdict[sname]['treeName'])\n", + " print(' - nEvents : %i' %samplesdict[sname]['nEvents'])\n", + " print(' - nGenEvents : %i' %samplesdict[sname]['nGenEvents'])\n", + " print(' - SumWeights : %f' %samplesdict[sname]['nSumOfWeights'])\n", + " print(' - Prefix : %s' %samplesdict[sname]['redirector'])\n", + " print(' - nFiles : %i' %len(samplesdict[sname]['files']))\n", + " for fname in samplesdict[sname]['files']: print(' %s'%fname)\n", + "\n", + "if pretend: \n", + " print('pretending...')\n", + " exit() \n", + "\n", + "# Check that all datasets have the same list of WCs\n", + "for i,k in enumerate(samplesdict.keys()):\n", + " if i == 0:\n", + " wc_lst = samplesdict[k]['WCnames']\n", + " if wc_lst != samplesdict[k]['WCnames']:\n", + " raise Exception(\"Not all of the datasets have the same list of WCs.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[###### ] | 16% Completed | 3min 16.2s\r" + ] + }, + { + "ename": "AttributeError", + "evalue": "Can't get attribute 'AnalysisProcessor' on ", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_581/2526281362.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;31m# Run the processor and get the output\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0mtic\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 30\u001b[0;31m output = processor.run_uproot_job(flist,\n\u001b[0m\u001b[1;32m 31\u001b[0m \u001b[0mtreename\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtreename\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0mprocessor_instance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mprocessor_instance\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/lib/python3.8/site-packages/coffea/processor/executor.py\u001b[0m in \u001b[0;36mrun_uproot_job\u001b[0;34m(fileset, treename, processor_instance, executor, executor_args, pre_executor, pre_args, chunksize, maxchunks, metadata_cache, dynamic_chunksize, dynamic_chunksize_targets)\u001b[0m\n\u001b[1;32m 1656\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1657\u001b[0m \u001b[0mexe_args\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexecutor_args\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1658\u001b[0;31m \u001b[0mwrapped_out\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mexecutor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchunks\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mclosure\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mexe_args\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1659\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1660\u001b[0m \u001b[0mprocessor_instance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpostprocess\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwrapped_out\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"out\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/lib/python3.8/site-packages/coffea/processor/executor.py\u001b[0m in \u001b[0;36mdask_executor\u001b[0;34m(items, function, accumulator, **kwargs)\u001b[0m\n\u001b[1;32m 1005\u001b[0m \u001b[0mprogress\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwork\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmulti\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnotebook\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1006\u001b[0m return accumulate(\n\u001b[0;32m-> 1007\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0mwork\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mclevel\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0m_decompress\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwork\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1008\u001b[0m \u001b[0maccumulator\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1009\u001b[0m )\n", + "\u001b[0;32m/opt/conda/lib/python3.8/site-packages/distributed/client.py\u001b[0m in \u001b[0;36mresult\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 225\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"error\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 226\u001b[0m \u001b[0mtyp\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 227\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 228\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"cancelled\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 229\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/lib/python3.8/site-packages/coffea/processor/executor.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m()\u001b[0m\n\u001b[1;32m 196\u001b[0m \u001b[0;31m# no @wraps due to pickle\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 197\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__call__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 198\u001b[0;31m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 199\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0m_compress\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlevel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 200\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/conda/lib/python3.8/site-packages/coffea/processor/executor.py\u001b[0m in \u001b[0;36m_work_function\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1144\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mprocessor_instance\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1145\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprocessor_instance\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mProcessorABC\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1146\u001b[0;31m \u001b[0mprocessor_instance\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcloudpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlz4f\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecompress\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprocessor_instance\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1147\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1148\u001b[0m \u001b[0mretry_count\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: Can't get attribute 'AnalysisProcessor' on " + ] + } + ], + "source": [ + "processor_instance = topeft.AnalysisProcessor(samplesdict,wc_lst,do_errors)\n", + "\n", + "from dask.distributed import Client, Worker, WorkerPlugin\n", + "import os, shutil\n", + "from typing import List\n", + "class DependencyInstaller(WorkerPlugin):\n", + " def __init__(self, dependencies: List[str]):\n", + " self._depencendies = \" \".join(f\"'{dep}'\" for dep in dependencies)\n", + " def setup(self, worker: Worker):\n", + " os.system(f\"pip install {self._depencendies}\")\n", + "dependency_installer = DependencyInstaller([\n", + " \"git+https://github.com/oshadura/topcoffea.git@coffea-casa-analysis\",\"awkward==1.3.0\"\n", + "])\n", + "\n", + "client = Client(\"tls://localhost:8786\")\n", + "client.register_worker_plugin(dependency_installer)\n", + "\n", + "shutil.make_archive(\"analysis\", \"zip\", base_dir=\"analysis\")\n", + "client.upload_file(\"analysis.zip\")\n", + "\n", + "executor_args = {\n", + " 'schema': NanoAODSchema,\n", + " 'client': client,\n", + " 'savemetrics': True\n", + "}\n", + "\n", + "\n", + "# Run the processor and get the output \n", + "tic = time.time()\n", + "output = processor.run_uproot_job(flist,\n", + " treename=treename,\n", + " processor_instance=processor_instance,\n", + " executor=processor.dask_executor,\n", + " executor_args=executor_args,\n", + " chunksize=chunksize,\n", + " maxchunks=nchunks\n", + " )\n", + "toc = time.time()\n", + "\n", + "print(\"Dask client:\", client)\n", + "print(\"Total time: %.0f\" % (toc - tic))\n", + "print(\"Events / s / thread: {:,.0f}\".format(output[1]['entries'] / output[1]['processtime']))\n", + "print(\"Events / s: {:,.0f}\".format(output[1]['entries'] / (toc - tic)))\n", + "\n", + "os.system(\"mkdir -p histos/\")\n", + "print('Saving output in %s...'%(\"histos/\" + outname + \".pkl.gz\"))\n", + "with gzip.open(\"histos/\" + outname + \".pkl.gz\", \"wb\") as fout:\n", + " cloudpickle.dump(output, fout)\n", + "print('Done!')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import print_function, division\n", + "from collections import defaultdict, OrderedDict\n", + "import gzip\n", + "import pickle\n", + "import json\n", + "import os\n", + "import uproot\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from coffea import hist, processor\n", + "from coffea.hist import plot\n", + "from cycler import cycler\n", + "\n", + "from topcoffea.plotter.OutText import OutText\n", + "\n", + "\n", + "path = 'histos/plotsTopEFT.pkl.gz'\n", + "outname = 'temp.png'\n", + "\n", + "# Select variable, channel and cuts\n", + "var = 'met'\n", + "channel = ['eemSSonZ', 'eemSSoffZ', 'mmeSSonZ', 'mmeSSoffZ','eeeSSonZ', 'eeeSSoffZ', 'mmmSSonZ', 'mmmSSoffZ']\n", + "cut = 'base'\n", + "\n", + "print('Opening path: ', path)\n", + "hists = {}\n", + "with gzip.open(path) as fin:\n", + " hin = pickle.load(fin)\n", + " print(' >> looking for histograms...')\n", + " for k in hin.keys():\n", + " if k in hists: hists[k]+=hin[k]\n", + " else: hists[k]=hin[k]\n", + "\n", + "\n", + "# Create figure\n", + "fig, (ax, rax) = plt.subplots(2, 1, figsize=(14,7), gridspec_kw={\"height_ratios\": (3, 1)}, sharex=True)\n", + "plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9)\n", + "\n", + "# Select the histogram var, channel and cut\n", + "h = hists[var]\n", + "h = h.integrate('channel', channel)\n", + "h = h.integrate('cut', cut)\n", + "\n", + "# Integrate over samples\n", + "h = h.sum('sample')\n", + " \n", + "# Plot and save figure to outname\n", + "hist.plot1d(h, ax=ax, line_opts={'color':'orange'})\n", + "fig.savefig(outname)\n", + "print('Output histogram saved in %s'%outname)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}