diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index ca3a1e0..0000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,24 +0,0 @@ -engines: - duplication: - enabled: true - config: - languages: - - python - fixme: - enabled: true - radon: - enabled: true - config: - python_version: 3 -ratings: - paths: - - "**.py" -exclude_paths: - - tests/ - - docs/ - - build/ - - dist/ - - legacy/ -checks: - argument-count: - enabled: false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3928304..8f72038 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -74,7 +74,17 @@ repos: - id: upgrade-type-hints args: [ '--futures=true' ] - - repo: https://github.com/psf/black - rev: 24.3.0 + - repo: https://github.com/MarcoGorelli/auto-walrus + rev: v0.2.2 hooks: - - id: black + - id: auto-walrus + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.3.5" + hooks: + - id: ruff + types_or: [ python, pyi, jupyter ] + args: [ --fix, --unsafe-fixes, --show-fixes , --line-length=120] + # Run the formatter. + - id: ruff-format + types_or: [ python, pyi, jupyter ] diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..82e2b5a --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,23 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.12" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +formats: [ ] + +python: + install: + - requirements: requirements_dev.txt + - requirements: requirements.txt + - method: pip + path: . diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index e7a075c..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,30 +0,0 @@ -checks: - python: - code_rating: true - duplicate_code: true -build: - environment: - python: '3.7.1' - dependencies: - # Runs before inferred commands - before: - - pip install -r requirements_dev.txt - nodes: - analysis: - project_setup: - override: - - 'true' - tests: - override: - - py-scrutinizer-run - - command: pylint-run - use_website_config: true - environment: - node: - version: 6.0.0 - tests: true -filter: - excluded_paths: - - '/tests/*' - dependency_paths: - - 'lib/*' diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css new file mode 100644 index 0000000..f1729be --- /dev/null +++ b/docs/_static/css/custom.css @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 zfit + */ + +/*pydata-sphinx-theme provides some css variables for customizing the look of the theme.*/ +/*See a list of supported css variables at*/ +/*https://github.com/pydata/pydata-sphinx-theme/blob/master/pydata_sphinx_theme/static/css/theme.css*/ +html[data-theme="light"] { + /*--pst-color-primary: #080c80 !important;*/ + --pst-color-primary: #D35827; + --pst-color-secondary: #27bcd3; + --pst-color-inline-code: #1d54e2; + /*--pst-color-target: yellow;*/ + + + /*Here we use css directly because for these attributes there exist no css variables defined by pydata-sphinx-theme.*/ + /*See https://github.com/pydata/pydata-sphinx-theme/issues/353 for possible changes in the future.*/ + + --pst-color-navbar-link: 255, 255, 255; + --pst-color-navbar-link-hover: 203, 86, 40; + --pst-color-navbar-link-active: 203, 86, 40; +} + +html[data-theme="dark"] { + /*--pst-color-primary: #080c80 !important;*/ + --pst-color-primary: #D35827; + --pst-color-secondary: #27bcd3; + --pst-color-inline-code: #1d54e2; + /*--pst-color-target: yellow;*/ + + --pst-color-navbar-link: 255, 255, 255; + --pst-color-navbar-link-hover: 203, 86, 40; + --pst-color-navbar-link-active: 203, 86, 40; +} + +i.fa-github-square:before { + color: #ffffffff !important; +} diff --git a/docs/api/static/zfit_physics.pdf.rst b/docs/api/static/zfit_physics.pdf.rst new file mode 100644 index 0000000..8c4d3c1 --- /dev/null +++ b/docs/api/static/zfit_physics.pdf.rst @@ -0,0 +1,7 @@ +pdf +=== + +.. automodule:: zfit_physics.pdf + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/tools/change_headline.py b/docs/api/tools/change_headline.py index 272dd4e..f62f101 100644 --- a/docs/api/tools/change_headline.py +++ b/docs/api/tools/change_headline.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import argparse +from pathlib import Path parser = argparse.ArgumentParser(description="replace first two line") @@ -7,15 +10,13 @@ n_files = 0 for rest_file in parsed_args.files: - with open(rest_file) as f: + with Path(rest_file).open() as f: first_word = f.readline().strip().split()[0] if "." not in first_word: continue replacement = first_word.split(".")[-1] underline = f.readline()[0] * len(replacement) lower_file = f.read() - with open(rest_file, "w") as f: + with Path(rest_file).open("w") as f: f.write("\n".join((replacement, underline, lower_file))) n_files += 1 - -print(f"finished successfully parsing {n_files} files") diff --git a/docs/conf.py b/docs/conf.py index 8bc6913..94f2f3c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,12 +17,12 @@ # -- Project information ----------------------------------------------------- -import os -import sys +from __future__ import annotations -import sphinx_bootstrap_theme +import sys +from pathlib import Path -sys.path.insert(0, os.path.abspath("..")) +sys.path.insert(0, str(Path("..").resolve())) import zfit_physics @@ -32,7 +32,7 @@ author = zfit_physics.__author__ # The short X.Y version -version = zfit_physics.__version__ +version = zfit_physics.__version__.split("+")[0] # The full version, including alpha/beta/rc tags release = zfit_physics.__version__ @@ -45,19 +45,36 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. +# +needs_sphinx = "3.0.0" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ "sphinx.ext.autodoc", - "sphinx.ext.doctest", + "sphinx.ext.napoleon", + "sphinx_autodoc_typehints", + # sphinx_autodoc_typehints must be imported after napoleon to properly work. + # See https://github.com/agronholm/sphinx-autodoc-typehints/issues/15 + "jupyter_sphinx", + "sphinx.ext.autosummary", + "sphinx.ext.viewcode", "sphinx.ext.intersphinx", - "sphinx.ext.todo", + "sphinxcontrib.images", "sphinx.ext.coverage", "sphinx.ext.mathjax", - "sphinx.ext.ifconfig", - "sphinx.ext.viewcode", "sphinx.ext.githubpages", - "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx_copybutton", + "sphinxcontrib.youtube", + "sphinx_panels", + "seed_intersphinx_mapping", + "myst_nb", + "sphinx_togglebutton", ] +panels_add_bootstrap_css = False # for sphinx_panel, use custom css from theme, not bootstrap + using_numpy_style = False # False -> google style # Napoleon settings (convert numpy/google docstrings to proper ReST @@ -73,6 +90,36 @@ napoleon_use_param = True napoleon_use_rtype = True +# -- sphinx_autodoc_typehints settings --------------------------------------------- + +# if True, set typing.TYPE_CHECKING to True to enable “expensive” typing imports +set_type_checking_flag = True +# if True, class names are always fully qualified (e.g. module.for.Class). If False, just the class +# name displays (e.g. Class) +typehints_fully_qualified = False +# (default: False): If False, do not add ktype info for undocumented parameters. If True, add stub documentation for +# undocumented parameters to be able to add type info. +always_document_param_types = False +# (default: True): If False, never add an :rtype: directive. If True, add the :rtype: directive if no existing :rtype: +# is found. +typehints_document_rtype = True + +# -- autodoc settings --------------------------------------------- + +# also doc __init__ docstrings +autoclass_content = "both" +autodoc_member_order = "bysource" +autodoc_default_options = { + "show-inheritance": True, + "inherited-members": True, +} +autodoc_inherit_docstrings = False + +# -- autosummary settings --------------------------------------------- + +autosummary_generate = True +autosummary_generate_overwrite = True + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -84,6 +131,7 @@ # source_suffix = ['.rst', '.md'] source_suffix = ".rst" + # The master toctree document. master_doc = "index" @@ -108,80 +156,47 @@ # a list of builtin themes. # -html_theme = "bootstrap" -html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() +# -- Options for HTML output ------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# + +html_theme = "pydata_sphinx_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # +html_css_files = [ + "css/custom.css", +] + +# Theme options are theme-specific and customize the look and feel of a +# theme further. + html_theme_options = { - # Navigation bar title. (Default: ``project`` value) - "navbar_title": "zfit", - # Tab name for entire site. (Default: "Site") - # 'navbar_site_name': "Docs", - # 'navbar_site_name': "Overview", - # A list of tuples containing pages or urls to link to. - # Valid tuples should be in the following forms: - # (name, page) # a link to a page - # (name, "/aa/bb", 1) # a link to an arbitrary relative url - # (name, "http://example.com", True) # arbitrary absolute url - # Note the "1" or "True" value above as the third argument to indicate - # an arbitrary url. - "navbar_links": [ - ("Getting started", "getting_started"), - ("Amplitude", "amplitude"), - # ("Parameter", "parameter"), - # ("Model", "model"), - # ("Data", "data"), - # ("Loss", "loss"), - # ("Minimize", "minimize"), - ("API", "API"), - # ("Link", "http://example.com", True), - ], - # Render the next and previous page links in navbar. (Default: true) - "navbar_sidebarrel": False, - # Render the current pages TOC in the navbar. (Default: true) - "navbar_pagenav": False, - # Tab name for the current pages TOC. (Default: "Page") - # 'navbar_pagenav_name': "Page", - # Global TOC depth for "site" navbar tab. (Default: 1) - # Switching to -1 shows all levels. - "globaltoc_depth": 1, - # Include hidden TOCs in Site navbar? - # - # Note: If this is "false", you cannot have mixed ``:hidden:`` and - # non-hidden ``toctree`` directives in the same page, or else the build - # will break. - # - # Values: "true" (default) or "false" - "globaltoc_includehidden": "true", - # HTML navbar class (Default: "navbar") to attach to
element. - # For black navbar, do "navbar navbar-inverse" - # 'navbar_class': "navbar navbar-inverse", - "navbar_class": "navbar", - # Fix navigation bar to top of page? - # Values: "true" (default) or "false" - "navbar_fixed_top": "true", - # Location of link to source. - # Options are "nav" (default), "footer" or anything else to exclude. - # 'source_link_position': "nav", - "source_link_position": False, - # Bootswatch (http://bootswatch.com/) theme. - # - # Options are nothing (default) or the name of a valid theme - # such as "cosmo" or "sandstone". - # - # The set of valid themes depend on the version of Bootstrap - # that's used (the next config option). - # - # Currently, the supported themes are: - # - Bootstrap 2: https://bootswatch.com/2 - # - Bootstrap 3: https://bootswatch.com/3 - "bootswatch_theme": "flatly", - # Choose Bootstrap version. - # Values: "3" (default) or "2" (in quotes) - "bootstrap_version": "4", + "logo": { + "image_light": "images/zfit-logo_400x168.png", + "image_dark": "images/zfit-logo-light_400x168.png", + }, + "github_url": "https://github.com/zfit/zfit", + "use_edit_page_button": True, + "navigation_depth": 3, + "search_bar_text": "Search zfit...", + "navigation_with_keys": True, + "search_bar_position": "sidebar", + "icon_links": [{}], # temporary fix for https://github.com/pydata/pydata-sphinx-theme/issues/1220 + # "repository_url": "https://github.com/zfit/zfit", # adding jupyter book somehow? + # "repository_branch": "develop", + # "path_to_docs": "docs", +} + +html_context = { + "github_user": "zfit", + "github_repo": "zfit", + "github_version": "develop", + "doc_path": "docs", } # Add any paths that contain custom static files (such as style sheets) here, @@ -274,7 +289,30 @@ # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"https://docs.python.org/": None} +# cross reference +default_role = "py:obj" +primary_domain = "py" +# nitpicky = True # warn if cross-references are missing +# nitpick_ignore = [ +# ("py:class", "tensorflow.keras.losses.Loss"), +# ] +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + # 'numdifftools': ('https://numdifftools.readthedocs.io/en/latest/index.html', None), + "tensorflow": ( + "https://www.tensorflow.org/api_docs/python", + "https://raw.githubusercontent.com/GPflow/tensorflow-intersphinx/master/tf2_py_objects.inv", + ), + "tensorflow_probability": ( + "https://www.tensorflow.org/probability/api_docs/python", + " https://raw.githubusercontent.com/GPflow/tensorflow-intersphinx/master/tfp_py_objects.inv", + ), + "uproot": ("https://uproot.readthedocs.io/en/latest/", None), + "python": ("https://docs.python.org/3", None), + "matplotlib": ("https://matplotlib.org/stable/", None), + "pandas": ("https://pandas.pydata.org/docs/", None), + "numpy": ("https://numpy.org/doc/stable/", None), +} # -- Options for todo extension ---------------------------------------------- diff --git a/docs/images/scikit-hep-logo_168x168.png b/docs/images/scikit-hep-logo_168x168.png index 2921a3b..1e30811 100644 Binary files a/docs/images/scikit-hep-logo_168x168.png and b/docs/images/scikit-hep-logo_168x168.png differ diff --git a/docs/images/zfit-favicon.png b/docs/images/zfit-favicon.png new file mode 100644 index 0000000..37fa196 Binary files /dev/null and b/docs/images/zfit-favicon.png differ diff --git a/docs/images/zfit-logo-light_400x168.png b/docs/images/zfit-logo-light_400x168.png new file mode 100644 index 0000000..c8a41a4 Binary files /dev/null and b/docs/images/zfit-logo-light_400x168.png differ diff --git a/docs/images/zfit-logo_400x168.png b/docs/images/zfit-logo_400x168.png new file mode 100644 index 0000000..8d54e39 Binary files /dev/null and b/docs/images/zfit-logo_400x168.png differ diff --git a/docs/images/zfit-logo_57x24.png b/docs/images/zfit-logo_57x24.png new file mode 100644 index 0000000..88b2f39 Binary files /dev/null and b/docs/images/zfit-logo_57x24.png differ diff --git a/docs/images/zfit-logo_hires.png b/docs/images/zfit-logo_hires.png new file mode 100644 index 0000000..a2d0e0c Binary files /dev/null and b/docs/images/zfit-logo_hires.png differ diff --git a/docs/images/zfit-logo_veryhires.png b/docs/images/zfit-logo_veryhires.png new file mode 100644 index 0000000..5465d34 Binary files /dev/null and b/docs/images/zfit-logo_veryhires.png differ diff --git a/docs/images/zfit-vector.svg b/docs/images/zfit-vector.svg new file mode 100644 index 0000000..0517765 --- /dev/null +++ b/docs/images/zfit-vector.svg @@ -0,0 +1 @@ + diff --git a/docs/images/zfit_workflow_v1.png b/docs/images/zfit_workflow_v1.png index d2ef943..42ebaae 100644 Binary files a/docs/images/zfit_workflow_v1.png and b/docs/images/zfit_workflow_v1.png differ diff --git a/docs/images/zfit_workflow_v2.png b/docs/images/zfit_workflow_v2.png new file mode 100644 index 0000000..2048c8d Binary files /dev/null and b/docs/images/zfit_workflow_v2.png differ diff --git a/docs/index.rst b/docs/index.rst index 3cdbb62..7dd522f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,20 +1,25 @@ -.. zfit-physics documentation master file, created by - sphinx-quickstart on Sat Mar 30 23:00:08 2019. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. -Welcome to zfit-physics's documentation! -======================================== +Welcome to zfit-physics +======================= -.. toctree:: - :maxdepth: 2 - :caption: Contents: +zfit-physics is a package that provides physics-related functionality to zfit. It is not a standalone package but requires `zfit `_ to be installed. + +It can be installed via pip: + +.. code-block:: bash + + pip install zfit-physics +or via conda: +.. code-block:: bash -Indices and tables -================== + conda install -c conda-forge zfit-physics + +PDF documentation +----------------- + +.. toctree:: + :maxdepth: 2 -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + api/static/zfit_physics.pdf diff --git a/pyproject.toml b/pyproject.toml index 3c8fe9e..c89b8a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,19 +8,56 @@ requires = [ build-backend = "setuptools.build_meta" -[tool.black] +[tool.ruff] +#src = ["src"] line-length = 120 -include = '\.pyi?$' -exclude = ''' -/( - \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist -)/ -''' +exclude = [ + ".tox/*", + "*/test*", + "*/__init__.py", + "*/_version.py", +] +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "NPY", # NumPy specific rules + "PD", # pandas-vet +] +ignore = [ + "UP007", # type annotation upgrade, breaks pydantic for Python 3.9 (remove once above) + "PLR09", # Too many <...> + "PLR2004", # Magic value used in comparison + "ISC001", # Conflicts with formatter + "RET505", # This is sometimes wanted, protets against accidental intendation + "PD901", # "avoid using `df[...].values`" -> no, this is a very good name if there is only one df + "PD011", # "replace `df[...].values` with `df[...].to_numpy()`" -> not yet, it's not deprecated. + # Prefer to have a single way to access the data if we don't care about whether it's a numpy array or not. + "PLW0603", # updating global variables with a function is bad, but we use it for + "PLW2901", # "for loop overwritten by assignment" -> we use this to update the loop variable + "PD013", # "melt over stack": df function, but triggers on tensors + "NPY002", # "Use rnd generator in numpy" -> we use np.random for some legacy stuff but do use the new one where we can + +] +isort.required-imports = ["from __future__ import annotations"] + +[tool.ruff.lint.per-file-ignores] +"tests/**" = ["T20"] +"noxfile.py" = ["T20"] diff --git a/requirements.txt b/requirements.txt index 93185ed..0fde880 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -zfit>=0.12 +zfit>=0.20 diff --git a/requirements_dev.txt b/requirements_dev.txt index 03c364d..89542ff 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -2,15 +2,26 @@ bumpversion>=0.5.3 coverage>=4.5.1 coverage>=4.5.1 flake8>=3.5.0 +jupyter-sphinx +myst-nb numba-stats @ git+https://github.com/HDembinski/numba-stats.git # CMSShape not yet released (expected 1.8.0) pip>=9.0.1 pre-commit +pydata-sphinx-theme>=0.9 # new dark theme configuration pytest>=3.4.2 pytest-cov pytest-rerunfailures>=6 pytest-runner>=2.11.1 -Sphinx>=1.7.1 -sphinx_bootstrap_theme +seed_intersphinx_mapping +setupext-janitor +Sphinx>=3.5.4 +sphinx-autodoc-typehints +sphinx-copybutton +sphinx-panels +sphinx_togglebutton +sphinxcontrib-applehelp<1.0.8 # needs sphinx>=0.5, why are we still stuck at <0.5? +sphinxcontrib-images +sphinxcontrib-youtube>=1.0.0,<1.2.0 tox>=2.9.1 twine>=1.10.0 twine diff --git a/setup.py b/setup.py index cfc6287..25d9a02 100644 --- a/setup.py +++ b/setup.py @@ -1,19 +1,19 @@ -#!/usr/bin/env python - """The setup script.""" -import os -from setuptools import find_packages, setup +from __future__ import annotations -here = os.path.abspath(os.path.dirname(__file__)) +from pathlib import Path + +from setuptools import find_packages, setup -with open(os.path.join(here, "requirements.txt"), encoding="utf-8") as requirements_file: +here = Path(__file__).parent.resolve() +with Path(here / "requirements.txt").open(encoding="utf-8") as requirements_file: requirements = requirements_file.read().splitlines() -with open(os.path.join(here, "requirements_dev.txt"), encoding="utf-8") as requirements_dev_file: +with Path(here / "requirements_dev.txt").open(encoding="utf-8") as requirements_dev_file: dev_requirements = requirements_dev_file.read().splitlines() -with open(os.path.join(here, "README.rst"), encoding="utf-8") as readme_file: +with Path(here / "README.rst").open(encoding="utf-8") as readme_file: readme = readme_file.read() setup( diff --git a/tests/conftest.py b/tests/conftest.py index d407136..dc91bb7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import pytest @@ -6,7 +8,7 @@ @pytest.fixture(autouse=True) -def setup_teardown(): +def _setup_teardown(): import zfit old_chunksize = zfit.run.chunking.max_n_points @@ -14,7 +16,7 @@ def setup_teardown(): old_graph_mode = zfit.run.get_graph_mode() old_autograd_mode = zfit.run.get_autograd_mode() - for m in sys.modules.keys(): + for m in sys.modules: if m not in init_modules: del sys.modules[m] @@ -32,7 +34,7 @@ def setup_teardown(): zfit.run.chunking.max_n_points = old_chunksize zfit.run.set_graph_mode(old_graph_mode) zfit.run.set_autograd_mode(old_autograd_mode) - for m in sys.modules.keys(): + for m in sys.modules: if m not in init_modules: del sys.modules[m] import gc diff --git a/tests/test_pdf_novosibirsk.py b/tests/test_pdf_novosibirsk.py index 27453ec..84750ca 100644 --- a/tests/test_pdf_novosibirsk.py +++ b/tests/test_pdf_novosibirsk.py @@ -2,7 +2,6 @@ import numpy as np import pytest -import ROOT import tensorflow as tf import zfit from zfit.core.testing import tester @@ -26,8 +25,9 @@ def create_novosibirsk(mu, sigma, lambd, limits): novosibirsk = zphys.pdf.Novosibirsk(mu=mu, sigma=sigma, lambd=lambd, obs=obs) return novosibirsk, obs - +@pytest.mark.skip def create_and_eval_root_novosibirsk_and_integral(mu, sigma, lambd, limits, x, lower, upper): + ROOT = pytest.importorskip("ROOT") obs = ROOT.RooRealVar("obs", "obs", *limits) peak = ROOT.RooRealVar("peak", "peak", mu) width = ROOT.RooRealVar("width", "width", sigma) diff --git a/zfit_physics/models/pdf_argus.py b/zfit_physics/models/pdf_argus.py index 2b0e155..082ebde 100644 --- a/zfit_physics/models/pdf_argus.py +++ b/zfit_physics/models/pdf_argus.py @@ -1,6 +1,6 @@ """ARGUS PDF (https://en.wikipedia.org/wiki/ARGUS_distribution)""" -from typing import Optional +from __future__ import annotations import numpy as np import tensorflow as tf @@ -42,8 +42,7 @@ def argus_func( m_frac = m / m0 m_factor = 1 - z.square(m_frac) - argus = m * z.pow(m_factor, p) * (z.exp(c * m_factor)) - return argus + return m * z.pow(m_factor, p) * (z.exp(c * m_factor)) class Argus(zfit.pdf.BasePDF): @@ -54,7 +53,7 @@ def __init__( c, p, name: str = "ArgusPDF", - extended: Optional[ztyping.ParamTypeInput] = None, + extended: ztyping.ParamTypeInput | None = None, ): r"""`ARGUS shape `_ describing the invariant mass of a particle in a continuous background. @@ -107,12 +106,11 @@ def uppergamma(s, x): @z.function(wraps="tensor") def argus_cdf_p_half_nonpositive(lim, c, m0): lim = tf.clip_by_value(lim, 0.0, m0) - cdf = tf.cond( + return tf.cond( tf.math.less(c, 0.0), lambda: argus_cdf_p_half_c_neg(lim=lim, c=c, m0=m0), lambda: argus_cdf_p_half_c_zero(lim=lim, c=c, m0=m0), ) - return cdf # Does not work, why? @@ -140,8 +138,7 @@ def argus_cdf_p_half_c_neg(lim, c, m0): def argus_cdf_p_half_c_zero(lim, c, m0): del c f1 = 1 - z.square(lim / m0) - cdf = -z.square(m0) / 3.0 * f1 * z.sqrt(f1) - return cdf + return -z.square(m0) / 3.0 * f1 * z.sqrt(f1) # TODO: add Faddeev function approximation @@ -158,6 +155,7 @@ def argus_integral_p_half_func(lower, upper, c, m0): def argus_integral_p_half(limits, params, model): + del model p = params["p"] if not isinstance(p, zfit.param.ConstantParameter) or not np.isclose(p.static_value, 0.5): raise zfit.exception.AnalyticIntegralNotImplementedError() @@ -169,8 +167,7 @@ def argus_integral_p_half(limits, params, model): lower, upper = limits.limit1d lower = z.convert_to_tensor(lower) upper = z.convert_to_tensor(upper) - integral = argus_integral_p_half_func(lower=lower, upper=upper, c=c, m0=m0) - return integral + return argus_integral_p_half_func(lower=lower, upper=upper, c=c, m0=m0) argus_integral_limits = zfit.Space(axes=(0,), limits=(zfit.Space.ANY_LOWER, zfit.Space.ANY_UPPER)) @@ -212,10 +209,8 @@ def argus_integral_p_half(limits, params, model): integral_expression = m * m_factor**p * (sp.exp(c * m_factor)) # integral_expression = (N * m * (1 - (m / m0) ** 2) ** p * sp.exp(c * (1 - (m / m0) ** 2))) integral = sp.integrate(integral_expression, m) - print(integral) func1 = sp.lambdify(integral.free_symbols, integral, "tensorflow") import inspect source = inspect.getsource(func1) - print(source) # sp.lambdify() diff --git a/zfit_physics/models/pdf_cmsshape.py b/zfit_physics/models/pdf_cmsshape.py index 196d40e..82f57a5 100644 --- a/zfit_physics/models/pdf_cmsshape.py +++ b/zfit_physics/models/pdf_cmsshape.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations import tensorflow as tf import zfit @@ -70,6 +70,7 @@ def cmsshape_integral(limits: ztyping.SpaceType, params: dict, model) -> tf.Tens Returns: The calculated integral. """ + del model lower, upper = limits.limit1d m = params["m"] beta = params["beta"] @@ -89,8 +90,8 @@ def __init__( gamma: ztyping.ParamTypeInput, obs: ztyping.ObsTypeInput, *, - extended: Optional[ztyping.ExtendedInputType] = None, - norm: Optional[ztyping.NormInputType] = None, + extended: ztyping.ExtendedInputType | None = None, + norm: ztyping.NormInputType | None = None, name: str = "CMSShape", ): """CMSShape PDF. diff --git a/zfit_physics/models/pdf_conv.py b/zfit_physics/models/pdf_conv.py index 2554508..eddbb5f 100644 --- a/zfit_physics/models/pdf_conv.py +++ b/zfit_physics/models/pdf_conv.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations import tensorflow as tf import tensorflow_probability as tfp @@ -19,7 +19,7 @@ def __init__( obs: ztyping.ObsTypeInput, ndraws: int = 20000, *, - extended: Optional[ztyping.ParamTypeInput] = None, + extended: ztyping.ParamTypeInput | None = None, name: str = "Convolution", experimental_pdf_normalized=False, ): @@ -39,9 +39,11 @@ def __init__( super().__init__(obs=obs, pdfs=[func, kernel], params={}, name=name, extended=extended) limits = self._check_input_limits(limits=limits) if limits.n_limits == 0: - raise exception.LimitsNotSpecifiedError("obs have to have limits to define where to integrate over.") + msg = "obs have to have limits to define where to integrate over." + raise exception.LimitsNotSpecifiedError(msg) if limits.n_limits > 1: - raise WorkInProgressError("Multiple Limits not implemented") + msg = "Multiple Limits not implemented" + raise WorkInProgressError(msg) # if not isinstance(func, zfit.pdf.BasePDF): # raise TypeError(f"func has to be a PDF, not {type(func)}") @@ -82,7 +84,8 @@ def _unnormalized_pdf(self, x): @zfit.supports(norm=True) @z.function - def _pdf(self, x, norm_range): + def _pdf(self, x, norm): + del norm if not self._experimental_pdf_normalized: raise FunctionNotImplementedError diff --git a/zfit_physics/models/pdf_cruijff.py b/zfit_physics/models/pdf_cruijff.py index 4619a47..86c2d9d 100644 --- a/zfit_physics/models/pdf_cruijff.py +++ b/zfit_physics/models/pdf_cruijff.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations import zfit from zfit import z @@ -35,8 +35,7 @@ def cruijff_pdf_func(x, mu, sigmal, alphal, sigmar, alphar): tleft / (1 + alphal * tleft), tright / (1 + alphar * tright), ) - value = znp.exp(-0.5 * exponent) - return value + return znp.exp(-0.5 * exponent) class Cruijff(zfit.pdf.BasePDF): @@ -51,9 +50,10 @@ def __init__( alphar: ztyping.ParamTypeInput, obs: ztyping.ObsTypeInput, *, - extended: Optional[ztyping.ExtendedInputType] = False, - norm: Optional[ztyping.NormInputType] = None, + extended: ztyping.ExtendedInputType | None = False, + norm: ztyping.NormInputType | None = None, name: str = "Cruijff", + label: str | None = None, ): """Cruijff PDF, a Gaussian with two width, left and right, and non-Gaussian tails. @@ -92,9 +92,10 @@ def __init__( or label of the PDF for better identification. Has no programmatical functional purpose as identification. |@docend:pdf.init.name| + label: |@doc:pdf.init.label| A human readable label to identify the PDF. |@docend:pdf.init.label| """ params = {"mu": mu, "sigmal": sigmal, "alphal": alphal, "sigmar": sigmar, "alphar": alphar} - super().__init__(obs=obs, params=params, extended=extended, norm=norm) + super().__init__(obs=obs, params=params, extended=extended, norm=norm, name=name, label=label) def _unnormalized_pdf(self, x): mu = self.params["mu"] diff --git a/zfit_physics/models/pdf_erfexp.py b/zfit_physics/models/pdf_erfexp.py index c948dbd..6fb1d10 100644 --- a/zfit_physics/models/pdf_erfexp.py +++ b/zfit_physics/models/pdf_erfexp.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations import tensorflow as tf import zfit @@ -49,9 +49,10 @@ def __init__( n: ztyping.ParamTypeInput, obs: ztyping.ObsTypeInput, *, - extended: Optional[ztyping.ExtendedInputType] = False, - norm: Optional[ztyping.NormInputType] = None, + extended: ztyping.ExtendedInputType | None = False, + norm: ztyping.NormInputType | None = None, name: str = "ErfExp", + label: str | None = None, ): """ErfExp PDF, the product of a complementary error function and an exponential function. @@ -86,9 +87,10 @@ def __init__( or label of the PDF for better identification. Has no programmatical functional purpose as identification. |@docend:pdf.init.name| + label: |@doc:pdf.init.label| A human readable label to identify the PDF. |@docend:pdf.init.label| """ params = {"mu": mu, "beta": beta, "gamma": gamma, "n": n} - super().__init__(obs=obs, params=params, extended=extended, norm=norm) + super().__init__(obs=obs, params=params, extended=extended, norm=norm, name=name, label=label) def _unnormalized_pdf(self, x): mu = self.params["mu"] diff --git a/zfit_physics/models/pdf_example.py b/zfit_physics/models/pdf_example.py index e1840e2..9ca304f 100644 --- a/zfit_physics/models/pdf_example.py +++ b/zfit_physics/models/pdf_example.py @@ -3,12 +3,17 @@ Create a module for each pdf that you add. """ +from __future__ import annotations + +import typing + import zfit class Example(zfit.pdf.ZPDF): - _PARAMS = ["param1"] + _PARAMS: typing.ClassVar = ["param1"] def _unnormalized_pdf(self, x): """Documentation here.""" - return [42.0] + x0 = x[0] + return [42.0 * x0] diff --git a/zfit_physics/models/pdf_kde.py b/zfit_physics/models/pdf_kde.py index 00693a0..5c02696 100644 --- a/zfit_physics/models/pdf_kde.py +++ b/zfit_physics/models/pdf_kde.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from collections import OrderedDict -from typing import Optional import tensorflow as tf import tensorflow_probability.python.distributions as tfd @@ -19,7 +20,7 @@ def __init__( obs: ztyping.ObsTypeInput, name: str = "GaussianKDE", *, - extended: Optional[ztyping.ParamTypeInput] = None, + extended: ztyping.ParamTypeInput | None = None, ): """Gaussian Kernel Density Estimation using Silverman's rule of thumb. @@ -31,21 +32,21 @@ def __init__( """ dtype = zfit.settings.ztypes.float if isinstance(data, zfit.core.interfaces.ZfitData): - raise WorkInProgressError("Currently, no dataset supported yet") + msg = "Currently, no dataset supported yet" + raise WorkInProgressError(msg) # size = data.nevents # dims = data.n_obs # with data. # data = data.value() # if data.weights is not None: - else: - if not isinstance(data, tf.Tensor): - data = z.convert_to_tensor(value=data) - data = z.to_real(data) + if not isinstance(data, tf.Tensor): + data = z.convert_to_tensor(value=data) + data = z.to_real(data) - shape_data = tf.shape(data) - size = tf.cast(shape_data[0], dtype=dtype) - dims = tf.cast(shape_data[-1], dtype=dtype) + shape_data = tf.shape(data) + size = tf.cast(shape_data[0], dtype=dtype) + dims = tf.cast(shape_data[-1], dtype=dtype) bandwidth = convert_to_container(bandwidth) # Bandwidth definition, use silverman's rule of thumb for nd @@ -56,19 +57,18 @@ def reshaped_kerner_factory(): # cov = tf.linalg.diag(cov_diag) # kernel prob output shape: (n,) # kernel = tfd.MultivariateNormalFullCovariance(loc=data, covariance_matrix=cov) - kernel = tfd.MultivariateNormalDiag(loc=data, scale_diag=cov_diag) + return tfd.MultivariateNormalDiag(loc=data, scale_diag=cov_diag) - return kernel # return tfd.Independent(kernel) # reshaped_kernel = kernel probs = tf.broadcast_to(1 / size, shape=(tf.cast(size, tf.int32),)) categorical = tfd.Categorical(probs=probs) # no grad -> no need to recreate - dist_kwargs = lambda: dict( - mixture_distribution=categorical, - components_distribution=reshaped_kerner_factory(), - ) + + def dist_kwargs(): + return {"mixture_distribution": categorical, "components_distribution": reshaped_kerner_factory()} + distribution = tfd.MixtureSameFamily # TODO lambda for params params = OrderedDict((f"bandwidth_{i}", h) for i, h in enumerate(bandwidth)) diff --git a/zfit_physics/models/pdf_novosibirsk.py b/zfit_physics/models/pdf_novosibirsk.py index ef00d58..e1206d4 100644 --- a/zfit_physics/models/pdf_novosibirsk.py +++ b/zfit_physics/models/pdf_novosibirsk.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations import numpy as np import tensorflow as tf @@ -58,6 +58,7 @@ def novosibirsk_integral(limits: ztyping.SpaceType, params: dict, model) -> tf.T Returns: The calculated integral. """ + del model lower, upper = limits.limit1d mu = params["mu"] sigma = params["sigma"] @@ -122,8 +123,8 @@ def __init__( lambd, obs, *, - extended: Optional[ztyping.ExtendedInputType] = False, - norm: Optional[ztyping.NormInputType] = None, + extended: ztyping.ExtendedInputType | None = False, + norm: ztyping.NormInputType | None = None, name: str = "Novosibirsk", ): """Novosibirsk PDF. diff --git a/zfit_physics/models/pdf_relbw.py b/zfit_physics/models/pdf_relbw.py index 47b20f4..fa2abeb 100644 --- a/zfit_physics/models/pdf_relbw.py +++ b/zfit_physics/models/pdf_relbw.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations import numpy as np import tensorflow as tf @@ -40,7 +40,7 @@ def __init__( gamma: ztyping.ParamTypeInput, obs: ztyping.ObsTypeInput, name: str = "RelativisticBreitWigner", - extended: Optional[ztyping.ParamTypeInput] = None, + extended: ztyping.ParamTypeInput | None = None, ): """Relativistic Breit-Wigner distribution. @@ -50,7 +50,7 @@ def __init__( m: the average value gamma: the width of the distribution """ - params = dict(m=m, gamma=gamma) + params = {"m": m, "gamma": gamma} super().__init__(obs=obs, params=params, name=name, extended=extended) def _unnormalized_pdf(self, x: tf.Tensor) -> tf.Tensor: @@ -116,8 +116,7 @@ def relbw_cdf_func(x, m, gamma): norm = z.to_complex(-1) ** (1.0 / 4.0) * k / (2.0 * alpha * m**3) cdf_ = shape * norm - cdf_ = z.to_real(cdf_) - return cdf_ + return z.to_real(cdf_) def relbw_integral(limits: ztyping.SpaceType, params: dict, model) -> tf.Tensor: @@ -131,6 +130,7 @@ def relbw_integral(limits: ztyping.SpaceType, params: dict, model) -> tf.Tensor: Returns: The calculated integral. """ + del model lower, upper = limits.rect_limits lower_cdf = relbw_cdf_func(x=lower, m=params["m"], gamma=params["gamma"]) upper_cdf = relbw_cdf_func(x=upper, m=params["m"], gamma=params["gamma"]) diff --git a/zfit_physics/models/pdf_tsallis.py b/zfit_physics/models/pdf_tsallis.py index ab14998..ece5f6c 100644 --- a/zfit_physics/models/pdf_tsallis.py +++ b/zfit_physics/models/pdf_tsallis.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations import tensorflow as tf import zfit @@ -30,7 +30,7 @@ def tsallis_pdf_func(x, m, t, n): msg = "n > 2 is required" raise ValueError(msg) elif run.numeric_checks: - tf.debugging.assert_greater(n, znp.asarray(2.0), message="n > 2 is required") + tf.debugging.assert_greater(n, znp.array(2.0), message="n > 2 is required") x = z.unstack_x(x) mt = znp.hypot(m, x) @@ -61,7 +61,7 @@ def tsallis_cdf_func(x, m, t, n): msg = "n > 2 is required" raise ValueError(msg) elif run.numeric_checks: - tf.debugging.assert_greater(n, znp.asarray(2.0), message="n > 2 is required") + tf.debugging.assert_greater(n, znp.asarray(2.0), "n > 2 is required") x = z.unstack_x(x) mt = znp.hypot(m, x) @@ -80,6 +80,7 @@ def tsallis_integral(limits: ztyping.SpaceType, params: dict, model) -> tf.Tenso Returns: The calculated integral. """ + del model lower, upper = limits._rect_limits_tf m = params["m"] t = params["t"] @@ -99,8 +100,8 @@ def __init__( n: ztyping.ParamTypeInput, obs: ztyping.ObsTypeInput, *, - extended: Optional[ztyping.ExtendedInputType] = None, - norm: Optional[ztyping.NormInputType] = None, + extended: ztyping.ExtendedInputType | None = None, + norm: ztyping.NormInputType | None = None, name: str = "Tsallis", ): """Tsallis-Hagedorn PDF. diff --git a/zfit_physics/pdf.py b/zfit_physics/pdf.py index eaa103e..8edd0a1 100644 --- a/zfit_physics/pdf.py +++ b/zfit_physics/pdf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .models.pdf_argus import Argus from .models.pdf_cmsshape import CMSShape from .models.pdf_cruijff import Cruijff diff --git a/zfit_physics/plot.py b/zfit_physics/plot.py deleted file mode 100644 index f4d67b1..0000000 --- a/zfit_physics/plot.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Simple plotting helpers. - -This module contains multiple helpers to plot a PDF. -""" - -# def plot1d(model, limits, npoints) diff --git a/zfit_physics/unstable/pdf.py b/zfit_physics/unstable/pdf.py index 508d29a..5877d39 100644 --- a/zfit_physics/unstable/pdf.py +++ b/zfit_physics/unstable/pdf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from ..models.pdf_conv import NumConvPDFUnbinnedV1 from ..models.pdf_kde import GaussianKDE