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/__pycache__/__init__.cpython-38.pyc b/analysis/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 000000000..41ab022a2 Binary files /dev/null and b/analysis/__pycache__/__init__.cpython-38.pyc differ diff --git a/analysis/btagMCeff/__init__.py b/analysis/btagMCeff/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/analysis/topEFT/__init__.py b/analysis/topEFT/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/analysis/ttTest/__init__.py b/analysis/ttTest/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/notebooks/topeft-coffea-casa.ipynb b/notebooks/topeft-coffea-casa.ipynb new file mode 100644 index 000000000..3a60f14d7 --- /dev/null +++ b/notebooks/topeft-coffea-casa.ipynb @@ -0,0 +1,445 @@ +{ + "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-k7xxsyh6\n", + "Requirement already satisfied (use --upgrade to upgrade): topcoffea==0.0.0 from git+https://github.com/oshadura/topcoffea.git@coffea-casa-analysis in /opt/conda/lib/python3.8/site-packages\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=4514059 sha256=0ef291425ef9276b5bcb9980c1d0030fa94cedda3e13c6a83879d4a683055742\n", + " Stored in directory: /tmp/pip-ephem-wheel-cache-9jixxi63/wheels/3a/95/24/bfbb2d1dc4571114a0106e7d0d6a8124bcd2ad9e72ec9ea14e\n", + "Successfully built topcoffea\n", + "/bin/bash: /opt/conda/lib/libtinfo.so.6: no version information available (required by /bin/bash)\n", + "Collecting awkward==1.3.0\n", + " Downloading awkward-1.3.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (8.0 MB)\n", + "\u001b[K |████████████████████████████████| 8.0 MB 3.6 MB/s eta 0:00:01\n", + "\u001b[?25hRequirement already satisfied: setuptools in /opt/conda/lib/python3.8/site-packages (from awkward==1.3.0) (57.0.0)\n", + "Requirement already satisfied: numpy>=1.13.1 in /opt/conda/lib/python3.8/site-packages (from awkward==1.3.0) (1.20.3)\n", + "Installing collected packages: awkward\n", + " Attempting uninstall: awkward\n", + " Found existing installation: awkward 1.2.0\n", + " Uninstalling awkward-1.2.0:\n", + " Successfully uninstalled awkward-1.2.0\n", + "Successfully installed awkward-1.3.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", + "#FIXME: analysis is not installed anywhere (should be installed as well)\n", + "import topcoffea.analysis.topEFT.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 /opt/conda/lib/python3.8/site-packages/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": [ + "['/opt/conda/lib/python3.8/site-packages/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": [ + "Dask client: \n", + "Total time: 444\n", + "Events / s / thread: 5,895\n", + "Events / s: 32,725\n", + "Saving output in histos/plotsTopEFT.pkl.gz...\n", + "Done!\n" + ] + } + ], + "source": [ + "processor_instance = topcoffea.analysis.topEFT.topeft.AnalysisProcessor(samplesdict,wc_lst,do_errors)\n", + "\n", + "from dask.distributed import Client, Worker, WorkerPlugin\n", + "import os\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", + "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": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Opening path: histos/plotsTopEFT.pkl.gz\n", + " >> looking for histograms...\n", + "Output histogram saved in temp.png\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "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", + "sumcharge = ['ch+', 'ch-']\n", + "systematic = 'nominal'\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[0].keys():\n", + " if k in hists: hists[k]+=hin[0][k]\n", + " else: hists[k]=hin[0][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", + "h = h.integrate('sumcharge', sumcharge)\n", + "h = h.integrate('systematic', systematic)\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)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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 +} 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..d3ce83902 --- /dev/null +++ b/topeft-coffea-casa.ipynb @@ -0,0 +1,407 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "5d03d87f", + "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-9zf5jcvu\n", + "Requirement already satisfied (use --upgrade to upgrade): topcoffea==0.0.0 from git+https://github.com/oshadura/topcoffea.git@coffea-casa-analysis in /home/cms-jovyan/topcoffea\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=4512948 sha256=e020a6dde8da5bedb5658fcf58b182244cc65fc5593209bae50ba8da1f429d85\n", + " Stored in directory: /tmp/pip-ephem-wheel-cache-b7hy8t1i/wheels/3a/95/24/bfbb2d1dc4571114a0106e7d0d6a8124bcd2ad9e72ec9ea14e\n", + "Successfully built topcoffea\n" + ] + } + ], + "source": [ + "!pip install git+https://github.com/oshadura/topcoffea.git@coffea-casa-analysis\n", + "#! pip install -e ." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "502972cd", + "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", + "#FIXME: analysis is not installed anywhere (should be installed as well)\n", + "import topcoffea.analysis.topEFT.topeft\n", + "\n", + "import importlib.resources\n", + "\n", + "if hasattr(__builtins__,'__IPYTHON__'):\n", + " import sys\n", + " sys.argv = ['']" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "dd76877f", + "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, + "id": "402ee04d", + "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": [ + "\n", + "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": null, + "id": "55f6755e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[################################# ] | 84% Completed | 1min 35.2s" + ] + } + ], + "source": [ + "processor_instance = topcoffea.analysis.topEFT.topeft.AnalysisProcessor(samplesdict,wc_lst,do_errors)\n", + "\n", + "from dask.distributed import Client, Worker, WorkerPlugin\n", + "import os\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\"\n", + "])\n", + "\n", + "client = Client(\"tls://localhost:8786\")\n", + "client.register_worker_plugin(dependency_installer)\n", + "\n", + "executor_args = {\n", + " 'schema': NanoAODSchema,\n", + " 'client': client\n", + "}\n", + "\n", + "# Run the processor and get the output \n", + "tstart = 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", + "dt = time.time() - tstart\n", + "\n", + "nbins = sum(sum(arr.size for arr in h._sumw.values()) for h in output.values() if isinstance(h, hist.Hist))\n", + "nfilled = sum(sum(np.sum(arr > 0) for arr in h._sumw.values()) for h in output.values() if isinstance(h, hist.Hist))\n", + "print(\"Filled %.0f bins, nonzero bins: %1.1f %%\" % (nbins, 100*nfilled/nbins,))\n", + "print(\"Processing time: %1.2f s with %i workers (%.2f s cpu overall)\" % (dt, nworkers, dt*nworkers, ))\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, + "id": "53c45688", + "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)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01fb4952", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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": 5 +}