{ "cells": [ { "cell_type": "markdown", "id": "7fbe00e3", "metadata": {}, "source": [ "# Correctionlib tutorial\n", "\n", "The purpose of this library is to provide a well-structured JSON data format for a\n", "wide variety of ad-hoc correction factors encountered in a typical HEP analysis and\n", "a companion evaluation tool suitable for use in C++ and python programs.\n", "Here we restrict our definition of correction factors to a class of functions with\n", "scalar inputs that produce a scalar output.\n", "\n", "In python, the function signature is:\n", "\n", "```python\n", "def f(*args: int | float | str) -> float: ...\n", "```\n", "\n", "In C++, the signature is:\n", "```cpp\n", "double Correction::evaluate(const std::vector>& values) const;\n", "```\n", "\n", "The supported function classes include:\n", "\n", " * multi-dimensional binned lookups;\n", " * binned lookups pointing to multi-argument formulas with a restricted\n", " math function set (`exp`, `sqrt`, etc.);\n", " * categorical (string or integer enumeration) maps;\n", " * input transforms (updating one input value in place);\n", " * pseudorandom number generation; and\n", " * compositions of the above.\n", "\n" ] }, { "cell_type": "markdown", "id": "7cf107e9", "metadata": {}, "source": [ "## Basic evaluator usage\n", "We can import a previously defined set of correction objects using the\n", "```python\n", "correctionlib.CorrectionSet.from_file(filename)\n", "```\n", "or from a string with `.from_string(\"...\")`. The `from_file` invocation accepts JSON or gzipped JSON data.\n", "The `CorrectionSet` acts as a dictionary of `Correction` objects." ] }, { "cell_type": "code", "execution_count": 1, "id": "ecf89960", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['gen2_to_gen1', 'phimod', 'ptweight']" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import correctionlib\n", "\n", "ceval = correctionlib.CorrectionSet.from_file(\"mycorrections.json\")\n", "list(ceval.keys())" ] }, { "cell_type": "markdown", "id": "a5e178c6", "metadata": {}, "source": [ "Each correction has a name, description, version, and a input and output specification:" ] }, { "cell_type": "code", "execution_count": 2, "id": "12ec8a54", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Correction gen2_to_gen1 has 2 inputs\n", " Input pt (real): pt\n", " Input eta (real): eta\n", "Correction phimod has 2 inputs\n", " Input phi (real): \n", " Input q (int): Particle charge\n", "Correction ptweight has 2 inputs\n", " Input pt (real): Muon transverse momentum\n", " Input syst (string): Systematic\n" ] } ], "source": [ "for corr in ceval.values():\n", " print(f\"Correction {corr.name} has {len(corr.inputs)} inputs\")\n", " for ix in corr.inputs:\n", " print(f\" Input {ix.name} ({ix.type}): {ix.description}\")" ] }, { "cell_type": "markdown", "id": "1a45a4c6", "metadata": {}, "source": [ "Most important, each correction has a `.evaluate(...)` method that accepts scalars or numpy arrays:" ] }, { "cell_type": "code", "execution_count": 3, "id": "fa574b22", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0278771158865732" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ceval[\"phimod\"].evaluate(1.2, -1)" ] }, { "cell_type": "markdown", "id": "3c511ff1", "metadata": {}, "source": [ "Note that the input types are strict (not coerced) to help catch bugs early, e.g." ] }, { "cell_type": "code", "execution_count": 4, "id": "da7f5ae9", "metadata": {}, "outputs": [], "source": [ "# will not work\n", "# ceval[\"phimod\"].evaluate(1.2, -1.0)" ] }, { "cell_type": "code", "execution_count": 5, "id": "43daa330", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1.1 , 1.02, 1.1 , 1.1 , 1.1 , 1.1 , 1.1 , 1.08, 1.1 , 1.02])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "ptvals = np.random.exponential(15.0, size=10)\n", "\n", "ceval[\"ptweight\"].evaluate(ptvals, \"nominal\")" ] }, { "cell_type": "markdown", "id": "780c7d72", "metadata": {}, "source": [ "Currently, only numpy-compatible awkward arrays are accepted, but a jagged array can be flattened and re-wrapped quite easily:" ] }, { "cell_type": "code", "execution_count": 6, "id": "f84938cf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import awkward as ak\n", "\n", "ptjagged = ak.Array([[10.1, 20.2, 30.3], [40.4, 50.5], [60.6]])\n", "\n", "ptflat, counts = ak.flatten(ptjagged), ak.num(ptjagged)\n", "weight = ak.unflatten(\n", " ceval[\"ptweight\"].evaluate(ptflat, \"nominal\"),\n", " counts=counts,\n", ")\n", "weight" ] }, { "cell_type": "markdown", "id": "f8789ade", "metadata": {}, "source": [ "## Creating new corrections\n", "\n", "Alongside the evaluator we just demonstrated, `correctionlib` also contains a complete JSON Schema defining the expected fields and types found in a correction json object. The complete schema (version 2) is defined in the [documentation](https://cms-nanoaod.github.io/correctionlib/schemav2.html). In the package, we use [pydantic](https://pydantic-docs.helpmanual.io/) to help us validate the data and build correction objects in an easier way. The basic object is the `Correction` which, besides some metadata like a name and version, defines upfront the inputs and output. Below we make our first correction, which will always return `1.1` as the output:" ] }, { "cell_type": "code", "execution_count": 7, "id": "445e56dd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Correction(name='ptweight', description=None, version=1, inputs=[Variable(name='pt', type='real', description='Muon transverse momentum')], output=Variable(name='weight', type='real', description='Multiplicative event weight'), generic_formulas=None, data=1.1)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import correctionlib.schemav2 as cs\n", "\n", "corr = cs.Correction(\n", " name=\"ptweight\",\n", " version=1,\n", " inputs=[\n", " cs.Variable(name=\"pt\", type=\"real\", description=\"Muon transverse momentum\"),\n", " ],\n", " output=cs.Variable(name=\"weight\", type=\"real\", description=\"Multiplicative event weight\"),\n", " data=1.1,\n", ")\n", "corr" ] }, { "cell_type": "markdown", "id": "7f07d14a", "metadata": {}, "source": [ "The resulting object can be manipulated in-place as needed. Note that this correction object is not an evluator instance as we saw before. We can convert from the schema to an evaluator with the `.to_evaluator()` function:" ] }, { "cell_type": "code", "execution_count": 8, "id": "70928d03", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.1" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "corr.to_evaluator().evaluate(12.3)" ] }, { "cell_type": "markdown", "id": "99d8e60a", "metadata": {}, "source": [ "A nicer printout is also available through `rich`:" ] }, { "cell_type": "code", "execution_count": 9, "id": "0f4f5fd6", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
๐Ÿ“ˆ ptweight (v1)\n",
       "No description\n",
       "Node counts: \n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ pt (real)                  โ”‚\n",
       "โ”‚ Muon transverse momentum   โ”‚\n",
       "โ”‚ Range: unused, overflow ok โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ weight (real)               โ”‚\n",
       "โ”‚ Multiplicative event weight โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "
\n" ], "text/plain": [ "๐Ÿ“ˆ \u001b[1mptweight\u001b[0m \u001b[1m(\u001b[0mv1\u001b[1m)\u001b[0m\n", "\u001b[3mNo description\u001b[0m\n", "Node counts: \n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mpt\u001b[0m (real) โ”‚\n", "โ”‚ Muon transverse momentum โ”‚\n", "โ”‚ Range: \u001b[1;31munused\u001b[0m, overflow ok โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mweight\u001b[0m (real) โ”‚\n", "โ”‚ Multiplicative event weight โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import rich\n", "\n", "rich.print(corr)" ] }, { "cell_type": "markdown", "id": "237a7a12", "metadata": {}, "source": [ "The `data=` field of the correction is the root node of a tree of objects defining how the correction is to be evaluated. In the first example, it simply terminates at this node, returning always the float value `1.1`. We have many possible node types:\n", "\n", "- Binning: for 1D binned variable, each bin can be any type;\n", "- MultiBinning: an optimization for nested 1D Binnings, this can lookup n-dimensional binned values;\n", "- Category: for discrete dimensions, either integer or string types;\n", "- Formula: arbitrary formulas in up to four (real or integer-valued) input variables;\n", "- FormulaRef: an optimization for repeated use of the same formula with different coefficients;\n", "- Transform: useful to rewrite an input for all downstream nodes;\n", "- HashPRNG: a deterministic pseudorandom number generator; and\n", "- float: a constant value\n", "\n", "Let's create our first binned correction. We'll have to decide how to handle inputs that are out of range with the `flow=` attribute. Try switching `\"clamp\"` with `\"error\"` or another content node." ] }, { "cell_type": "code", "execution_count": 10, "id": "682bb99a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
๐Ÿ“ˆ ptweight (v1)\n",
       "No description\n",
       "Node counts: Binning: 1\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ pt (real)                         โ”‚\n",
       "โ”‚ Muon transverse momentum          โ”‚\n",
       "โ”‚ Range: [10.0, 120.0), overflow ok โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ weight (real)               โ”‚\n",
       "โ”‚ Multiplicative event weight โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "
\n" ], "text/plain": [ "๐Ÿ“ˆ \u001b[1mptweight\u001b[0m \u001b[1m(\u001b[0mv1\u001b[1m)\u001b[0m\n", "\u001b[3mNo description\u001b[0m\n", "Node counts: \u001b[1mBinning\u001b[0m: \u001b[1;36m1\u001b[0m\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mpt\u001b[0m (real) โ”‚\n", "โ”‚ Muon transverse momentum โ”‚\n", "โ”‚ Range: [10.0, 120.0), overflow ok โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mweight\u001b[0m (real) โ”‚\n", "โ”‚ Multiplicative event weight โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ptweight = cs.Correction(\n", " name=\"ptweight\",\n", " version=1,\n", " inputs=[cs.Variable(name=\"pt\", type=\"real\", description=\"Muon transverse momentum\")],\n", " output=cs.Variable(name=\"weight\", type=\"real\", description=\"Multiplicative event weight\"),\n", " data=cs.Binning(\n", " nodetype=\"binning\",\n", " input=\"pt\",\n", " edges=[10, 20, 30, 40, 50, 80, 120],\n", " content=[1.1, 1.08, 1.06, 1.04, 1.02, 1.0],\n", " flow=\"clamp\",\n", " ),\n", ")\n", "\n", "rich.print(ptweight)" ] }, { "cell_type": "code", "execution_count": 11, "id": "1cc178ba", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ptweight.to_evaluator().evaluate(230.0)" ] }, { "cell_type": "markdown", "id": "736f8216", "metadata": {}, "source": [ "## Formulas\n", "\n", "Formula support currently includes a mostly-complete subset of the ROOT library TFormula class, and is implemented in a threadsafe standalone manner. The parsing grammar is formally defined and parsed through the use of a header-only PEG parser library. This allows for extremely fast parsing of thousands of formulas encountered sometimes in binned formula (spline) correction types. Below we demonstrate a simple formula for a made-up $\\phi$-dependent efficiency correction. This also demonstrates nesting a content node inside another for the first time, with the outer Category node defining which formula to use depending on the particle charge" ] }, { "cell_type": "code", "execution_count": 12, "id": "e86a74de", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
๐Ÿ“ˆ phimod (v1)\n",
       "Phi-dependent tracking efficiency, or something?\n",
       "Node counts: Category: 1, Formula: 2\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ phi (real)                      โ”‚ โ”‚ q (int)         โ”‚\n",
       "โ”‚ No description                  โ”‚ โ”‚ Particle charge โ”‚\n",
       "โ”‚ Range: [-inf, inf), overflow ok โ”‚ โ”‚ Values: -1, 1   โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ weight (real)               โ”‚\n",
       "โ”‚ Multiplicative event weight โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "
\n" ], "text/plain": [ "๐Ÿ“ˆ \u001b[1mphimod\u001b[0m \u001b[1m(\u001b[0mv1\u001b[1m)\u001b[0m\n", "Phi-dependent tracking efficiency, or something?\n", "Node counts: \u001b[1mCategory\u001b[0m: \u001b[1;36m1\u001b[0m, \u001b[1mFormula\u001b[0m: \u001b[1;36m2\u001b[0m\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mphi\u001b[0m (real) โ”‚ โ”‚ \u001b[1mq\u001b[0m (int) โ”‚\n", "โ”‚ \u001b[3mNo description\u001b[0m โ”‚ โ”‚ Particle charge โ”‚\n", "โ”‚ Range: [-inf, inf), overflow ok โ”‚ โ”‚ Values: -1, 1 โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mweight\u001b[0m (real) โ”‚\n", "โ”‚ Multiplicative event weight โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "phimod = cs.Correction(\n", " name=\"phimod\",\n", " description=\"Phi-dependent tracking efficiency, or something?\",\n", " version=1,\n", " inputs=[\n", " cs.Variable(name=\"phi\", type=\"real\"),\n", " cs.Variable(name=\"q\", type=\"int\", description=\"Particle charge\"),\n", " ],\n", " output=cs.Variable(name=\"weight\", type=\"real\", description=\"Multiplicative event weight\"),\n", " data=cs.Category(\n", " nodetype=\"category\",\n", " input=\"q\",\n", " content=[\n", " cs.CategoryItem(\n", " key=1,\n", " value=cs.Formula(\n", " nodetype=\"formula\",\n", " variables=[\"phi\"],\n", " parser=\"TFormula\",\n", " expression=\"(1+0.1*sin(x+0.3))/(1+0.07*sin(x+0.4))\",\n", " ),\n", " ),\n", " cs.CategoryItem(\n", " key=-1,\n", " value=cs.Formula(\n", " nodetype=\"formula\",\n", " variables=[\"phi\"],\n", " parser=\"TFormula\",\n", " expression=\"(1+0.1*sin(x+0.31))/(1+0.07*sin(x+0.39))\",\n", " ),\n", " ),\n", " ]\n", " ),\n", ")\n", "rich.print(phimod)" ] }, { "cell_type": "code", "execution_count": 13, "id": "9c8d375c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0280774577481218" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "phimod.to_evaluator().evaluate(1.23, 1)" ] }, { "cell_type": "markdown", "id": "aff9b1ef", "metadata": {}, "source": [ "Try evaluating the correction for a neutral particle (`charge=0`) What can we change to the above definition to allow it to return a reasonable value for neutral particles rather than an error?" ] }, { "cell_type": "markdown", "id": "398610dc", "metadata": {}, "source": [ "## Converting from histograms\n", "\n", "Often one wants to convert a histogram into a correction object. Here we show how to do that using histgrams made with the [hist](https://hist.readthedocs.io/en/latest/) package, but any histogram that respects the [Unified Histogram Interface Plottable](https://uhi.readthedocs.io/en/latest/plotting.html#plotting) protocol (including, for example, ROOT TH1s) should work as well.\n", "\n", "Note: some of the conversion utilities require extra packages installed. The simplest way to ensure you have all dependencies is via the `pip install correctionlib[convert]` extras configuration.\n", "\n", "Here we create some mock data for two slightly different pt and eta spectra (say, from two different generators) and derive a correction to reweight one sample to the other." ] }, { "cell_type": "code", "execution_count": 14, "id": "8f8ad2ee", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjAAAAGwCAYAAAC3qV8qAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAABAmElEQVR4nO3deXhU9aH/8c9kmZAJWUggm4awqOxIAImpglByCUipKG0VUaBSqTa4gFDAIgZcoEBR9Hr10Qp4FcTan6JFiyyKuIQtGtk0CoLxSkJakQzJSCbL+f2RMjASkpkwk8kJ79fzzPOcOed7zvnOuVfy6Xc7FsMwDAEAAJhIUKArAAAA4C0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMJ2QQFfAX2pqanTkyBFFRkbKYrEEujoAAMADhmHoxIkTSk5OVlDQudtZWmyAOXLkiFJSUgJdDQAA0AjffvutLr744nMeb7EBJjIyUlLtA4iKigpwbQAAgCfsdrtSUlJcf8fPpcUGmFPdRlFRUQQYAABMpqHhHwziBQAApkOAAQAApkOAAQAAptNix8AAAOBr1dXVqqysDHQ1TC00NFTBwcHnfR0CDAAADTAMQ8XFxTp+/Higq9IixMTEKDEx8bzWaSPAAADQgFPhJT4+XjabjQVSG8kwDDkcDpWUlEiSkpKSGn0tAgwAAPWorq52hZe4uLhAV8f0wsPDJUklJSWKj49vdHcSg3gBAKjHqTEvNpstwDVpOU49y/MZT0SAAQDAA3Qb+Y4vniUBBgAAmA4BBgAAmA4BBgCAABo8eLDuvffeQFfDdAgwAACYxJYtW2SxWJp8PZqcnBz16dOnSe/ZEAIMAAAwHQIMAABNpLy8XOPHj1fr1q2VlJSkv/zlL27HX3zxRfXv31+RkZFKTEzUzTff7Fr07fDhwxoyZIgkqU2bNrJYLJo4caIkaf369br66qsVExOjuLg4/eIXv9DBgwdd13U6nZoyZYqSkpLUqlUrpaamasGCBa7jx48f1+9+9zu1a9dOUVFR+vnPf67PPvtMkrRy5UrNmzdPn332mSwWiywWi1auXOnHp+QZAgzcOJxV6jDrLXWY9ZYczqpAVwcAWpQZM2bo/fff1xtvvKENGzZoy5Yt+uSTT1zHKysr9dBDD+mzzz7T2rVrdfjwYVdISUlJ0f/7f/9PklRQUKCioiItW7ZMUm0wmjZtmnbt2qXNmzcrKChI119/vWpqaiRJTzzxhN5880397W9/U0FBgVatWqUOHTq47vvrX/9aJSUl+uc//6m8vDz17dtXQ4cO1bFjx3TjjTfqvvvuU48ePVRUVKSioiLdeOONTfPA6sFKvAAANIGysjI9//zzeumllzR06FBJ0gsvvKCLL77YVea2225zbXfq1ElPPPGErrjiCpWVlal169aKjY2VJMXHxysmJsZVdsyYMW73Wr58udq1a6f9+/erZ8+eKiws1KWXXqqrr75aFotFqamprrIffvihduzYoZKSEoWFhUmSlixZorVr1+rvf/+7Jk+erNatWyskJESJiYk+fy6NRQsMAABN4ODBg3I6nUpPT3fti42NVZcuXVzf8/LyNGrUKLVv316RkZG65pprJEmFhYX1Xvurr77S2LFj1alTJ0VFRblaV06dN3HiROXn56tLly66++67tWHDBte5n332mcrKyhQXF6fWrVu7PocOHXLrhmpuaIEBAKAZKC8vV1ZWlrKysrRq1Sq1a9dOhYWFysrKktPprPfcUaNGKTU1Vc8995ySk5NVU1Ojnj17us7r27evDh06pH/+85/atGmTfvOb3ygzM1N///vfVVZWpqSkJG3ZsuWs657ZytPcEGAAAGgCnTt3VmhoqLZv36727dtLkn744Qd9+eWXuuaaa/TFF1/o+++/18KFC5WSkiJJ2rVrl9s1rFarpNoXTJ7y/fffq6CgQM8995wGDhwoqbZb6KeioqJ044036sYbb9SvfvUrDR8+XMeOHVPfvn1VXFyskJAQt3ExP73vmfdsDggwAAA0gdatW2vSpEmaMWOG4uLiFB8frz/96U8KCqodzdG+fXtZrVY9+eSTuuOOO7R371499NBDbtdITU2VxWLRunXrdO211yo8PFxt2rRRXFycnn32WSUlJamwsFCzZs1yO2/p0qVKSkpSWlqagoKC9OqrryoxMVExMTHKzMxURkaGRo8erUWLFumyyy7TkSNH9NZbb+n6669X//791aFDBx06dEj5+fm6+OKLFRkZ6RovEyiMgWnhDMOQw1nl1ecUb84xDCOAvxIAzGHx4sUaOHCgRo0apczMTF199dXq16+fJKldu3ZauXKlXn31VXXv3l0LFy7UkiVL3M6/6KKLNG/ePM2aNUsJCQmaMmWK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qi+++EIDBgxQaWmpa/rzddddF+CanT8CTDPhycJIp5w5EKyuke7uZT27JgDAvwL1stwlS5aooKBAVqtV/fr10wcffKC2bds2eT18jQDTTDR2YaT+D2/2Q20AAC1BWlqa8vLyAl0Nv2AQLwAAMB1aYJqhXXMyZatjgaNTHM4qV8vLrjlDPV5LwJcLIAEAEEgEmGbIZg32OJTYrCGsxAsAuODQhQQAAEyHAAMAAEyHAAMAQFNwlks50bUfZ3mga2N6BBgAAGA6BBgAANBozz33nAYOHKg2bdqoTZs2yszM1I4dO/x+X6avmFCgVnMEAOCntmzZorFjx+pnP/uZWrVqpT//+c8aNmyY9u3bp4suushv96UFBgCAFurEiRMaN26cIiIilJSUpMcee0yDBw/WvffeK0mqqKjQ9OnTddFFFykiIkLp6enasmWL6/yVK1cqJiZG77zzjrp166bWrVtr+PDhKioqcpVZtWqV/vCHP6hPnz7q2rWr/vrXv6qmpkabN/t3pXhaYAAA8IZhSJWO+ss46zh+5r6yf0vWOspYbfVfN9QmWSwN1/E/pk2bpo8++khvvvmmEhISNHfuXH3yySfq06ePJGnKlCnav3+/1qxZo+TkZL3++usaPny49uzZo0svvVSS5HA4tGTJEr344osKCgrSLbfcounTp7u95fpMDodDlZWVio2N9biejUGAAQDAG5UO6dHk87vGE70bd979RyRrhEdFT5w4oRdeeEGrV6/W0KFDJUkrVqxQcnJt3QsLC7VixQoVFha69k2fPl3r16/XihUr9Oijj0qSKisr9cwzz6hz586SakPPqbda12XmzJlKTk5WZmZm436jhwgwAAC0QF9//bUqKys1YMAA177o6Gh16dJFkrRnzx5VV1frsssuczuvoqJCcXFxru82m80VXiQpKSlJJSUldd5z4cKFWrNmjbZs2aJWrVr58uechQADAIA3Qm21LSH1OVcX0qmWl7t3191d5EkXko+UlZUpODhYeXl5Cg52f1de69atT98yNNTtmMVikWEYZ11vyZIlWrhwoTZt2qTevRvZwuQFAgwAAN6wWBruxqnr+JmL17Vu63FXUGN16tRJoaGh2rlzp9q3by9JKi0t1ZdffqlBgwYpLS1N1dXVKikp0cCBA8/rXosWLdIjjzyid955R/379/dF9RtEgAEAoAWKjIzU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AF7/S19WVqYDBw64vh86dEj5+fmKjY1VUlKSfvWrX+mTTz7RunXrVF1dreLiYklSbGysrFarcnNztX37dg0ZMkSRkZHKzc3V1KlTdcstt7jCyc0336x58+Zp0qRJmjlzpvbu3atly5bpscce89HPRoviLNfhVjdLkhzOQskaHeAKAQD8zesAs2vXLg0ZMsT1/dR4lgkTJignJ0dvvvmmJKlPnz5u57333nsaPHiwwsLCtGbNGuXk5KiiokIdO3bU1KlT3cbFREdHa8OGDcrOzla/fv3Utm1bzZ0795xTqAEAwIXF6wAzePDgeqefNjQ1tW/fvtq2bVuD9+ndu7c++OADb6sHAAAuALwLCQAAmA4BBqZ35qBdBvACwIWBf+3R/Dkdnh9vsGyVwnWydpuVeAHAtAgwaP6WXOKzsjZJn/9nUV9HZaEUxowlADAjupAAAIDp0AKD5inUJt1/xLOyTsfplpfpBySr7ZxFHeV22ZZ19UEFAQCBRIBB82SxNO5N21Zb/eed8eZqAIB50YUEAABMhwADAABMhwADAABMhzEwMD9rhJRTGuhaAACaEC0wAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdAgwAADAdLwOMFu3btWoUaOUnJwsi8WitWvXuh03DENz585VUlKSwsPDlZmZqa+++sqtzLFjxzRu3DhFRUUpJiZGkyZNUllZmVuZ3bt3a+DAgWrVqpVSUlK0aNEi738dAABokbwOMOXl5br88sv11FNP1Xl80aJFeuKJJ/TMM89o+/btioiIUFZWlk6ePOkqM27cOO3bt08bN27UunXrtHXrVk2ePNl13G63a9iwYUpNTVVeXp4WL16snJwcPfvss434iQAAoKUJ8faEESNGaMSIEXUeMwxDjz/+uObMmaPrrrtOkvS///u/SkhI0Nq1a3XTTTfp888/1/r167Vz5071799fkvTkk0/q2muv1ZIlS5ScnKxVq1bJ6XRq+fLlslqt6tGjh/Lz87V06VK3oHOmiooKVVRUuL7b7XZvfxrg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165druOGYWju3LlKSkpSeHi4MjMz9dVXXwWwxuZTXV2tBx54QB07dlR4eLg6d+6shx56yO3dOTznxtm6datGjRql5ORkWSwWrV271u24J8/12LFjGjdunKKiohQTE6NJkyaprKzM95U14LE1a9YYVqvVWL58ubFv3z7j9ttvN2JiYoyjR48GumqmlZWVZaxYscLYu3evkZ+fb1x77bVG+/btjbKyMleZO+64w0hJSTE2b95s7Nq1y7jyyiuNn/3sZwGstbnt2LHD6NChg9G7d2/jnnvuce3nOZ+/Y8eOGampqcbEiRON7du3G19//bXxzjvvGAcOHHCVWbhwoREdHW2sXbvW+Oyzz4xf/vKXRseOHY0ff/wxgDU3l0ceecSIi4sz1q1bZxw6dMh49dVXjdatWxvLli1zleE5N87bb79t/OlPfzJee+01Q5Lx+uuvux335LkOHz7cuPzyy41t27YZH3zwgXHJJZcYY8eO9XldCTBeGDBggJGdne36Xl1dbSQnJxsLFiwIYK1alpKSEkOS8f777xuGYRjHjx83QkNDjVdffdVV5vPPPzckGbm5uYGqpmmdOHHCuPTSS42NGzca11xzjSvA8Jx9Y+bMmcbVV199zuM1NTVGYmKisXjxYte+48ePG2FhYcbLL7/cFFVsEUaOHGncdtttbvtuuOEGY9y4cYZh8Jx95acBxpPnun//fkOSsXPnTleZf/7zn4bFYjG+++47n9aPLiQPOZ1O5eXlKTMz07UvKChImZmZys3NDWDNWpbS0lJJUmxsrCQpLy9PlZWVbs+9a9euat++Pc+9EbKzszVy5Ei35ynxnH3lzTffVP/+/fXrX/9a8fHxSktL03PPPec6fujQIRUXF7s95+joaKWnp/OcvfCzn/1Mmzdv1pdffilJ+uyzz/Thhx9qxIgRknjO/uLJc83NzVVMTIz69+/vKpOZmamgoCBt377dp/VptivxNjf//ve/VV1dfdZKwAkJCfriiy8CVKuWpaamRvfee6+uuuoq9ezZU5JUXFwsq9V61os5ExISVFxcHIBamteaNWv0ySefaOfOnWcd4zn7xtdff62nn35a06ZN0/3336+dO3fq7rvvltVq1YQJE1zPsq5/R3jOnps1a5bsdru6du2q4OBgVVdX65FHHtG4ceMkiefsJ5481+LiYsXHx7sdDwkJUWxsrM+fPQEGzUZ2drb27t2rDz/8MNBVaXG+/fZb3XPPPdq4caNatWoV6Oq0WDU1Nerfv78effRRSVJaWpr27t2rZ555RhMmTAhw7VqOv/3tb1q1apVWr16tHj16KD8/X/fee6+Sk5N5zhcQupA81LZtWwUHB581K+Po0aNKTEwMUK1ajilTpmjdunV67733dPHFF7v2JyYmyul06vjx427lee7eycvLU0lJifr27auQkBCFhITo/fff1xNPPKGQkBAlJCTwnH0gKSlJ3bt3d9vXrVs3FRYWSpLrWfLvyPmZMWOGZs2apZtuukm9evXSrbfeqqlTp2rBggWSeM7+4slzTUxMVElJidvxqqoqHTt2zOfPngDjIavVqn79+mnz5s2ufTU1Ndq8ebMyMjICWDNzMwxDU6ZM0euvv653331XHTt2dDver18/hYaGuj33goICFRYW8ty9MHToUO3Zs0f5+fmuT//+/TVu3DjXNs/5/F111VVnLQPw5ZdfKjU1VZLUsWNHJSYmuj1nu92u7du385y94HA4FBTk/ucrODhYNTU1knjO/uLJc83IyNDx48eVl5fnKvPuu++qpqZG6enpvq2QT4cEt3Br1qwxwsLCjJUrVxr79+83Jk+ebMTExBjFxcWBrppp3XnnnUZ0dLSxZcsWo6ioyPVxOByuMnfccYfRvn1749133zV27dplZGRkGBkZGQGsdctw5iwkw+A5+8KOHTuMkJAQ45FHHjG++uorY9WqVYbNZjNeeuklV5mFCxcaMTExxhtvvGHs3r3buO6665je66UJEyYYF110kWsa9WuvvWa0bdvW+OMf/+gqw3NunBMnThiffvqp8emnnxqSjKVLlxqffvqp8c033xiG4dlzHT58uJGWlmZs377d+PDDD41LL72UadTNwZNPPmm0b9/esFqtxoABA4xt27YFukqmJqnOz4oVK1xlfvzxR+MPf/iD0aZNG8NmsxnXX3+9UVRUFLhKtxA/DTA8Z9/4xz/+YfTs2dMICwszunbtajz77LNux2tqaowHHnjASEhIMMLCwoyhQ4caBQUFAaqtOdntduOee+4x2rdvb7Rq1cro1KmT8ac//cmoqKhwleE5N857771X57/JEyZMMAzDs+f6/fffG2PHjjVat25tREVFGb/97W+NEydO+LyuFsM4Y+lCAAAAE2AMDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDAAAMB0CDABT69Chgx5//PFAVwNAEyPAAAAA0+FdSACatcGDB6tnz56SpBdffFGhoaG68847NX/+fA0ZMkTvv/++W3n+SQMuDLTAAGj2XnjhBYWEhGjHjh1atmyZli5dqr/+9a967bXXdPHFF2v+/PkqKipSUVFRoKsKoImEBLoCANCQlJQUPfbYY7JYLOrSpYv27Nmjxx57TLfffruCg4MVGRmpxMTEQFcTQBOiBQZAs3fllVfKYrG4vmdkZOirr75SdXV1AGsFIJAIMAAAwHQIMACave3bt7t937Ztmy699FIFBwfLarXSEgNcgAgwAJq9wsJCTZs2TQUFBXr55Zf15JNP6p577pFUuw7M1q1b9d133+nf//53gGsKoKkwjRpAszZ48GD16NFDNTU1Wr16tYKDg3XnnXfq4YcflsVi0bZt2/T73/9eBQUFqqioYBo1cIEgwABo1gYPHqw+ffqw2i4AN3QhAQAA0yHAAAAA06ELCQAAmA4tMAAAwHQIMAAAwHQIMAAAwHQIMAAAwHQIMAAAwHQIMAAAwHQIMAAAwHQIMAAAwHT+P5vlNwNKnlqgAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import numpy as np\n", "import hist\n", "import matplotlib.pyplot as plt\n", "\n", "dists = (\n", " hist.Hist.new\n", " .StrCat([\"gen1\", \"gen2\"], name=\"dataset\", growth=True)\n", " .Reg(20, 0, 100, name=\"pt\")\n", " .Reg(4, -3, 3, name=\"eta\")\n", " .Weight()\n", " .fill(\n", " dataset=\"gen1\",\n", " pt=np.random.exponential(scale=10.0, size=10000) + np.random.exponential(scale=10.0, size=10000),\n", " eta=np.random.normal(scale=1, size=10000)\n", " )\n", " .fill(\n", " dataset=\"gen2\",\n", " pt=np.random.exponential(scale=10.0, size=10000) + np.random.exponential(scale=15.0, size=10000),\n", " eta=np.random.normal(scale=1.1, size=10000)\n", " )\n", ")\n", "\n", "fig, ax = plt.subplots()\n", "dists[:, :, sum].plot1d(ax=ax)\n", "ax.legend(title=\"dataset\")" ] }, { "cell_type": "markdown", "id": "e9adbde5", "metadata": {}, "source": [ "Now we derive a correction as a function of $p_T$ and $\\eta$ to `gen2` such that it agrees with `gen1`. Weโ€™ll set it to 1 anywhere we run out of statistics for the correction, to avoid divide by zero issues." ] }, { "cell_type": "code", "execution_count": 15, "id": "b07843ef", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "ColormeshArtists(pcolormesh=, cbar=, text=[])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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b9b31AwfPvy4R6784x//UPfu3SVJaWlpCgQCYWtcVVWl9evXs8YeHDhwQDEx4b+OYmNj5TiOJNbXNC/rmZ6err1792rTpk2hc1atWiXHcTR06NDTPudmzfbdAk3Vyy+/7Pr9fjc/P9/9+OOP3V/96ldu27Zt3fLycttTizo333yzm5SU5BYWFrq7du0KtQMHDoTO+fWvf+1269bNXbVqlbtx40Y3PT3dTU9Ptzjr6PbjuyZdl/U9VR988IHbokUL97777nM/++wz96WXXnJbtWrlvvjii6Fz7r//frdt27bu8uXL3b///e/ulVde6aalpbkHDx60OPPoMGnSJLdz587uihUr3B07drhvvPGG26FDB3fWrFmhc1jfhtm3b5+7efNmd/Pmza4k95FHHnE3b97sfvHFF67relvPMWPGuAMHDnTXr1/vrl271j333HPd6667ztZHarYIxOrx6KOPut26dXPj4+PdIUOGuOvWrbM9pagkqc727LPPhs45ePCg+5//+Z9uu3bt3FatWrlXXXWVu2vXLnuTjnL/GoixvqfuzTffdPv27ev6/X63V69e7pNPPhn2vuM47p133ummpKS4fr/fHTlypFtSUmJpttGlqqrKnT59ututWzc3ISHBPeecc9zf/e53bk1NTegc1rdh3nvvvTp/7k6aNMl1XW/r+c0337jXXXed27p1azcxMdGdPHmyu2/fPgufpnnzue6PHl0MAACA04Y9YgAAAJYQiAEAAFhCIAYAAGAJgRgAAIAlBGIAAACWEIgBAABYQiAGAABgCYEYAACAJQRiAJqss88+WwsWLLA9DQCIGAIxAAAAS/iKIwDWZGZmqm/fvpKkF154QXFxcbr55ps1d+5cjRgxQqtXrw47nx9XAJobMmIArHruuefUokULffDBB1q4cKEeeeQRPfXUU3rjjTfUpUsXzZ07V7t27dKuXbtsTxUAjGthewIAzmxdu3bV/Pnz5fP51LNnT23ZskXz58/X1KlTFRsbqzZt2igQCNieJgBEBBkxAFYNGzZMPp8v9Do9PV2fffaZgsGgxVkBwOlBIAYAAGAJgRgAq9avXx/2et26dTr33HMVGxur+Ph4MmMAmjUCMQBWlZaWKicnRyUlJfrzn/+sRx99VNOnT5d09Dlia9as0c6dO7Vnzx7LMwUA83h8BQBrMjMzdd5558lxHC1evFixsbG6+eabde+998rn82ndunX6j//4D5WUlKimpobHVwBodgjEAFiTmZmpAQMG8PR8AGcsSpMAAACWEIgBAABYQmkSAADAEjJiAAAAlhCIAQAAWEIgBgAAYAmBGAAAgCUEYgAAAJYQiAEAAFhCIAYAAGAJgRgAAIAlBGIAAACW/D/xifs5XBhKrgAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "num = dists[\"gen1\", :, :].values()\n", "den = dists[\"gen2\", :, :].values()\n", "sf = np.where(\n", " (num > 0) & (den > 0),\n", " num / np.maximum(den, 1) * den.sum() / num.sum(),\n", " 1.0,\n", ")\n", "\n", "# a quick way to plot the scale factor is to steal the axis definitions from the input histograms:\n", "sfhist = hist.Hist(*dists.axes[1:], data=sf)\n", "sfhist.plot2d()" ] }, { "cell_type": "markdown", "id": "fc40af2c", "metadata": {}, "source": [ "Now we use `correctionlib.convert.from_histogram(...)` to convert the scale factor into a correction object" ] }, { "cell_type": "code", "execution_count": 16, "id": "7d54dc24", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
๐Ÿ“ˆ gen2_to_gen1 (v0)\n",
       "Reweights gen2 to agree with gen1\n",
       "Node counts: MultiBinning: 1\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ pt (real)                        โ”‚ โ”‚ eta (real)                      โ”‚\n",
       "โ”‚ pt                               โ”‚ โ”‚ eta                             โ”‚\n",
       "โ”‚ Range: [0.0, 100.0), overflow ok โ”‚ โ”‚ Range: [-3.0, 3.0), overflow ok โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "โ•ญโ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ out (real)     โ”‚\n",
       "โ”‚ No description โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "
\n" ], "text/plain": [ "๐Ÿ“ˆ \u001b[1mgen2_to_gen1\u001b[0m \u001b[1m(\u001b[0mv0\u001b[1m)\u001b[0m\n", "Reweights gen2 to agree with gen1\n", "Node counts: \u001b[1mMultiBinning\u001b[0m: \u001b[1;36m1\u001b[0m\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mpt\u001b[0m (real) โ”‚ โ”‚ \u001b[1meta\u001b[0m (real) โ”‚\n", "โ”‚ pt โ”‚ โ”‚ eta โ”‚\n", "โ”‚ Range: [0.0, 100.0), overflow ok โ”‚ โ”‚ Range: [-3.0, 3.0), overflow ok โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n", "โ•ญโ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mout\u001b[0m (real) โ”‚\n", "โ”‚ \u001b[3mNo description\u001b[0m โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import correctionlib.convert\n", "\n", "# without a name, the resulting object will fail validation\n", "sfhist.name = \"gen2_to_gen1\"\n", "sfhist.label = \"out\"\n", "gen2_to_gen1 = correctionlib.convert.from_histogram(sfhist)\n", "gen2_to_gen1.description = \"Reweights gen2 to agree with gen1\"\n", "# set overflow bins behavior (default is to raise an error when out of bounds)\n", "gen2_to_gen1.data.flow = \"clamp\"\n", "rich.print(gen2_to_gen1)" ] }, { "cell_type": "markdown", "id": "8437d322", "metadata": {}, "source": [ "Now we generate some new mock data as if it was drawn from `gen2` and reweight it with our correction. Let's see if our correction closes:" ] }, { "cell_type": "code", "execution_count": 17, "id": "bc2bbfc9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ptvals = np.random.exponential(scale=10.0, size=10000) + np.random.exponential(scale=15.0, size=10000)\n", "etavals = np.random.normal(scale=1.1, size=10000)\n", "\n", "dists.fill(\n", " dataset=\"gen2rwt\",\n", " pt=ptvals,\n", " eta=etavals,\n", " weight=gen2_to_gen1.to_evaluator().evaluate(ptvals, etavals)\n", ")\n", "\n", "fig, ax = plt.subplots()\n", "dists[:, :, sum].plot1d(ax=ax)\n", "ax.legend(title=\"dataset\")" ] }, { "cell_type": "markdown", "id": "3d8b6a03", "metadata": {}, "source": [ "## Polynomial fits\n", "\n", "It is apparent from the plot of the 2D correction factor that we do not have sufficient sample statistics to derive a smooth correction. One approach to improve the quality is to fit it to a polynomial. A utility method, `correctionlib.convert.ndpolyfit` allows to fit an arbitrary-dimensional polynomial to a set of data points and return a correction object representing the result." ] }, { "cell_type": "code", "execution_count": 18, "id": "646de98e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
๐Ÿ“ˆ gen2_to_gen1_poly (v1)\n",
       "Fit to polynomial of order 2,2\n",
       "Fit status: The unconstrained solution is optimal.\n",
       "chi2 = 5.305322148600006, P(dof=71) = 1.000\n",
       "Node counts: Formula: 1\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ pt (real)                       โ”‚ โ”‚ eta (real)                      โ”‚\n",
       "โ”‚ No description                  โ”‚ โ”‚ No description                  โ”‚\n",
       "โ”‚ Range: [-inf, inf), overflow ok โ”‚ โ”‚ Range: [-inf, inf), overflow ok โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "โ•ญโ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ output (real)  โ”‚\n",
       "โ”‚ No description โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "
\n" ], "text/plain": [ "๐Ÿ“ˆ \u001b[1mgen2_to_gen1_poly\u001b[0m \u001b[1m(\u001b[0mv1\u001b[1m)\u001b[0m\n", "Fit to polynomial of order \u001b[1;36m2\u001b[0m,\u001b[1;36m2\u001b[0m\n", "Fit status: The unconstrained solution is optimal.\n", "chi2 = \u001b[1;36m5.305322148600006\u001b[0m, \u001b[1;35mP\u001b[0m\u001b[1m(\u001b[0m\u001b[33mdof\u001b[0m=\u001b[1;36m71\u001b[0m\u001b[1m)\u001b[0m = \u001b[1;36m1.000\u001b[0m\n", "Node counts: \u001b[1mFormula\u001b[0m: \u001b[1;36m1\u001b[0m\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mpt\u001b[0m (real) โ”‚ โ”‚ \u001b[1meta\u001b[0m (real) โ”‚\n", "โ”‚ \u001b[3mNo description\u001b[0m โ”‚ โ”‚ \u001b[3mNo description\u001b[0m โ”‚\n", "โ”‚ Range: [-inf, inf), overflow ok โ”‚ โ”‚ Range: [-inf, inf), overflow ok โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n", "โ•ญโ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1moutput\u001b[0m (real) โ”‚\n", "โ”‚ \u001b[3mNo description\u001b[0m โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "centers = np.meshgrid(*[ax.centers for ax in sfhist.axes], indexing=\"ij\")\n", "\n", "gen2_to_gen1_poly, fit = correctionlib.convert.ndpolyfit(\n", " points=[c.flatten() for c in centers],\n", " values=sfhist.values().flatten(),\n", " weights=1/sfhist.variances().flatten(),\n", " varnames=[ax.name for ax in sfhist.axes],\n", " degree=(2, 2),\n", ")\n", "gen2_to_gen1_poly.name = \"gen2_to_gen1_poly\"\n", "rich.print(gen2_to_gen1_poly)" ] }, { "cell_type": "markdown", "id": "c84435af", "metadata": {}, "source": [ "Let's check the closure of this method to the previous one:" ] }, { "cell_type": "code", "execution_count": 19, "id": "b9fbd038", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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JCIiInI7rIGhZknt4SltZz2wGzKN2mKs9vJ/cTHhbgBA26zPoAm80WJscUkRhn85ynEFJSIil2ACQ81S3bWQNAo1ZAqNxViT4mpy46lQQ2MltrJOYkRERO6LTUhERETkdpjAkPvz0NS/TURELRYTGCIiInI77ANDzZ6pstL6+apKs22TQmsxVqyshEpfM/8L54EhInJfTGCo2ft5wECbY3+/7Y4GY9bVboysalyBiIjI5diERERERG6HNTDULAlqNaKO5NgUa6qslGppOu/7DjK15TljLhf+ikt33uuQMhIRkeswgaFmSRAECBr7RxTJ1GrIrFwnqDkPDBFRS8AmJCIiInI7TGCIiIjI7TCBISIiIrfDPjDk9mQaDbqdOunqYhARURNiDQwRERG5HSYwRERE5HaYwBAREZHbYQJDREREbocJDBEREbkdJjBERETkdpjAEBERkdthAkNERERuhwkMERERuR0mMEREROR2mMAQERGR22EC40RagxY91/ZEz7U9oTVoXV0cIiKiFoMJDBEREbkdJjBERETkdpjAEBERkduxO4HZs2cPRo0ahfDwcAiCgM2bN5udF0URc+fORVhYGNRqNRITE/Hzzz+bxRQXF2PcuHHw9fWFv78/Jk6ciPLycrOYo0ePYtCgQfD09ERERAQWL15s/7dzMZO2Eh8vqsbHi6ph0la6ujhEREQtht0JTEVFBXr16oW333673vOLFy/Gm2++iVWrVuHgwYPw8vJCUlISqqqqpJhx48bhp59+wo4dO7Blyxbs2bMHkyZNks6XlpZi2LBhaN++PXJycrBkyRLMmzcP7777biO+ouOIogitQWvzp8p4NWmpMlZaja2s1rnwmxEREbkXD3svGD58OIYPH17vOVEUsWLFCrz88su4++67AQD/+7//i5CQEGzevBkPPfQQTp48ia1bt+LQoUPo27cvAOCtt97CnXfeiYyMDISHh2P9+vXQ6/VYvXo1lEolbr75ZuTm5mLZsmVmiU5Tq6yuRNyGOJvjVXoR6/7aTv5PMnRKwaZYIiIiss6hfWDOnTuHwsJCJCYmSsf8/PwQFxeH7OxsAEB2djb8/f2l5AUAEhMTIZPJcPDgQSlm8ODBUCqVUkxSUhLy8vLw559/1vtsnU6H0tJSsw/RddFXAPP8aj76CleXhoiI6rC7BsaawsJCAEBISIjZ8ZCQ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T09PVxenxTKZTOjbty8WLlwIAIiNjcXx48exatUqpKSkuLh0LcfHH3+M9evXY8OGDbj55puRm5uLadOmITw8nO+5FWETko2CgoIgl8uvGZVx4cIFhIaGuqhULcfUqVOxZcsWfPvtt7jxxhul46GhodDr9bhy5YpZPN+7fXJyclBUVITevXvDw8MDHh4e2L17N9588014eHggJCSE79kBwsLC0L17d7Nj3bp1Q35+PgBI75I/R67PzJkzMXv2bDz00EPo2bMnHn30UUyfPh2LFi0CwPfsLLa819DQUBQVFZmdr66uRnFxscPfPRMYGymVSvTp0we7du2SjplMJuzatQvx8fEuLJl7E0URU6dOxaZNm/DNN9+gQ4cOZuf79OkDhUJh9t7z8vKQn5/P926HoUOH4tixY8jNzZU+ffv2xbhx46RtvufrN2DAgGumATh9+jTat28PAOjQoQNCQ0PN3nNpaSkOHjzI92wHrVYLmcz815dcLofJZALA9+wstrzX+Ph4XLlyBTk5OVLMN998A5PJhLi4OMcWyKFdglu4jRs3iiqVSlyzZo144sQJcdKkSaK/v79YWFjo6qK5raeeekr08/MTs7KyxIKCAumj1WqlmMmTJ4vt2rUTv/nmG/Hw4cNifHy8GB8f78JStwx1RyGJIt+zI3z//feih4eH+Prrr4s///yzuH79elGj0YgffvihFJOeni76+/uLn332mXj06FHx7rvv5vBeO6WkpIg33HCDNIz6008/FYOCgsQXXnhBiuF7bpyysjLxhx9+EH/44QcRgLhs2TLxhx9+EH/99VdRFG17r8nJyWJsbKx48OBB8bvvvhM7d+7MYdTNwVtvvSW2a9dOVCqVYv/+/cUDBw64ukhuDUC9n8zMTCmmsrJSfPrpp8U2bdqIGo1GvOeee8SCggLXFbqF+HsCw/fsGF988YXYo0cPUaVSiV27dhXfffdds/Mmk0l85ZVXxJCQEFGlUolDhw4V8/LyXFRa91RaWio+99xzYrt27URPT0+xY8eO4ksvvSTqdDophu+5cb799tt6fyanpKSIomjbe718+bI4duxY0dvbW/T19RUfe+wxsayszOFlFUSxztSFRERERG6AfWCIiIjI7TCBISIiIrfDBIaIiIjcDhMYIiIicjtMYIiIiMjtMIEhIiIit8MEhoiIiNwOExgiIiJyO0xgiIiIyO0wgSEitxYZGYkVK1a4uhhE1MSYwBAREZHb4VpIRNSsJSQkoEePHgCAdevWQaFQ4KmnnsL8+fMxZMgQ7N692yyeP9KIWgfWwBBRs7d27Vp4eHjg+++/x8qVK7Fs2TK8//77+PTTT3HjjTdi/vz5KCgoQEFBgauLSkRNxMPVBSAiakhERASWL18OQRAQFRWFY8eOYfny5XjyySchl8vh4+OD0NBQVxeTiJoQa2CIqNm75ZZbIAiCtB8fH4+ff/4ZRqPRhaUiIldiAkNERERuhwkMETV7Bw8eNNs/cOAAOnfuDLlcDqVSyZoYolaICQwRNXv5+fmYMWMG8vLy8NFHH+Gtt97Cc889B6BmHpg9e/bg999/x6VLl1xcUiJqKhxGTUTNWkJCAm6++WaYTCZs2LABcrkcTz31FF577TUIgoADBw7gH//4B/Ly8qDT6TiMmqiVYAJDRM1aQkICYmJiONsuEZlhExIRERG5HSYwRERE5HbYhERERERuhzUwRERE5HaYwBAREZHbYQJDREREbocJDBEREbkdJjBERETkdpjAEBERkdthAkNERERuhwkMERERuZ3/B9RjeYCJnEWbAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "dists.fill(\n", " dataset=\"gen2rwt_poly\",\n", " pt=ptvals,\n", " eta=etavals,\n", " weight=gen2_to_gen1_poly.to_evaluator().evaluate(ptvals, etavals)\n", ")\n", "\n", "\n", "fig, ax = plt.subplots()\n", "dists[:, :, sum].plot1d(ax=ax)\n", "ax.legend(title=\"dataset\")" ] }, { "cell_type": "markdown", "id": "8aae69ba", "metadata": {}, "source": [ "Another important consideration is that evaluating a polynomial in Horner form is $O(k)$ where $k$ is the order of the polynomial, while looking up a value in a non-uniform binning is $O(log(n))$ in $n$ bins. Depending on the situation, an acceptable $k$ may be lower than $log(n)$. In our case, the $(2,2)$ polynomial we derived evaluates slower than the binning, partially because it is not evaluated in Horner form:" ] }, { "cell_type": "code", "execution_count": 20, "id": "01ae867c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "404 ยตs ยฑ 3.54 ยตs per loop (mean ยฑ std. dev. of 7 runs, 1,000 loops each)\n", "3.28 ms ยฑ 59.2 ยตs per loop (mean ยฑ std. dev. of 7 runs, 100 loops each)\n" ] } ], "source": [ "corr_bin = gen2_to_gen1.to_evaluator()\n", "corr_pol = gen2_to_gen1_poly.to_evaluator()\n", "\n", "%timeit corr_bin.evaluate(ptvals, etavals)\n", "%timeit corr_pol.evaluate(ptvals, etavals)" ] }, { "cell_type": "markdown", "id": "08564fd8", "metadata": {}, "source": [ "However, in an alternative situation, the same may not hold:" ] }, { "cell_type": "code", "execution_count": 21, "id": "752bdad2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "199 ยตs ยฑ 4.31 ยตs per loop (mean ยฑ std. dev. of 7 runs, 1,000 loops each)\n", "36.6 ยตs ยฑ 1.65 ยตs per loop (mean ยฑ std. dev. of 7 runs, 10,000 loops each)\n" ] } ], "source": [ "%timeit np.searchsorted([0., 5., 10., 15., 20., 25., 30., 35.], ptvals)\n", "%timeit np.polyval([0.01, 0.1, 1.0], ptvals)" ] }, { "cell_type": "markdown", "id": "18cfc2ed", "metadata": {}, "source": [ "## Resolution models\n", "\n", "In some instances, one might want to smear the value of a variable, e.g. jet energy, to simulate a degradation of resolution with respect to what was expected from simulation. If we can deterministically generate pseudorandom numbers, we can then use them after suitable scaling to correct the jet momentum. To do so in correctionlib, we gather entropy sources such as the kinematics of the jet and event-level quantities, hash them together using the extremely fast [xxhash](https://cyan4973.github.io/xxHash/) algorithm to generate an integer seed, and use that to initialize a [PCG64](https://www.pcg-random.org/) random number generator, which can then be drawn from to build a normal-distributed (or otherwise) value. See [issue #130](https://github.com/cms-nanoAOD/correctionlib/issues/130) for further details." ] }, { "cell_type": "code", "execution_count": 22, "id": "0375e2f5", "metadata": {}, "outputs": [], "source": [ "resrng = cs.Correction(\n", " name=\"resrng\",\n", " description=\"Deterministic smearing value generator\",\n", " version=1,\n", " inputs=[\n", " cs.Variable(name=\"pt\", type=\"real\", description=\"Unsmeared jet pt\"),\n", " cs.Variable(name=\"eta\", type=\"real\", description=\"Jet pseudorapdity\"),\n", " cs.Variable(name=\"phi\", type=\"real\", description=\"Jet phi (entropy source)\"),\n", " cs.Variable(name=\"evt\", type=\"int\", description=\"Event number (entropy source)\"),\n", " ],\n", " output=cs.Variable(name=\"rng\", type=\"real\"),\n", " data=cs.HashPRNG(\n", " nodetype=\"hashprng\",\n", " inputs=[\"pt\", \"eta\", \"phi\", \"evt\"],\n", " distribution=\"stdnormal\",\n", " )\n", ")\n", "\n", "resmodel = cs.Correction(\n", " name=\"resmodel\",\n", " description=\"A jet energy resolution smearing model\",\n", " version=1,\n", " inputs=[\n", " cs.Variable(name=\"pt\", type=\"real\", description=\"Unsmeared jet pt\"),\n", " ],\n", " output=cs.Variable(name=\"scale\", type=\"real\"),\n", " data=cs.Binning(\n", " nodetype=\"binning\",\n", " input=\"pt\",\n", " edges=[10, 20, 30, 40, 50, 80, 120],\n", " content=[0.3, 0.25, 0.20, 0.14, 0.06, 0.02],\n", " flow=\"clamp\",\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": 23, "id": "f93ca4d8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Text(0.5, 0, 'Smeared $p_T$ - Unsmeared $p_T$')" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# dummy distributions\n", "phivals = np.random.uniform(-np.pi, np.pi, size=10000)\n", "eventnumber = np.random.randint(123456, 123567, size=10000)\n", "\n", "# apply a pT-dependent smearing by scaling the standard normal draw\n", "smear_val = (\n", " resrng.to_evaluator().evaluate(ptvals, etavals, phivals, eventnumber)\n", " * resmodel.to_evaluator().evaluate(ptvals)\n", ")\n", "pt_smeared = np.maximum(ptvals + smear_val, 0.0)\n", "\n", "\n", "fig, ax = plt.subplots()\n", "ax.hist(pt_smeared - ptvals, bins=50)\n", "ax.set_xlabel(\"Smeared $p_T$ - Unsmeared $p_T$\")" ] }, { "cell_type": "markdown", "id": "4ffea3dd", "metadata": {}, "source": [ "## Chaining with CompoundCorrection\n", "\n", "A CompoundCorrection allows to apply a sequence of corrections in order, refering to other corrections in the same CorrectionSet object. For example, we can merge the smearing and RNG into one:" ] }, { "cell_type": "code", "execution_count": 24, "id": "8dfe7c7f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "One-shot smearing is equivalent to two-step procedure?\n", "True\n" ] } ], "source": [ "cset = correctionlib.schemav2.CorrectionSet(\n", " schema_version=2,\n", " corrections=[\n", " resmodel,\n", " resrng,\n", " ],\n", " compound_corrections=[\n", " cs.CompoundCorrection(\n", " name=\"resolution_model\",\n", " inputs=[\n", " cs.Variable(name=\"pt\", type=\"real\", description=\"Unsmeared jet pt\"),\n", " cs.Variable(name=\"eta\", type=\"real\", description=\"Jet pseudorapdity\"),\n", " cs.Variable(name=\"phi\", type=\"real\", description=\"Jet phi (entropy source)\"),\n", " cs.Variable(name=\"evt\", type=\"int\", description=\"Event number (entropy source)\"),\n", " ],\n", " output=cs.Variable(name=\"shift\", type=\"real\", description=\"Additive shift to jet pT\"),\n", " inputs_update=[],\n", " input_op=\"*\",\n", " output_op=\"*\",\n", " stack=[\"resmodel\", \"resrng\"],\n", " )\n", " ]\n", ")\n", "\n", "oneshot = cset.to_evaluator().compound[\"resolution_model\"]\n", "\n", "print(\"One-shot smearing is equivalent to two-step procedure?\")\n", "print(np.allclose(\n", " oneshot.evaluate(ptvals, etavals, phivals, eventnumber),\n", " smear_val,\n", "))" ] }, { "cell_type": "markdown", "id": "f2807bad", "metadata": {}, "source": [ "Note the `inputs_update` and `input_op` fields can be used to update inputs as they go through the stack, which is useful for chained corrections such as jet energy corrections." ] }, { "cell_type": "markdown", "id": "b533ebae", "metadata": {}, "source": [ "## Systematics\n", "\n", "There are many ways to encode systematic uncertainties within correctionlib, although no nodes are dedicated to the task. See [issue #4](https://github.com/cms-nanoAOD/correctionlib/issues/4) to discuss further the idea of having a dedicated systematic node. The most straightforward option is to use a Category node with string lookup to switch the behavior depending on the active systematic. Below we modify our `ptweight` from before to produce a systematically larger event weight when the `MuonEffUp` systematic is specified, while producing the nominal event weight for any other string key, by taking advantage of the `default=` keywoard in the Category node. We also use the `flow=` keyword in the shifted binning to increase the systematic uncertainty for data with muon $p_T$ larger than 120." ] }, { "cell_type": "code", "execution_count": 25, "id": "65c7ee44", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
๐Ÿ“ˆ ptweight (v1)\n",
       "No description\n",
       "Node counts: Category: 1, Binning: 2\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ pt (real)                        โ”‚ โ”‚ syst (string)     โ”‚\n",
       "โ”‚ Muon transverse momentum         โ”‚ โ”‚ Systematic        โ”‚\n",
       "โ”‚ Range: [0.0, 120.0), overflow ok โ”‚ โ”‚ Values: MuonEffUp โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚ has default       โ”‚\n",
       "                                     โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n",
       "โ”‚ weight (real)               โ”‚\n",
       "โ”‚ Multiplicative event weight โ”‚\n",
       "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n",
       "
\n" ], "text/plain": [ "๐Ÿ“ˆ \u001b[1mptweight\u001b[0m \u001b[1m(\u001b[0mv1\u001b[1m)\u001b[0m\n", "\u001b[3mNo description\u001b[0m\n", "Node counts: \u001b[1mCategory\u001b[0m: \u001b[1;36m1\u001b[0m, \u001b[1mBinning\u001b[0m: \u001b[1;36m2\u001b[0m\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€โ”€ โ–ถ input โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mpt\u001b[0m (real) โ”‚ โ”‚ \u001b[1msyst\u001b[0m (string) โ”‚\n", "โ”‚ Muon transverse momentum โ”‚ โ”‚ Systematic โ”‚\n", "โ”‚ Range: [0.0, 120.0), overflow ok โ”‚ โ”‚ Values: MuonEffUp โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚ \u001b[1;32mhas default\u001b[0m โ”‚\n", " โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n", "โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ—€ output โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ\n", "โ”‚ \u001b[1mweight\u001b[0m (real) โ”‚\n", "โ”‚ Multiplicative event weight โ”‚\n", "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ptweight = cs.Correction(\n", " name=\"ptweight\",\n", " version=1,\n", " inputs=[\n", " cs.Variable(name=\"pt\", type=\"real\", description=\"Muon transverse momentum\"),\n", " cs.Variable(name=\"syst\", type=\"string\", description=\"Systematic\")\n", " ],\n", " output=cs.Variable(name=\"weight\", type=\"real\", description=\"Multiplicative event weight\"),\n", " data=cs.Category(\n", " nodetype=\"category\",\n", " input=\"syst\",\n", " content=[\n", " cs.CategoryItem(\n", " key=\"MuonEffUp\",\n", " value=cs.Binning(\n", " nodetype=\"binning\",\n", " input=\"pt\",\n", " edges=[0, 10, 20, 30, 40, 50, 80, 120],\n", " content=[1.14, 1.14, 1.09, 1.07, 1.05, 1.03, 1.01],\n", " flow=1.03,\n", " ),\n", " ),\n", " ],\n", " default=cs.Binning(\n", " nodetype=\"binning\",\n", " input=\"pt\",\n", " edges=[10, 20, 30, 40, 50, 80, 120],\n", " content=[1.1, 1.08, 1.06, 1.04, 1.02, 1.0],\n", " flow=\"clamp\",\n", " ),\n", " ),\n", ")\n", "\n", "rich.print(ptweight)" ] }, { "cell_type": "code", "execution_count": 26, "id": "d359ec0e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ptweight.to_evaluator().evaluate(135., \"nominal\")" ] }, { "cell_type": "markdown", "id": "37ba6ef2", "metadata": {}, "source": [ "## Writing it all out" ] }, { "cell_type": "code", "execution_count": 27, "id": "398b8b6c", "metadata": {}, "outputs": [], "source": [ "cset = correctionlib.schemav2.CorrectionSet(\n", " schema_version=2,\n", " description=\"my custom corrections\",\n", " corrections=[\n", " gen2_to_gen1,\n", " ptweight,\n", " phimod,\n", " ],\n", ")\n", "\n", "with open(\"mycorrections.json\", \"w\") as fout:\n", " fout.write(cset.json(exclude_unset=True))\n", " \n", "import gzip\n", "\n", "with gzip.open(\"mycorrections.json.gz\", \"wt\") as fout:\n", " fout.write(cset.json(exclude_unset=True))" ] }, { "cell_type": "markdown", "id": "8fb88c12", "metadata": {}, "source": [ "## Command-line utility\n", "\n", "The `correction` utility, bundled with the library, provides useful tools for viewing, combining, and validating correction json sets. It also can provide the necessary compile flags for C++ programs to use correctionlib:" ] }, { "cell_type": "code", "execution_count": 28, "id": "9765cb34", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "usage: correction [-h] [--width WIDTH] [--html HTML]\r\n", " {validate,summary,merge,config} ...\r\n", "\r\n", "Command-line interface to correctionlib\r\n", "\r\n", "positional arguments:\r\n", " {validate,summary,merge,config}\r\n", " validate Check if all files are valid\r\n", " summary Print a summmary of the corrections\r\n", " merge Merge one or more correction files and print to stdout\r\n", " config Configuration and linking information\r\n", "\r\n", "options:\r\n", " -h, --help show this help message and exit\r\n", " --width WIDTH Rich output width\r\n", " --html HTML Save terminal output to an HTML file\r\n" ] } ], "source": [ "!correction --help" ] }, { "cell_type": "code", "execution_count": 29, "id": "3a8458d4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "usage: correction config [-h] [-v] [--incdir] [--cflags] [--libdir]\r\n", " [--ldflags] [--rpath] [--cmake]\r\n", "\r\n", "options:\r\n", " -h, --help show this help message and exit\r\n", " -v, --version\r\n", " --incdir\r\n", " --cflags\r\n", " --libdir\r\n", " --ldflags\r\n", " --rpath Include library path hint in linker\r\n", " --cmake CMake dependency flags\r\n" ] } ], "source": [ "!correction config -h" ] }, { "cell_type": "code", "execution_count": 30, "id": "b0e5ee3d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting main.cc\n" ] } ], "source": [ "%%file main.cc\n", "#include \n", "#include \"correction.h\"\n", "\n", "int main() {\n", " auto cset = correction::CorrectionSet::from_file(\"mycorrections.json.gz\");\n", " \n", " double val = cset->at(\"ptweight\")->evaluate({15.0, \"nominal\"});\n", " std::cout << val << std::endl;\n", " return 0;\n", "}" ] }, { "cell_type": "code", "execution_count": 31, "id": "0bd8a625", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ld: warning: dylib (/usr/local/lib/python3.10/site-packages/correctionlib/lib/libcorrectionlib.dylib) was built for newer macOS version (12.0) than being linked (11.0)\r\n" ] } ], "source": [ "!g++ main.cc -o main $(correction config --cflags --ldflags --rpath)" ] }, { "cell_type": "markdown", "id": "2b9251f4", "metadata": {}, "source": [ "On some platforms, if you see errors such as\n", "```\n", "main.cc:(.text+0x17d): undefined reference to `correction::CorrectionSet::from_file(std::__cxx11::basic_string, std::allocator > const&)'\n", "```\n", "in the above compilation, you may need to add `-D_GLIBCXX_USE_CXX11_ABI=0` to the arguments." ] }, { "cell_type": "code", "execution_count": 32, "id": "b083d0d3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.1\r\n" ] } ], "source": [ "!./main" ] } ], "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.10.6" } }, "nbformat": 4, "nbformat_minor": 5 }