diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 56fcaaf..ee02c8c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -9,7 +9,7 @@ body: value: | ## Before posting a feature request Search existing [GitHub issues](https://github.com/SpeysideHEP/spey-pyhf/issues) to make sure the issue does not already exist. - + * **Please use [Markdown syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).** - type: textarea id: system @@ -49,4 +49,3 @@ body: label: Additional information description: | Add any other context about the problem here. - diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index ad5d6a6..6b88ceb 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -10,9 +10,9 @@ body: ## Before posting a question Search existing [GitHub issues](https://github.com/SpeysideHEP/spey-pyhf/issues) to make sure the issue does not already exist. - + If your question involves software issues, please include your system settings as shown below; - + **System Settings:** Please copy and paste the output of `spey.about()` function. If you are working on a specific branch please add the name of the branch and last commit ID. The abbreviated commit ID can be found via `git log -n1 --format="%h"` command. To retreive the branch name please use `git rev-parse --abbrev-ref HEAD` command.) - type: textarea @@ -21,7 +21,7 @@ body: label: Question description: | How can we help? - + * **Please use [Markdown syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).** validations: required: true diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml deleted file mode 100644 index 66c08a5..0000000 --- a/.github/workflows/black.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Lint - -on: - push: - branches: - - release/* - # Each pull request should be validated before merging with main or dev - pull_request: - branches: - - main - - dev - # Enables manual action execution. - workflow_dispatch: - -jobs: - lint: - name: runner / black - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: psf/black@stable - id: action_black - with: - options: "-l 100" - src: "./src" \ No newline at end of file diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 0000000..779b699 --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,17 @@ +on: + pull_request: + branches: ["main", "releases/**"] + push: + branches: ["main", "releases/**", "testing"] + +name: Check if pre-commit checks pass + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.8" + - uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1a94238 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + - id: check-added-large-files + args: ["--maxkb=1024"] + - id: check-ast + - id: check-docstring-first + - id: check-merge-conflict + - id: check-symlinks + - id: check-yaml + - id: forbid-submodules + + - repo: https://github.com/asottile/pyupgrade + rev: v3.3.1 + hooks: + - id: pyupgrade + args: [--py38-plus] + language_version: python3.8 + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: rst-directive-colons + - id: rst-inline-touching-normal + + - repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black + args: ["--line-length=90", "--target-version=py38"] + language_version: python3.8 diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b6c7111..a01c286 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -23,4 +23,4 @@ python: install: - requirements: docs/requirements.txt - method: pip - path: . \ No newline at end of file + path: . diff --git a/.zenodo.json b/.zenodo.json index 81596d6..d3330ea 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,8 +1,8 @@ { "description": "pyhf plug-in for spey package", "license": "MIT", - "title": "SpeysideHEP/spey-pyhf: v0.1.8", - "version": "v0.1.8", + "title": "SpeysideHEP/spey-pyhf: v0.1.9", + "version": "v0.1.9", "upload_type": "software", "creators": [ { @@ -29,7 +29,7 @@ }, { "scheme": "url", - "identifier": "https://github.com/SpeysideHEP/spey-pyhf/tree/v0.1.8", + "identifier": "https://github.com/SpeysideHEP/spey-pyhf/tree/v0.1.9", "relation": "isSupplementTo" }, { @@ -43,4 +43,4 @@ "relation": "requires" } ] -} \ No newline at end of file +} diff --git a/CITATIONS.bib b/CITATIONS.bib index e3ddb2f..76a2460 100644 --- a/CITATIONS.bib +++ b/CITATIONS.bib @@ -49,4 +49,4 @@ @article{pyhf_joss author = {Lukas Heinrich and Matthew Feickert and Giordon Stark and Kyle Cranmer}, title = {pyhf: pure-Python implementation of HistFactory statistical models}, journal = {Journal of Open Source Software} -} \ No newline at end of file +} diff --git a/Makefile b/Makefile index 8fe894e..267d2ba 100755 --- a/Makefile +++ b/Makefile @@ -31,8 +31,3 @@ testpypi: .PHONY: pypi pypi: twine --repository spey-pyhf upload dist/* - - - - - diff --git a/docs/Makefile b/docs/Makefile index 93165bd..bcb2705 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,4 +1,4 @@ -# Makefile for Sphinx documentation +# Makefile for Sphinx documentation SPHINXOPTS = -W --keep-going #-n SPHINXBUILD = sphinx-build @@ -78,4 +78,4 @@ latex: @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." \ No newline at end of file + "(use \`make latexpdf' here to do that automatically)." diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css index 0a9e078..06c92e2 100644 --- a/docs/_static/css/custom.css +++ b/docs/_static/css/custom.css @@ -87,4 +87,4 @@ span.label { background-color: var(--pst-color-surface); color: var(--pst-color-text-base); border: 1px solid var(--pst-color-border); -} \ No newline at end of file +} diff --git a/docs/api.rst b/docs/api.rst index c7abdd5..de7e510 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -12,7 +12,7 @@ Managers .. currentmodule:: spey_pyhf -.. autosummary:: +.. autosummary:: :toctree: _generated/ manager.PyhfManager @@ -63,4 +63,4 @@ Helper functions .. autoclass:: spey_pyhf.WorkspaceInterpreter :members: - :undoc-members: \ No newline at end of file + :undoc-members: diff --git a/docs/bib/references.bib b/docs/bib/references.bib index 1a2091c..f3da651 100644 --- a/docs/bib/references.bib +++ b/docs/bib/references.bib @@ -1,10 +1,10 @@ %% This BibTeX bibliography file was created using BibDesk. %% https://bibdesk.sourceforge.io/ -%% Created for Jack Araz at 2023-04-01 8:42:56 am +0100 +%% Created for Jack Araz at 2023-04-01 8:42:56 am +0100 -%% Saved with string encoding Unicode (UTF-8) +%% Saved with string encoding Unicode (UTF-8) diff --git a/docs/citations.rst b/docs/citations.rst index 17584bc..3221896 100644 --- a/docs/citations.rst +++ b/docs/citations.rst @@ -38,4 +38,4 @@ This plug-in uses ``pyhf`` internally; thus, please also cite the following year = {2021}, bdsk-url-1 = {https://doi.org/10.21105/joss.02823}} -.. include:: ZENODO-PYHF.rst \ No newline at end of file +.. include:: ZENODO-PYHF.rst diff --git a/docs/conf.py b/docs/conf.py index 0e6cc13..4065a1f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,7 +16,7 @@ sys.path.insert(0, str(Path("./ext").resolve())) project = "spey-pyhf" -copyright = "2023, Jack Y. Araz" +copyright = "2024, Jack Y. Araz" author = "Jack Y. Araz" release = get_distribution("spey_pyhf").version version = ".".join(release.split(".")[:3]) @@ -137,8 +137,12 @@ html_static_path = ["_static"] html_css_files = ["css/custom.css"] -html_logo = "https://raw.githubusercontent.com/SpeysideHEP/spey/main/docs/img/spey-plug-in.png" -html_favicon = "https://raw.githubusercontent.com/SpeysideHEP/spey/main/docs/img/spey-plug-in.png" +html_logo = ( + "https://raw.githubusercontent.com/SpeysideHEP/spey/main/docs/img/spey-plug-in.png" +) +html_favicon = ( + "https://raw.githubusercontent.com/SpeysideHEP/spey/main/docs/img/spey-plug-in.png" +) logo_only = True # Output file base name for HTML help builder. diff --git a/docs/quick_start.rst b/docs/quick_start.rst index de6abdf..a63f6c9 100644 --- a/docs/quick_start.rst +++ b/docs/quick_start.rst @@ -20,7 +20,7 @@ Installation Python >=3.8 is required. This will also automatically install ``pyhf`` since it is a requirement. For Gradient and Hessian implementations in likelihood optimisation, we recommend also installing ``Jax``. -Once this package is installed, ``spey`` can automatically detect it, which can be tested using +Once this package is installed, ``spey`` can automatically detect it, which can be tested using :func:`~spey.AvailableBackends` function; .. code-block:: python3 @@ -99,7 +99,7 @@ descriptions within ``spey``; >>> statistical_model.exclusion_confidence_level() # [0.9474850259721279] -For the rest of the functionalities, please refer to the ``spey`` documentation, which can be found +For the rest of the functionalities, please refer to the ``spey`` documentation, which can be found `in this link `_. Due to Spey's fully backend agnostic structure, all the functionalities of the :class:`~spey.StatisticalModel` class also applies to ``pyhf`` plug-in. @@ -109,13 +109,13 @@ applies to ``pyhf`` plug-in. * ``background_only_model``: This background-only model dictionary includes information about background yields, uncertainties and observations. Details on constructing these dictionaries can be found in `pyhf's online documentation `_. - * ``signal_patch``: This signal patch includes dictionaries describing which regions will be added or + * ``signal_patch``: This signal patch includes dictionaries describing which regions will be added or removed from the statistical model. * ``analysis`` (optional): Unique identifier for the analysis. * ``xsection`` (optional): Cross-section value for the signal hypothesis. Units determined by the user. -Additionally, this plug-in is shipped with simple uncorrelated background-attachment which accesses +Additionally, this plug-in is shipped with simple uncorrelated background-attachment which accesses ``pyhf``'s ``uncorrelated_backgound`` function can be accessed through spey with the following function .. code-block:: python3 @@ -152,7 +152,7 @@ Additionally, this plug-in is shipped with simple uncorrelated background-attach .. note:: - ``pyhf`` offers an interface to combine the likelihoods that are described as JSON serialised + ``pyhf`` offers an interface to combine the likelihoods that are described as JSON serialised files. This has been exploited in ``spey`` interface via :func:`combine` `function `_. This function combines ``pyhf`` workspaces and adjusts the signal structure accordingly. For more information - about how ``pyhf`` handles the workspace combination `see the dedicated tutorial here `_. \ No newline at end of file + about how ``pyhf`` handles the workspace combination `see the dedicated tutorial here `_. diff --git a/docs/release_notes.rst b/docs/release_notes.rst index adca2f1..066701c 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -4,4 +4,4 @@ Release Notes .. toctree:: :maxdepth: 2 - releases/changelog-v0.1 \ No newline at end of file + releases/changelog-v0.1 diff --git a/docs/releases/changelog-v0.1.md b/docs/releases/changelog-v0.1.md index ea16cc7..780f34a 100644 --- a/docs/releases/changelog-v0.1.md +++ b/docs/releases/changelog-v0.1.md @@ -45,6 +45,9 @@ * Bugfix in uncertainty quantification for full statistical model mapping on effective sigma ([#15](https://github.com/SpeysideHEP/spey-pyhf/pull/15)) +* Issue with implementing removed channels to the patch + ([#16](https://github.com/SpeysideHEP/spey-pyhf/pull/16)) + ## Contributors This release contains contributions from (in alphabetical order): diff --git a/docs/requirements.txt b/docs/requirements.txt index 007038c..e8c3f37 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -8,4 +8,4 @@ sphinx-togglebutton>=0.3.0 myst-parser sphinx-rtd-size sphinx-book-theme -myst-nb \ No newline at end of file +myst-nb diff --git a/docs/simplify.rst b/docs/simplify.rst index e74816c..de39682 100644 --- a/docs/simplify.rst +++ b/docs/simplify.rst @@ -7,10 +7,10 @@ Converting full statistical models to the simplified likelihood framework :property=og:url: https://spey-pyhf.readthedocs.io/en/main/simplify.html Although full statistical models contain all the necessary information -to reconstruct the original analysis, it might be computationally costly. -Thus, we implement methodologies to convert full likelihoods into simplified -likelihood frameworks using ``"default_pdf.correlated_background"`` or -``"default_pdf.third_moment_expansion"`` models. Details on the +to reconstruct the original analysis, it might be computationally costly. +Thus, we implement methodologies to convert full likelihoods into simplified +likelihood frameworks using ``"default_pdf.correlated_background"`` or +``"default_pdf.third_moment_expansion"`` models. Details on the `simplified models can be found in this link `_. This particular example requires the installation of three packages, which can be achieved @@ -23,73 +23,73 @@ by using the line below Methodology ----------- -The Simplified likelihood framework contracts all the nuisance parameters -into a single bin and represents the background uncertainty as a single source. -To capture the correlations between nuisance parameters, one needs to construct -a statistical model only from **control and validation** regions, which is ideally -purely dominated by the background, henceforth called the control model :math:`\mathcal{L}^{c}`. -Once nuisance parameters are fitted for the control model without the signal, one can -compute the covariance matrix between the nuisance parameters using the Hessian of +The Simplified likelihood framework contracts all the nuisance parameters +into a single bin and represents the background uncertainty as a single source. +To capture the correlations between nuisance parameters, one needs to construct +a statistical model only from **control and validation** regions, which is ideally +purely dominated by the background, henceforth called the control model :math:`\mathcal{L}^{c}`. +Once nuisance parameters are fitted for the control model without the signal, one can +compute the covariance matrix between the nuisance parameters using the Hessian of the negative log probability distribution, .. math:: :label: eq:hess - + \mathbf{V}^{-1}_{ij} = - \frac{\partial^2}{\partial\theta_i\partial\theta_j} \log\mathcal{L}^{\rm c}(0,\theta_0^{\rm c}) -where :math:`\theta_0^{\rm c}` represents the nuisance parameters that maximises -:math:`\mathcal{L}^{\rm c}` at :math:`\mu=0`. Covariance matrix :math:`\mathbf{V}_{ij}` -allows the construction of a multivariate Gaussian distribution -:math:`\mathcal{N}(\theta_0^{\rm c}, \mathbf{V}_{ij})` where one can sample nuisance parameters, -:math:`\tilde{\theta}\sim\mathcal{N}(\theta_0^{\rm c}, \mathbf{V}_{ij})`, +where :math:`\theta_0^{\rm c}` represents the nuisance parameters that maximises +:math:`\mathcal{L}^{\rm c}` at :math:`\mu=0`. Covariance matrix :math:`\mathbf{V}_{ij}` +allows the construction of a multivariate Gaussian distribution +:math:`\mathcal{N}(\theta_0^{\rm c}, \mathbf{V}_{ij})` where one can sample nuisance parameters, +:math:`\tilde{\theta}\sim\mathcal{N}(\theta_0^{\rm c}, \mathbf{V}_{ij})`, without losing the correlations between them. .. attention:: - This method is highly dependent on which channels or regions are considered within the control model since + This method is highly dependent on which channels or regions are considered within the control model since this will determine how much of the statistical model is summarised as a multivariate (skewed) Gaussian. It is essential to note that the nuisance parameters of :math:`\mathcal{L}^{\rm c}` does not -necessarily need to match the requested statistical model, which might be reduced compared to the entire model. -For the sake of simplicity, let us call the requested statistical model :math:`\mathcal{L}^{\rm SR}`, but bear +necessarily need to match the requested statistical model, which might be reduced compared to the entire model. +For the sake of simplicity, let us call the requested statistical model :math:`\mathcal{L}^{\rm SR}`, but bear in mind that this model does not necessarily only contain signal regions. -In the case where :math:`|\theta^{\rm SR}|>|\tilde{\theta}^{\rm c}|` the remaining -nuisance parameters are fitted to maximize :math:`\mathcal{L}^{\rm SR}` for a given set of +In the case where :math:`|\theta^{\rm SR}|>|\tilde{\theta}^{\rm c}|` the remaining +nuisance parameters are fitted to maximize :math:`\mathcal{L}^{\rm SR}` for a given set of :math:`\tilde{\theta}^{\rm c}` and :math:`\mu=0`. The remaining nuisance parameters that maximise this likelihood are :math:`\hat\theta^{\rm SR}`. The simplified likelihood framework requires a covariance matrix, :math:`\Sigma`, representing the correlations between each bin for the background-only model. -To construct the covariance matrix, one can sample from :math:`\mathcal{L}^{\rm SR}` using +To construct the covariance matrix, one can sample from :math:`\mathcal{L}^{\rm SR}` using :math:`\hat\theta^{\rm SR}` and :math:`\tilde{\theta}^{\rm c}`; .. math:: \tilde{n}_b \sim \mathcal{L}^{\rm SR}(\mu=0, \tilde{\theta}^{\rm c}, \hat\theta^{\rm SR}) -where :math:`\Sigma = {\rm cov}(\tilde{n}_b)` and :math:`n_b=\mathbb{E}[\tilde{n}_b]`. Similarly one +where :math:`\Sigma = {\rm cov}(\tilde{n}_b)` and :math:`n_b=\mathbb{E}[\tilde{n}_b]`. Similarly one can compute third moments of :math:`\tilde{n}_b` to extend the model for ``"default_pdf.third_moment_expansion"``. .. seealso:: Other techniques have been employed to simplify the full statistical models. - One can find `such a method in this GitHub repository `_. - Since this approach provides a ``pyhf`` compatible dictionary as an output, it + One can find `such a method in this GitHub repository `_. + Since this approach provides a ``pyhf`` compatible dictionary as an output, it can be directly used with the ``spey-pyhf`` plug-in without additional modifications. The method presented here is different from their approach. Usage ----- -A full statistical model can be constructed using a background-only JSON serialised file +A full statistical model can be constructed using a background-only JSON serialised file (usually found in the HEPData entry for a given analysis). Details on constructing a full -likelihood through the ``spey-pyhf`` interface can be found in +likelihood through the ``spey-pyhf`` interface can be found in :ref:`this section `. As an example, let us use the JSON files provided for ATLAS-SUSY-2019-08 analysis in -`HEPData `_. +`HEPData `_. One can read the file using json package .. code:: python3 @@ -111,17 +111,17 @@ can be constructed as ... ) >>> full_statistical_model.backend.manager.backend = "jax" -where ``background_only`` refers to background-only the JSON file retrieved from HEPData and -``signal`` refers to a signal patch constructed by the user. Note that the computation of the +where ``background_only`` refers to background-only the JSON file retrieved from HEPData and +``signal`` refers to a signal patch constructed by the user. Note that the computation of the Hessian in eq. :eq:`eq:hess` currently requires ``pyhf``'s ``jax`` backend, which is ensured -by the last line in the snippet above. ``full_statistical_model`` can be converted into +by the last line in the snippet above. ``full_statistical_model`` can be converted into simplified likelihood by using ``pyhf.simplify`` backend. .. code:: python3 >>> converter = spey.get_backend("pyhf.simplify") >>> simplified_model = converter( - ... statistical_model=full_statistical_model, + ... statistical_model=full_statistical_model, ... convert_to="default_pdf.correlated_background", ... control_region_indices=[ ... 'WREM_cuts', 'STCREM_cuts', 'TRHMEM_cuts', 'TRMMEM_cuts', 'TRLMEM_cuts' @@ -137,16 +137,16 @@ simplified likelihood by using ``pyhf.simplify`` backend. default ``"default_pdf.correlated_background"``. * ``number_of_samples``: Sets the number of samples to be generated to construct covariance matrix, :math:`\Sigma`, for the background bins, default ``1000``. - * ``control_region_indices``: Usually, the algorithm can pick up the differences between signal, - control and validation regions; however, there is no fixed convention in naming, which leads to + * ``control_region_indices``: Usually, the algorithm can pick up the differences between signal, + control and validation regions; however, there is no fixed convention in naming, which leads to choosing the wrong channels for the construction of the :math:`\mathcal{L}^{\rm c}`. One can overwrite the system selection by providing the indices of the control and validation regions within the channel list from the background-only statistical model dictionary. The channel names of the ``statistical_model`` can be extracted via ``list(statistical_model.backend.model.channels)`` property. For details, see :attr:`~spey_pyhf.data.FullStatisticalModelData.channels`. * ``include_modifiers_in_control_model``: This flag enables the usage of the signal modifiers in the control model. - Note that the yield values will still be zero, but the modifiers within the signal model will be copied - to the control model. This flag allows the contribution of the signal uncertainties in the nuisance + Note that the yield values will still be zero, but the modifiers within the signal model will be copied + to the control model. This flag allows the contribution of the signal uncertainties in the nuisance covariance matrix, as shown in eq. :eq:`eq:hess`. .. note:: @@ -160,17 +160,17 @@ Validation ---------- Following the above example, we converted the full likelihood provided for ATLAS-SUSY-2019-08 analysis -into the ``"default_pdf.correlated_background"`` model (for details +into the ``"default_pdf.correlated_background"`` model (for details `see dedicated documentation `_). -The following results use all available channels for the control model while including the modifiers of the +The following results use all available channels for the control model while including the modifiers of the signal patchset within the control model. Postfit configuration has been used throughout the simulation. -The background yields and covariance matrix of the background-only model have been computed by generating -Five hundred samples from the full statistical model. Scan includes 67 randomly choosen points in +The background yields and covariance matrix of the background-only model have been computed by generating +Five hundred samples from the full statistical model. Scan includes 67 randomly choosen points in :math:`(m_{\tilde{\chi}^\pm_1/\tilde{\chi}^0_2},m_{\tilde{\chi}_1^0})` mass plane. -The following plot shows the observed exclusion limit comparison for the full statistical model and its simplified +The following plot shows the observed exclusion limit comparison for the full statistical model and its simplified version, mapped on the ``"default_pdf.correlated_background"`` model. Data points only include the -ones provided by the ATLAS collaboration within HEPData. +ones provided by the ATLAS collaboration within HEPData. .. image:: ./figs/atlas_susy_2019_08_simp_obs.png :align: center @@ -184,6 +184,6 @@ using the entire patch set provided by the collaboration. Acknowledgements ---------------- -This functionality has been discussed and requested during +This functionality has been discussed and requested during `8th (Re)interpretation Forum `_. -Thanks to Nicholas Wardle, Sabine Kraml and Wolfgang Waltenberger for the lively discussion. \ No newline at end of file +Thanks to Nicholas Wardle, Sabine Kraml and Wolfgang Waltenberger for the lively discussion. diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 774e7dd..10fa191 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -4,4 +4,4 @@ Tutorials .. toctree:: :maxdepth: 2 - tutorials/utils \ No newline at end of file + tutorials/utils diff --git a/setup.py b/setup.py index 67ca780..4f9ac48 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ from setuptools import setup, find_packages -with open("README.md", mode="r", encoding="utf-8") as f: +with open("README.md", encoding="utf-8") as f: long_description = f.read() -with open("src/spey_pyhf/_version.py", mode="r", encoding="UTF-8") as f: +with open("src/spey_pyhf/_version.py", encoding="UTF-8") as f: version = f.readlines()[-1].split()[-1].strip("\"'") requirements = ["pyhf==0.7.6", "spey>=0.1.9"] diff --git a/src/spey_pyhf/_version.py b/src/spey_pyhf/_version.py index 8dc4389..b12fd12 100644 --- a/src/spey_pyhf/_version.py +++ b/src/spey_pyhf/_version.py @@ -1,3 +1,3 @@ """Version of the spey - pyhf plugin""" -__version__ = "0.1.8" +__version__ = "0.1.9" diff --git a/src/spey_pyhf/data.py b/src/spey_pyhf/data.py index fad90d4..adcd415 100644 --- a/src/spey_pyhf/data.py +++ b/src/spey_pyhf/data.py @@ -3,7 +3,7 @@ import os from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import Dict, Iterator, List, Optional, Text, Tuple, Union +from typing import Dict, Iterator, List, Optional, Tuple, Union import numpy as np from spey import ExpectationType @@ -184,13 +184,13 @@ class FullStatisticalModelData(Base): """ signal_patch: List[Dict] - background_only_model: Union[Dict, Text] + background_only_model: Union[Dict, str] def __post_init__(self): if isinstance(self.background_only_model, str): if not os.path.isfile(self.background_only_model): raise FileNotFoundError(f"Can not find {self.background_only_model}") - with open(self.background_only_model, "r", encoding="uft-8") as f: + with open(self.background_only_model, encoding="uft-8") as f: self.background_only_model = json.load(f) interpreter = WorkspaceInterpreter(self.background_only_model) @@ -245,12 +245,12 @@ def __post_init__(self): } @property - def channels(self) -> Iterator[Text]: + def channels(self) -> Iterator[str]: """Return channel names""" return (ch["name"] for ch in self.background_only_model["channels"]) @property - def channel_properties(self) -> Iterator[Tuple[int, Text, int]]: + def channel_properties(self) -> Iterator[Tuple[int, str, int]]: """Returns an iterator for channel index, name and number of bins""" for idx, channel in enumerate(self.channels): yield idx, channel, self.workspace.channel_nbins[channel] diff --git a/src/spey_pyhf/helper_functions.py b/src/spey_pyhf/helper_functions.py index 694e060..214d569 100644 --- a/src/spey_pyhf/helper_functions.py +++ b/src/spey_pyhf/helper_functions.py @@ -1,6 +1,6 @@ """Helper function for creating and interpreting pyhf inputs""" import logging -from typing import Dict, Iterator, List, Optional, Text, Tuple, Union +from typing import Dict, Generator, List, Optional, Tuple, Union __all__ = ["WorkspaceInterpreter"] @@ -14,7 +14,7 @@ def __dir__(): log = logging.getLogger("Spey") -def remove_from_json(idx: int) -> Dict[Text, Text]: +def remove_from_json(idx: int) -> Dict[str, str]: """ Remove channel from the json file @@ -48,7 +48,7 @@ def add_to_json(idx: int, yields: List[float], modifiers: List[Dict]) -> Dict: } -def _default_modifiers(poi_name: Text) -> List[Dict]: +def _default_modifiers(poi_name: str) -> List[Dict]: """Retreive default modifiers""" return [ {"data": None, "name": "lumi", "type": "lumi"}, @@ -83,22 +83,22 @@ def __getitem__(self, item): return self.background_only_model[item] @property - def channels(self) -> Iterator[List[Text]]: + def channels(self) -> Generator[List[str]]: """Retreive channel names as iterator""" return (ch["name"] for ch in self["channels"]) @property - def poi_name(self) -> Dict[Text, Text]: + def poi_name(self) -> Dict[str, str]: """Retreive poi name per measurement""" return [(mes["name"], mes["config"]["poi"]) for mes in self["measurements"]] @property - def bin_map(self) -> Dict[Text, int]: + def bin_map(self) -> Dict[str, int]: """Get number of bins per channel""" return {ch["name"]: len(ch["samples"][0]["data"]) for ch in self["channels"]} @property - def expected_background_yields(self) -> Dict[Text, List[float]]: + def expected_background_yields(self) -> Dict[str, List[float]]: """Retreive expected background yields with respect to signal injection""" yields = {} undefined_channels = [] @@ -126,7 +126,7 @@ def expected_background_yields(self) -> Dict[Text, List[float]]: ) return yields - def guess_channel_type(self, channel_name: Text) -> Text: + def guess_channel_type(self, channel_name: str) -> str: """Guess the type of the channel as CR VR or SR""" if channel_name not in self.channels: raise ValueError(f"Unknown channel: {channel_name}") @@ -136,7 +136,7 @@ def guess_channel_type(self, channel_name: Text) -> Text: return "__unknown__" - def guess_CRVR(self) -> List[Text]: + def guess_CRVR(self) -> List[str]: """Retreive control and validation channel names by guess""" return [ name @@ -144,7 +144,7 @@ def guess_CRVR(self) -> List[Text]: if self.guess_channel_type(name) in ["CR", "VR"] ] - def get_channels(self, channel_index: Union[List[int], List[Text]]) -> List[Text]: + def get_channels(self, channel_index: Union[List[int], List[str]]) -> List[str]: """ Retreive channel names with respect to their index @@ -162,7 +162,7 @@ def get_channels(self, channel_index: Union[List[int], List[Text]]) -> List[Text ] def inject_signal( - self, channel: Text, data: List[float], modifiers: Optional[List[Dict]] = None + self, channel: str, data: List[float], modifiers: Optional[List[Dict]] = None ) -> None: """ Inject signal to the model @@ -204,7 +204,7 @@ def inject_signal( ) @property - def signal_per_channel(self) -> Dict[Text, List[float]]: + def signal_per_channel(self) -> Dict[str, List[float]]: """Return signal yields in each channel""" return self._signal_dict @@ -229,14 +229,14 @@ def make_patch(self) -> List[Dict]: patch = [] to_remove = [] for ich, channel in enumerate(self.channels): - if channel in self._signal_dict: + if channel in self._to_remove: + to_remove.append(remove_from_json(ich)) + elif channel in self._signal_dict: patch.append( add_to_json( ich, self._signal_dict[channel], self._signal_modifiers[channel] ) ) - elif channel in self._to_remove: - to_remove.append(remove_from_json(ich)) else: log.warning(f"Undefined channel in the patch set: {channel}") @@ -255,7 +255,7 @@ def add_patch(self, signal_patch: List[Dict]) -> None: signal_patch=signal_patch, return_remove_list=True ) - def remove_channel(self, channel_name: Text) -> None: + def remove_channel(self, channel_name: str) -> None: """ Remove channel from the likelihood @@ -275,7 +275,7 @@ def remove_channel(self, channel_name: Text) -> None: ) @property - def remove_list(self) -> List[Text]: + def remove_list(self) -> List[str]: """ Channels to be removed from the model @@ -287,8 +287,8 @@ def remove_list(self) -> List[Text]: def patch_to_map( self, signal_patch: List[Dict], return_remove_list: bool = False ) -> Union[ - Tuple[Dict[Text, Dict], Dict[Text, Dict], List[Text]], - Tuple[Dict[Text, Dict], Dict[Text, Dict]], + Tuple[Dict[str, Dict], Dict[str, Dict], List[str]], + Tuple[Dict[str, Dict], Dict[str, Dict]], ]: """ Convert JSONPatch into signal map diff --git a/src/spey_pyhf/interface.py b/src/spey_pyhf/interface.py index 868d3db..3c1f85c 100644 --- a/src/spey_pyhf/interface.py +++ b/src/spey_pyhf/interface.py @@ -67,15 +67,15 @@ class PyhfInterface(BackendBase): and ``data`` are in ``JSON`` format. """ - name: Text = "pyhf.base" + name: str = "pyhf.base" """Name of the backend""" - version: Text = __version__ + version: str = __version__ """Version of the backend""" - author: Text = "SpeysideHEP" + author: str = "SpeysideHEP" """Author of the backend""" - spey_requires: Text = ">=0.1.9,<0.2.0" + spey_requires: str = ">=0.1.9,<0.2.0" """Spey version required for the backend""" - doi: List[Text] = ["10.5281/zenodo.1169739", "10.21105/joss.02823"] + doi: List[str] = ["10.5281/zenodo.1169739", "10.21105/joss.02823"] """Citable DOI for the backend""" __slots__ = ["_model", "manager"] @@ -309,15 +309,15 @@ class UncorrelatedBackground(PyhfInterface): absolute_uncertainties (``List[float]``): absolute uncertainties on the background """ - name: Text = "pyhf.uncorrelated_background" + name: str = "pyhf.uncorrelated_background" """Name of the backend""" - version: Text = __version__ + version: str = __version__ """Version of the backend""" - author: Text = "SpeysideHEP" + author: str = "SpeysideHEP" """Author of the backend""" - spey_requires: Text = PyhfInterface.spey_requires + spey_requires: str = PyhfInterface.spey_requires """Spey version required for the backend""" - doi: List[Text] = PyhfInterface.doi + doi: List[str] = PyhfInterface.doi """Citable DOI for the backend""" def __init__( @@ -396,21 +396,21 @@ class FullStatisticalModel(PyhfInterface): >>> statistical_model.exclusion_confidence_level() # [0.9474850259721279] """ - name: Text = "pyhf" + name: str = "pyhf" """Name of the backend""" - version: Text = __version__ + version: str = __version__ """Version of the backend""" - author: Text = "SpeysideHEP" + author: str = "SpeysideHEP" """Author of the backend""" - spey_requires: Text = PyhfInterface.spey_requires + spey_requires: str = PyhfInterface.spey_requires """Spey version required for the backend""" - doi: List[Text] = PyhfInterface.doi + doi: List[str] = PyhfInterface.doi """Citable DOI for the backend""" def __init__( self, signal_patch: Dict, - background_only_model: Union[Text, Dict], + background_only_model: Union[str, Dict], ): super().__init__() self._model = FullStatisticalModelData(signal_patch, background_only_model) diff --git a/src/spey_pyhf/manager.py b/src/spey_pyhf/manager.py index 0a54bd3..b1bc301 100644 --- a/src/spey_pyhf/manager.py +++ b/src/spey_pyhf/manager.py @@ -1,7 +1,7 @@ """Manager for pyhf integration""" import importlib import logging -from typing import Callable, List, Text +from collections.abc import Callable from spey.system.exceptions import MethodNotAvailable @@ -19,7 +19,7 @@ def __init__(self): self.shim = importlib.import_module("pyhf.optimize.common").shim - def __repr__(self) -> Text: + def __repr__(self) -> str: return ( f"pyhfManager(pyhf_backend='{self.backend}'," + f" available_backends={self.available_backends})" @@ -34,7 +34,7 @@ def grad_available(self) -> bool: return self.backend != "numpy" @property - def available_backends(self) -> List[Text]: + def available_backends(self) -> list[str]: """ Retreive the names of available backends @@ -47,12 +47,12 @@ def available_backends(self) -> List[Text]: ] @property - def backend(self) -> Text: + def backend(self) -> str: """Retreive current backend name""" return PyhfManager.pyhf.tensorlib.name @backend.setter - def backend(self, backend: Text) -> None: + def backend(self, backend: str) -> None: """ Modify pyhf backend. diff --git a/src/spey_pyhf/simplify.py b/src/spey_pyhf/simplify.py index 0600861..c55848d 100644 --- a/src/spey_pyhf/simplify.py +++ b/src/spey_pyhf/simplify.py @@ -164,13 +164,13 @@ class Simplify(spey.ConverterBase): >>> # "default_pdf.correlated_background" """ - name: Text = "pyhf.simplify" + name: str = "pyhf.simplify" """Name of the backend""" - version: Text = __version__ + version: str = __version__ """Version of the backend""" - author: Text = "SpeysideHEP" + author: str = "SpeysideHEP" """Author of the backend""" - spey_requires: Text = ">=0.1.5,<0.2.0" + spey_requires: str = ">=0.1.5,<0.2.0" """Spey version required for the backend""" def __call__( @@ -183,9 +183,9 @@ def __call__( "default_pdf.effective_sigma", ] = "default_pdf.correlated_background", number_of_samples: int = 1000, - control_region_indices: Optional[Union[List[int], List[Text]]] = None, + control_region_indices: Optional[Union[List[int], List[str]]] = None, include_modifiers_in_control_model: bool = False, - save_model: Optional[Text] = None, + save_model: Optional[str] = None, ) -> Union[CorrelatedBackground, ThirdMomentExpansion, EffectiveSigma]: assert statistical_model.backend_type == "pyhf", (