├── .all-contributorsrc ├── .github ├── dependabot.yml ├── matchers │ └── pylint.json └── workflows │ ├── cd.yml │ └── ci.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .zenodo.json ├── CITATION.cff ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── admin ├── dump_pdgid_to_corsika7.py └── dump_pdgid_to_lhcb.py ├── codecov.yml ├── docs ├── CHANGELOG.md ├── ParticleLogo.svg └── ParticleLogo300.png ├── environment.yml ├── notebooks └── ParticleDemo.ipynb ├── noxfile.py ├── pyproject.toml ├── src └── particle │ ├── __init__.py │ ├── __main__.py │ ├── _compat │ ├── __init__.py │ └── typing.py │ ├── converters │ ├── __init__.py │ ├── bimap.py │ ├── corsika.py │ ├── evtgen.py │ ├── geant.py │ ├── py.typed │ └── pythia.py │ ├── corsika │ ├── __init__.py │ └── corsika7id.py │ ├── data │ ├── README.rst │ ├── __init__.py │ ├── conversions.csv │ ├── mass_width_2008.fwf │ ├── mass_width_2008_ext.fwf │ ├── mass_width_2022.mcd │ ├── mass_width_2023.mcd │ ├── mass_width_2024.mcd │ ├── nuclei2020.csv │ ├── nuclei2022.csv │ ├── particle2022.csv │ ├── particle2023.csv │ ├── particle2024.csv │ ├── pdgid_to_corsika7id.csv │ ├── pdgid_to_evtgenname.csv │ ├── pdgid_to_geant3id.csv │ ├── pdgid_to_latexname.csv │ ├── pdgid_to_pythiaid.csv │ └── py.typed │ ├── exceptions.py │ ├── geant │ ├── __init__.py │ ├── geant3id.py │ └── py.typed │ ├── lhcb │ ├── __init__.py │ ├── converters.py │ ├── data │ │ ├── __init__.py │ │ ├── pdgid_to_lhcbname.csv │ │ └── py.typed │ ├── functions.py │ └── py.typed │ ├── particle │ ├── __init__.py │ ├── convert.py │ ├── enums.py │ ├── kinematics.py │ ├── literals.py │ ├── particle.py │ ├── py.typed │ ├── regex.py │ └── utilities.py │ ├── pdgid │ ├── __init__.py │ ├── functions.py │ ├── literals.py │ ├── pdgid.py │ └── py.typed │ ├── py.typed │ ├── pythia │ ├── __init__.py │ ├── py.typed │ └── pythiaid.py │ ├── shared_literals.py │ ├── typing.py │ └── version.pyi └── tests ├── __init__.py ├── conftest.py ├── converters ├── __init__.py ├── test_corsika.py └── test_maps.py ├── corsika ├── __init__.py └── test_corsika7id.py ├── data ├── README.rst └── test_PDG_mcd_file_duplicates.mcd ├── geant ├── __init__.py └── test_geant3id.py ├── lhcb └── test_lhcb_name.py ├── particle ├── __init__.py ├── test_convert.py ├── test_decfilenames.py ├── test_enums.py ├── test_generation.py ├── test_kinematics.py ├── test_literals.py ├── test_particle.py ├── test_performance.py └── test_utilities.py ├── pdgid ├── __init__.py ├── test_functions.py ├── test_literals.py └── test_pdgid.py ├── pythia ├── __init__.py └── test_pythiaid.py ├── test_module_apis.py └── test_package.py /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitType": "docs", 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "eduardo-rodrigues", 12 | "name": "Eduardo Rodrigues", 13 | "avatar_url": "https://avatars.githubusercontent.com/u/5013581?v=4", 14 | "profile": "http://cern.ch/eduardo.rodrigues", 15 | "contributions": [ 16 | "maintenance", 17 | "code", 18 | "doc" 19 | ] 20 | }, 21 | { 22 | "login": "henryiii", 23 | "name": "Henry Schreiner", 24 | "avatar_url": "https://avatars.githubusercontent.com/u/4616906?v=4", 25 | "profile": "http://iscinumpy.dev", 26 | "contributions": [ 27 | "maintenance", 28 | "code", 29 | "doc" 30 | ] 31 | }, 32 | { 33 | "login": "HDembinski", 34 | "name": "Hans Dembinski", 35 | "avatar_url": "https://avatars.githubusercontent.com/u/2631586?v=4", 36 | "profile": "https://github.com/HDembinski", 37 | "contributions": [ 38 | "code" 39 | ] 40 | }, 41 | { 42 | "login": "The-Ludwig", 43 | "name": "Ludwig Neste", 44 | "avatar_url": "https://avatars.githubusercontent.com/u/31670556?v=4", 45 | "profile": "https://ludwigneste.space", 46 | "contributions": [ 47 | "code", 48 | "doc" 49 | ] 50 | }, 51 | { 52 | "login": "tamasgal", 53 | "name": "Tamas Gal", 54 | "avatar_url": "https://avatars.githubusercontent.com/u/1730350?v=4", 55 | "profile": "http://www.tamasgal.com", 56 | "contributions": [ 57 | "code" 58 | ] 59 | }, 60 | { 61 | "login": "matthewfeickert", 62 | "name": "Matthew Feickert", 63 | "avatar_url": "https://avatars.githubusercontent.com/u/5142394?v=4", 64 | "profile": "http://www.matthewfeickert.com/", 65 | "contributions": [ 66 | "code" 67 | ] 68 | }, 69 | { 70 | "login": "JostMigenda", 71 | "name": "Jost Migenda", 72 | "avatar_url": "https://avatars.githubusercontent.com/u/16189747?v=4", 73 | "profile": "https://github.com/JostMigenda", 74 | "contributions": [ 75 | "doc" 76 | ] 77 | }, 78 | { 79 | "login": "jonas-eschle", 80 | "name": "Jonas Eschle", 81 | "avatar_url": "https://avatars.githubusercontent.com/u/17454848?v=4", 82 | "profile": "https://github.com/jonas-eschle", 83 | "contributions": [ 84 | "code" 85 | ] 86 | }, 87 | { 88 | "login": "chrisburr", 89 | "name": "Chris Burr", 90 | "avatar_url": "https://avatars.githubusercontent.com/u/5220533?v=4", 91 | "profile": "https://github.com/chrisburr", 92 | "contributions": [ 93 | "code" 94 | ] 95 | }, 96 | { 97 | "login": "admorris", 98 | "name": "Adam Morris", 99 | "avatar_url": "https://avatars.githubusercontent.com/u/15155249?v=4", 100 | "profile": "https://gitlab.cern.ch/users/admorris", 101 | "contributions": [ 102 | "code" 103 | ] 104 | }, 105 | { 106 | "login": "doronbehar", 107 | "name": "Doron Behar", 108 | "avatar_url": "https://avatars.githubusercontent.com/u/10998835?v=4", 109 | "profile": "http://doronbehar.com", 110 | "contributions": [ 111 | "doc" 112 | ] 113 | }, 114 | { 115 | "login": "APN-Pucky", 116 | "name": "Alexander Puck Neuwirth", 117 | "avatar_url": "https://avatars.githubusercontent.com/u/4533248?v=4", 118 | "profile": "https://github.com/APN-Pucky", 119 | "contributions": [ 120 | "code", 121 | "doc" 122 | ] 123 | }, 124 | { 125 | "login": "amanmdesai", 126 | "name": "Aman Desai", 127 | "avatar_url": "https://avatars.githubusercontent.com/u/98302868?v=4", 128 | "profile": "https://github.com/amanmdesai", 129 | "contributions": [ 130 | "code" 131 | ] 132 | }, 133 | { 134 | "login": "JOTELLECHEA", 135 | "name": "Jonathan Tellechea", 136 | "avatar_url": "https://avatars.githubusercontent.com/u/49012693?v=4", 137 | "profile": "http://jonathantellechea.com", 138 | "contributions": [ 139 | "doc" 140 | ] 141 | }, 142 | { 143 | "login": "redeboer", 144 | "name": "Remco de Boer", 145 | "avatar_url": "https://avatars.githubusercontent.com/u/29308176?v=4", 146 | "profile": "https://github.com/redeboer", 147 | "contributions": [ 148 | "code" 149 | ] 150 | }, 151 | { 152 | "login": "maxnoe", 153 | "name": "Maximilian Linhoff", 154 | "avatar_url": "https://avatars.githubusercontent.com/u/5488440?v=4", 155 | "profile": "https://github.com/maxnoe", 156 | "contributions": [ 157 | "code" 158 | ] 159 | } 160 | ], 161 | "contributorsPerLine": 7, 162 | "skipCi": true, 163 | "repoType": "github", 164 | "repoHost": "https://github.com", 165 | "projectName": "particle", 166 | "projectOwner": "scikit-hep" 167 | } 168 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "monthly" 8 | groups: 9 | actions: 10 | patterns: 11 | - "*" 12 | -------------------------------------------------------------------------------- /.github/matchers/pylint.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "severity": "warning", 5 | "pattern": [ 6 | { 7 | "regexp": "^([^:]+):(\\d+):(\\d+): ([A-DF-Z]\\d+): \\033\\[[\\d;]+m([^\\033]+).*$", 8 | "file": 1, 9 | "line": 2, 10 | "column": 3, 11 | "code": 4, 12 | "message": 5 13 | } 14 | ], 15 | "owner": "pylint-warning" 16 | }, 17 | { 18 | "severity": "error", 19 | "pattern": [ 20 | { 21 | "regexp": "^([^:]+):(\\d+):(\\d+): (E\\d+): \\033\\[[\\d;]+m([^\\033]+).*$", 22 | "file": 1, 23 | "line": 2, 24 | "column": 3, 25 | "code": 4, 26 | "message": 5 27 | } 28 | ], 29 | "owner": "pylint-error" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: CD 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | release: 9 | types: 10 | - published 11 | 12 | jobs: 13 | dist: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Build wheel and SDist 21 | run: pipx run build 22 | 23 | - uses: actions/upload-artifact@v4 24 | with: 25 | path: dist/* 26 | 27 | - name: Check metadata 28 | run: pipx run twine check --strict dist/* 29 | 30 | zipapp: 31 | name: ZipApp 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v4 35 | with: 36 | fetch-depth: 0 37 | 38 | - uses: wntrblm/nox@2025.05.01 39 | with: 40 | python-versions: "3.8" 41 | 42 | - name: Make ZipApp 43 | run: nox -s zipapp 44 | 45 | - uses: actions/upload-artifact@v4 46 | with: 47 | name: zipapp 48 | path: particle.pyz 49 | 50 | 51 | publish: 52 | needs: [dist] 53 | runs-on: ubuntu-latest 54 | if: github.event_name == 'release' && github.event.action == 'published' 55 | environment: 56 | name: pypi 57 | url: https://pypi.org/p/particle 58 | permissions: 59 | id-token: write 60 | attestations: write 61 | 62 | steps: 63 | - uses: actions/download-artifact@v4 64 | with: 65 | name: artifact 66 | path: dist 67 | 68 | - name: Generate artifact attestation for sdist and wheel 69 | uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0 70 | with: 71 | subject-path: "dist/particle*" 72 | 73 | - name: Upload package to PyPI 74 | uses: pypa/gh-action-pypi-publish@release/v1 75 | with: 76 | attestations: true 77 | 78 | - uses: actions/download-artifact@v4 79 | with: 80 | name: zipapp 81 | path: zipapp 82 | 83 | - name: Upload ZipApp 84 | uses: softprops/action-gh-release@v2 85 | with: 86 | files: ./zipapp/particle.pyz 87 | 88 | - name: Generate artifact attestation for zipapp 89 | uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0 90 | with: 91 | subject-path: zipapp/particle.pyz 92 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | pre-commit: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | - uses: actions/setup-python@v5 22 | with: 23 | python-version: "3.x" 24 | - uses: pre-commit/action@v3.0.1 25 | with: 26 | extra_args: --all-files --hook-stage manual 27 | - name: PyLint 28 | run: | 29 | echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json" 30 | pipx run nox -s pylint 31 | 32 | checks: 33 | name: Check ${{ matrix.os }} 🐍 ${{ matrix.python-version }} 34 | runs-on: ${{ matrix.os }} 35 | strategy: 36 | fail-fast: false 37 | matrix: 38 | os: [ubuntu-latest] 39 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 40 | include: 41 | - {os: macos-13, python-version: '3.8'} 42 | - {os: macos-13, python-version: '3.13'} 43 | - {os: windows-latest, python-version: '3.8'} 44 | - {os: windows-latest, python-version: '3.13'} 45 | 46 | steps: 47 | - uses: actions/checkout@v4 48 | with: 49 | fetch-depth: 0 50 | 51 | - uses: actions/setup-python@v5 52 | with: 53 | python-version: ${{ matrix.python-version }} 54 | allow-prereleases: true 55 | 56 | - uses: astral-sh/setup-uv@v6 57 | 58 | - name: Test package 59 | run: uvx nox -s tests --force-python=${{ matrix.python-version }} 60 | 61 | - name: Test coverage with Codecov 62 | uses: codecov/codecov-action@v5 63 | env: 64 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 65 | 66 | - name: Test docstrings with doctest 67 | if: runner.os == 'Linux' && matrix.python-version == '3.12' 68 | run: uvx nox -s tests -- --doctest-modules src/particle --ignore=src/particle/particle/convert.py 69 | 70 | notebooks: 71 | runs-on: ubuntu-latest 72 | 73 | steps: 74 | - uses: actions/checkout@v4 75 | with: 76 | fetch-depth: 0 77 | 78 | - uses: actions/setup-python@v5 79 | with: 80 | python-version: "3.x" 81 | 82 | - uses: astral-sh/setup-uv@v6 83 | 84 | - name: Install package 85 | run: uv pip install --system -e .[test] 86 | 87 | - name: Install notebook requirements 88 | run: uv pip install --system nbconvert jupyter_client ipykernel 89 | 90 | - name: Run the notebooks inplace 91 | run: jupyter nbconvert --execute --inplace notebooks/*.ipynb 92 | 93 | 94 | zipapp: 95 | name: ZipApp 96 | runs-on: ubuntu-latest 97 | steps: 98 | - uses: actions/checkout@v4 99 | with: 100 | fetch-depth: 0 101 | 102 | - uses: wntrblm/nox@2025.05.01 103 | with: 104 | python-versions: "3.8" 105 | 106 | - name: Make ZipApp 107 | run: nox -s zipapp 108 | 109 | - uses: actions/upload-artifact@v4 110 | with: 111 | name: zipapp 112 | path: particle.pyz 113 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | .eggs 13 | parts 14 | bin 15 | var 16 | sdist 17 | wheelhouse 18 | develop-eggs 19 | .installed.cfg 20 | lib 21 | lib64 22 | venv*/ 23 | pyvenv*/ 24 | 25 | # Installer logs 26 | pip-log.txt 27 | 28 | # Unit test / coverage reports 29 | .coverage 30 | .tox 31 | .coverage.* 32 | coverage.xml 33 | coverage* 34 | htmlcov 35 | nosetests.xml 36 | 37 | # Translations 38 | *.mo 39 | 40 | # Mr Developer 41 | .mr.developer.cfg 42 | .project 43 | .pydevproject 44 | .idea 45 | *.iml 46 | *.komodoproject 47 | .editorconfig 48 | 49 | # Complexity 50 | output/*.html 51 | output/*/index.html 52 | 53 | # Sphinx 54 | docs/_build 55 | 56 | .DS_Store 57 | *~ 58 | .*.sw[po] 59 | .build 60 | .ve 61 | .env* 62 | .cache 63 | .pytest 64 | .bootstrap 65 | .appveyor.token 66 | *.bak 67 | 68 | .ipynb_checkpoints 69 | .pytest_cache 70 | /docs/html 71 | *.gv* 72 | /src/particle/version.py 73 | /.mypy_cache/* 74 | /pip-wheel-metadata 75 | 76 | *.pyz 77 | *.pixi 78 | 79 | */__pycache__/* 80 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ci: 2 | autoupdate_commit_msg: "chore(deps): update pre-commit hooks" 3 | autofix_commit_msg: "style: pre-commit fixes" 4 | 5 | repos: 6 | - repo: https://github.com/pre-commit/pre-commit-hooks 7 | rev: v5.0.0 8 | hooks: 9 | - id: check-added-large-files 10 | args: ['--maxkb=1000'] 11 | - id: mixed-line-ending 12 | - id: trailing-whitespace 13 | - id: check-merge-conflict 14 | - id: check-case-conflict 15 | - id: check-symlinks 16 | - id: check-yaml 17 | - id: requirements-txt-fixer 18 | - id: debug-statements 19 | - id: end-of-file-fixer 20 | 21 | - repo: https://github.com/astral-sh/ruff-pre-commit 22 | rev: "v0.11.12" 23 | hooks: 24 | - id: ruff 25 | args: ["--fix", "--show-fixes"] 26 | - id: ruff-format 27 | types_or: [python, pyi, jupyter] 28 | 29 | - repo: https://github.com/pre-commit/mirrors-mypy 30 | rev: v1.16.0 31 | hooks: 32 | - id: mypy 33 | files: src 34 | additional_dependencies: [attrs==21.4.0, hepunits>=2.2.0, importlib_resources] 35 | args: [--show-error-codes] 36 | 37 | - repo: https://github.com/codespell-project/codespell 38 | rev: v2.4.1 39 | hooks: 40 | - id: codespell 41 | exclude: ^(src/particle/data/.*\.csv|src/particle/data/.*\.fwf)$ 42 | args: ["-L", "Lamda,lamda,HEP"] 43 | 44 | - repo: https://github.com/pre-commit/pygrep-hooks 45 | rev: v1.10.0 46 | hooks: 47 | - id: rst-backticks 48 | - id: rst-directive-colons 49 | - id: rst-inline-touching-normal 50 | -------------------------------------------------------------------------------- /.zenodo.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "PDG particle data and identification codes", 3 | "license": "other-open", 4 | "upload_type": "software", 5 | "creators": [ 6 | { 7 | "affiliation": "University of Liverpool", 8 | "name": "Eduardo Rodrigues", 9 | "orcid": "0000-0003-2846-7625" 10 | }, 11 | { 12 | "affiliation": "Princeton University", 13 | "name": "Henry Schreiner", 14 | "orcid": "0000-0002-7833-783X" 15 | } 16 | ], 17 | "access_right": "open", 18 | "keywords": [ 19 | "High Energy Physics", 20 | "PDG", 21 | "particle data", 22 | "MC identification codes" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: Particle 3 | message: >- 4 | If you use this software, please cite it using the 5 | metadata from this file. 6 | type: software 7 | abstract: "Particle is a Python library for PDG particle data and identification codes." 8 | authors: 9 | - family-names: Rodrigues 10 | given-names: Eduardo 11 | affiliation: University of Liverpool 12 | orcid: "https://orcid.org/0000-0003-2846-7625" 13 | - family-names: Schreiner 14 | given-names: Henry 15 | affiliation: Princeton University 16 | orcid: "https://orcid.org/0000-0002-7833-783X" 17 | doi: 10.5281/zenodo.2552429 18 | repository-code: "https://github.com/scikit-hep/particle" 19 | keywords: 20 | - python 21 | - PDG particle data 22 | - MC identification codes 23 | - scikit-hep 24 | license: "BSD-3-Clause" 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | See the [Scikit-HEP Developer introduction][skhep-dev-intro] for a 2 | detailed description of best practices for developing Scikit-HEP packages. 3 | 4 | [skhep-dev-intro]: https://scikit-hep.org/developer/intro 5 | 6 | # Setting up a development environment 7 | 8 | You can set up a development environment by running: 9 | 10 | ```bash 11 | python3 -m venv .env 12 | source ./.env/bin/activate 13 | pip install -v -e .[all] 14 | ``` 15 | 16 | # Post setup 17 | 18 | You should prepare pre-commit, which will help you by checking that commits 19 | pass required checks: 20 | 21 | ```bash 22 | pip install pre-commit # or brew install pre-commit on macOS 23 | pre-commit install # Will install a pre-commit hook into the git repo 24 | ``` 25 | 26 | You can also/alternatively run `pre-commit run` (changes only) or `pre-commit 27 | run --all-files` to check even without installing the hook. 28 | 29 | # Testing 30 | 31 | Use PyTest to run the unit checks: 32 | 33 | ```bash 34 | pytest 35 | ``` 36 | 37 | # Developers: making a new release 38 | 39 | * Make sure the changelog is up to date. 40 | * Copy the contents of the changelog entry for that version. 41 | * Make a new release on the GitHub Releases page, using the tag name `v#.#.#` (will be created). 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the particle package developers nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /admin/dump_pdgid_to_corsika7.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 3 | # 4 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 5 | # or https://github.com/scikit-hep/particle for details. 6 | """ 7 | Script to generate the pdgid_to_corsika7id.csv conversion table from Corsika7ID to PDGID and vice-versa. 8 | This script should be kept, so the table won't need to be hand-edited in the future. 9 | """ 10 | 11 | from __future__ import annotations 12 | 13 | import contextlib 14 | import csv 15 | import datetime as dt 16 | import pathlib 17 | 18 | from particle import Particle, ParticleNotFound 19 | from particle.shared_literals import common_particles 20 | 21 | # Pairs of matching (Corsika7ID, PDGID), 22 | # if the Corsika7ID has a matching PDGID, if not 23 | # then (Corsika7ID, str), with the string from 24 | # the Corsika7 user guide 25 | corsica_pdg_id = [ 26 | (1, common_particles["gamma"]), 27 | (50, common_particles["omega_782"]), 28 | (2, common_particles["e_plus"]), 29 | (51, common_particles["rho_770_0"]), 30 | (3, common_particles["e_minus"]), 31 | (52, common_particles["rho_770_plus"]), 32 | (53, common_particles["rho_770_minus"]), 33 | (5, common_particles["mu_plus"]), 34 | (54, common_particles["Delta_1232_pp"]), 35 | (6, common_particles["mu_minus"]), 36 | (55, common_particles["Delta_1232_plus"]), 37 | (7, common_particles["pi_0"]), 38 | (56, common_particles["Delta_1232_0"]), 39 | (8, common_particles["pi_plus"]), 40 | (57, common_particles["Delta_1232_minus"]), 41 | (9, common_particles["pi_minus"]), 42 | (58, common_particles["Delta_1232_mm_bar"]), 43 | (10, common_particles["K_L_0"]), 44 | (59, common_particles["Delta_1232_minus_bar"]), 45 | (11, common_particles["K_plus"]), 46 | (60, common_particles["Delta_1232_0_bar"]), 47 | (12, common_particles["K_minus"]), 48 | (61, common_particles["Delta_1232_plus_bar"]), 49 | (13, common_particles["neutron"]), 50 | (62, common_particles["Kst_892_0"]), 51 | (14, common_particles["proton"]), 52 | (63, common_particles["Kst_892_plus"]), 53 | (15, common_particles["antiproton"]), 54 | (64, common_particles["Kst_892_minus"]), 55 | (16, common_particles["K_S_0"]), 56 | (65, common_particles["Kst_892_0_bar"]), 57 | (17, common_particles["eta"]), 58 | (66, common_particles["nu_e"]), 59 | (18, common_particles["Lambda"]), 60 | (67, common_particles["nu_e_bar"]), 61 | (19, common_particles["Sigma_plus"]), 62 | (68, common_particles["nu_mu"]), 63 | (20, common_particles["Sigma_0"]), 64 | (69, common_particles["nu_mu_bar"]), 65 | (21, common_particles["Sigma_minus"]), 66 | (22, common_particles["Xi_0"]), 67 | (71, "η → γγ"), 68 | (23, common_particles["Xi_minus"]), 69 | (72, "η → 3π◦"), 70 | (24, common_particles["Omega_minus"]), 71 | (73, "η → π+π−π◦"), 72 | (25, common_particles["antineutron"]), 73 | (74, "η → π+π−γ"), 74 | (26, common_particles["Lambda_bar"]), 75 | (75, "μ+ add. info."), 76 | (27, common_particles["Sigma_minus_bar"]), 77 | (76, "μ− add. info."), 78 | (28, common_particles["Sigma_0_bar"]), 79 | (29, common_particles["Sigma_plus_bar"]), 80 | (85, "decaying μ+ at start"), 81 | (30, common_particles["Xi_0_bar"]), 82 | (86, "decaying μ− at start"), 83 | (31, common_particles["Xi_plus_bar"]), 84 | (32, common_particles["Omega_plus_bar"]), 85 | (95, "decaying μ+ at end"), 86 | (48, common_particles["etap_958"]), 87 | (49, common_particles["phi_1020"]), 88 | (96, "decaying μ− at end"), 89 | (116, common_particles["D_0"]), 90 | (155, common_particles["Xi_cp_minus_bar"]), 91 | (117, common_particles["D_plus"]), 92 | (156, common_particles["Xi_cp_0_bar"]), 93 | (118, common_particles["D_minus"]), 94 | (157, common_particles["Omega_c_0_bar"]), 95 | (119, common_particles["D_0_bar"]), 96 | (120, common_particles["D_s_plus"]), 97 | (161, common_particles["Sigma_c_2520_pp"]), 98 | (121, common_particles["D_s_minus"]), 99 | (162, common_particles["Sigma_c_2520_plus"]), 100 | (122, common_particles["eta_c_1S"]), 101 | (163, common_particles["Sigma_c_2520_0"]), 102 | (123, common_particles["Dst_2007_0"]), 103 | (124, common_particles["Dst_2010_plus"]), 104 | (171, common_particles["Sigma_c_2520_mm_bar"]), 105 | (125, common_particles["Dst_2010_minus"]), 106 | (172, common_particles["Sigma_c_2520_minus_bar"]), 107 | (126, common_particles["Dst_2007_0_bar"]), 108 | (173, common_particles["Sigma_c_2520_0_bar"]), 109 | (127, common_particles["D_sst_plus"]), 110 | (128, common_particles["D_sst_minus"]), 111 | (176, common_particles["B_0"]), 112 | (177, common_particles["B_plus"]), 113 | (130, common_particles["Jpsi_1S"]), 114 | (178, common_particles["B_minus"]), 115 | (131, common_particles["tau_plus"]), 116 | (179, common_particles["B_0_bar"]), 117 | (132, common_particles["tau_minus"]), 118 | (180, common_particles["B_s_0"]), 119 | (133, common_particles["nu_tau"]), 120 | (181, common_particles["B_s_0_bar"]), 121 | (134, common_particles["nu_tau_bar"]), 122 | (182, common_particles["B_c_plus"]), 123 | (183, common_particles["B_c_minus"]), 124 | (137, common_particles["Lambda_c_plus"]), 125 | (184, common_particles["Lambda_b_0"]), 126 | (138, common_particles["Xi_c_plus"]), 127 | (185, common_particles["Sigma_b_minus"]), 128 | (139, common_particles["Xi_c_0"]), 129 | (186, common_particles["Sigma_b_plus"]), 130 | (140, common_particles["Sigma_c_2455_pp"]), 131 | (187, common_particles["Xi_b_0"]), 132 | (141, common_particles["Sigma_c_2455_plus"]), 133 | (188, common_particles["Xi_b_minus"]), 134 | (142, common_particles["Sigma_c_2455_0"]), 135 | (189, common_particles["Omega_b_minus"]), 136 | (143, common_particles["Xi_cp_plus"]), 137 | (190, common_particles["Lambda_b_0_bar"]), 138 | (144, common_particles["Xi_cp_0"]), 139 | (191, common_particles["Sigma_b_plus_bar"]), 140 | (145, common_particles["Omega_c_0"]), 141 | (192, common_particles["Sigma_b_minus_bar"]), 142 | (193, common_particles["Xi_b_0_bar"]), 143 | (149, common_particles["Lambda_c_minus_bar"]), 144 | (194, common_particles["Xi_b_plus_bar"]), 145 | (150, common_particles["Xi_c_minus_bar"]), 146 | (195, common_particles["Omega_b_plus_bar"]), 147 | (151, common_particles["Xi_c_0_bar"]), 148 | (152, common_particles["Sigma_c_2455_mm_bar"]), 149 | (153, common_particles["Sigma_c_2455_minus_bar"]), 150 | (154, common_particles["Sigma_c_2455_0_bar"]), 151 | ] 152 | 153 | 154 | def dump_pdgid_to_corsika7(file: pathlib.Path | None = None) -> None: 155 | """ 156 | Generates the conversion .csv file with the patching PDGID to Corsika7ID under 'src/particle/data/pdgid_to_corsika7id.csv' 157 | (if file is None, else in the specified path). 158 | """ 159 | # Loop over all thinkable values and only add them if the PDG ID exists 160 | for a in range(2, 56 + 1): 161 | for z in range(a + 1): 162 | corsikaid = a * 100 + z 163 | with contextlib.suppress(ParticleNotFound): 164 | corsica_pdg_id.append( 165 | (corsikaid, int(Particle.from_nucleus_info(a=a, z=z).pdgid)) 166 | ) 167 | 168 | if file is None: 169 | file = ( 170 | pathlib.Path(__file__) 171 | .parent.parent.resolve() 172 | .absolute() 173 | .joinpath("src/particle/data/pdgid_to_corsika7id.csv") 174 | ) 175 | 176 | date = dt.datetime.today().strftime("%Y-%m-%d") 177 | 178 | with open( 179 | file, 180 | "w", 181 | newline="", 182 | encoding="utf-8", 183 | ) as csvfile: 184 | csvfile.write( 185 | f"# (c) Scikit-HEP project - Particle package data file - pdgid_to_corsika7id.csv - {date}\n" 186 | ) 187 | csvfile.write( 188 | "# Auto generated by 'admin/dump_pdgid_to_corsika7.py'\n", 189 | ) 190 | 191 | writer = csv.writer(csvfile) 192 | # Header 193 | writer.writerow(("PDGID", "CORSIKA7ID")) 194 | for corsikaid, pdgid in sorted(corsica_pdg_id, key=lambda x: x[0]): 195 | if isinstance(pdgid, int): 196 | writer.writerow((pdgid, corsikaid)) 197 | 198 | 199 | if __name__ == "__main__": 200 | dump_pdgid_to_corsika7() 201 | -------------------------------------------------------------------------------- /admin/dump_pdgid_to_lhcb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 3 | # 4 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 5 | # or https://github.com/scikit-hep/particle for details. 6 | """This script generates the PDGID<->LHCb name mapping using the table from the LHCb DDDB package.""" 7 | 8 | from __future__ import annotations 9 | 10 | import csv 11 | import datetime as dt 12 | 13 | import requests 14 | 15 | 16 | def download_table( 17 | url="https://gitlab.cern.ch/lhcb-conddb/DDDB/-/raw/main/param/ParticleTable.txt", 18 | ): 19 | r = requests.get(url) 20 | r.raise_for_status() 21 | 22 | lines = r.text.split("\n") 23 | 24 | return [line.split() for line in filter(lambda x: x and x[0] == " ", lines)] 25 | 26 | 27 | def main(): 28 | date = dt.datetime.today().strftime("%Y-%m-%d") 29 | table = download_table() 30 | lhcb_names = {int(pdg_id): name for name, _, pdg_id, *_ in table} 31 | 32 | with open("src/particle/lhcb/data/pdgid_to_lhcbname.csv", "w") as out_csv: 33 | out_csv.write( 34 | f"# (c) Scikit-HEP project - Particle package data file - pdgid_to_lhcbname.csv - {date}\n" 35 | ) 36 | writer = csv.DictWriter( 37 | out_csv, fieldnames=("PDGID", "STR"), lineterminator="\n" 38 | ) 39 | writer.writeheader() 40 | 41 | for pid, name in sorted( 42 | lhcb_names.items(), key=lambda x: (abs(int(x[0])), -int(x[0])) 43 | ): 44 | writer.writerow({"PDGID": pid, "STR": name}) 45 | 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: true 3 | 4 | ignore: 5 | - "src/particle/__main__.py" 6 | - "src/particle/typing.py" 7 | - "src/particle/particle/convert.py" 8 | -------------------------------------------------------------------------------- /docs/ParticleLogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 25 | 32 | 33 | 56 | 58 | 59 | 61 | image/svg+xml 62 | 64 | 65 | 66 | 67 | 68 | 73 | 78 | 84 | 89 | 94 | 100 | 105 | 110 | 115 | 124 | 133 | 141 | 154 | 159 | 172 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /docs/ParticleLogo300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/docs/ParticleLogo300.png -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: particle_demo 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python>=3.8 6 | # Setting recent versions to make the conda solve faster 7 | - numpy>=1.16 8 | - pandas>=1 9 | - attrs>=19 10 | - jupyterlab>=4 11 | - tabulate 12 | - pip: 13 | - . 14 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pathlib import Path 4 | 5 | import nox 6 | 7 | nox.options.sessions = ["lint", "pylint", "tests"] 8 | nox.needs_version = ">=2024.4.15" 9 | nox.options.default_venv_backend = "uv|virtualenv" 10 | 11 | 12 | @nox.session 13 | def lint(session: nox.Session) -> None: 14 | session.install("pre-commit") 15 | session.run("pre-commit", "run", "--all-files", *session.posargs) 16 | 17 | 18 | @nox.session 19 | def pylint(session: nox.Session) -> None: 20 | """ 21 | Run pylint. 22 | """ 23 | 24 | session.install("pylint~=3.3.0") 25 | session.install("-e", ".[dev]") 26 | session.run("pylint", "src", *session.posargs) 27 | 28 | 29 | @nox.session 30 | def tests(session: nox.Session) -> None: 31 | session.install("-e", ".[test]") 32 | session.run( 33 | "pytest", 34 | "--cov=src/particle", 35 | "--cov-report=xml", 36 | "--cov-report=term", 37 | *session.posargs, 38 | ) 39 | 40 | 41 | @nox.session 42 | def build(session: nox.Session) -> None: 43 | """ 44 | Build an SDist and wheel. 45 | """ 46 | 47 | session.install("build", "twine", "check-wheel-contents") 48 | session.run("python", "-m", "build") 49 | session.run("twine", "check", "--strict", "dist/*") 50 | session.run( 51 | "check-wheel-contents", str(*Path("dist").glob("*.whl")), "--ignore=W002" 52 | ) 53 | 54 | 55 | @nox.session(python="3.8", venv_backend="virtualenv") 56 | def zipapp(session: nox.Session) -> None: 57 | tmpdir = session.create_tmp() 58 | 59 | # Build a distribution 60 | session.run( 61 | "python", 62 | "-m", 63 | "pip", 64 | "install", 65 | "--no-compile", 66 | ".", 67 | "importlib_resources", 68 | "typing_extensions", 69 | f"--target={tmpdir}", 70 | ) 71 | 72 | # Build the zipapp out of the local directory 73 | outfile = Path("particle.pyz").resolve() 74 | session.chdir(tmpdir) 75 | session.run( 76 | "python", 77 | "-m", 78 | "zipapp", 79 | "--compress", 80 | "--python=/usr/bin/env python3", 81 | "--main=particle.__main__:main", 82 | f"--output={outfile}", 83 | ".", 84 | ) 85 | 86 | # Quick test to verify it works 87 | session.chdir(str(outfile.parent)) 88 | result = session.run("python", "particle.pyz", "search", "D0", silent=True) 89 | if "Name: D0" not in result: 90 | session.error( 91 | f"Expected valid result, was unable to run zipapp. Produced: {result}" 92 | ) 93 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["hatchling", "hatch-vcs"] 3 | build-backend = "hatchling.build" 4 | 5 | [project] 6 | name = "particle" 7 | description = "Extended PDG particle data and MC identification codes" 8 | readme = "README.md" 9 | requires-python = ">=3.8" 10 | authors = [ 11 | { name = "Eduardo Rodrigues", email = "eduardo.rodrigues@cern.ch" }, 12 | { name = "Henry Schreiner", email = "henryfs@princeton.edu" }, 13 | ] 14 | maintainers = [ 15 | { name = "Scikit-HEP", email = "scikit-hep-admins@googlegroups.com" }, 16 | ] 17 | keywords = [ 18 | "HEP", 19 | "MC identification codes", 20 | "PDG", 21 | "PDGID", 22 | "particle", 23 | "particle data table", 24 | "particle properties", 25 | ] 26 | classifiers = [ 27 | "Development Status :: 5 - Production/Stable", 28 | "Intended Audience :: Developers", 29 | "Intended Audience :: Science/Research", 30 | "License :: OSI Approved :: BSD License", 31 | "Operating System :: OS Independent", 32 | "Programming Language :: Python", 33 | "Programming Language :: Python :: 3", 34 | "Programming Language :: Python :: 3 :: Only", 35 | "Programming Language :: Python :: 3.8", 36 | "Programming Language :: Python :: 3.9", 37 | "Programming Language :: Python :: 3.10", 38 | "Programming Language :: Python :: 3.11", 39 | "Programming Language :: Python :: 3.12", 40 | "Programming Language :: Python :: 3.13", 41 | "Topic :: Scientific/Engineering", 42 | ] 43 | dependencies = [ 44 | "attrs>=19.2", 45 | "hepunits>=2.0.0", 46 | "importlib-resources>=2.0;python_version<\"3.9\"", 47 | "typing-extensions>=4.5;python_version<\"3.13\"", 48 | ] 49 | dynamic = ["version"] 50 | 51 | [project.optional-dependencies] 52 | dev = [ 53 | "pandas", 54 | "pytest-benchmark", 55 | "pytest>=6", 56 | "tabulate", 57 | "pre-commit", 58 | ] 59 | test = [ 60 | "pandas", 61 | "pytest-benchmark", 62 | "pytest-cov", 63 | "pytest>=6", 64 | "tabulate", 65 | ] 66 | all = [ 67 | "particle[dev,test]", 68 | ] 69 | 70 | [project.urls] 71 | Homepage = "https://github.com/scikit-hep/particle" 72 | 73 | 74 | [tool.hatch] 75 | version.source = "vcs" 76 | build.hooks.vcs.version-file = "src/particle/version.py" 77 | 78 | 79 | [tool.mypy] 80 | warn_unused_configs = true 81 | warn_unused_ignores = true 82 | python_version = "3.9" 83 | files = "src" 84 | strict = true 85 | warn_unreachable = true 86 | enable_error_code = [ 87 | "ignore-without-code", 88 | "redundant-expr", 89 | "truthy-bool", 90 | ] 91 | 92 | [[tool.mypy.overrides]] 93 | module = [ 94 | "pandas.*", 95 | "numpy.*", 96 | ] 97 | ignore_missing_imports = true 98 | 99 | 100 | [tool.pytest.ini_options] 101 | minversion = "6.0" 102 | testpaths = ["tests"] 103 | junit_family = "xunit2" 104 | log_cli_level = "info" 105 | xfail_strict = true 106 | addopts = [ 107 | "--benchmark-disable", 108 | "-ra", 109 | "--showlocals", 110 | "--strict-markers", 111 | "--strict-config", 112 | ] 113 | filterwarnings = [ 114 | "error", 115 | '''ignore:\s*A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method:FutureWarning''', 116 | ] 117 | 118 | [tool.pylint] 119 | py-version = "3.8" 120 | reports.output-format = "colorized" 121 | similarities.ignore-imports = "yes" 122 | jobs = "0" 123 | messages_control.enable = [ 124 | "useless-suppression", 125 | ] 126 | messages_control.disable = [ 127 | "duplicate-code", 128 | "fixme", 129 | "invalid-name", 130 | "invalid-unary-operand-type", 131 | "line-too-long", 132 | "missing-class-docstring", 133 | "missing-function-docstring", 134 | "missing-module-docstring", 135 | "too-few-public-methods", 136 | "too-many-arguments", 137 | "too-many-branches", 138 | "too-many-instance-attributes", 139 | "too-many-lines", 140 | "too-many-locals", 141 | "too-many-positional-arguments", 142 | "too-many-public-methods", 143 | "too-many-return-statements", 144 | "too-many-statements", 145 | "unsubscriptable-object", 146 | "unsupported-assignment-operation", 147 | "unused-argument", # Handled by Ruff 148 | "wrong-import-position", 149 | ] 150 | 151 | 152 | [tool.ruff] 153 | src = ["src"] 154 | 155 | [tool.ruff.lint] 156 | extend-select = [ 157 | "B", # flake8-bugbear 158 | "I", # isort 159 | "ARG", # flake8-unused-arguments 160 | "C4", # flake8-comprehensions 161 | "ICN", # flake8-import-conventions 162 | "ISC", # flake8-implicit-str-concat 163 | "PGH", # pygrep-hooks 164 | "PIE", # flake8-pie 165 | "PL", # pylint 166 | "PT", # flake8-pytest-style 167 | "RET", # flake8-return 168 | "RUF", # Ruff-specific 169 | "SIM", # flake8-simplify 170 | "T20", # flake8-print 171 | "UP", # pyupgrade 172 | "YTT", # flake8-2020 173 | ] 174 | ignore = [ 175 | "RUF001", # Ambiguous unicode 176 | "RUF002", # Ambiguous unicode docstring 177 | "PLR2004", # Magic value used in comparison 178 | "PLR09", # Too many X 179 | "ISC001", # Conflicts with the formatter 180 | "E741", # Ambiguous variable name 181 | "SIM103", 182 | "T201", 183 | ] 184 | isort.required-imports = ["from __future__ import annotations"] 185 | mccabe.max-complexity = 24 186 | 187 | [tool.ruff.lint.per-file-ignores] 188 | "src/particle/__main__.py" = ["T20"] 189 | "tests/**.py" = [ 190 | "PT013", # Importing approx from pytest is fine 191 | "E402", # Module level import not at top of file (doesn't recognise pytest.importorskip) 192 | ] 193 | 194 | 195 | [tool.repo-review] 196 | ignore = ["RTD"] 197 | 198 | 199 | [tool.pixi.project] 200 | name = "particle" 201 | channels = ["conda-forge"] 202 | platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"] 203 | 204 | [tool.pixi.pypi-dependencies] 205 | particle = { path = ".", editable = true} 206 | 207 | [tool.pixi.dependencies] 208 | numpy = ">=1.16" 209 | pandas = ">=1" 210 | attrs = ">=19" 211 | jupyterlab = ">=4" 212 | tabulate = "*" 213 | 214 | [tool.pixi.tasks] 215 | lab = "jupyter lab" 216 | -------------------------------------------------------------------------------- /src/particle/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | import sys 10 | 11 | from .corsika import Corsika7ID 12 | from .geant import Geant3ID 13 | 14 | # Direct access to Particle literals 15 | # Direct access to Particle (the CSV file is not read until a particle is accessed) 16 | # Direct access to handy LaTeX to HTML particle name conversions 17 | # Direct access to kinematics functions 18 | from .particle import ( 19 | InvalidParticle, 20 | Particle, 21 | ParticleNotFound, 22 | latex_to_html_name, 23 | lifetime_to_width, 24 | literals, 25 | width_to_lifetime, 26 | ) 27 | from .particle.enums import Charge, Inv, Parity, SpinType, Status 28 | 29 | # Direct access to PDGID and other ID classes 30 | from .pdgid import PDGID 31 | from .pythia import PythiaID 32 | 33 | # Convenient access to the version number 34 | from .version import version as __version__ 35 | 36 | # Literals direct access 37 | sys.modules["particle.literals"] = literals 38 | 39 | __all__ = ( 40 | "PDGID", 41 | "Charge", 42 | "Corsika7ID", 43 | "Geant3ID", 44 | "Inv", 45 | "InvalidParticle", 46 | "Parity", 47 | "Particle", 48 | "ParticleNotFound", 49 | "PythiaID", 50 | "SpinType", 51 | "Status", 52 | "__version__", 53 | "latex_to_html_name", 54 | "lifetime_to_width", 55 | "width_to_lifetime", 56 | ) 57 | 58 | 59 | def __dir__() -> tuple[str, ...]: 60 | return __all__ 61 | -------------------------------------------------------------------------------- /src/particle/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 3 | # 4 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 5 | # or https://github.com/scikit-hep/particle for details. 6 | 7 | 8 | from __future__ import annotations 9 | 10 | import argparse 11 | import sys 12 | 13 | from . import __version__ 14 | from .particle import Particle 15 | from .pdgid import PDGID 16 | 17 | 18 | def main() -> None: 19 | parser = argparse.ArgumentParser( 20 | prog="particle", 21 | description="Particle command line display utility. Has two modes.", 22 | ) 23 | 24 | parser.add_argument( 25 | "--version", 26 | action="version", 27 | version=f"%(prog)s {__version__}", 28 | ) 29 | 30 | subparsers = parser.add_subparsers(help="Subcommands") 31 | 32 | search = subparsers.add_parser( 33 | "search", 34 | help="Look up particles by PID or name (Ex.: python -m particle search D+ D-)", 35 | ) 36 | search.add_argument("particle", nargs="+", help="Name(s) or ID(s)") 37 | 38 | pdgid = subparsers.add_parser( 39 | "pdgid", help="Print info from PID (Ex.: python -m particle pdgid 11 13)" 40 | ) 41 | pdgid.add_argument("pdgid", nargs="+", help="ID(s)") 42 | 43 | opts = parser.parse_args() 44 | 45 | if "particle" in opts: 46 | for cand in opts.particle: 47 | if hasattr(cand, "decode"): 48 | cand = cand.decode("utf-8") # noqa: PLW2901 49 | 50 | try: 51 | value = int(cand) 52 | except ValueError: 53 | value = 0 54 | 55 | if value: 56 | particles = [Particle.from_pdgid(value)] 57 | else: 58 | particles = Particle.findall(cand) 59 | 60 | if not particles: 61 | print("Particle", cand, "not found.") 62 | sys.exit(1) 63 | elif len(particles) == 1: 64 | print(particles[0].describe()) 65 | else: 66 | for particle in particles: 67 | print(repr(particle)) 68 | 69 | print() 70 | 71 | if "pdgid" in opts: 72 | for value in opts.pdgid: 73 | p = PDGID(value) 74 | print(p) 75 | print(PDGID(value).info()) 76 | 77 | 78 | if __name__ == "__main__": 79 | main() 80 | -------------------------------------------------------------------------------- /src/particle/_compat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/_compat/__init__.py -------------------------------------------------------------------------------- /src/particle/_compat/typing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | import sys 10 | 11 | if sys.version_info < (3, 9): 12 | from importlib_resources.abc import Traversable 13 | elif sys.version_info < (3, 11): 14 | from importlib.abc import Traversable # pylint: disable=deprecated-class 15 | else: 16 | from importlib.resources.abc import Traversable 17 | 18 | 19 | __all__ = ("Traversable",) 20 | -------------------------------------------------------------------------------- /src/particle/converters/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from .corsika import Corsika72PDGIDBiMap 10 | from .evtgen import EvtGen2PDGNameMap, EvtGenName2PDGIDBiMap, PDG2EvtGenNameMap 11 | from .geant import Geant2PDGIDBiMap 12 | from .pythia import Pythia2PDGIDBiMap 13 | 14 | __all__ = ( 15 | "Corsika72PDGIDBiMap", 16 | "EvtGen2PDGNameMap", 17 | "EvtGenName2PDGIDBiMap", 18 | "Geant2PDGIDBiMap", 19 | "PDG2EvtGenNameMap", 20 | "Pythia2PDGIDBiMap", 21 | ) 22 | 23 | 24 | def __dir__() -> tuple[str, ...]: 25 | return __all__ 26 | -------------------------------------------------------------------------------- /src/particle/converters/bimap.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | import contextlib 10 | import csv 11 | import sys 12 | from collections.abc import Mapping 13 | from typing import ( 14 | IO, 15 | Any, 16 | Callable, 17 | Generic, 18 | Iterator, 19 | TypeVar, 20 | Union, 21 | overload, 22 | ) 23 | 24 | from .. import data 25 | from ..exceptions import MatchingIDNotFound 26 | from ..typing import HasOpen, HasRead, StringOrIO 27 | 28 | A = TypeVar("A") 29 | B = TypeVar("B") 30 | A_conv = Callable[[str], Union[A, int]] 31 | B_conv = Callable[[str], Union[B, int]] 32 | 33 | 34 | class BiMap(Generic[A, B]): 35 | def __init__( 36 | self, 37 | class_A: type[A], 38 | class_B: type[B], 39 | converters: tuple[A_conv, B_conv] = (int, int), # type: ignore[type-arg] 40 | filename: StringOrIO | None = None, 41 | ) -> None: 42 | """ 43 | Bi-bidirectional map class. 44 | 45 | Parameters 46 | ---------- 47 | class_A, class_B: class types 48 | Input class types. 49 | converters: tuple, optional, default=(int,int) 50 | Converter functions applied on each entry (row) of the file 51 | providing the class_a-class_B matches. 52 | The order of the list elements must agree with that of the classes 53 | passed in in the constructor. 54 | By default, data on the file is assumed to be integers, 55 | which is the typical case for PDG IDs and alike. 56 | filename: string or file object, optional, 57 | default='_to_.csv', 58 | where the names are taken as lowercase. 59 | Specify a file from which to read all class_a-class_B matches. 60 | It does not matter whether the file contains the input as 61 | val_A,val_B or val_B,val_A. 62 | 63 | Examples 64 | -------- 65 | >>> from particle import PDGID, PythiaID 66 | 67 | Basic/standard usage: 68 | >>> bimap = BiMap(PDGID, PythiaID) 69 | 70 | >>> bimap[PDGID(9010221)] 71 | 72 | >>> bimap[PythiaID(10221)] 73 | 74 | 75 | Advanced usage: 76 | >>> # Either pass a file name or a file object 77 | >>> from particle import data 78 | >>> filename = data.basepath / "pdgid_to_pythiaid.csv" 79 | >>> bimap = BiMap(PDGID, PythiaID, filename=filename) 80 | """ 81 | 82 | self.class_A: type[A] = class_A 83 | self.class_B: type[B] = class_B 84 | 85 | name_A = self.class_A.__name__.upper() 86 | name_B = self.class_B.__name__.upper() 87 | 88 | file_object: IO[str] 89 | if filename is None: 90 | filename = f"{name_A.lower()}_to_{name_B.lower()}.csv" 91 | file_object = data.basepath.joinpath(filename).open() 92 | elif isinstance(filename, HasRead): 93 | file_object = filename 94 | elif isinstance(filename, HasOpen): 95 | file_object = filename.open() 96 | else: 97 | file_object = open(filename, encoding="utf_8") # type: ignore[arg-type] # noqa: SIM115 98 | 99 | with file_object as _f: 100 | self._to_map = { 101 | converters[1](v[name_B]): converters[0](v[name_A]) 102 | for v in csv.DictReader(line for line in _f if not line.startswith("#")) 103 | } 104 | _f.seek(0) 105 | self._from_map = { 106 | converters[0](v[name_A]): converters[1](v[name_B]) 107 | for v in csv.DictReader(line for line in _f if not line.startswith("#")) 108 | } 109 | 110 | @overload 111 | def __getitem__(self, value: A) -> B: 112 | pass 113 | 114 | @overload 115 | def __getitem__(self, value: B) -> A: 116 | pass 117 | 118 | def __getitem__(self, value: Any) -> Any: 119 | if isinstance(value, self.class_B): 120 | with contextlib.suppress(KeyError): 121 | return self.class_A(self._to_map[value]) # type: ignore[call-arg] 122 | elif isinstance(value, self.class_A): 123 | with contextlib.suppress(KeyError): 124 | return self.class_B(self._from_map[value]) # type: ignore[call-arg] 125 | 126 | name_A = self.class_A.__name__ 127 | name_B = self.class_B.__name__ 128 | msg = f"Matching {name_A}-{name_B} for input {value} not found !" 129 | raise MatchingIDNotFound(msg) 130 | 131 | def __repr__(self) -> str: 132 | name_A = self.class_A.__name__ 133 | name_B = self.class_B.__name__ 134 | 135 | return f"<{self.__class__.__name__}({name_A}-{name_B}): {len(self)} matches>" 136 | 137 | def __len__(self) -> int: 138 | """Returns the number of matches.""" 139 | return len(self._to_map) 140 | 141 | 142 | def DirectionalMaps( 143 | name_A: str, 144 | name_B: str, 145 | converters: tuple[Callable[[str], str], Callable[[str], str]] = (str, str), 146 | filename: StringOrIO | None = None, 147 | ) -> tuple[DirectionalMap, DirectionalMap]: 148 | """ 149 | Directional map class providing a to and from mapping. 150 | 151 | Parameters 152 | ---------- 153 | name_A, name_B: str 154 | Input names of information to be mapped. 155 | converters: tuple, optional, default=(str,str) 156 | Converter functions applied on each entry (row) of the file 157 | providing the name_a-name_B matches. 158 | The order of the list elements must agree with that of the 159 | object names passed in in the constructor. 160 | By default, data on the file is assumed to be strings, 161 | which is the typical case for particle names. 162 | filename: string or file object, optional, default='particle/data/conversions.csv'. 163 | Specify a file from which to read all name_a-name_B matches. 164 | It is assumed that the order of items in the file matches the order 165 | of arguments specified in the class constructor, hence val_A,val_B. 166 | 167 | Examples 168 | -------- 169 | 170 | >>> from particle import data # doctest: +SKIP 171 | >>> filename = data.basepath / "a_to_b.csv" # doctest: +SKIP 172 | >>> A2BMap, B2AMap = DirectionalMaps('A', 'B', filename=filename) # doctest: +SKIP 173 | """ 174 | 175 | name_A = name_A.upper() 176 | name_B = name_B.upper() 177 | 178 | fieldnames = None 179 | file_object: IO[str] 180 | if filename is None: 181 | file_object = data.basepath.joinpath("conversions.csv").open() 182 | elif isinstance(filename, HasOpen): 183 | file_object = filename.open() 184 | elif isinstance(filename, HasRead): 185 | file_object = filename 186 | else: 187 | file_object = open(filename, encoding="utf_8") # type: ignore[arg-type] # noqa: SIM115 188 | 189 | with file_object as _f: 190 | skipinitialspace = True 191 | 192 | to_map = { 193 | converters[1](v[name_B]): converters[0](v[name_A]) 194 | for v in csv.DictReader( 195 | (line for line in _f if not line.startswith("#")), 196 | fieldnames=fieldnames, 197 | skipinitialspace=skipinitialspace, 198 | ) 199 | } 200 | _f.seek(0) 201 | from_map = { 202 | converters[0](v[name_A]): converters[1](v[name_B]) 203 | for v in csv.DictReader( 204 | (line for line in _f if not line.startswith("#")), 205 | fieldnames=fieldnames, 206 | skipinitialspace=skipinitialspace, 207 | ) 208 | } 209 | 210 | return ( 211 | DirectionalMap(name_A, name_B, from_map), 212 | DirectionalMap(name_B, name_A, to_map), 213 | ) 214 | 215 | 216 | if sys.version_info < (3, 9): 217 | StrStrMapping = Mapping 218 | else: 219 | StrStrMapping = Mapping[str, str] 220 | 221 | 222 | class DirectionalMap(StrStrMapping): 223 | # pylint: disable-next=redefined-builtin 224 | def __init__(self, name_A: str, name_B: str, map: dict[str, str]) -> None: 225 | """ 226 | Directional map class providing a A -> B mapping. 227 | 228 | Parameters 229 | ---------- 230 | name_A, name_B: str 231 | Input names of information to be mapped. 232 | map: dict 233 | Input mapping as a dictionary. 234 | """ 235 | 236 | self.name_A = name_A.upper() 237 | self.name_B = name_B.upper() 238 | 239 | self._map = map 240 | 241 | def __getitem__(self, value: str) -> str: 242 | try: 243 | return self._map[value] 244 | except KeyError: 245 | msg = f"Matching {self.name_A}->{self.name_B} for input {value} not found !" 246 | raise MatchingIDNotFound(msg) from None 247 | 248 | def __iter__(self) -> Iterator[str]: 249 | return iter(self._map) 250 | 251 | def __repr__(self) -> str: 252 | return f"<{self.__class__.__name__}({self.name_A}->{self.name_B}): {len(self)} matches>" 253 | 254 | def __len__(self) -> int: 255 | """Returns the number of matches.""" 256 | return len(self._map) 257 | -------------------------------------------------------------------------------- /src/particle/converters/corsika.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from ..corsika import Corsika7ID 10 | from ..pdgid import PDGID 11 | from .bimap import BiMap 12 | 13 | Corsika72PDGIDBiMap = BiMap(PDGID, Corsika7ID) 14 | Corsika72PDGIDBiMap.__doc__ = """ 15 | Bi-bidirectional map between PDG and Corsika7 IDs. 16 | 17 | Examples 18 | -------- 19 | >>> cid = Corsika72PDGIDBiMap[PDGID(-13)] 20 | >>> cid 21 | 22 | 23 | >>> cid = Corsika72PDGIDBiMap[Corsika7ID(5)] 24 | >>> cid 25 | 26 | """ 27 | -------------------------------------------------------------------------------- /src/particle/converters/evtgen.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from .. import data 10 | from ..pdgid import PDGID 11 | from .bimap import BiMap, DirectionalMaps 12 | 13 | EvtGenName2PDGIDBiMap = BiMap( 14 | PDGID, 15 | str, 16 | converters=(int, str), 17 | filename=data.basepath / "pdgid_to_evtgenname.csv", 18 | ) 19 | EvtGenName2PDGIDBiMap.__doc__ = """ 20 | Bi-bidirectional map between PDG IDs and EvtGen names. 21 | 22 | Examples 23 | -------- 24 | >>> name = EvtGenName2PDGIDBiMap[PDGID(22)] 25 | >>> name 26 | 'gamma' 27 | 28 | >>> pdgid = EvtGenName2PDGIDBiMap['gamma'] 29 | >>> pdgid 30 | 31 | """ 32 | 33 | 34 | PDG2EvtGenNameMap, EvtGen2PDGNameMap = DirectionalMaps("PDGName", "EvtGenName") 35 | 36 | PDG2EvtGenNameMap.__doc__ = """ 37 | Directional map between PDG and EvtGen names. 38 | 39 | Examples 40 | -------- 41 | >>> PDG2EvtGenNameMap['J/psi(1S)'] 42 | 'J/psi' 43 | """ 44 | 45 | 46 | EvtGen2PDGNameMap.__doc__ = """ 47 | Directional map between EvtGen and names. 48 | 49 | Examples 50 | -------- 51 | >>> EvtGen2PDGNameMap['J/psi'] 52 | >>> 'J/psi(1S)' 53 | """ 54 | 55 | del BiMap 56 | del DirectionalMaps 57 | -------------------------------------------------------------------------------- /src/particle/converters/geant.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from ..geant import Geant3ID 10 | from ..pdgid import PDGID 11 | from .bimap import BiMap 12 | 13 | Geant2PDGIDBiMap = BiMap(PDGID, Geant3ID) 14 | Geant2PDGIDBiMap.__doc__ = """ 15 | Bi-bidirectional map between PDG and Geant3 IDs. 16 | 17 | Examples 18 | -------- 19 | >>> gid = Geant2PDGIDBiMap[PDGID(211)] 20 | >>> gid 21 | 22 | 23 | >>> pdgid = Geant2PDGIDBiMap[Geant3ID(8)] 24 | >>> pdgid 25 | 26 | """ 27 | -------------------------------------------------------------------------------- /src/particle/converters/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/converters/py.typed -------------------------------------------------------------------------------- /src/particle/converters/pythia.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from ..pdgid import PDGID 10 | from ..pythia import PythiaID 11 | from .bimap import BiMap 12 | 13 | Pythia2PDGIDBiMap = BiMap(PDGID, PythiaID) 14 | Pythia2PDGIDBiMap.__doc__ = """ 15 | Bi-bidirectional map between PDG and Pythia IDs. 16 | 17 | Examples 18 | -------- 19 | >>> pyid = Pythia2PDGIDBiMap[PDGID(9010221)] 20 | >>> pyid 21 | 22 | 23 | >>> pdgid = Pythia2PDGIDBiMap[PythiaID(10221)] 24 | >>> pdgid 25 | 26 | """ 27 | -------------------------------------------------------------------------------- /src/particle/corsika/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from .corsika7id import Corsika7ID 10 | 11 | __all__ = ("Corsika7ID",) 12 | 13 | 14 | def __dir__() -> tuple[str, ...]: 15 | return __all__ 16 | -------------------------------------------------------------------------------- /src/particle/corsika/corsika7id.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Class representing a Corsika7 ID. 8 | 9 | Note 10 | ---- 11 | Corsika8 uses Geant3 Particle IDs. 12 | """ 13 | 14 | from __future__ import annotations 15 | 16 | import csv 17 | from typing import TypeVar 18 | 19 | from .. import data 20 | from ..exceptions import MatchingIDNotFound 21 | from ..pdgid import PDGID 22 | 23 | Self = TypeVar("Self", bound="Corsika7ID") 24 | 25 | 26 | with data.basepath.joinpath("pdgid_to_corsika7id.csv").open() as _f: 27 | _bimap = { 28 | int(v["CORSIKA7ID"]): int(v["PDGID"]) 29 | for v in csv.DictReader(line for line in _f if not line.startswith("#")) 30 | } 31 | 32 | # Some Corsika7 ID's are not really particles 33 | _non_particles = { 34 | 71: "η → γγ", 35 | 72: "η → 3π◦", 36 | 73: "η → π+π−π◦", 37 | 74: "η → π+π−γ", 38 | 75: "μ+ add. info.", 39 | 76: "μ− add. info.", 40 | 85: "decaying μ+ at start", 41 | 86: "decaying μ− at start", 42 | 95: "decaying μ+ at end", 43 | 96: "decaying μ− at end", 44 | } 45 | 46 | 47 | class Corsika7ID(int): 48 | """ 49 | Holds a Corsika7 ID. 50 | 51 | All arithmetic operations on the class (like `-Corsika7ID(5)`) will 52 | return an integer. This is unlike for example `-PDGID(13)`, which will 53 | return `PDGID(-13)`. But since negative values have no direct meaning 54 | as a Corsika7ID, (in the output file they are used to indicate mother-particles) 55 | we omit this feature. 56 | 57 | Examples 58 | -------- 59 | >>> cid = Corsika7ID(6) 60 | 61 | >>> from particle import Particle 62 | >>> p = Particle.from_pdgid(cid.to_pdgid()) 63 | 64 | >>> (p,) = Particle.finditer(pdgid=cid.to_pdgid()) 65 | >>> p.name 66 | 'mu-' 67 | """ 68 | 69 | __slots__ = () # Keep Corsika7ID a slots based class 70 | 71 | @classmethod 72 | def from_pdgid(cls: type[Self], pdgid: int) -> Self: 73 | """ 74 | Constructor from a PDGID. 75 | """ 76 | for k, v in _bimap.items(): 77 | if v == pdgid: 78 | return cls(k) 79 | raise MatchingIDNotFound(f"Non-existent Corsika7ID for input PDGID {pdgid}!") 80 | 81 | @classmethod 82 | def from_particle_description( 83 | cls: type[Self], particle_description: int 84 | ) -> tuple[Self, bool]: 85 | """ 86 | Constructor from the particle description returned by Corsika7 87 | in the particle data sub-block, mother particle data sub-block or 88 | the grandmother particle data sub-block. 89 | 90 | Returns 91 | ------- 92 | A tuple with 93 | 94 | Corsika7ID: The Corsika7 id 95 | bool: If the particle is a (grand)mother particle. 96 | """ 97 | cid = abs(particle_description) // 1000 98 | ismother = particle_description < 0 99 | 100 | if cls._is_non_particle_id(cid): 101 | return cls(cid), ismother 102 | 103 | # This catches the cases of nuclei with no known PDG ID 104 | if 200 <= cid < 5699: 105 | return cls(cid), ismother 106 | 107 | if cid in _bimap: 108 | return cls(cid), ismother 109 | 110 | raise MatchingIDNotFound( 111 | f"Non-existent Corsika7ID for particle description {particle_description}!" 112 | ) 113 | 114 | @classmethod 115 | def _is_non_particle_id(cls: type[Self], corsikaid: int) -> bool: 116 | """ 117 | Returns True if the ID is valid but does not correspond to a particle, False otherwise. 118 | """ 119 | return ( 120 | corsikaid in _non_particles 121 | or corsikaid // 1000 == 8888 122 | or corsikaid == 9900 123 | ) 124 | 125 | def is_particle(self) -> bool: 126 | """ 127 | Returns True if the ID really belongs to a particle, since some are for example additional information. 128 | 129 | Examples 130 | -------- 131 | >>> mu_minus = Corsika7ID(6) 132 | >>> mu_minus.is_particle() 133 | True 134 | >>> mu_info = Corsika7ID(76) 135 | >>> mu_info.is_particle() 136 | False 137 | >>> mu_info.name() 138 | 'μ− add. info.' 139 | """ 140 | iid = int(self) 141 | 142 | return not self._is_non_particle_id(iid) 143 | 144 | def name(self) -> str: 145 | """ 146 | Returns a human readable name of the Corsika7ID. 147 | This also works for non-particles (is_particle()==false). 148 | 149 | Raises 150 | ------ 151 | ParticleNotFound 152 | If it is a 'valid' PDG particle, but unknown. 153 | This for example happens with strange nuclei, which are not in the nuclei list. 154 | 155 | InvalidParticle 156 | If the Corsika7ID itself is not valid. 157 | 158 | Examples 159 | -------- 160 | >>> mu_minus = Corsika7ID(6) 161 | >>> mu_minus.is_particle() 162 | True 163 | >>> mu_minus.name() # For a particle, this returns the same name as `Particle.name` 164 | 'mu-' 165 | >>> mu_info = Corsika7ID(76) 166 | >>> mu_info.is_particle() 167 | False 168 | >>> mu_info.name() 169 | 'μ− add. info.' 170 | >>> ch_photons_of = Corsika7ID(9900) 171 | >>> ch_photons_of.is_particle() 172 | False 173 | >>> ch_photons_of.name() 174 | 'Cherenkov photons on particle output file' 175 | """ 176 | from ..particle.particle import Particle # pylint: disable=C0415 177 | 178 | if not self.is_particle(): 179 | iid = int(self) 180 | 181 | if iid in _non_particles: 182 | return _non_particles[iid] 183 | 184 | if iid // 1000 == 8888: 185 | return "weights of preceding particle (MULTITHIN option)" 186 | 187 | if iid == 9900: 188 | return "Cherenkov photons on particle output file" 189 | 190 | return str(Particle.from_pdgid(self.to_pdgid()).name) 191 | 192 | def to_pdgid(self) -> PDGID: 193 | """ 194 | Raises 195 | ------ 196 | InvalidParticle 197 | If it is a valid Corsika particle, but not a valid PDGID. 198 | 199 | Examples 200 | -------- 201 | >>> Corsika7ID(6).to_pdgid() 202 | 203 | >>> Corsika7ID(76).to_pdgid() # doctest: +SKIP 204 | InvalidParticle: The Corsika7ID does not correspond to a particle and thus has no equivalent PDGID. 205 | """ 206 | from ..particle.particle import InvalidParticle # pylint: disable=C0415 207 | 208 | if self not in _bimap: 209 | raise InvalidParticle( 210 | f"The Corsika7ID {self} does not correspond to a particle and thus has no equivalent PDGID." 211 | ) 212 | return PDGID(_bimap[self]) 213 | 214 | def __repr__(self) -> str: 215 | return f"<{self.__class__.__name__}: {int(self):d}>" 216 | 217 | def __str__(self) -> str: 218 | return repr(self) 219 | -------------------------------------------------------------------------------- /src/particle/data/README.rst: -------------------------------------------------------------------------------- 1 | Particle Data folder contents 2 | ----------------------------- 3 | 4 | You can ``import particle.data``, then use ``particle.data.basepath / "particle2024.csv"`` 5 | to access data reliably regardless of how you have installed or are running the package (even from a zip file!). 6 | 7 | 8 | ``mass_width_2008.fwf`` 9 | ======================= 10 | 11 | The extended PDG data file, produced once, in 2008. This is the basis for the particle information. 12 | This file originally had a CSV extension, but it not a comma separated value file, but rather a fixed 13 | width format. 14 | 15 | 16 | ``mass_width_2008_ext.fwf`` 17 | =========================== 18 | 19 | An extension file for the extended PDG data file, prepared by this package's maintainers. 20 | It contains entries necessary to provide extended information for the particles in the standard .mcd file. 21 | 22 | 23 | ``mass_width_2024.mcd`` 24 | ======================= 25 | 26 | The latest version of the PDG particle data file, downloaded from the PDG website 27 | (renamed from .txt to the .mcd extension as in previous years), 28 | with much less information, but with more particles and more up to date. 29 | A few older years are included, too. 30 | 31 | 32 | ``particle2024.csv`` 33 | ==================== 34 | 35 | The combined data file, in a format that is easy for the ``Particle`` class to read and easy for physicists to extend or edit. 36 | If you'd like to append to this file, write a similar file with the same header, then use 37 | 38 | .. code-block:: python 39 | 40 | Particle.read_table() 41 | Particle.read_table("...", append=True) 42 | 43 | to read in the original table and then the new file you've written. 44 | 45 | This file was created from ``pdgid_to_latexname.csv``, ``mass_width_2008.fwf``, 46 | ``mass_width_2008_ext.fwf`` and ``mass_width_2024.mcd``. 47 | The 2008 version of the file was created with only the first two. 48 | 49 | 50 | ``nuclei2022.csv`` 51 | ================== 52 | 53 | Information on nuclei extracted and adapted from package ``periodictable``, 54 | available in the same format as that of ``particle2024.csv``. 55 | 56 | 57 | ``conversions.csv`` 58 | =================== 59 | 60 | Master conversions file containing all matching MC IDs and names. 61 | This is the file internally used to produce all other ``x_to_y.csv`` files. 62 | Updates to converters data should be made to this file and subsequently 63 | propagated to the ``x_to_y.csv`` files. 64 | 65 | This file and all ``x_to_y.csv`` files are versioned, see the first-line comments. 66 | 67 | 68 | ``pdgid_to_latexname.csv`` 69 | ========================== 70 | 71 | A list of matching particle PDG identification codes and LaTeX names. 72 | The negative values are normally generated based on the ``Inv`` rule, 73 | but if you have a special case, you can set a negative value as well and it will override. 74 | 75 | 76 | ``pdgid_to_pythiaid.csv`` 77 | ========================= 78 | 79 | A list of matching particle PDG and Pythia identification codes. 80 | Note that this file contains entries for particles not in the PDG data file, 81 | for completeness (e.g., non-yet-observed baryons, leptoquarks). 82 | 83 | 84 | ``pdgid_to_geant3id.csv`` 85 | ========================= 86 | 87 | A list of matching particle PDG and Geant3 identification codes; 88 | Geant4 follows the PDG rules, hence uses the standard PDG IDs. 89 | Note that this file contains entries for particles not in the PDG data file, 90 | for completeness (e.g., non-yet-observed baryons, leptoquarks). 91 | 92 | 93 | ``pdgid_to_evtgenname.csv`` 94 | =========================== 95 | 96 | A list of matching particle PDG IDs and particle names used by EvtGen. 97 | -------------------------------------------------------------------------------- /src/particle/data/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import sys 9 | 10 | if sys.version_info < (3, 9): 11 | import importlib_resources as resources 12 | else: 13 | from importlib import resources 14 | 15 | __all__ = ("basepath",) 16 | 17 | 18 | basepath = resources.files(__name__) 19 | 20 | 21 | def __dir__() -> tuple[str, ...]: 22 | return __all__ 23 | -------------------------------------------------------------------------------- /src/particle/data/pdgid_to_corsika7id.csv: -------------------------------------------------------------------------------- 1 | # (c) Scikit-HEP project - Particle package data file - pdgid_to_corsika7id.csv - version 14 - 2024-08-08 2 | # Auto generated by 'admin/dump_pdgid_to_corsika7.py' 3 | PDGID,CORSIKA7ID 4 | 22,1 5 | -11,2 6 | 11,3 7 | -13,5 8 | 13,6 9 | 111,7 10 | 211,8 11 | -211,9 12 | 130,10 13 | 321,11 14 | -321,12 15 | 2112,13 16 | 2212,14 17 | -2212,15 18 | 310,16 19 | 221,17 20 | 3122,18 21 | 3222,19 22 | 3212,20 23 | 3112,21 24 | 3322,22 25 | 3312,23 26 | 3334,24 27 | -2112,25 28 | -3122,26 29 | -3222,27 30 | -3212,28 31 | -3112,29 32 | -3322,30 33 | -3312,31 34 | -3334,32 35 | 331,48 36 | 333,49 37 | 223,50 38 | 113,51 39 | 213,52 40 | -213,53 41 | 2224,54 42 | 2214,55 43 | 2114,56 44 | 1114,57 45 | -2224,58 46 | -2214,59 47 | -2114,60 48 | -1114,61 49 | 313,62 50 | 323,63 51 | -323,64 52 | -313,65 53 | 12,66 54 | -12,67 55 | 14,68 56 | -14,69 57 | 421,116 58 | 411,117 59 | -411,118 60 | -421,119 61 | 431,120 62 | -431,121 63 | 441,122 64 | 423,123 65 | 413,124 66 | -413,125 67 | -423,126 68 | 433,127 69 | -433,128 70 | 443,130 71 | -15,131 72 | 15,132 73 | 16,133 74 | -16,134 75 | 4122,137 76 | 4232,138 77 | 4132,139 78 | 4222,140 79 | 4212,141 80 | 4112,142 81 | 4322,143 82 | 4312,144 83 | 4332,145 84 | -4122,149 85 | -4232,150 86 | -4132,151 87 | -4222,152 88 | -4212,153 89 | -4112,154 90 | -4322,155 91 | -4312,156 92 | -4332,157 93 | 4224,161 94 | 4214,162 95 | 4114,163 96 | -4224,171 97 | -4214,172 98 | -4114,173 99 | 511,176 100 | 521,177 101 | -521,178 102 | -511,179 103 | 531,180 104 | -531,181 105 | 541,182 106 | -541,183 107 | 5122,184 108 | 5112,185 109 | 5222,186 110 | 5232,187 111 | 5132,188 112 | 5332,189 113 | -5122,190 114 | -5112,191 115 | -5222,192 116 | -5232,193 117 | -5132,194 118 | -5332,195 119 | 1000010020,201 120 | 1000010030,301 121 | 1000020030,302 122 | 1000010040,401 123 | 1000020040,402 124 | 1000030040,403 125 | 1000010050,501 126 | 1000020050,502 127 | 1000030050,503 128 | 1000040050,504 129 | 1000010060,601 130 | 1000020060,602 131 | 1000030060,603 132 | 1000040060,604 133 | 1000020070,702 134 | 1000030070,703 135 | 1000040070,704 136 | 1000050070,705 137 | 1000020080,802 138 | 1000030080,803 139 | 1000040080,804 140 | 1000050080,805 141 | 1000060080,806 142 | 1000020090,902 143 | 1000030090,903 144 | 1000040090,904 145 | 1000050090,905 146 | 1000060090,906 147 | 1000020100,1002 148 | 1000030100,1003 149 | 1000040100,1004 150 | 1000050100,1005 151 | 1000060100,1006 152 | 1000070100,1007 153 | 1000030110,1103 154 | 1000040110,1104 155 | 1000050110,1105 156 | 1000060110,1106 157 | 1000070110,1107 158 | 1000030120,1203 159 | 1000040120,1204 160 | 1000050120,1205 161 | 1000060120,1206 162 | 1000070120,1207 163 | 1000080120,1208 164 | 1000040130,1304 165 | 1000050130,1305 166 | 1000060130,1306 167 | 1000070130,1307 168 | 1000080130,1308 169 | 1000040140,1404 170 | 1000050140,1405 171 | 1000060140,1406 172 | 1000070140,1407 173 | 1000080140,1408 174 | 1000090140,1409 175 | 1000050150,1505 176 | 1000060150,1506 177 | 1000070150,1507 178 | 1000080150,1508 179 | 1000090150,1509 180 | 1000050160,1605 181 | 1000060160,1606 182 | 1000070160,1607 183 | 1000080160,1608 184 | 1000090160,1609 185 | 1000100160,1610 186 | 1000050170,1705 187 | 1000060170,1706 188 | 1000070170,1707 189 | 1000080170,1708 190 | 1000090170,1709 191 | 1000100170,1710 192 | 1000050180,1805 193 | 1000060180,1806 194 | 1000070180,1807 195 | 1000080180,1808 196 | 1000090180,1809 197 | 1000100180,1810 198 | 1000110180,1811 199 | 1000050190,1905 200 | 1000060190,1906 201 | 1000070190,1907 202 | 1000080190,1908 203 | 1000090190,1909 204 | 1000100190,1910 205 | 1000110190,1911 206 | 1000060200,2006 207 | 1000070200,2007 208 | 1000080200,2008 209 | 1000090200,2009 210 | 1000100200,2010 211 | 1000110200,2011 212 | 1000120200,2012 213 | 1000060210,2106 214 | 1000070210,2107 215 | 1000080210,2108 216 | 1000090210,2109 217 | 1000100210,2110 218 | 1000110210,2111 219 | 1000120210,2112 220 | 1000130210,2113 221 | 1000060220,2206 222 | 1000070220,2207 223 | 1000080220,2208 224 | 1000090220,2209 225 | 1000100220,2210 226 | 1000110220,2211 227 | 1000120220,2212 228 | 1000130220,2213 229 | 1000140220,2214 230 | 1000070230,2307 231 | 1000080230,2308 232 | 1000090230,2309 233 | 1000100230,2310 234 | 1000110230,2311 235 | 1000120230,2312 236 | 1000130230,2313 237 | 1000140230,2314 238 | 1000070240,2407 239 | 1000080240,2408 240 | 1000090240,2409 241 | 1000100240,2410 242 | 1000110240,2411 243 | 1000120240,2412 244 | 1000130240,2413 245 | 1000140240,2414 246 | 1000150240,2415 247 | 1000080250,2508 248 | 1000090250,2509 249 | 1000100250,2510 250 | 1000110250,2511 251 | 1000120250,2512 252 | 1000130250,2513 253 | 1000140250,2514 254 | 1000150250,2515 255 | 1000080260,2608 256 | 1000090260,2609 257 | 1000100260,2610 258 | 1000110260,2611 259 | 1000120260,2612 260 | 1000130260,2613 261 | 1000140260,2614 262 | 1000150260,2615 263 | 1000160260,2616 264 | 1000090270,2709 265 | 1000100270,2710 266 | 1000110270,2711 267 | 1000120270,2712 268 | 1000130270,2713 269 | 1000140270,2714 270 | 1000150270,2715 271 | 1000160270,2716 272 | 1000090280,2809 273 | 1000100280,2810 274 | 1000110280,2811 275 | 1000120280,2812 276 | 1000130280,2813 277 | 1000140280,2814 278 | 1000150280,2815 279 | 1000160280,2816 280 | 1000170280,2817 281 | 1000090290,2909 282 | 1000100290,2910 283 | 1000110290,2911 284 | 1000120290,2912 285 | 1000130290,2913 286 | 1000140290,2914 287 | 1000150290,2915 288 | 1000160290,2916 289 | 1000170290,2917 290 | 1000100300,3010 291 | 1000110300,3011 292 | 1000120300,3012 293 | 1000130300,3013 294 | 1000140300,3014 295 | 1000150300,3015 296 | 1000160300,3016 297 | 1000170300,3017 298 | 1000180300,3018 299 | 1000100310,3110 300 | 1000110310,3111 301 | 1000120310,3112 302 | 1000130310,3113 303 | 1000140310,3114 304 | 1000150310,3115 305 | 1000160310,3116 306 | 1000170310,3117 307 | 1000180310,3118 308 | 1000100320,3210 309 | 1000110320,3211 310 | 1000120320,3212 311 | 1000130320,3213 312 | 1000140320,3214 313 | 1000150320,3215 314 | 1000160320,3216 315 | 1000170320,3217 316 | 1000180320,3218 317 | 1000190320,3219 318 | 1000110330,3311 319 | 1000120330,3312 320 | 1000130330,3313 321 | 1000140330,3314 322 | 1000150330,3315 323 | 1000160330,3316 324 | 1000170330,3317 325 | 1000180330,3318 326 | 1000190330,3319 327 | 1000110340,3411 328 | 1000120340,3412 329 | 1000130340,3413 330 | 1000140340,3414 331 | 1000150340,3415 332 | 1000160340,3416 333 | 1000170340,3417 334 | 1000180340,3418 335 | 1000190340,3419 336 | 1000200340,3420 337 | 1000110350,3511 338 | 1000120350,3512 339 | 1000130350,3513 340 | 1000140350,3514 341 | 1000150350,3515 342 | 1000160350,3516 343 | 1000170350,3517 344 | 1000180350,3518 345 | 1000190350,3519 346 | 1000200350,3520 347 | 1000120360,3612 348 | 1000130360,3613 349 | 1000140360,3614 350 | 1000150360,3615 351 | 1000160360,3616 352 | 1000170360,3617 353 | 1000180360,3618 354 | 1000190360,3619 355 | 1000200360,3620 356 | 1000210360,3621 357 | 1000120370,3712 358 | 1000130370,3713 359 | 1000140370,3714 360 | 1000150370,3715 361 | 1000160370,3716 362 | 1000170370,3717 363 | 1000180370,3718 364 | 1000190370,3719 365 | 1000200370,3720 366 | 1000210370,3721 367 | 1000130380,3813 368 | 1000140380,3814 369 | 1000150380,3815 370 | 1000160380,3816 371 | 1000170380,3817 372 | 1000180380,3818 373 | 1000190380,3819 374 | 1000200380,3820 375 | 1000210380,3821 376 | 1000220380,3822 377 | 1000130390,3913 378 | 1000140390,3914 379 | 1000150390,3915 380 | 1000160390,3916 381 | 1000170390,3917 382 | 1000180390,3918 383 | 1000190390,3919 384 | 1000200390,3920 385 | 1000210390,3921 386 | 1000220390,3922 387 | 1000140400,4014 388 | 1000150400,4015 389 | 1000160400,4016 390 | 1000170400,4017 391 | 1000180400,4018 392 | 1000190400,4019 393 | 1000200400,4020 394 | 1000210400,4021 395 | 1000220400,4022 396 | 1000230400,4023 397 | 1000140410,4114 398 | 1000150410,4115 399 | 1000160410,4116 400 | 1000170410,4117 401 | 1000180410,4118 402 | 1000190410,4119 403 | 1000200410,4120 404 | 1000210410,4121 405 | 1000220410,4122 406 | 1000230410,4123 407 | 1000140420,4214 408 | 1000150420,4215 409 | 1000160420,4216 410 | 1000170420,4217 411 | 1000180420,4218 412 | 1000190420,4219 413 | 1000200420,4220 414 | 1000210420,4221 415 | 1000220420,4222 416 | 1000230420,4223 417 | 1000240420,4224 418 | 1000150430,4315 419 | 1000160430,4316 420 | 1000170430,4317 421 | 1000180430,4318 422 | 1000190430,4319 423 | 1000200430,4320 424 | 1000210430,4321 425 | 1000220430,4322 426 | 1000230430,4323 427 | 1000240430,4324 428 | 1000150440,4415 429 | 1000160440,4416 430 | 1000170440,4417 431 | 1000180440,4418 432 | 1000190440,4419 433 | 1000200440,4420 434 | 1000210440,4421 435 | 1000220440,4422 436 | 1000230440,4423 437 | 1000240440,4424 438 | 1000250440,4425 439 | 1000150450,4515 440 | 1000160450,4516 441 | 1000170450,4517 442 | 1000180450,4518 443 | 1000190450,4519 444 | 1000200450,4520 445 | 1000210450,4521 446 | 1000220450,4522 447 | 1000230450,4523 448 | 1000240450,4524 449 | 1000250450,4525 450 | 1000260450,4526 451 | 1000150460,4615 452 | 1000160460,4616 453 | 1000170460,4617 454 | 1000180460,4618 455 | 1000190460,4619 456 | 1000200460,4620 457 | 1000210460,4621 458 | 1000220460,4622 459 | 1000230460,4623 460 | 1000240460,4624 461 | 1000250460,4625 462 | 1000260460,4626 463 | 1000160470,4716 464 | 1000170470,4717 465 | 1000180470,4718 466 | 1000190470,4719 467 | 1000200470,4720 468 | 1000210470,4721 469 | 1000220470,4722 470 | 1000230470,4723 471 | 1000240470,4724 472 | 1000250470,4725 473 | 1000260470,4726 474 | 1000160480,4816 475 | 1000170480,4817 476 | 1000180480,4818 477 | 1000190480,4819 478 | 1000200480,4820 479 | 1000210480,4821 480 | 1000220480,4822 481 | 1000230480,4823 482 | 1000240480,4824 483 | 1000250480,4825 484 | 1000260480,4826 485 | 1000270480,4827 486 | 1000160490,4916 487 | 1000170490,4917 488 | 1000180490,4918 489 | 1000190490,4919 490 | 1000200490,4920 491 | 1000210490,4921 492 | 1000220490,4922 493 | 1000230490,4923 494 | 1000240490,4924 495 | 1000250490,4925 496 | 1000260490,4926 497 | 1000270490,4927 498 | 1000170500,5017 499 | 1000180500,5018 500 | 1000190500,5019 501 | 1000200500,5020 502 | 1000210500,5021 503 | 1000220500,5022 504 | 1000230500,5023 505 | 1000240500,5024 506 | 1000250500,5025 507 | 1000260500,5026 508 | 1000270500,5027 509 | 1000280500,5028 510 | 1000170510,5117 511 | 1000180510,5118 512 | 1000190510,5119 513 | 1000200510,5120 514 | 1000210510,5121 515 | 1000220510,5122 516 | 1000230510,5123 517 | 1000240510,5124 518 | 1000250510,5125 519 | 1000260510,5126 520 | 1000270510,5127 521 | 1000280510,5128 522 | 1000180520,5218 523 | 1000190520,5219 524 | 1000200520,5220 525 | 1000210520,5221 526 | 1000220520,5222 527 | 1000230520,5223 528 | 1000240520,5224 529 | 1000250520,5225 530 | 1000260520,5226 531 | 1000270520,5227 532 | 1000280520,5228 533 | 1000290520,5229 534 | 1000180530,5318 535 | 1000190530,5319 536 | 1000200530,5320 537 | 1000210530,5321 538 | 1000220530,5322 539 | 1000230530,5323 540 | 1000240530,5324 541 | 1000250530,5325 542 | 1000260530,5326 543 | 1000270530,5327 544 | 1000280530,5328 545 | 1000290530,5329 546 | 1000190540,5419 547 | 1000200540,5420 548 | 1000210540,5421 549 | 1000220540,5422 550 | 1000230540,5423 551 | 1000240540,5424 552 | 1000250540,5425 553 | 1000260540,5426 554 | 1000270540,5427 555 | 1000280540,5428 556 | 1000290540,5429 557 | 1000300540,5430 558 | 1000190550,5519 559 | 1000200550,5520 560 | 1000210550,5521 561 | 1000220550,5522 562 | 1000230550,5523 563 | 1000240550,5524 564 | 1000250550,5525 565 | 1000260550,5526 566 | 1000270550,5527 567 | 1000280550,5528 568 | 1000290550,5529 569 | 1000300550,5530 570 | 1000200560,5620 571 | 1000210560,5621 572 | 1000220560,5622 573 | 1000230560,5623 574 | 1000240560,5624 575 | 1000250560,5625 576 | 1000260560,5626 577 | 1000270560,5627 578 | 1000280560,5628 579 | 1000290560,5629 580 | 1000300560,5630 581 | 1000310560,5631 582 | -------------------------------------------------------------------------------- /src/particle/data/pdgid_to_geant3id.csv: -------------------------------------------------------------------------------- 1 | # (c) Scikit-HEP project - Particle package data file - pdgid_to_geant3id.csv - version 14 - 2024-08-08 2 | PDGID,GEANT3ID 3 | 1,303 4 | -1,304 5 | 2,305 6 | -2,306 7 | 3,307 8 | -3,308 9 | 4,309 10 | -4,310 11 | 5,311 12 | -5,312 13 | 6,313 14 | -6,314 15 | 7,315 16 | -7,316 17 | 8,317 18 | -8,318 19 | 11,3 20 | -11,2 21 | 12,4 22 | -12,302 23 | 13,6 24 | -13,5 25 | 14,300 26 | -14,301 27 | 15,52 28 | -15,51 29 | 16,319 30 | -16,320 31 | 17,321 32 | -17,322 33 | 18,323 34 | -18,324 35 | 21,325 36 | 22,1 37 | 23,55 38 | 24,53 39 | -24,54 40 | 25,87 41 | 32,326 42 | 33,327 43 | 34,328 44 | -34,329 45 | 35,88 46 | 36,89 47 | 37,90 48 | -37,91 49 | 39,330 50 | 41,331 51 | -41,332 52 | 42,333 53 | -42,334 54 | 43,335 55 | 44,336 56 | -44,337 57 | 81,338 58 | 82,339 59 | -82,340 60 | 83,341 61 | 84,342 62 | -84,343 63 | 85,344 64 | -85,345 65 | 86,346 66 | -86,347 67 | 87,348 68 | -87,349 69 | 88,350 70 | 90,351 71 | 91,352 72 | 92,353 73 | 93,354 74 | 94,355 75 | 95,356 76 | 96,357 77 | 97,358 78 | 98,359 79 | 111,7 80 | 113,33 81 | 115,136 82 | 117,361 83 | 119,362 84 | 130,10 85 | 150,99999 86 | 211,8 87 | -211,9 88 | 213,34 89 | -213,35 90 | 215,137 91 | -215,138 92 | 217,363 93 | -217,364 94 | 219,365 95 | -219,366 96 | 221,17 97 | 223,36 98 | 225,367 99 | 227,368 100 | 229,369 101 | 310,16 102 | 311,370 103 | -311,371 104 | 313,40 105 | -313,41 106 | 315,153 107 | -315,154 108 | 317,372 109 | -317,373 110 | 319,374 111 | -319,375 112 | 321,11 113 | -321,12 114 | 323,38 115 | -323,39 116 | 325,151 117 | -325,152 118 | 327,376 119 | -327,377 120 | 329,378 121 | -329,379 122 | 331,127 123 | 333,37 124 | 335,380 125 | 337,381 126 | 350,99997 127 | 411,56 128 | -411,57 129 | 413,65 130 | -413,66 131 | 415,162 132 | -415,158 133 | 421,58 134 | -421,59 135 | 423,67 136 | -423,68 137 | 425,170 138 | -425,166 139 | 431,60 140 | -431,61 141 | 433,69 142 | -433,70 143 | 435,174 144 | -435,178 145 | 441,128 146 | 443,64 147 | 445,131 148 | 510,99998 149 | 511,73 150 | -511,74 151 | 513,189 152 | -513,190 153 | 515,204 154 | -515,208 155 | 521,71 156 | -521,72 157 | 523,188 158 | -523,187 159 | 525,196 160 | -525,200 161 | 530,99996 162 | 531,75 163 | -531,76 164 | 533,191 165 | -533,192 166 | 535,212 167 | -535,216 168 | 541,77 169 | -541,78 170 | 543,382 171 | -543,383 172 | 545,384 173 | -545,385 174 | 551,386 175 | 553,387 176 | 555,388 177 | 557,389 178 | 1103,394 179 | -1103,395 180 | 1112,396 181 | -1112,397 182 | 1114,182 183 | -1114,186 184 | 1116,398 185 | -1116,399 186 | 1118,400 187 | -1118,401 188 | 1212,402 189 | -1212,403 190 | 1214,404 191 | -1214,405 192 | 1216,406 193 | -1216,407 194 | 1218,408 195 | -1218,409 196 | 2101,410 197 | -2101,411 198 | 2103,412 199 | -2103,413 200 | 2112,13 201 | -2112,25 202 | 2114,181 203 | -2114,185 204 | 2116,414 205 | -2116,415 206 | 2118,416 207 | -2118,417 208 | 2122,418 209 | -2122,419 210 | 2124,420 211 | -2124,421 212 | 2126,422 213 | -2126,423 214 | 2128,424 215 | -2128,425 216 | 2203,426 217 | -2203,427 218 | 2212,14 219 | -2212,15 220 | 2214,180 221 | -2214,184 222 | 2216,428 223 | -2216,429 224 | 2218,430 225 | -2218,431 226 | 2222,432 227 | -2222,433 228 | 2224,179 229 | -2224,183 230 | 2226,434 231 | -2226,435 232 | 2228,436 233 | -2228,437 234 | 3101,438 235 | -3101,439 236 | 3103,440 237 | -3103,441 238 | 3112,21 239 | -3112,29 240 | 3114,442 241 | -3114,443 242 | 3116,444 243 | -3116,445 244 | 3118,446 245 | -3118,447 246 | 3122,18 247 | -3122,26 248 | 3124,448 249 | -3124,449 250 | 3126,450 251 | -3126,451 252 | 3128,452 253 | -3128,453 254 | 3201,454 255 | -3201,455 256 | 3203,456 257 | -3203,457 258 | 3212,20 259 | -3212,28 260 | 3214,458 261 | -3214,459 262 | 3216,460 263 | -3216,461 264 | 3218,462 265 | -3218,463 266 | 3222,19 267 | -3222,27 268 | 3224,464 269 | -3224,465 270 | 3226,466 271 | -3226,467 272 | 3228,468 273 | -3228,469 274 | 3303,470 275 | -3303,471 276 | 3312,23 277 | -3312,31 278 | 3314,472 279 | -3314,473 280 | 3322,22 281 | -3322,30 282 | 3324,474 283 | -3324,475 284 | 3334,24 285 | -3334,32 286 | 4101,476 287 | -4101,477 288 | 4103,478 289 | -4103,479 290 | 4112,81 291 | -4112,82 292 | 4114,480 293 | -4114,481 294 | 4122,62 295 | -4122,63 296 | 4132,106 297 | -4132,107 298 | 4201,482 299 | -4201,483 300 | 4203,484 301 | -4203,485 302 | 4212,83 303 | -4212,84 304 | 4214,486 305 | -4214,487 306 | 4222,85 307 | -4222,86 308 | 4224,488 309 | -4224,489 310 | 4232,108 311 | -4232,109 312 | 4301,490 313 | -4301,491 314 | 4303,492 315 | -4303,493 316 | 4312,100 317 | -4312,101 318 | 4314,494 319 | -4314,495 320 | 4322,102 321 | -4322,103 322 | 4324,496 323 | -4324,497 324 | 4332,104 325 | -4332,105 326 | 4334,498 327 | -4334,499 328 | 4403,500 329 | -4403,501 330 | 4412,502 331 | -4412,503 332 | 4414,504 333 | -4414,505 334 | 4422,506 335 | -4422,507 336 | 4424,508 337 | -4424,509 338 | 4432,510 339 | -4432,511 340 | 4434,512 341 | -4434,513 342 | 4444,514 343 | -4444,515 344 | 5101,516 345 | -5101,517 346 | 5103,518 347 | -5103,519 348 | 5112,114 349 | -5112,115 350 | 5114,520 351 | -5114,521 352 | 5122,79 353 | -5122,80 354 | 5124,1067 355 | -5124,1068 356 | 5132,122 357 | -5132,123 358 | 5142,522 359 | -5142,523 360 | 5201,524 361 | -5201,525 362 | 5203,526 363 | -5203,527 364 | 5212,112 365 | -5212,113 366 | 5214,528 367 | -5214,529 368 | 5222,110 369 | -5222,111 370 | 5224,530 371 | -5224,531 372 | 5232,124 373 | -5232,125 374 | 5242,532 375 | -5242,533 376 | 5301,534 377 | -5301,535 378 | 5303,536 379 | -5303,537 380 | 5312,116 381 | -5312,117 382 | 5314,538 383 | -5314,539 384 | 5322,118 385 | -5322,119 386 | 5324,540 387 | -5324,541 388 | 5332,120 389 | -5332,121 390 | 5334,542 391 | -5334,543 392 | 5342,544 393 | -5342,545 394 | 5401,546 395 | -5401,547 396 | 5403,548 397 | -5403,549 398 | 5412,550 399 | -5412,551 400 | 5414,552 401 | -5414,553 402 | 5422,554 403 | -5422,555 404 | 5424,556 405 | -5424,557 406 | 5432,558 407 | -5432,559 408 | 5434,560 409 | -5434,561 410 | 5442,562 411 | -5442,563 412 | 5444,564 413 | -5444,565 414 | 5503,566 415 | -5503,567 416 | 5512,568 417 | -5512,569 418 | 5514,570 419 | -5514,571 420 | 5522,572 421 | -5522,573 422 | 5524,574 423 | -5524,575 424 | 5532,576 425 | -5532,577 426 | 5534,578 427 | -5534,579 428 | 5542,580 429 | -5542,581 430 | 5544,582 431 | -5544,583 432 | 5554,584 433 | -5554,585 434 | 10022,586 435 | 10111,587 436 | 10113,588 437 | 10115,589 438 | 10211,590 439 | -10211,591 440 | 10213,592 441 | -10213,593 442 | 10215,594 443 | -10215,595 444 | 10221,686 445 | 10223,597 446 | 10225,598 447 | 10311,149 448 | -10311,150 449 | 10313,141 450 | -10313,142 451 | 10315,599 452 | -10315,600 453 | 10321,147 454 | -10321,148 455 | 10323,139 456 | -10323,140 457 | 10325,601 458 | -10325,602 459 | 10331,603 460 | 10333,604 461 | 10335,605 462 | 10411,155 463 | -10411,159 464 | 10413,157 465 | -10413,161 466 | 10421,163 467 | -10421,167 468 | 10423,165 469 | -10423,169 470 | 10431,171 471 | -10431,175 472 | 10433,173 473 | -10433,177 474 | 10441,129 475 | 10443,606 476 | 10511,201 477 | -10511,205 478 | 10513,203 479 | -10513,207 480 | 10521,193 481 | -10521,197 482 | 10523,195 483 | -10523,199 484 | 10531,209 485 | -10531,213 486 | 10533,211 487 | -10533,215 488 | 10541,607 489 | -10541,608 490 | 10543,609 491 | -10543,610 492 | 10551,611 493 | 10553,612 494 | 10555,613 495 | 11112,614 496 | -11112,615 497 | 11114,616 498 | -11114,617 499 | 11116,618 500 | -11116,619 501 | 11212,620 502 | -11212,621 503 | 11216,622 504 | -11216,623 505 | 12112,624 506 | -12112,625 507 | 12114,626 508 | -12114,627 509 | 12116,628 510 | -12116,629 511 | 12118,630 512 | -12118,631 513 | 12122,632 514 | -12122,633 515 | 12126,634 516 | -12126,635 517 | 12212,636 518 | -12212,637 519 | 12214,638 520 | -12214,639 521 | 12216,640 522 | -12216,641 523 | 12218,642 524 | -12218,643 525 | 12222,644 526 | -12222,645 527 | 12224,646 528 | -12224,647 529 | 12226,648 530 | -12226,649 531 | 13112,650 532 | -13112,651 533 | 13114,652 534 | -13114,653 535 | 13116,654 536 | -13116,655 537 | 13122,656 538 | -13122,657 539 | 13124,658 540 | -13124,659 541 | 13126,660 542 | -13126,661 543 | 13212,662 544 | -13212,663 545 | 13214,664 546 | -13214,665 547 | 13216,666 548 | -13216,667 549 | 13222,668 550 | -13222,669 551 | 13224,670 552 | -13224,671 553 | 13226,672 554 | -13226,673 555 | 13314,674 556 | -13314,675 557 | 13324,678 558 | -13324,679 559 | 14122,682 560 | -14122,683 561 | 15122,1065 562 | -15122,1066 563 | 20022,50 564 | 20113,135 565 | 20213,42 566 | -20213,43 567 | 20223,687 568 | 20313,145 569 | -20313,146 570 | 20315,688 571 | -20315,689 572 | 20323,143 573 | -20323,144 574 | 20325,690 575 | -20325,691 576 | 20333,692 577 | 20413,156 578 | -20413,160 579 | 20423,164 580 | -20423,168 581 | 20433,172 582 | -20433,176 583 | 20443,130 584 | 20513,202 585 | -20513,206 586 | 20523,194 587 | -20523,198 588 | 20533,210 589 | -20533,214 590 | 20543,693 591 | -20543,694 592 | 20553,695 593 | 20555,696 594 | 21112,697 595 | -21112,698 596 | 21114,699 597 | -21114,700 598 | 21212,701 599 | -21212,702 600 | 21214,703 601 | -21214,704 602 | 22112,705 603 | -22112,706 604 | 22114,707 605 | -22114,708 606 | 22122,709 607 | -22122,710 608 | 22124,711 609 | -22124,712 610 | 22212,713 611 | -22212,714 612 | 22214,715 613 | -22214,716 614 | 22222,717 615 | -22222,718 616 | 22224,719 617 | -22224,720 618 | 23112,721 619 | -23112,722 620 | 23114,723 621 | -23114,724 622 | 23122,725 623 | -23122,726 624 | 23124,727 625 | -23124,728 626 | 23126,729 627 | -23126,730 628 | 23212,731 629 | -23212,732 630 | 23214,733 631 | -23214,734 632 | 23222,735 633 | -23222,736 634 | 23224,737 635 | -23224,738 636 | 30113,743 637 | 30213,744 638 | -30213,745 639 | 30223,746 640 | 30313,747 641 | -30313,748 642 | 30323,749 643 | -30323,750 644 | 30343,751 645 | -30343,752 646 | 30353,753 647 | -30353,754 648 | 30363,755 649 | -30363,756 650 | 30443,765 651 | 30553,766 652 | 31114,767 653 | -31114,768 654 | 31214,769 655 | -31214,770 656 | 32112,771 657 | -32112,772 658 | 32114,773 659 | -32114,774 660 | 32124,775 661 | -32124,776 662 | 32212,777 663 | -32212,778 664 | 32214,779 665 | -32214,780 666 | 32224,781 667 | -32224,782 668 | 33122,783 669 | -33122,784 670 | 41214,789 671 | -41214,790 672 | 42112,791 673 | -42112,792 674 | 42124,793 675 | -42124,794 676 | 42212,795 677 | -42212,796 678 | 43122,797 679 | -43122,798 680 | 52114,799 681 | -52114,800 682 | 52214,801 683 | -52214,802 684 | 53122,803 685 | -53122,804 686 | 100111,805 687 | 100113,806 688 | 100211,807 689 | -100211,808 690 | 100213,809 691 | -100213,810 692 | 100221,811 693 | 100223,812 694 | 100311,814 695 | -100311,815 696 | 100313,816 697 | -100313,817 698 | 100321,820 699 | -100321,821 700 | 100323,822 701 | -100323,823 702 | 100331,826 703 | 100333,827 704 | 100411,757 705 | -100411,758 706 | 100413,759 707 | -100413,760 708 | 100421,761 709 | -100421,762 710 | 100423,763 711 | -100423,764 712 | 100441,829 713 | 100443,126 714 | 100445,1031 715 | 100551,830 716 | 100553,831 717 | 100555,832 718 | 100557,833 719 | 103112,1063 720 | -103112,1064 721 | 103212,1059 722 | -103212,1060 723 | 103222,1061 724 | -103222,1062 725 | 103316,1037 726 | -103316,1038 727 | 103326,1039 728 | -103326,1040 729 | 104122,1047 730 | -104122,1048 731 | 104312,1057 732 | -104312,1058 733 | 104314,1053 734 | -104314,1054 735 | 104322,1055 736 | -104322,1056 737 | 104324,1051 738 | -104324,1052 739 | 110551,834 740 | 110553,835 741 | 110555,836 742 | 120553,837 743 | 120555,838 744 | 130553,839 745 | 200551,843 746 | 200553,844 747 | 200555,845 748 | 203312,1033 749 | -203312,1034 750 | 203316,1041 751 | -203316,1042 752 | 203322,1035 753 | -203322,1036 754 | 203326,1043 755 | -203326,1044 756 | 203338,1045 757 | -203338,1046 758 | 204126,1049 759 | -204126,1050 760 | 210551,846 761 | 210553,847 762 | 220553,848 763 | 300553,849 764 | 1000001,859 765 | -1000001,860 766 | 1000002,861 767 | -1000002,862 768 | 1000003,863 769 | -1000003,864 770 | 1000004,865 771 | -1000004,866 772 | 1000005,867 773 | -1000005,868 774 | 1000006,869 775 | -1000006,870 776 | 1000011,871 777 | -1000011,872 778 | 1000012,873 779 | -1000012,874 780 | 1000013,875 781 | -1000013,876 782 | 1000014,877 783 | -1000014,878 784 | 1000015,879 785 | -1000015,880 786 | 1000016,881 787 | -1000016,882 788 | 1000021,883 789 | 1000022,884 790 | 1000023,885 791 | 1000024,886 792 | -1000024,887 793 | 1000025,888 794 | 1000035,889 795 | 1000037,890 796 | -1000037,891 797 | 1000039,892 798 | 2000001,893 799 | -2000001,894 800 | 2000002,895 801 | -2000002,896 802 | 2000003,897 803 | -2000003,898 804 | 2000004,899 805 | -2000004,900 806 | 2000005,901 807 | -2000005,902 808 | 2000006,903 809 | -2000006,904 810 | 2000011,905 811 | -2000011,906 812 | 2000012,907 813 | -2000012,908 814 | 2000013,909 815 | -2000013,910 816 | 2000014,911 817 | -2000014,912 818 | 2000015,913 819 | -2000015,914 820 | 2000016,915 821 | -2000016,916 822 | 3000111,917 823 | 3000113,918 824 | 3000211,919 825 | -3000211,920 826 | 3000213,921 827 | -3000213,922 828 | 3000221,923 829 | 3000223,924 830 | 3000331,925 831 | 3100021,926 832 | 4000001,933 833 | -4000001,934 834 | 4000002,935 835 | -4000002,936 836 | 4000011,937 837 | -4000011,938 838 | 4000012,939 839 | -4000012,940 840 | 5000039,941 841 | 9000111,132 842 | 9000113,1021 843 | 9000211,133 844 | -9000211,134 845 | 9000213,1023 846 | -9000213,1024 847 | 9000221,850 848 | 9000443,851 849 | 9000553,852 850 | 9010111,840 851 | 9010113,1027 852 | 9010211,841 853 | -9010211,842 854 | 9010213,1029 855 | -9010213,1030 856 | 9010221,596 857 | 9010315,818 858 | -9010315,819 859 | 9010325,824 860 | -9010325,825 861 | 9010443,853 862 | 9010553,854 863 | 9020221,1025 864 | 9020443,856 865 | 9030221,855 866 | 9042413,1018 867 | -9042413,1019 868 | 9050225,813 869 | 9060225,828 870 | 9080225,857 871 | 9090225,858 872 | 9910445,1017 873 | 9920443,1016 874 | -99000000,971 875 | 480000000,48 876 | 1000010020,45 877 | -1000010020,390 878 | 1000010030,46 879 | -1000010030,392 880 | -1000020030,391 881 | 1000020030,49 882 | -1000020040,393 883 | 1000020040,47 884 | 1000030070,988 885 | 1000040080,992 886 | 1000040090,959 887 | 1000040100,993 888 | 1000050100,994 889 | 1000050110,974 890 | 1000050120,975 891 | 1000060120,953 892 | 1000060130,976 893 | 1000060140,977 894 | 1000070140,955 895 | 1000070150,982 896 | 1000070160,995 897 | 1000080160,956 898 | 1000080170,996 899 | 1000080180,967 900 | 1000080190,997 901 | 1000090190,960 902 | 1000100220,983 903 | 1000100230,998 904 | 1000110240,999 905 | 1000120240,979 906 | 1000120250,989 907 | 1000120260,980 908 | 1000120270,981 909 | 1000130270,952 910 | 1000130280,972 911 | 1000140280,957 912 | 1000140290,964 913 | 1000140300,968 914 | 1000150310,1000 915 | 1000170390,1001 916 | 1000170400,1002 917 | 1000180360,1003 918 | 1000180400,973 919 | 1000240500,1004 920 | 1000240520,978 921 | 1000240530,990 922 | 1000240540,1005 923 | 1000250550,991 924 | 1000260540,966 925 | 1000260560,961 926 | 1000260570,969 927 | 1000260590,1006 928 | 1000280580,984 929 | 1000280600,985 930 | 1000280610,1007 931 | 1000280620,986 932 | 1000280630,1008 933 | 1000280640,987 934 | 1000290630,954 935 | 1000290650,958 936 | 1000420920,1009 937 | 1000420950,1010 938 | 1000420960,1011 939 | 1000420970,1012 940 | 1000420980,1013 941 | 1000421000,1014 942 | 1000461080,1015 943 | 1000791970,1020 944 | 1000822040,970 945 | 1000822060,965 946 | 1000822070,962 947 | 1000822080,963 948 | -------------------------------------------------------------------------------- /src/particle/data/pdgid_to_latexname.csv: -------------------------------------------------------------------------------- 1 | # (c) Scikit-HEP project - Particle package data file - pdgid_to_latexname.csv - version 14 - 2024-08-08 2 | PDGID,LATEXNAME 3 | 1,d 4 | 2,u 5 | 3,s 6 | 4,c 7 | 5,b 8 | 6,t 9 | 7,b^\prime 10 | 8,t^\prime 11 | 11,e^{-} 12 | 12,\nu_{e} 13 | 13,\mu^{-} 14 | 14,\nu_{\mu} 15 | 15,\tau^{-} 16 | 16,\nu_{\tau} 17 | 17,\tau^{\prime -} 18 | 18,\nu_{\tau^\prime} 19 | 21,g 20 | 22,\gamma 21 | 23,Z^{0} 22 | 24,W^{+} 23 | 25,H^{0} 24 | 32,Z^{\prime 0} 25 | 33,Z^{\prime\prime 0} 26 | 34,W^{\prime +} 27 | 35,H_{2}^{0} 28 | 36,H_{3}^{0} 29 | 37,H^{+} 30 | 38,H^{++} 31 | 39,G 32 | 40,H_{4}^{0} 33 | 41,R^{0} 34 | 42,LQ^{c} 35 | 43,X_{u}^{0} 36 | 44,X_{u}^{+} 37 | 81,specflav 38 | 82,rndmflav 39 | 83,phasespa 40 | 84,c-hadron 41 | 85,b-hadron 42 | 86,t-hadron 43 | 87,b^\prime-hadron 44 | 88,junction 45 | 90,system 46 | 91,cluster 47 | 92,string 48 | 93,indep 49 | 94,CMshower 50 | 95,SPHEaxis 51 | 96,THRUaxis 52 | 97,CLUSjet 53 | 98,CELLjet 54 | 111,\pi^{0} 55 | 113,\rho(770)^{0} 56 | 115,a_{2}(1320)^{0} 57 | 117,\rho_{3}(1690)^{0} 58 | 119,a_{4}(1970)^{0} 59 | 130,K_{L}^{0} 60 | 150,B_{L}^{0} 61 | 211,\pi^{+} 62 | 213,\rho(770)^{+} 63 | 215,a_{2}(1320)^{+} 64 | 217,\rho_{3}(1690)^{+} 65 | 219,a_{4}(1970)^{+} 66 | 221,\eta 67 | 223,\omega(782) 68 | 225,f_{2}(1270) 69 | 227,\omega_{3}(1670) 70 | 229,f_{4}(2050) 71 | 310,K_{S}^{0} 72 | 311,K^{0} 73 | 313,K^{*}(892)^{0} 74 | 315,K_{2}^{*}(1430)^{0} 75 | 317,K_{3}^{*}(1780)^{0} 76 | 319,K_{4}^{*}(2045)^{0} 77 | 321,K^{+} 78 | 323,K^{*}(892)^{+} 79 | 325,K_{2}^{*}(1430)^{+} 80 | 327,K_{3}^{*}(1780)^{+} 81 | 329,K_{4}^{*}(2045)^{+} 82 | 331,\eta^\prime(958) 83 | 333,\phi(1020) 84 | 335,f_{2}^\prime(1525) 85 | 337,\phi_{3}(1850) 86 | 350,B_{sL}^{0} 87 | 411,D^{+} 88 | 413,D^{*}(2010)^{+} 89 | 415,D_{2}^{*}(2460)^{+} 90 | 421,D^{0} 91 | 423,D^{*}(2007)^{0} 92 | 425,D_{2}^{*}(2460)^{0} 93 | 431,D_{s}^{+} 94 | 433,D_{s}^{*+} 95 | 435,D_{s2}^{*}(2573)^{+} 96 | 441,\eta_{c}(1S) 97 | 443,J/\psi(1S) 98 | 445,\chi_{c2}(1P) 99 | 510,B_{H}^{0} 100 | 511,B^{0} 101 | 513,B^{*0} 102 | 515,B_{2}^{*}(5747)^{0} 103 | 521,B^{+} 104 | 523,B^{*+} 105 | 525,B_{2}^{*}(5747)^{+} 106 | 530,B_{sH}^{0} 107 | 531,B_{s}^{0} 108 | 533,B_{s}^{*0} 109 | 535,B_{s2}^{*}(5840)^{0} 110 | 541,B_{c}^{+} 111 | 543,B_{c}^{*+} 112 | 545,B_{c2}^{*+} 113 | 551,\eta_{b}(1S) 114 | 553,\Upsilon(1S) 115 | 555,\chi_{b2}(1P) 116 | 557,\Upsilon_{3}(1D) 117 | 1103,(dd)_{1} 118 | 1112,\Delta(1620)^{-} 119 | 1114,\Delta(1232)^{-} 120 | 1116,\Delta(1905)^{-} 121 | 1118,\Delta(1950)^{-} 122 | 1212,\Delta(1620)^{0} 123 | 1214,N(1520)^{0} 124 | 1216,\Delta(1905)^{0} 125 | 1218,N(2190)^{0} 126 | 2101,(ud)_{0} 127 | 2103,(ud)_{1} 128 | 2112,n 129 | 2114,\Delta(1232)^{0} 130 | 2116,N(1675)^{0} 131 | 2118,\Delta(1950)^{0} 132 | 2122,\Delta(1620)^{+} 133 | 2124,N(1520)^{+} 134 | 2126,\Delta(1905)^{+} 135 | 2128,N(2190)^{+} 136 | 2203,(uu)_{1} 137 | 2212,p 138 | 2214,\Delta(1232)^{+} 139 | 2216,N(1675)^{+} 140 | 2218,\Delta(1950)^{+} 141 | 2222,\Delta(1620)^{++} 142 | 2224,\Delta(1232)^{++} 143 | 2226,\Delta(1905)^{++} 144 | 2228,\Delta(1950)^{++} 145 | 3101,(sd)_{0} 146 | 3103,(sd)_{1} 147 | 3112,\Sigma^{-} 148 | 3114,\Sigma(1385)^{-} 149 | 3116,\Sigma(1775)^{-} 150 | 3118,\Sigma(2030)^{-} 151 | 3122,\Lambda 152 | 3124,\Lambda(1520) 153 | 3126,\Lambda(1820) 154 | 3128,\Lambda(2100) 155 | 3201,(su)_{0} 156 | 3203,(su)_{1} 157 | 3212,\Sigma^{0} 158 | 3214,\Sigma(1385)^{0} 159 | 3216,\Sigma(1775)^{0} 160 | 3218,\Sigma(2030)^{0} 161 | 3222,\Sigma^{+} 162 | 3224,\Sigma(1385)^{+} 163 | 3226,\Sigma(1775)^{+} 164 | 3228,\Sigma(2030)^{+} 165 | 3303,(ss)_{1} 166 | 3312,\Xi^{-} 167 | 3314,\Xi(1530)^{-} 168 | 3322,\Xi^{0} 169 | 3324,\Xi(1530)^{0} 170 | 3334,\Omega^{-} 171 | 4101,(cd)_{0} 172 | 4103,(cd)_{1} 173 | 4112,\Sigma_{c}^{0} 174 | 4114,\Sigma_{c}(2520)^{0} 175 | 4122,\Lambda_{c}^{+} 176 | 4132,\Xi_{c}^{0} 177 | 4201,(cu)_{0} 178 | 4203,(cu)_{1} 179 | 4212,\Sigma_{c}(2455)^{+} 180 | 4214,\Sigma_{c}(2520)^{+} 181 | 4222,\Sigma_{c}(2455)^{++} 182 | 4224,\Sigma_{c}(2520)^{++} 183 | 4232,\Xi_{c}^{+} 184 | 4301,(cs)_{0} 185 | 4303,(cs)_{1} 186 | 4312,\Xi_{c}^{\prime 0} 187 | 4314,\Xi_{c}(2645)^{0} 188 | 4322,\Xi_{c}^{\prime +} 189 | 4324,\Xi_{c}(2645)^{+} 190 | 4332,\Omega_{c}^{0} 191 | 4334,\Omega_{c}(2770)^{0} 192 | 4403,(cc)_{1} 193 | 4412,\Xi_{cc}^{+} 194 | 4414,\Xi_{cc}^{*+} 195 | 4422,\Xi_{cc}^{++} 196 | 4424,\Xi_{cc}^{*++} 197 | 4432,\Omega_{cc}^{+} 198 | 4434,\Omega_{cc}^{*+} 199 | 4444,\Omega_{ccc}^{*++} 200 | 5101,(bd)_{0} 201 | 5103,(bd)_{1} 202 | 5112,\Sigma_{b}^{-} 203 | 5114,\Sigma_{b}^{*-} 204 | 5122,\Lambda_{b}^{0} 205 | 5124,\Lambda_{b}(5920)^{0} 206 | 5132,\Xi_{b}^{-} 207 | 5142,\Xi_{bc}^{0} 208 | 5201,(bu)_{0} 209 | 5203,(bu)_{1} 210 | 5212,\Sigma_{b}^{0} 211 | 5214,\Sigma_{b}^{*0} 212 | 5222,\Sigma_{b}^{+} 213 | 5224,\Sigma_{b}^{*+} 214 | 5232,\Xi_{b}^{0} 215 | 5242,\Xi_{bc}^{+} 216 | 5301,(bs)_{0} 217 | 5303,(bs)_{1} 218 | 5312,\Xi_{b}^{\prime -} 219 | 5314,\Xi_{b}^{*-} 220 | 5322,\Xi_{b}^{\prime 0} 221 | 5324,\Xi_{b}^{*0} 222 | 5332,\Omega_{b}^{-} 223 | 5334,\Omega_{b}^{*-} 224 | 5342,\Omega_{bc}^{0} 225 | 5401,(bc)_{0} 226 | 5403,(bc)_{1} 227 | 5412,\Xi_{bc}^{\prime 0} 228 | 5414,\Xi_{bc}^{*0} 229 | 5422,\Xi_{bc}^{\prime +} 230 | 5424,\Xi_{bc}^{*+} 231 | 5432,\Omega_{bc}^{\prime 0} 232 | 5434,\Omega_{bc}^{*0} 233 | 5442,\Omega_{bcc}^{+} 234 | 5444,\Omega_{bcc}^{*+} 235 | 5503,(bb)_{1} 236 | 5512,\Xi_{bb}^{-} 237 | 5514,\Xi_{bb}^{*-} 238 | 5522,\Xi_{bb}^{0} 239 | 5524,\Xi_{bb}^{*0} 240 | 5532,\Omega_{bb}^{-} 241 | 5534,\Omega_{bb}^{*-} 242 | 5542,\Omega_{bbc}^{0} 243 | 5544,\Omega_{bbc}^{*0} 244 | 5554,\Omega_{bbb}^{-} 245 | 10022,vpho 246 | 10111,a_{0}(1450)^{0} 247 | 10113,b_{1}(1235)^{0} 248 | 10115,\pi_{2}(1670)^{0} 249 | 10211,a_{0}(1450)^{+} 250 | 10213,b_{1}(1235)^{+} 251 | 10215,\pi_{2}(1670)^{+} 252 | 10221,f_{0}(1370) 253 | 10223,h_{1}(1170) 254 | 10225,\eta_{2}(1645) 255 | 10311,K_{0}^{*}(1430)^{0} 256 | 10313,K_{1}(1270)^{0} 257 | 10315,K_{2}(1770)^{0} 258 | 10321,K_{0}^{*}(1430)^{+} 259 | 10323,K_{1}(1270)^{+} 260 | 10325,K_{2}(1770)^{+} 261 | 10331,f_{0}(1710) 262 | 10333,h_{1}(1415) 263 | 10335,\eta_{2}(1870) 264 | 10411,D_{0}^{*}(2300)^{+} 265 | 10413,D_{1}(2420)^{+} 266 | 10421,D_{0}^{*}(2300)^{0} 267 | 10423,D_{1}(2420)^{0} 268 | 10431,D_{s0}^{*}(2317)^{+} 269 | 10433,D_{s1}(2536)^{+} 270 | 10441,\chi_{c0}(1P) 271 | 10443,h_{c}(1P) 272 | 10511,B_{0}^{*0} 273 | 10513,B_{1}(5721)^{0} 274 | 10521,B_{0}^{*+} 275 | 10523,B_{1}(5721)^{+} 276 | 10531,B_{s0}^{*0} 277 | 10533,B_{s1}(L)^{0} 278 | 10541,B_{c0}^{*+} 279 | 10543,B_{c1}(L)^{+} 280 | 10551,\chi_{b0}(1P) 281 | 10553,h_{b}(1P) 282 | 10555,\eta_{b2}(1D) 283 | 11112,\Delta(1900)^{-} 284 | 11114,\Delta(1700)^{-} 285 | 11116,\Delta(1930)^{-} 286 | 11212,\Delta(1900)^{0} 287 | 11216,\Delta(1930)^{0} 288 | 12112,N(1440)^{0} 289 | 12114,\Delta(1700)^{0} 290 | 12116,N(1680)^{0} 291 | 12118,N(1990)^{0} 292 | 12122,\Delta(1900)^{+} 293 | 12126,\Delta(1930)^{+} 294 | 12212,N(1440)^{+} 295 | 12214,\Delta(1700)^{+} 296 | 12216,N(1680)^{+} 297 | 12218,N(1990)^{+} 298 | 12222,\Delta(1900)^{++} 299 | 12224,\Delta(1700)^{++} 300 | 12226,\Delta(1930)^{++} 301 | 13112,\Sigma(1660)^{-} 302 | 13114,\Sigma(1670)^{-} 303 | 13116,\Sigma(1915)^{-} 304 | 13122,\Lambda(1405) 305 | 13124,\Lambda(1690) 306 | 13126,\Lambda(1830) 307 | 13212,\Sigma(1660)^{0} 308 | 13214,\Sigma(1670)^{0} 309 | 13216,\Sigma(1915)^{0} 310 | 13222,\Sigma(1660)^{+} 311 | 13224,\Sigma(1670)^{+} 312 | 13226,\Sigma(1915)^{+} 313 | 13314,\Xi(1820)^{-} 314 | 13324,\Xi(1820)^{0} 315 | 14122,\Lambda_{c}(2593)^{+} 316 | 15122,\Lambda_{b}(5912)^{0} 317 | 20022,opticalphoton 318 | 20113,a_{1}(1260)^{0} 319 | 20213,a_{1}(1260)^{+} 320 | 20223,f_{1}(1285) 321 | 20313,K_{1}(1400)^{0} 322 | 20315,K_{2}(1820)^{0} 323 | 20323,K_{1}(1400)^{+} 324 | 20325,K_{2}(1820)^{+} 325 | 20333,f_{1}(1420) 326 | 20413,D_{1}(H)^{+} 327 | 20423,D_{1}(2430)^{0} 328 | 20433,D_{s1}(2460)^{+} 329 | 20443,\chi_{c1}(1P) 330 | 20513,B_{1}(H)^{0} 331 | 20523,B_{1}(H)^{+} 332 | 20533,B_{s1}(H)^{0} 333 | 20543,B_{c1}(H)^{+} 334 | 20553,\chi_{b1}(1P) 335 | 20555,\Upsilon_{2}(1D) 336 | 21112,\Delta(1910)^{-} 337 | 21114,\Delta(1920)^{-} 338 | 21212,\Delta(1910)^{0} 339 | 21214,N(1700)^{0} 340 | 22112,\Delta(1910)^{0} 341 | 22114,\Delta(1920)^{0} 342 | 22122,\Delta(1910)^{+} 343 | 22124,N(1700)^{+} 344 | 22212,N(1535)^{+} 345 | 22214,\Delta(1920)^{+} 346 | 22222,\Delta(1910)^{++} 347 | 22224,\Delta(1920)^{++} 348 | 23112,\Sigma(1750)^{-} 349 | 23114,\Sigma(1940)^{-} 350 | 23122,\Lambda(1600) 351 | 23124,\Lambda(1890) 352 | 23126,\Lambda(2110) 353 | 23212,\Sigma(1750)^{0} 354 | 23214,\Sigma(1940)^{0} 355 | 23222,\Sigma(1750)^{+} 356 | 23224,\Sigma(1940)^{+} 357 | 30113,\rho(1700)^{0} 358 | 30213,\rho(1700)^{+} 359 | 30223,\omega(1650) 360 | 30313,K^{*}(1680)^{0} 361 | 30323,K^{*}(1680)^{+} 362 | 30343,X_{sd} 363 | 30353,X_{su} 364 | 30363,X_{ss} 365 | 30443,\psi(3770) 366 | 30553,\Upsilon_{1}(1D) 367 | 31114,\Delta(1600)^{-} 368 | 31214,N(1720)^{0} 369 | 32112,N(1650)^{0} 370 | 32114,\Delta(1600)^{0} 371 | 32124,N(1720)^{+} 372 | 32212,N(1650)^{+} 373 | 32214,\Delta(1600)^{+} 374 | 32224,\Delta(1600)^{++} 375 | 33122,\Lambda(1670) 376 | 41214,N(1900)^{0} 377 | 42112,N(1710)^{0} 378 | 42124,N(1900)^{+} 379 | 42212,N(1710)^{+} 380 | 43122,\Lambda(1800) 381 | 52114,N(2090)^{0} 382 | 52214,N(2090)^{+} 383 | 53122,\Lambda(1810) 384 | 100111,\pi(1300)^{0} 385 | 100113,\rho(1450)^{0} 386 | 100211,\pi(1300)^{+} 387 | 100213,\rho(1450)^{+} 388 | 100221,\eta(1295) 389 | 100223,\omega(1420) 390 | 100311,K(1460)^{0} 391 | 100313,K^{*}(1410)^{0} 392 | 100321,K(1460)^{+} 393 | 100323,K^{*}(1410)^{+} 394 | 100331,\eta(1475) 395 | 100333,\phi(1680) 396 | 100411,D(2S)^{+} 397 | 100413,D^{*}(2640)^{+} 398 | 100421,D(2S)^{0} 399 | 100423,D^{*}(2640)^{0} 400 | 100441,\eta_{c}(2S) 401 | 100443,\psi(2S) 402 | 100445,\chi_{c2}(2P) 403 | 100551,\eta_{b}(2S) 404 | 100553,\Upsilon(2S) 405 | 100555,\chi_{b2}(2P) 406 | 100557,\Upsilon_{3}(2D) 407 | 103112,\Sigma(2250)^{-} 408 | 103212,\Sigma(2250)^{0} 409 | 103222,\Sigma(2250)^{+} 410 | 103316,\Xi(1950)^{-} 411 | 103326,\Xi(1950)^{0} 412 | 104122,\Lambda_{c}(2625)^{+} 413 | 104312,\Xi_{c}(2815)^{0} 414 | 104314,\Xi_{c}(2790)^{0} 415 | 104322,\Xi_{c}(2815)^{+} 416 | 104324,\Xi_{c}(2790)^{+} 417 | 110551,\chi_{b0}(2P) 418 | 110553,h_{b}(2P) 419 | 110555,\eta_{b2}(2D) 420 | 120553,\chi_{b1}(2P) 421 | 120555,\Upsilon_2(2D) 422 | 130553,\Upsilon_1(2D) 423 | 200551,\eta_{b}(3S) 424 | 200553,\Upsilon(3S) 425 | 200555,\chi_{b2}(3P) 426 | 203312,\Xi(1690)^{-} 427 | 203316,\Xi(2030)^{-} 428 | 203322,\Xi(1690)^{0} 429 | 203326,\Xi(2030)^{0} 430 | 203338,\Omega(2250)^{-} 431 | 204126,\Lambda_{c}(2880)^{+} 432 | 210551,\chi_{b0}(3P) 433 | 210553,h_{b}(3P) 434 | 220553,\chi_{b1}(3P) 435 | 300553,\Upsilon(4S) 436 | 1000001,\tilde{d}_{L} 437 | 1000002,\tilde{u}_{L} 438 | 1000003,\tilde{s}_{L} 439 | 1000004,\tilde{c}_{L} 440 | 1000005,\tilde{b}_{1} 441 | 1000006,\tilde{t}_{1} 442 | 1000011,\tilde{e}_{L}^{-} 443 | 1000012,\tilde{\nu}_{eL} 444 | 1000013,\tilde{\mu}_{L}^{-} 445 | 1000014,\tilde{\nu}_{\mu L} 446 | 1000015,\tilde{\tau}_{1}^{-} 447 | 1000016,\tilde{\nu}_{\tau L} 448 | 1000021,\tilde{g} 449 | 1000022,\tilde{\chi}_{1}^{0} 450 | 1000023,\tilde{\chi}_{2}^{0} 451 | 1000024,\tilde{\chi}_{1}^{+} 452 | 1000025,\tilde{\chi}_{3}^{0} 453 | 1000035,\tilde{\chi}_{4}^{0} 454 | 1000037,\tilde{\chi}_{2}^{+} 455 | 1000039,\tilde{G} 456 | 2000001,\tilde{d}_{R} 457 | 2000002,\tilde{u}_{R} 458 | 2000003,\tilde{s}_{R} 459 | 2000004,\tilde{c}_{R} 460 | 2000005,\tilde{b}_{2} 461 | 2000006,\tilde{t}_{2} 462 | 2000011,\tilde{e}_{R}^{-} 463 | 2000012,\tilde{\nu}_{eR} 464 | 2000013,\tilde{\mu}_{R}^{-} 465 | 2000014,\tilde{\nu}_{\mu R} 466 | 2000015,\tilde{\tau}_{2}^{-} 467 | 2000016,\tilde{\nu}_{\tau R} 468 | 3000111,\pi_{tc}^{0} 469 | 3000113,\rho_{tc}^{0} 470 | 3000211,\pi_{tc}^{+} 471 | 3000213,\rho_{tc}^{+} 472 | 3000221,\pi_{tc}^{\prime 0} 473 | 3000223,\omega_{tc} 474 | 3000331,\eta_{tc} 475 | 3100021,V_{8} 476 | 4000001,d^{*} 477 | 4000002,u^{*} 478 | 4000011,e^{*-} 479 | 4000012,\nu_{e}^{*0} 480 | 5000039,G^{*} 481 | 9000111,a_{0}(980)^{0} 482 | 9000113,\pi_{1}(1400)^{0} 483 | 9000115,a_{2}(1700)^{0} 484 | 9000117,\rho_{3}(1990)^{0} 485 | 9000211,a_{0}(980)^{+} 486 | 9000213,\pi_{1}(1400)^{+} 487 | 9000215,a_{2}(1700)^{+} 488 | 9000217,\rho_{3}(1990)^{+} 489 | 9000221,f_{0}(500) 490 | 9000223,f_{1}(1510) 491 | 9000225,f_{2}(1430) 492 | 9000229,f_{J}(2220) 493 | 9000311,K_{0}^{*}(700)^{0} 494 | 9000313,K_{1}(1650)^{0} 495 | 9000315,K_{2}(1580)^{0} 496 | 9000319,K_{4}(2500)^{0} 497 | 9000321,K_{0}^{*}(700)^{+} 498 | 9000323,K_{1}(1650)^{+} 499 | 9000325,K_{2}(1580)^{+} 500 | 9000329,K_{4}(2500)^{+} 501 | 9000443,\psi(4040) 502 | 9000553,\Upsilon(10860) 503 | 9010111,\pi(1800)^{0} 504 | 9010113,\pi_{1}(1600)^{0} 505 | 9010117,\rho_{3}(2250)^{0} 506 | 9010211,\pi(1800)^{+} 507 | 9010213,\pi_{1}(1600)^{+} 508 | 9010217,\rho_{3}(2250)^{+} 509 | 9010221,f_{0}(980) 510 | 9010223,h_{1}(1595) 511 | 9010225,f_{2}(1565) 512 | 9010229,f_{4}(2300) 513 | 9010311,K(1830)^{0} 514 | 9010315,K_{2}^{*}(1980)^{0} 515 | 9010317,K_{3}(2320)^{0} 516 | 9010321,K(1830)^{+} 517 | 9010325,K_{2}^{*}(1980)^{+} 518 | 9010327,K_{3}(2320)^{+} 519 | 9010443,\psi(4160) 520 | 9010553,\Upsilon(11020) 521 | 9020113,a_{1}(1640)^{0} 522 | 9020213,a_{1}(1640)^{+} 523 | 9020221,\eta(1405) 524 | 9020225,f_{2}(1640) 525 | 9020311,K_{0}^{*}(1950)^{0} 526 | 9020315,K_{2}(2250)^{0} 527 | 9020321,K_{0}^{*}(1950)^{+} 528 | 9020325,K_{2}(2250)^{+} 529 | 9020443,\psi(4415) 530 | 9030113,\rho(1900)^{0} 531 | 9030213,\rho(1900)^{+} 532 | 9030221,f_{0}(1500) 533 | 9030225,f_{2}(1810) 534 | 9040113,\rho(2150)^{0} 535 | 9040213,\rho(2150)^{+} 536 | 9040221,\eta(1760) 537 | 9040225,f_{2}(1910) 538 | 9042413,Z(4430)^{+} 539 | 9050221,f_{0}(2020) 540 | 9050225,f_{2}(1950) 541 | 9060221,f_{0}(2100) 542 | 9060225,f_{2}(2010) 543 | 9070221,f_{0}(2200) 544 | 9070225,f_{2}(2150) 545 | 9080221,\eta(2225) 546 | 9080225,f_{2}(2300) 547 | 9090221,f_{0}(2330) 548 | 9090225,f_{2}(2340) 549 | 9910445,X_{2}(3872) 550 | 9920443,X_{1}(3872) 551 | 480000000,geantino 552 | 1000010020,^{2}\mathrm{H} 553 | 1000010030,^{3}\mathrm{H} 554 | 1000020030,^{3}\mathrm{He} 555 | 1000020040,^{2}\mathrm{He} 556 | 1000030070,^{7}\mathrm{Li} 557 | 1000040080,^{8}\mathrm{Be} 558 | 1000040090,^{9}\mathrm{Be} 559 | 1000040100,^{10}\mathrm{Be} 560 | 1000050100,^{10}\mathrm{B} 561 | 1000050110,^{11}\mathrm{B} 562 | 1000050120,^{12}\mathrm{B} 563 | 1000060120,^{12}\mathrm{C} 564 | 1000060130,^{13}\mathrm{C} 565 | 1000060140,^{14}\mathrm{C} 566 | 1000070140,^{14}\mathrm{N} 567 | 1000070150,^{15}\mathrm{N} 568 | 1000070160,^{16}\mathrm{N} 569 | 1000080160,^{16}\mathrm{O} 570 | 1000080170,^{17}\mathrm{O} 571 | 1000080180,^{18}\mathrm{O} 572 | 1000080190,^{19}\mathrm{O} 573 | 1000090190,^{19}\mathrm{F} 574 | 1000100220,^{22}\mathrm{Ne} 575 | 1000100230,^{23}\mathrm{Ne} 576 | 1000110240,^{24}\mathrm{Na} 577 | 1000120240,^{24}\mathrm{Mg} 578 | 1000120250,^{25}\mathrm{Mg} 579 | 1000120260,^{26}\mathrm{Mg} 580 | 1000120270,^{27}\mathrm{Mg} 581 | 1000130270,^{27}\mathrm{Al} 582 | 1000130280,^{28}\mathrm{Al} 583 | 1000140280,^{28}\mathrm{Si} 584 | 1000140290,^{29}\mathrm{Si} 585 | 1000140300,^{30}\mathrm{Si} 586 | 1000150310,^{31}\mathrm{P} 587 | 1000170390,^{39}\mathrm{Cl} 588 | 1000170400,^{40}\mathrm{Cl} 589 | 1000180360,^{36}\mathrm{Ar} 590 | 1000180400,^{40}\mathrm{Ar} 591 | 1000240500,^{50}\mathrm{Cr} 592 | 1000240520,^{52}\mathrm{Cr} 593 | 1000240530,^{53}\mathrm{Cr} 594 | 1000240540,^{54}\mathrm{Cr} 595 | 1000250550,^{55}\mathrm{Mn} 596 | 1000260540,^{54}\mathrm{Fe} 597 | 1000260560,^{56}\mathrm{Fe} 598 | 1000260570,^{57}\mathrm{Fe} 599 | 1000260590,^{59}\mathrm{Fe} 600 | 1000280580,^{58}\mathrm{Ni} 601 | 1000280600,^{60}\mathrm{Ni} 602 | 1000280610,^{61}\mathrm{Ni} 603 | 1000280620,^{62}\mathrm{Ni} 604 | 1000280630,^{63}\mathrm{Ni} 605 | 1000280640,^{64}\mathrm{Ni} 606 | 1000290630,^{63}\mathrm{Cu} 607 | 1000290650,^{65}\mathrm{Cu} 608 | 1000420920,^{92}\mathrm{Mo} 609 | 1000420950,^{95}\mathrm{Mo} 610 | 1000420960,^{96}\mathrm{Mo} 611 | 1000420970,^{97}\mathrm{Mo} 612 | 1000420980,^{98}\mathrm{Mo} 613 | 1000421000,^{100}\mathrm{Mo} 614 | 1000461080,^{108}\mathrm{Pd} 615 | 1000791970,^{197}\mathrm{Au} 616 | 1000822040,^{204}\mathrm{Pb} 617 | 1000822060,^{206}\mathrm{Pb} 618 | 1000822070,^{207}\mathrm{Pb} 619 | 1000822080,^{208}\mathrm{Pb} 620 | -------------------------------------------------------------------------------- /src/particle/data/pdgid_to_pythiaid.csv: -------------------------------------------------------------------------------- 1 | # (c) Scikit-HEP project - Particle package data file - pdgid_to_pythiaid.csv - version 14 - 2024-08-08 2 | PDGID,PYTHIAID 3 | 1,1 4 | -1,-1 5 | 2,2 6 | -2,-2 7 | 3,3 8 | -3,-3 9 | 4,4 10 | -4,-4 11 | 5,5 12 | -5,-5 13 | 6,6 14 | -6,-6 15 | 7,7 16 | -7,-7 17 | 8,8 18 | -8,-8 19 | 11,11 20 | -11,-11 21 | 12,12 22 | -12,-12 23 | 13,13 24 | -13,-13 25 | 14,14 26 | -14,-14 27 | 15,15 28 | -15,-15 29 | 16,16 30 | -16,-16 31 | 17,17 32 | -17,-17 33 | 18,18 34 | -18,-18 35 | 21,21 36 | 22,22 37 | 23,23 38 | 24,24 39 | -24,-24 40 | 25,25 41 | 32,32 42 | 33,33 43 | 34,34 44 | -34,-34 45 | 35,35 46 | 36,36 47 | 37,37 48 | -37,-37 49 | 38,38 50 | -38,-38 51 | 39,39 52 | 40,40 53 | 41,41 54 | -41,-41 55 | 42,42 56 | -42,-42 57 | 43,43 58 | 44,44 59 | -44,-44 60 | 81,81 61 | 82,82 62 | -82,-82 63 | 83,83 64 | 84,84 65 | -84,-84 66 | 85,85 67 | -85,-85 68 | 88,88 69 | 90,90 70 | 91,91 71 | 92,92 72 | 93,93 73 | 94,94 74 | 95,95 75 | 96,96 76 | 97,97 77 | 98,98 78 | 111,111 79 | 113,113 80 | 115,115 81 | 130,130 82 | 211,211 83 | -211,-211 84 | 213,213 85 | -213,-213 86 | 215,215 87 | -215,-215 88 | 221,221 89 | 223,223 90 | 225,225 91 | 310,310 92 | 311,311 93 | -311,-311 94 | 313,313 95 | -313,-313 96 | 315,315 97 | -315,-315 98 | 321,321 99 | -321,-321 100 | 323,323 101 | -323,-323 102 | 325,325 103 | -325,-325 104 | 331,331 105 | 333,333 106 | 335,335 107 | 411,411 108 | -411,-411 109 | 413,413 110 | -413,-413 111 | 415,415 112 | -415,-415 113 | 421,421 114 | -421,-421 115 | 423,423 116 | -423,-423 117 | 425,425 118 | -425,-425 119 | 431,431 120 | -431,-431 121 | 433,433 122 | -433,-433 123 | 435,435 124 | -435,-435 125 | 441,441 126 | 443,443 127 | 445,445 128 | 511,511 129 | -511,-511 130 | 513,513 131 | -513,-513 132 | 515,515 133 | -515,-515 134 | 521,521 135 | -521,-521 136 | 523,523 137 | -523,-523 138 | 525,525 139 | -525,-525 140 | 531,531 141 | -531,-531 142 | 533,533 143 | -533,-533 144 | 535,535 145 | -535,-535 146 | 541,541 147 | -541,-541 148 | 543,543 149 | -543,-543 150 | 545,545 151 | -545,-545 152 | 551,551 153 | 553,553 154 | 555,555 155 | 557,557 156 | 1103,1103 157 | -1103,-1103 158 | 1114,1114 159 | -1114,-1114 160 | 2101,2101 161 | -2101,-2101 162 | 2103,2103 163 | -2103,-2103 164 | 2112,2112 165 | -2112,-2112 166 | 2114,2114 167 | -2114,-2114 168 | 2203,2203 169 | -2203,-2203 170 | 2212,2212 171 | -2212,-2212 172 | 2214,2214 173 | -2214,-2214 174 | 2224,2224 175 | -2224,-2224 176 | 3101,3101 177 | -3101,-3101 178 | 3103,3103 179 | -3103,-3103 180 | 3112,3112 181 | -3112,-3112 182 | 3114,3114 183 | -3114,-3114 184 | 3122,3122 185 | -3122,-3122 186 | 3201,3201 187 | -3201,-3201 188 | 3203,3203 189 | -3203,-3203 190 | 3212,3212 191 | -3212,-3212 192 | 3214,3214 193 | -3214,-3214 194 | 3222,3222 195 | -3222,-3222 196 | 3224,3224 197 | -3224,-3224 198 | 3303,3303 199 | -3303,-3303 200 | 3312,3312 201 | -3312,-3312 202 | 3314,3314 203 | -3314,-3314 204 | 3322,3322 205 | -3322,-3322 206 | 3324,3324 207 | -3324,-3324 208 | 3334,3334 209 | -3334,-3334 210 | 4101,4101 211 | -4101,-4101 212 | 4103,4103 213 | -4103,-4103 214 | 4112,4112 215 | -4112,-4112 216 | 4114,4114 217 | -4114,-4114 218 | 4122,4122 219 | -4122,-4122 220 | 4132,4132 221 | -4132,-4132 222 | 4201,4201 223 | -4201,-4201 224 | 4203,4203 225 | -4203,-4203 226 | 4212,4212 227 | -4212,-4212 228 | 4214,4214 229 | -4214,-4214 230 | 4222,4222 231 | -4222,-4222 232 | 4224,4224 233 | -4224,-4224 234 | 4232,4232 235 | -4232,-4232 236 | 4301,4301 237 | -4301,-4301 238 | 4303,4303 239 | -4303,-4303 240 | 4312,4312 241 | -4312,-4312 242 | 4314,4314 243 | -4314,-4314 244 | 4322,4322 245 | -4322,-4322 246 | 4324,4324 247 | -4324,-4324 248 | 4332,4332 249 | -4332,-4332 250 | 4334,4334 251 | -4334,-4334 252 | 4403,4403 253 | -4403,-4403 254 | 4412,4412 255 | -4412,-4412 256 | 4414,4414 257 | -4414,-4414 258 | 4422,4422 259 | -4422,-4422 260 | 4424,4424 261 | -4424,-4424 262 | 4432,4432 263 | -4432,-4432 264 | 4434,4434 265 | -4434,-4434 266 | 4444,4444 267 | -4444,-4444 268 | 5101,5101 269 | -5101,-5101 270 | 5103,5103 271 | -5103,-5103 272 | 5112,5112 273 | -5112,-5112 274 | 5114,5114 275 | -5114,-5114 276 | 5122,5122 277 | -5122,-5122 278 | 5124,5124 279 | -5124,-5124 280 | 5132,5132 281 | -5132,-5132 282 | 5142,5142 283 | -5142,-5142 284 | 5201,5201 285 | -5201,-5201 286 | 5203,5203 287 | -5203,-5203 288 | 5212,5212 289 | -5212,-5212 290 | 5214,5214 291 | -5214,-5214 292 | 5222,5222 293 | -5222,-5222 294 | 5224,5224 295 | -5224,-5224 296 | 5232,5232 297 | -5232,-5232 298 | 5242,5242 299 | -5242,-5242 300 | 5301,5301 301 | -5301,-5301 302 | 5303,5303 303 | -5303,-5303 304 | 5312,5312 305 | -5312,-5312 306 | 5314,5314 307 | -5314,-5314 308 | 5322,5322 309 | -5322,-5322 310 | 5324,5324 311 | -5324,-5324 312 | 5332,5332 313 | -5332,-5332 314 | 5334,5334 315 | -5334,-5334 316 | 5342,5342 317 | -5342,-5342 318 | 5401,5401 319 | -5401,-5401 320 | 5403,5403 321 | -5403,-5403 322 | 5412,5412 323 | -5412,-5412 324 | 5414,5414 325 | -5414,-5414 326 | 5422,5422 327 | -5422,-5422 328 | 5424,5424 329 | -5424,-5424 330 | 5432,5432 331 | -5432,-5432 332 | 5434,5434 333 | -5434,-5434 334 | 5442,5442 335 | -5442,-5442 336 | 5444,5444 337 | -5444,-5444 338 | 5503,5503 339 | -5503,-5503 340 | 5512,5512 341 | -5512,-5512 342 | 5514,5514 343 | -5514,-5514 344 | 5522,5522 345 | -5522,-5522 346 | 5524,5524 347 | -5524,-5524 348 | 5532,5532 349 | -5532,-5532 350 | 5534,5534 351 | -5534,-5534 352 | 5542,5542 353 | -5542,-5542 354 | 5544,5544 355 | -5544,-5544 356 | 5554,5554 357 | -5554,-5554 358 | 10113,10113 359 | 10213,10213 360 | -10213,-10213 361 | 10221,10331 362 | 10223,10223 363 | 10311,10311 364 | -10311,-10311 365 | 10313,10313 366 | -10313,-10313 367 | 10321,10321 368 | -10321,-10321 369 | 10323,10323 370 | -10323,-10323 371 | 10333,10333 372 | 10411,10411 373 | -10411,-10411 374 | 10413,10413 375 | -10413,-10413 376 | 10421,10421 377 | -10421,-10421 378 | 10423,10423 379 | -10423,-10423 380 | 10431,10431 381 | -10431,-10431 382 | 10433,10433 383 | -10433,-10433 384 | 10441,10441 385 | 10443,10443 386 | 10511,10511 387 | -10511,-10511 388 | 10513,10513 389 | -10513,-10513 390 | 10521,10521 391 | -10521,-10521 392 | 10523,10523 393 | -10523,-10523 394 | 10531,10531 395 | -10531,-10531 396 | 10533,10533 397 | -10533,-10533 398 | 10541,10541 399 | -10541,-10541 400 | 10543,10543 401 | -10543,-10543 402 | 10551,10551 403 | 10553,10553 404 | 10555,10555 405 | 15122,15122 406 | -15122,-15122 407 | 20113,20113 408 | 20213,20213 409 | -20213,-20213 410 | 20223,20223 411 | 20313,20313 412 | -20313,-20313 413 | 20323,20323 414 | -20323,-20323 415 | 20333,20333 416 | 20413,20413 417 | -20413,-20413 418 | 20423,20423 419 | -20423,-20423 420 | 20433,20433 421 | -20433,-20433 422 | 20443,20443 423 | 20513,20513 424 | -20513,-20513 425 | 20523,20523 426 | -20523,-20523 427 | 20533,20533 428 | -20533,-20533 429 | 20543,20543 430 | -20543,-20543 431 | 20553,20553 432 | 20555,20555 433 | 30343,30343 434 | -30343,-30343 435 | 30353,30353 436 | -30353,-30353 437 | 30363,30363 438 | -30363,-30363 439 | 30443,30443 440 | 30553,30553 441 | 100441,100441 442 | 100443,100443 443 | 100553,100553 444 | 100555,100555 445 | 100557,100557 446 | 110551,110551 447 | 110553,110553 448 | 110555,110555 449 | 120553,120553 450 | 120555,120555 451 | 130553,130553 452 | 200553,200553 453 | 200555,200555 454 | 210551,210551 455 | 210553,210553 456 | 220553,220553 457 | 300553,300553 458 | 1000001,1000001 459 | -1000001,-1000001 460 | 1000002,1000002 461 | -1000002,-1000002 462 | 1000003,1000003 463 | -1000003,-1000003 464 | 1000004,1000004 465 | -1000004,-1000004 466 | 1000005,1000005 467 | -1000005,-1000005 468 | 1000006,1000006 469 | -1000006,-1000006 470 | 1000011,1000011 471 | -1000011,-1000011 472 | 1000012,1000012 473 | -1000012,-1000012 474 | 1000013,1000013 475 | -1000013,-1000013 476 | 1000014,1000014 477 | -1000014,-1000014 478 | 1000015,1000015 479 | -1000015,-1000015 480 | 1000016,1000016 481 | -1000016,-1000016 482 | 1000021,1000021 483 | 1000022,1000022 484 | 1000023,1000023 485 | 1000024,1000024 486 | -1000024,-1000024 487 | 1000025,1000025 488 | 1000035,1000035 489 | 1000037,1000037 490 | -1000037,-1000037 491 | 1000039,1000039 492 | 2000001,2000001 493 | -2000001,-2000001 494 | 2000002,2000002 495 | -2000002,-2000002 496 | 2000003,2000003 497 | -2000003,-2000003 498 | 2000004,2000004 499 | -2000004,-2000004 500 | 2000005,2000005 501 | -2000005,-2000005 502 | 2000006,2000006 503 | -2000006,-2000006 504 | 2000011,2000011 505 | -2000011,-2000011 506 | 2000012,2000012 507 | -2000012,-2000012 508 | 2000013,2000013 509 | -2000013,-2000013 510 | 2000014,2000014 511 | -2000014,-2000014 512 | 2000015,2000015 513 | -2000015,-2000015 514 | 2000016,2000016 515 | -2000016,-2000016 516 | 3000111,3000111 517 | 3000113,3000113 518 | 3000211,3000211 519 | -3000211,-3000211 520 | 3000213,3000213 521 | -3000213,-3000213 522 | 3000221,3000221 523 | 3000223,3000223 524 | 3000331,3000331 525 | 3100021,3100021 526 | 4000001,4000001 527 | -4000001,-4000001 528 | 4000002,4000002 529 | -4000002,-4000002 530 | 4000011,4000011 531 | -4000011,-4000011 532 | 4000012,4000012 533 | -4000012,-4000012 534 | 5000039,5000039 535 | 9000111,10111 536 | 9000211,10211 537 | -9000211,-10211 538 | 9010221,10221 539 | 9042413,9042413 540 | -9042413,-9042413 541 | 9910445,9910445 542 | 9920443,9920443 543 | -------------------------------------------------------------------------------- /src/particle/data/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/data/py.typed -------------------------------------------------------------------------------- /src/particle/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | 10 | class MatchingIDNotFound(ValueError): 11 | pass 12 | -------------------------------------------------------------------------------- /src/particle/geant/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from .geant3id import Geant3ID 10 | 11 | __all__ = ("Geant3ID",) 12 | 13 | 14 | def __dir__() -> tuple[str, ...]: 15 | return __all__ 16 | -------------------------------------------------------------------------------- /src/particle/geant/geant3id.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Class representing a Geant3 ID. 8 | 9 | Note 10 | ---- 11 | No equivalent Geant4 ID class is available/necessary given that Geant4 12 | follows the PDG rules, hence uses the standard PDG IDs. 13 | """ 14 | 15 | from __future__ import annotations 16 | 17 | import csv 18 | from typing import TypeVar 19 | 20 | from .. import data 21 | from ..exceptions import MatchingIDNotFound 22 | from ..pdgid import PDGID 23 | 24 | Self = TypeVar("Self", bound="Geant3ID") 25 | 26 | 27 | with data.basepath.joinpath("pdgid_to_geant3id.csv").open() as _f: 28 | _bimap = { 29 | int(v["GEANT3ID"]): int(v["PDGID"]) 30 | for v in csv.DictReader(line for line in _f if not line.startswith("#")) 31 | } 32 | 33 | 34 | class Geant3ID(int): 35 | """ 36 | Holds a Geant3 ID. 37 | 38 | Examples 39 | -------- 40 | >>> gid = Geant3ID(8) 41 | 42 | >>> from particle import Particle 43 | >>> p = Particle.from_pdgid(gid.to_pdgid()) 44 | 45 | >>> (p,) = Particle.finditer(pdgid=gid.to_pdgid()) 46 | >>> p.name 47 | 'pi+' 48 | """ 49 | 50 | __slots__ = () # Keep PythiaID a slots based class 51 | 52 | @classmethod 53 | def from_pdgid(cls: type[Self], pdgid: int) -> Self: 54 | """ 55 | Constructor from a PDGID. 56 | """ 57 | for k, v in _bimap.items(): 58 | if v == pdgid: 59 | return cls(k) 60 | raise MatchingIDNotFound(f"Non-existent Geant3ID for input PDGID {pdgid} !") 61 | 62 | def to_pdgid(self) -> PDGID: 63 | return PDGID(_bimap[self]) 64 | 65 | def __repr__(self) -> str: 66 | return f"<{self.__class__.__name__}: {int(self):d}>" 67 | 68 | def __str__(self) -> str: 69 | return repr(self) 70 | 71 | def __neg__(self: Self) -> Self: 72 | """ 73 | Note: 74 | Allowed operation though ALL Geant3 identification codes are positive! 75 | """ 76 | return self.__class__(-int(self)) 77 | 78 | __invert__ = __neg__ 79 | -------------------------------------------------------------------------------- /src/particle/geant/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/geant/py.typed -------------------------------------------------------------------------------- /src/particle/lhcb/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | from .converters import LHCbName2PDGIDBiMap 9 | from .functions import from_lhcb_name, to_lhcb_name 10 | 11 | __all__ = ( 12 | "LHCbName2PDGIDBiMap", 13 | "from_lhcb_name", 14 | "to_lhcb_name", 15 | ) 16 | 17 | 18 | def __dir__() -> tuple[str, ...]: 19 | return __all__ 20 | -------------------------------------------------------------------------------- /src/particle/lhcb/converters.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | from ..converters.bimap import BiMap 9 | from ..pdgid import PDGID 10 | from . import data 11 | 12 | LHCbName2PDGIDBiMap = BiMap( 13 | PDGID, 14 | str, 15 | converters=(int, str), 16 | filename=data.basepath / "pdgid_to_lhcbname.csv", 17 | ) 18 | LHCbName2PDGIDBiMap.__doc__ = """ 19 | Bi-bidirectional map between PDG IDs and LHCb names. 20 | 21 | Examples 22 | -------- 23 | >>> name = LHCbName2PDGIDBiMap[PDGID(-531)] 24 | >>> name 25 | 'B_s~0' 26 | 27 | >>> pdgid = LHCbName2PDGIDBiMap['B_s~0'] 28 | >>> pdgid 29 | 30 | """ 31 | -------------------------------------------------------------------------------- /src/particle/lhcb/data/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import sys 9 | 10 | if sys.version_info < (3, 9): 11 | import importlib_resources as resources 12 | else: 13 | from importlib import resources 14 | 15 | 16 | __all__ = ("basepath",) 17 | 18 | 19 | basepath = resources.files(__name__) 20 | 21 | 22 | def __dir__() -> tuple[str, ...]: 23 | return __all__ 24 | -------------------------------------------------------------------------------- /src/particle/lhcb/data/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/lhcb/data/py.typed -------------------------------------------------------------------------------- /src/particle/lhcb/functions.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | from ..particle import Particle 9 | from .converters import LHCbName2PDGIDBiMap 10 | 11 | 12 | def to_lhcb_name(p: Particle) -> str: 13 | """ 14 | Convert to the name used in the LHCb software framework. 15 | 16 | Examples 17 | -------- 18 | >>> p = Particle.from_pdgid(-531) 19 | >>> p 20 | 21 | >>> to_lhcb_name(p) 22 | 'B_s~0' 23 | """ 24 | return LHCbName2PDGIDBiMap[p.pdgid] 25 | 26 | 27 | def from_lhcb_name(name: str) -> Particle: 28 | """ 29 | Get a `Particle` from an LHCb particle name, as used in LHCb Gaudi applications. 30 | 31 | Examples 32 | -------- 33 | >>> from_lhcb_name("B_s~0") 34 | 35 | 36 | Raises 37 | ------ 38 | ParticleNotFound 39 | If `from_pdgid` returns no match. 40 | MatchingIDNotFound 41 | If the matching LHCb name - PDG ID done internally is unsuccessful. 42 | """ 43 | return Particle.from_pdgid(LHCbName2PDGIDBiMap[name]) 44 | -------------------------------------------------------------------------------- /src/particle/lhcb/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/lhcb/py.typed -------------------------------------------------------------------------------- /src/particle/particle/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from .enums import Charge, Inv, Parity, SpinType, Status 10 | from .kinematics import lifetime_to_width, width_to_lifetime 11 | from .particle import InvalidParticle, Particle, ParticleNotFound 12 | from .utilities import latex_name_unicode, latex_to_html_name, programmatic_name 13 | 14 | __all__ = ( 15 | "Charge", 16 | "Inv", 17 | "InvalidParticle", 18 | "Parity", 19 | "Particle", 20 | "ParticleNotFound", 21 | "SpinType", 22 | "Status", 23 | "latex_name_unicode", 24 | "latex_to_html_name", 25 | "lifetime_to_width", 26 | "programmatic_name", 27 | "width_to_lifetime", 28 | ) 29 | 30 | 31 | def __dir__() -> tuple[str, ...]: 32 | return __all__ 33 | -------------------------------------------------------------------------------- /src/particle/particle/enums.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Collection of enums to help characterising particle properties 8 | Examples are charge, spin and parity. 9 | """ 10 | 11 | from __future__ import annotations 12 | 13 | from enum import IntEnum 14 | 15 | 16 | class SpinType(IntEnum): 17 | """ 18 | Enum representing the spin type. Relevant only for bosons. 19 | 20 | SpinType.Unknown is returned for bosons if one of the values (J,P) is not known/relevant. 21 | SpinType.NonDefined is to be used for non-bosons. 22 | """ 23 | 24 | # Values of (J, P) 25 | Scalar = 1 # (0, 1) 26 | PseudoScalar = -1 # (0,-1) 27 | Vector = 2 # (1,-1) 28 | Axial = -2 # (1, 1) 29 | Tensor = 3 # (2, 1) 30 | PseudoTensor = -3 # (2,-1) 31 | Unknown = 0 32 | NonDefined = 5 33 | 34 | 35 | class Parity(IntEnum): 36 | """Enum representing a particle parity.""" 37 | 38 | p = 1 39 | m = -1 40 | u = 5 41 | 42 | 43 | class Charge(IntEnum): 44 | """Enum representing the particle charge * 3.""" 45 | 46 | pp = 6 47 | p43 = 4 # 4/3 48 | p = 3 49 | p23 = 2 # 2/3 50 | p13 = 1 # 1/3 51 | o = 0 52 | m13 = -1 # -1/3 53 | m23 = -2 # -2/3 54 | m = -3 55 | m43 = -4 # -4/3 56 | mm = -6 57 | u = 50 58 | 59 | 60 | class Inv(IntEnum): 61 | """Enum defining what happens when a particle is inverted. 62 | 63 | Possible Values 64 | --------------- 65 | Same : particle = antiparticle, e.g. pi0. 66 | Barred : antiparticle is denoted with a bar, e.g. proton, Lambda. 67 | Note that the charge may or may not be part of the name, e.g. Lb0 vs neutrinos. 68 | ChargeInv: antiparticle is obtained with a change of charge, e.g. pi+ vs pi-. 69 | """ 70 | 71 | Same = 0 72 | Barred = 1 73 | ChargeInv = 2 74 | 75 | 76 | class Status(IntEnum): 77 | """ 78 | The status of the particle, a one-letter code used by the PDG 79 | e.g. in the extended particle data table (PDT), see our .fwf files. 80 | The meanings are reproduced here for completeness, 81 | see also the Status_mapping dictionary in this module. 82 | RPP stands for the (PDG) Review of Particle Properties. 83 | 84 | Possible Values 85 | --------------- 86 | Common : extended PDT code "R" - established particle 87 | in RPP Summary Table in Particle Physics Booklet 88 | (established quarks, gauge bosons, leptons, mesons and baryons, 89 | except those in D below). 90 | Rare : extended PDT code "D" - the particle is omitted from the 91 | Summary Tables in Particle Physics Booklet, but not from the Review. 92 | These entries are omitted only to save space even though they are well established. 93 | Unsure : extended PDT code "S" - the particle is omitted from the 94 | particle properties Summary Tables because it is not well established. 95 | Further : extended PDT code "F" - special case "Further mesons", see RPP. 96 | These states are in the RPP database but are poorly established 97 | or observed by a single group and thus need confirmation. 98 | NotInPDT : an extra code (empty string "") we here use for non-standard 99 | and exotic particles not in the PDT. 100 | """ 101 | 102 | Common = 0 103 | Rare = 1 104 | Unsure = 2 105 | Further = 3 106 | NotInPDT = 4 107 | 108 | 109 | # Mappings that allow the above classes to be produced from text mappings 110 | Parity_mapping = { 111 | "+": Parity.p, 112 | "-": Parity.m, 113 | "?": Parity.u, 114 | "": Parity.u, 115 | } 116 | Charge_mapping = { 117 | "++": Charge.pp, 118 | "+4/3": Charge.p43, 119 | "+": Charge.p, 120 | "+2/3": Charge.p23, 121 | "+1/3": Charge.p13, 122 | "0": Charge.o, 123 | "-1/3": Charge.m13, 124 | "-2/3": Charge.m23, 125 | "-": Charge.m, 126 | "-4/3": Charge.m43, 127 | "--": Charge.mm, 128 | "?": Charge.u, 129 | "": Charge.u, 130 | } 131 | 132 | Inv_mapping = {"": Inv.Same, "F": Inv.Barred, "B": Inv.ChargeInv} 133 | Status_mapping = { 134 | "R": Status.Common, 135 | "D": Status.Rare, 136 | "S": Status.Unsure, 137 | "F": Status.Further, 138 | "": Status.NotInPDT, 139 | } 140 | 141 | # Mappings that allow the above classes to be turned into text mappings 142 | Parity_undo = {Parity.p: "+", Parity.m: "-", Parity.u: "None"} 143 | Parity_prog = {Parity.p: "p", Parity.m: "m", Parity.u: "u"} 144 | 145 | Charge_undo = { 146 | Charge.pp: "++", 147 | Charge.p43: "+4/3", 148 | Charge.p: "+", 149 | Charge.p23: "+2/3", 150 | Charge.p13: "+1/3", 151 | Charge.o: "0", 152 | Charge.m13: "-1/3", 153 | Charge.m23: "-2/3", 154 | Charge.m: "-", 155 | Charge.m43: "-4/3", 156 | Charge.mm: "--", 157 | Charge.u: "None", 158 | } 159 | Charge_prog = { 160 | Charge.pp: "pp", 161 | Charge.p43: "p43", 162 | Charge.p: "p", 163 | Charge.p23: "p23", 164 | Charge.p13: "p13", 165 | Charge.o: "0", 166 | Charge.m13: "m13", 167 | Charge.m23: "m23", 168 | Charge.m: "m", 169 | Charge.m43: "m43", 170 | Charge.mm: "mm", 171 | Charge.u: "u", 172 | } 173 | -------------------------------------------------------------------------------- /src/particle/particle/kinematics.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Functions relevant to particle kinematics. 8 | """ 9 | 10 | from __future__ import annotations 11 | 12 | from hepunits.constants import hbar 13 | from hepunits.units import MeV, ns 14 | 15 | 16 | def width_to_lifetime(Gamma: float) -> float: 17 | """ 18 | Convert from a particle decay width to a lifetime. 19 | 20 | Parameters 21 | ---------- 22 | Gamma : float > 0 23 | Particle decay width, in the HEP standard energy unit MeV. 24 | 25 | Returns 26 | ------- 27 | Gamma > 0: particle lifetime, in the HEP standard time unit ns. 28 | Gamma = 0: Infinity (float("inf")). 29 | Gamma < 0: an exception ValueError is raised. 30 | 31 | Examples 32 | -------- 33 | Manipulation with no explicit usage of units: 34 | 35 | >>> width_to_lifetime(4.33e-10) # result returned in ns 36 | 0.0015201199929582136 37 | 38 | Manipulations with explicit units defined in the HEP system of units: 39 | 40 | >>> from hepunits.units import MeV, eV, ps # handy module with units in the HEP system of units 41 | >>> 42 | >>> width_to_lifetime(4.33e-10*MeV) # result returned in ns 43 | 0.0015201199929582136 44 | >>> 45 | >>> width_to_lifetime(4.33e-4*eV) # result again returned in ns 46 | 0.0015201199929582136 47 | >>> 48 | >>> width_to_lifetime(4.33e-10*MeV)/ps # result converted to ps 49 | 1.5201199929582137 50 | """ 51 | 52 | if Gamma < 0.0: 53 | raise ValueError(f"Input provided, {Gamma} <= 0!") 54 | if Gamma == 0: 55 | return float("inf") 56 | 57 | # Just need to first make sure that the width is in the standard unit MeV 58 | return hbar / float(Gamma / MeV) 59 | 60 | 61 | def lifetime_to_width(tau: float) -> float: 62 | """ 63 | Convert from a particle lifetime to a decay width. 64 | 65 | Parameters 66 | ----------- 67 | tau : float > 0 68 | Particle lifetime, in the HEP standard time unit ns. 69 | 70 | Returns 71 | ------- 72 | Particle decay width, in the HEP standard energy unit MeV. 73 | tau > 0: particle lifetime, in the HEP standard time unit ns. 74 | tau = 0: Infinity (float("inf")). 75 | tau < 0: an exception ValueError is raised. 76 | 77 | Examples 78 | -------- 79 | Manipulation with no explicit usage of units: 80 | 81 | >>> lifetime_to_width(0.0015201199929582136) # result returned in MeV 82 | 4.33e-10 83 | 84 | Manipulations with explicit units defined in the HEP system of units: 85 | 86 | >>> from hepunits.units import MeV, eV, ps # handy module with units in the HEP system of units 87 | >>> 88 | >>> lifetime_to_width(0.0015201199929582136*ns) # result returned in MeV 89 | 4.33e-10 90 | >>> 91 | >>> lifetime_to_width(1.5201199929582137*ps) # result again returned in MeV 92 | 4.33e-10 93 | >>> 94 | >>> lifetime_to_width(1.5201199929582137*ps)/eV # result converted to eV 95 | 0.000433 96 | """ 97 | 98 | if tau < 0: 99 | raise ValueError(f"Input provided, {tau} <= 0!") 100 | if tau == 0: 101 | return float("inf") 102 | 103 | # Just need to first make sure that the lifetime is in the standard unit ns 104 | return hbar / float(tau / ns) 105 | -------------------------------------------------------------------------------- /src/particle/particle/literals.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Definitions of handy particle `Particle` literals 8 | ================================================= 9 | 10 | The particle literals provide aliases for most common particles, with easily recognisable names. 11 | The aliases are instances of the Particle class. 12 | 13 | Typical use cases:: 14 | 15 | >>> from particle import literals as lp 16 | >>> lp.pi_plus 17 | 18 | >>> lp.pi_plus.name 19 | 'pi+' 20 | >>> from particle.literals import Lambda_b_0 21 | >>> Lambda_b_0 22 | 23 | >>> Lambda_b_0.J 24 | 0.5 25 | 26 | List of available/defined literals: 27 | 28 | {0} 29 | """ 30 | 31 | from __future__ import annotations 32 | 33 | from ..shared_literals import common_particles 34 | from .particle import Particle 35 | 36 | 37 | def __dir__() -> list[str]: # pragma: no cover 38 | return list(common_particles) 39 | 40 | 41 | for item in common_particles: 42 | locals()[item] = Particle.from_pdgid(common_particles[item]) 43 | 44 | 45 | __doc = "".join( 46 | f" {item} = Particle.from_pdgid({common_particles[item]})\n" 47 | for item in common_particles 48 | ) 49 | __doc__ = __doc__.format(__doc) 50 | -------------------------------------------------------------------------------- /src/particle/particle/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/particle/py.typed -------------------------------------------------------------------------------- /src/particle/particle/regex.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Collection of regular expression helper utilities for the ``Particle`` class. 8 | """ 9 | 10 | from __future__ import annotations 11 | 12 | import re 13 | 14 | getname = re.compile( 15 | r""" 16 | ^ # Beginning of string 17 | (?P \w+? ) # One or more characters, non-greedy 18 | (?:\( (?P [udsctb][\w]*) \) )? # Optional family like (s) 19 | (?:\( (?P \d+ ) \) # Optional state in () 20 | (?= \*? \( ) )? # - lookahead for mass 21 | (?P \* )? # Optional star 22 | (?:\( (?P \d+ ) \) )? # Optional mass in () 23 | (?P (bar|~) )? # Optional bar 24 | (?P [0\+\-][+-]?) # Required 0, -, --, or +, ++ 25 | $ # End of string 26 | """, 27 | re.VERBOSE, 28 | ) 29 | 30 | 31 | # Help manipulating .dec DecFile style names 32 | getdec = re.compile( 33 | r""" 34 | ^ # Beginning of string 35 | (?P (anti-) )? # Optional anti- 36 | (?P [a-zA-Z]+? ) # One or more characters, non-greedy 37 | (?P '* ) # Optional prime(s) 38 | (?: _ (?P \d+ ) )? # Optional state in () 39 | (?: (?P _[udsctbemna][\w]*) )?# Optional family like (s) 40 | (?:\( (?P \d+ ) \) )? # Optional mass in () 41 | (?P \*? ) # Optional star 42 | (?P [0\+\-][+-]?)? # Optional 0, -, --, or +, ++ 43 | $ # End of string 44 | """, 45 | re.VERBOSE, 46 | ) 47 | -------------------------------------------------------------------------------- /src/particle/particle/utilities.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import math 9 | import re 10 | import unicodedata 11 | from html.entities import name2codepoint 12 | 13 | 14 | def programmatic_name(name: str, is_nucleus: bool) -> str: 15 | """ 16 | Return a name safe to use as a variable name. 17 | 18 | Note 19 | ---- 20 | The function needs to know if the name relates to a nucleus 21 | because zeros at the end of a name are charges for all particles except for nuclei. 22 | Charges need to be make explicit as '_0', as in a(0)(1450)0 or H0, 23 | whereas in Carbon C10 the last 0 is part of the atomic mass number A. 24 | """ 25 | # Last 0 in names is not a charge for nuclei ;-) 26 | name = re.sub("0$", "_0", name) if not is_nucleus else name 27 | # Deal first with antiparticles of sparticles, e.g. "~d(R)~" antiparticle of "~d(R)" 28 | name = re.sub("^~", "tilde_", name) 29 | # The remaining "~" now always means it's an antiparticle 30 | name = name if "~" not in name else "".join(name.split("~")) + "_bar" 31 | name = ( 32 | name.replace(")(", "_") 33 | .replace("(", "_") 34 | .replace(")", "") 35 | .replace("*", "st") 36 | .replace("'", "p") 37 | .replace("::", "_") 38 | .replace("/", "") 39 | .replace("--", "_mm") 40 | .replace("++", "_pp") 41 | .replace("-", "_minus") 42 | .replace("+", "_plus") 43 | ) 44 | # Strip off the ugly "_" at beginning of a name, such as when dealing with name="(bs)(0)"" 45 | return name.lstrip("_") 46 | 47 | 48 | def str_with_unc(value: float, upper: float | None, lower: float | None = None) -> str: 49 | """ 50 | Utility to print out an uncertainty with different or 51 | identical upper/lower bounds. Nicely formats numbers using PDG rule. 52 | """ 53 | 54 | # If no errors are available, simply return the value alone 55 | if upper is None: 56 | return str(value) 57 | 58 | # If no lower passed, make them the same 59 | if lower is None: 60 | lower = upper 61 | 62 | # Uncertainties are always positive 63 | upper = abs(upper) 64 | lower = abs(lower) 65 | 66 | error = min(upper, lower) 67 | 68 | if error == 0: 69 | return str(value) 70 | 71 | value_digits = math.floor(math.log10(value)) 72 | error_digits = math.floor(math.log10(error) - math.log10(2.5)) 73 | # This is split based on the value being larger than 1000000 or smaller than 0.001 - scientific notation split 74 | 75 | # This is normal notation 76 | if -3 < value_digits < 6: 77 | if error_digits < 0: 78 | fsv = fse = f".{-error_digits}f" 79 | else: 80 | fsv = fse = ".0f" 81 | 82 | # This is scientific notation - a little odd, but better than the other options. 83 | else: 84 | fsv = f".{abs(error_digits - value_digits)}e" 85 | pure_error_digits = math.floor(math.log10(error)) 86 | 87 | fse = ".0e" if error_digits == pure_error_digits else ".1e" 88 | 89 | # Now, print values based on upper=lower being true or not (even if they print the same) 90 | if upper != lower: 91 | return f"{value:{fsv}} + {upper:{fse}} - {lower:{fse}}" 92 | 93 | return f"{value:{fsv}} ± {upper:{fse}}" 94 | 95 | 96 | # List of greek letter names as used in Unicode (see unicodedata package) 97 | _list_name_greek_letters = [ 98 | "Alpha", 99 | "Beta", 100 | "Chi", 101 | "Delta", 102 | "Epsilon", 103 | "Eta", 104 | "Gamma", 105 | "Iota", 106 | "Kappa", 107 | "Lamda", # unicodedata library uses "lamda" for "lambda" :S! 108 | "Mu", 109 | "Nu", 110 | "Omega", 111 | "Omicron", 112 | "Phi", 113 | "Pi", 114 | "Psi", 115 | "Rho", 116 | "Sigma", 117 | "Tau", 118 | "Theta", 119 | "Upsilon", 120 | "Xi", 121 | "Zeta", 122 | ] 123 | _list_name_greek_letters += [item.lower() for item in _list_name_greek_letters] 124 | 125 | 126 | def greek_letter_name_to_unicode(letter: str) -> str: 127 | """ 128 | Return a greek letter name as a Unicode character, 129 | the same as the input if no match is found. 130 | 131 | Raises 132 | ------ 133 | KeyError 134 | If the input letter name is unknown to the `unicodedata` library, 135 | e.g. "lambda" since `unicodedata` uses "lamda" for "lambda"! 136 | 137 | Examples 138 | -------- 139 | Lamda -> Λ (Unicodedata library uses "lamda" for "lambda" :S!) 140 | Omega -> Ω 141 | omega -> ω 142 | """ 143 | case = "SMALL" if letter == letter.lower() else "CAPITAL" 144 | name = letter.upper() 145 | 146 | return unicodedata.lookup(f"GREEK {case} LETTER {name}") 147 | 148 | 149 | def latex_name_unicode(name: str) -> str: 150 | r""" 151 | Convert in particle names in LaTeX all greek letters by their unicode. 152 | 153 | Examples 154 | -------- 155 | >>> from particle import Particle 156 | >>> n = Particle.from_pdgid(3124).latex_name 157 | >>> print(n) 158 | \Lambda(1520) 159 | >>> latex_name_unicode(n) 160 | 'Λ(1520)' 161 | >>> latex_name_unicode("\\alpha_{x}^{0}\\beta\\Gamma(1234)\\Omega") 162 | 'α_{x}^{0}βΓ(1234)Ω' 163 | """ 164 | # Make sure "Lambda" and "lambda" are naturally deal with given that the 165 | # unicodedata library uses "lamda" for "lambda" :S! 166 | if "ambda" in name: 167 | name = name.replace("ambda", "amda") 168 | for gl in _list_name_greek_letters: 169 | name = name.replace(rf"\{gl}", greek_letter_name_to_unicode(gl)) 170 | return name 171 | 172 | 173 | def latex_to_html_name(name: str) -> str: 174 | """Conversion of particle names from LaTeX to HTML.""" 175 | name = re.sub(r"\^\{(.*?)\}", r"\1", name) 176 | name = re.sub(r"\_\{(.*?)\}", r"\1", name) 177 | name = re.sub(r"\^\\prime(.*?)", r"", name) 178 | name = re.sub(r"\\prime(.*?)", r"′", name) 179 | name = re.sub(r"\\mathrm\{(.*?)\}", r"\1", name) 180 | name = re.sub(r"\\left\[(.*?)\\right\]", r"[\1] ", name) 181 | for gl_orig in _list_name_greek_letters: 182 | # Deal with unicode name "feature", see _list_name_greek_letters 183 | gl = gl_orig.replace("amda", "ambda") 184 | # Special formatting since for example 185 | # f"{hex(html.entities.name2codepoint['Delta'])}" gives '0x394' whereas HTML needs 'x0394', 186 | # as in 'Δ', equivalent to 'Δ' 187 | name = name.replace(rf"\{gl}", f"&#x{name2codepoint[gl]:04x};") 188 | name = re.sub(r"\\tilde\{(.*?)\}", r"\1̃", name) 189 | name = re.sub(r"\\overline\{(.*?)\}", r"\1̅", name) 190 | return re.sub(r"\\bar\{(.*?)\}", r"\1̅", name) 191 | -------------------------------------------------------------------------------- /src/particle/pdgid/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | r""" 7 | The Particle Data Group (PDG) defines the standard particle identification numbering scheme 8 | in the form of a signed 7-digit number +/- N Nr Nl Nq1 Nq2 Nq3 Nj. 9 | 10 | PDG IDs with more than 7 digits exist for non-standard particles such as Q-balls. 11 | 12 | This module provides the following: 13 | 14 | - A pythonic version of the functions defined in HepPID and HepPDT, 15 | which work with PDG particle identification codes (PDG IDs). 16 | - A handy `PDGID` class. 17 | - A few other functions extending the functionality of the HepXXX code. 18 | 19 | 20 | Matrix of spin states for mesons 21 | -------------------------------- 22 | 23 | The table below provides a handy overview of the "links" between PDG IDs 24 | and meson quantum numbers. It is provided here for reference (for lack of a better place!), 25 | as it is not at all easy to find ... not to say impossible. 26 | 27 | Useful definitions: 28 | 29 | - State: (2S+1)^L_J 30 | - Parity P = (-1)^(L+1) 31 | - Charge conjugation C = (-1)^(L+S), valid only for neutral mesons 32 | - "q q" stands for "nq2 nq3" in the table below 33 | 34 | ==== === === ======================== ======== ================= ====================== ======================= 35 | J S L State J^PC Name Mesons PDG nL nq1 nq2 nq3 nJ 36 | ---- --- --- ------------------------ -------- ----------------- ---------------------- ----------------------- 37 | 0 0 0 L=J , S=0 (1^S_0) 0^-+ pseudo-scalar pi eta eta' K 00qq1 38 | 0 1 \- L=J-1 , S=1 \- \- \- \- 39 | 0 1 \- L=J , S=1 \- \- \- \- 40 | 0 1 1 L=J+1 , S=1 (3^P_0) 0^++ scalar a_0 f_0 f'_0 K*_0 10qq1 41 | 1 0 1 L=J , S=0 (1^P_1) 1^+- pseudo-vector b_1 h_1 h'_1 K_1 10qq3 42 | 1 1 0 L=J-1 , S=1 (3^S_1) 1^-- vector rho omega phi K* 00qq3 43 | 1 1 1 L=J , S=1 (3^P_1) 1^++ axial vector a_1 f_1 f'_1 K_1 20qq3 44 | 1 1 2 L=J+1 , S=1 1^-- \- 30qq3 45 | 2 0 2 L=J , S=0 2^-+ \- 10qq5 46 | 2 1 1 L=J-1 , S=1 2^++ \- 00qq5 47 | 2 1 2 L=J , S=1 2^-- \- 20qq5 48 | 2 1 3 L=J+1 , S=1 (3^P_2) 2^++ vector a_2 f_2 f'_2 K*_2 30qq5 49 | 3 0 3 L=J , S=0 3^+- \- 10qq7 50 | 3 1 2 L=J-1 , S=1 3^-- \- 00qq7 51 | 3 1 3 L=J , S=1 3^++ \- 20qq7 52 | 3 1 4 L=J+1 , S=1 3^-- \- 30qq7 53 | 4 0 4 L=J , S=0 4^-+ \- 10qq9 54 | 4 1 3 L=J-1 , S=1 4^++ \- 00qq9 55 | 4 1 4 L=J , S=1 4^-- \- 20qq9 56 | 4 1 5 L=J+1 , S=1 4^++ \- 30qq9 57 | ==== === === ======================== ======== ================= ====================== ======================= 58 | 59 | """ 60 | 61 | from __future__ import annotations 62 | 63 | from .functions import ( 64 | A, 65 | J, 66 | L, 67 | S, 68 | Z, 69 | abspid, 70 | charge, 71 | has_bottom, 72 | has_charm, 73 | has_down, 74 | has_fundamental_anti, 75 | has_strange, 76 | has_top, 77 | has_up, 78 | is_baryon, 79 | is_diquark, 80 | is_dyon, 81 | is_excited_quark_or_lepton, 82 | is_gauge_boson_or_higgs, 83 | is_generator_specific, 84 | is_hadron, 85 | is_lepton, 86 | is_meson, 87 | is_nucleus, 88 | is_pentaquark, 89 | is_Qball, 90 | is_quark, 91 | is_Rhadron, 92 | is_sm_gauge_boson_or_higgs, 93 | is_sm_lepton, 94 | is_sm_quark, 95 | is_special_particle, 96 | is_SUSY, 97 | is_technicolor, 98 | is_valid, 99 | j_spin, 100 | l_spin, 101 | s_spin, 102 | three_charge, 103 | ) 104 | from .pdgid import PDGID 105 | 106 | __all__ = ( 107 | "PDGID", 108 | "A", 109 | "J", 110 | "L", 111 | "S", 112 | "Z", 113 | "abspid", 114 | "charge", 115 | "has_bottom", 116 | "has_charm", 117 | "has_down", 118 | "has_fundamental_anti", 119 | "has_strange", 120 | "has_top", 121 | "has_up", 122 | "is_Qball", 123 | "is_Rhadron", 124 | "is_SUSY", 125 | "is_baryon", 126 | "is_diquark", 127 | "is_dyon", 128 | "is_excited_quark_or_lepton", 129 | "is_gauge_boson_or_higgs", 130 | "is_generator_specific", 131 | "is_hadron", 132 | "is_lepton", 133 | "is_meson", 134 | "is_nucleus", 135 | "is_pentaquark", 136 | "is_quark", 137 | "is_sm_gauge_boson_or_higgs", 138 | "is_sm_lepton", 139 | "is_sm_quark", 140 | "is_special_particle", 141 | "is_technicolor", 142 | "is_valid", 143 | "j_spin", 144 | "l_spin", 145 | "s_spin", 146 | "three_charge", 147 | ) 148 | 149 | 150 | def __dir__() -> tuple[str, ...]: 151 | return __all__ 152 | -------------------------------------------------------------------------------- /src/particle/pdgid/literals.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Definitions of handy particle `PDGID` literals 8 | ============================================== 9 | 10 | The PDGID literals provide aliases for most common particle PDGIDs, with easily recognisable names. 11 | The aliases are instances of the PDGID class. 12 | 13 | Typical use cases:: 14 | 15 | >>> from particle.pdgid import literals as lid 16 | >>> lid.pi_plus 17 | 18 | >>> lid.pi_plus.is_meson 19 | True 20 | >>> from particle.pdgid.literals import Lambda_b_0 21 | >>> Lambda_b_0 22 | 23 | >>> Lambda_b_0.has_bottom 24 | True 25 | 26 | List of available/defined literals: 27 | 28 | {0} 29 | """ 30 | 31 | from __future__ import annotations 32 | 33 | from ..shared_literals import common_particles 34 | from .pdgid import PDGID 35 | 36 | 37 | def __dir__() -> list[str]: # pragma: no cover 38 | return list(common_particles) 39 | 40 | 41 | for item in common_particles: 42 | locals()[item] = PDGID(common_particles[item]) 43 | 44 | 45 | __doc = "".join( 46 | f" {item!s} = PDGID({common_particles[item]})\n" for item in common_particles 47 | ) 48 | __doc__ = __doc__.format(__doc) 49 | -------------------------------------------------------------------------------- /src/particle/pdgid/pdgid.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Class representing a PDG ID. 8 | 9 | All methods of HepPID are implemented in a Pythonic version, see the functions module. 10 | """ 11 | 12 | from __future__ import annotations 13 | 14 | from inspect import isfunction 15 | from typing import TypeVar 16 | 17 | from . import functions as _functions 18 | 19 | # Collect all the user defined, non-hidden functions in the pdgid.functions module 20 | _fnames = [ 21 | fname 22 | for fname in dir(_functions) 23 | if not fname.startswith("_") and isfunction(getattr(_functions, fname)) 24 | ] 25 | 26 | 27 | Self = TypeVar("Self", bound="PDGID") 28 | 29 | 30 | class PDGID(int): 31 | """ 32 | Holds a PDG ID. 33 | 34 | Example 35 | ------- 36 | >>> PDGID(11).is_lepton 37 | True 38 | """ 39 | 40 | __slots__ = () # Keep PDGID a slots based class 41 | 42 | def __repr__(self) -> str: 43 | is_valid_str = "" if _functions.is_valid(self) else " (is_valid==False)" 44 | return f"<{self.__class__.__name__}: {int(self):d}{is_valid_str}>" 45 | 46 | def __str__(self) -> str: 47 | return repr(self) 48 | 49 | def __neg__(self: Self) -> Self: 50 | return self.__class__(-int(self)) 51 | 52 | __invert__ = __neg__ 53 | 54 | def info(self) -> str: 55 | """ 56 | Print all PDGID properties one per line, for easy inspection. 57 | """ 58 | return "".join(f"{item:14} {getattr(self, item)}\n" for item in _fnames) 59 | 60 | A = property(_functions.A, doc=_functions.A.__doc__) 61 | J = property(_functions.J, doc=_functions.J.__doc__) 62 | L = property(_functions.L, doc=_functions.L.__doc__) 63 | S = property(_functions.S, doc=_functions.S.__doc__) 64 | Z = property(_functions.Z, doc=_functions.Z.__doc__) 65 | abspid = property(_functions.abspid, doc=_functions.abspid.__doc__) 66 | charge = property(_functions.charge, doc=_functions.charge.__doc__) 67 | has_bottom = property(_functions.has_bottom, doc=_functions.has_bottom.__doc__) 68 | has_charm = property(_functions.has_charm, doc=_functions.has_charm.__doc__) 69 | has_down = property(_functions.has_down, doc=_functions.has_down.__doc__) 70 | has_fundamental_anti = property( 71 | _functions.has_fundamental_anti, doc=_functions.has_fundamental_anti.__doc__ 72 | ) 73 | has_strange = property(_functions.has_strange, doc=_functions.has_strange.__doc__) 74 | has_top = property(_functions.has_top, doc=_functions.has_top.__doc__) 75 | has_up = property(_functions.has_up, doc=_functions.has_up.__doc__) 76 | is_Qball = property(_functions.is_Qball, doc=_functions.is_Qball.__doc__) 77 | is_Rhadron = property(_functions.is_Rhadron, doc=_functions.is_Rhadron.__doc__) 78 | is_SUSY = property(_functions.is_SUSY, doc=_functions.is_SUSY.__doc__) 79 | is_baryon = property(_functions.is_baryon, doc=_functions.is_baryon.__doc__) 80 | is_diquark = property(_functions.is_diquark, doc=_functions.is_diquark.__doc__) 81 | is_dyon = property(_functions.is_dyon, doc=_functions.is_dyon.__doc__) 82 | is_excited_quark_or_lepton = property( 83 | _functions.is_excited_quark_or_lepton, 84 | doc=_functions.is_excited_quark_or_lepton.__doc__, 85 | ) 86 | is_gauge_boson_or_higgs = property( 87 | _functions.is_gauge_boson_or_higgs, 88 | doc=_functions.is_gauge_boson_or_higgs.__doc__, 89 | ) 90 | is_generator_specific = property( 91 | _functions.is_generator_specific, doc=_functions.is_generator_specific.__doc__ 92 | ) 93 | is_hadron = property(_functions.is_hadron, doc=_functions.is_hadron.__doc__) 94 | is_lepton = property(_functions.is_lepton, doc=_functions.is_lepton.__doc__) 95 | is_meson = property(_functions.is_meson, doc=_functions.is_meson.__doc__) 96 | is_nucleus = property(_functions.is_nucleus, doc=_functions.is_nucleus.__doc__) 97 | is_pentaquark = property( 98 | _functions.is_pentaquark, doc=_functions.is_pentaquark.__doc__ 99 | ) 100 | is_quark = property(_functions.is_quark, doc=_functions.is_quark.__doc__) 101 | is_sm_gauge_boson_or_higgs = property( 102 | _functions.is_sm_gauge_boson_or_higgs, 103 | doc=_functions.is_sm_gauge_boson_or_higgs.__doc__, 104 | ) 105 | is_sm_lepton = property( 106 | _functions.is_sm_lepton, doc=_functions.is_sm_lepton.__doc__ 107 | ) 108 | is_sm_quark = property(_functions.is_sm_quark, doc=_functions.is_sm_quark.__doc__) 109 | is_special_particle = property( 110 | _functions.is_special_particle, doc=_functions.is_special_particle.__doc__ 111 | ) 112 | is_technicolor = property( 113 | _functions.is_technicolor, doc=_functions.is_technicolor.__doc__ 114 | ) 115 | is_valid = property(_functions.is_valid, doc=_functions.is_valid.__doc__) 116 | j_spin = property(_functions.j_spin, doc=_functions.j_spin.__doc__) 117 | l_spin = property(_functions.l_spin, doc=_functions.l_spin.__doc__) 118 | s_spin = property(_functions.s_spin, doc=_functions.s_spin.__doc__) 119 | three_charge = property( 120 | _functions.three_charge, doc=_functions.three_charge.__doc__ 121 | ) 122 | 123 | 124 | # Verify the PDGID class has all relevant functions defined in the pdgid.functions module 125 | for _n in _fnames: 126 | assert _n in dir(PDGID), ( 127 | f"{_n} missing from PDGID class! Update the list in pdgid.py" 128 | ) 129 | -------------------------------------------------------------------------------- /src/particle/pdgid/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/pdgid/py.typed -------------------------------------------------------------------------------- /src/particle/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/py.typed -------------------------------------------------------------------------------- /src/particle/pythia/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from .pythiaid import PythiaID 10 | 11 | __all__ = ("PythiaID",) 12 | 13 | 14 | def __dir__() -> tuple[str, ...]: 15 | return __all__ 16 | -------------------------------------------------------------------------------- /src/particle/pythia/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/particle/6380dc9c66c784aa9a4706fd9a23118e928091c3/src/particle/pythia/py.typed -------------------------------------------------------------------------------- /src/particle/pythia/pythiaid.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Class representing a Pythia ID. 8 | """ 9 | 10 | from __future__ import annotations 11 | 12 | import csv 13 | from typing import TypeVar 14 | 15 | from .. import data 16 | from ..exceptions import MatchingIDNotFound 17 | from ..pdgid import PDGID 18 | 19 | with data.basepath.joinpath("pdgid_to_pythiaid.csv").open() as _f: 20 | _bimap = { 21 | int(v["PYTHIAID"]): int(v["PDGID"]) 22 | for v in csv.DictReader(line for line in _f if not line.startswith("#")) 23 | } 24 | 25 | 26 | Self = TypeVar("Self", bound="PythiaID") 27 | 28 | 29 | class PythiaID(int): 30 | """ 31 | Holds a Pythia ID. 32 | 33 | Examples 34 | -------- 35 | >>> pythiaid = PythiaID(211) 36 | 37 | >>> from particle import Particle 38 | >>> p = Particle.from_pdgid(pythiaid.to_pdgid()) 39 | 40 | >>> (p,) = Particle.finditer(pdgid=pythiaid.to_pdgid()) 41 | >>> p.name 42 | 'pi+' 43 | """ 44 | 45 | __slots__ = () # Keep PythiaID a slots based class 46 | 47 | @classmethod 48 | def from_pdgid(cls: type[Self], pdgid: int) -> Self: 49 | """ 50 | Constructor from a PDGID. 51 | """ 52 | for k, v in _bimap.items(): 53 | if v == pdgid: 54 | return cls(k) 55 | raise MatchingIDNotFound(f"Non-existent PythiaID for input PDGID {pdgid} !") 56 | 57 | def to_pdgid(self) -> PDGID: 58 | return PDGID(_bimap[self]) 59 | 60 | def __repr__(self) -> str: 61 | return f"<{self.__class__.__name__}: {int(self):d}>" 62 | 63 | def __str__(self) -> str: 64 | return repr(self) 65 | 66 | def __neg__(self: Self) -> Self: 67 | return self.__class__(-int(self)) 68 | 69 | __invert__ = __neg__ 70 | -------------------------------------------------------------------------------- /src/particle/shared_literals.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | """ 7 | Helper (internal) module with particle aliases 8 | for all particles in the loaded "database" CSV file, excluding nuclei. 9 | 10 | See the particle.literals and the pdgid.literals submodules for the actually exposed aliases. 11 | """ 12 | 13 | from __future__ import annotations 14 | 15 | from .particle import Particle 16 | 17 | # Make aliases for all particles in the latest "database", excluding nuclei 18 | common_particles = { 19 | p.programmatic_name: int(p.pdgid) 20 | for p in Particle.findall(lambda p: abs(p.pdgid) < 1000000000) 21 | } 22 | 23 | # Some extra names that are expected: 24 | common_particles.update( 25 | photon=22, # official programmatic name is "gamma" 26 | Higgs=25, # official programmatic name is "H_0" 27 | proton=2212, # official programmatic name is "p" 28 | antiproton=-2212, # official programmatic name is "p_bar" 29 | neutron=2112, # official programmatic name is "n" 30 | antineutron=-2112, # official programmatic name is "n_bar" 31 | ) 32 | -------------------------------------------------------------------------------- /src/particle/typing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from typing import IO, Any, Protocol, Union, runtime_checkable 10 | 11 | from ._compat.typing import Traversable 12 | 13 | __all__ = ( 14 | "HasOpen", 15 | "HasRead", 16 | "StringOrIO", 17 | ) 18 | 19 | 20 | StringOrIO = Union[Traversable, IO[str], str] 21 | 22 | 23 | @runtime_checkable 24 | class HasOpen(Protocol): 25 | def open(self) -> Any: 26 | pass 27 | 28 | 29 | @runtime_checkable 30 | class HasRead(Protocol): 31 | def read(self) -> str: 32 | pass 33 | -------------------------------------------------------------------------------- /src/particle/version.pyi: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | version: str 4 | version_tuple: tuple[int, int, int] | tuple[int, int, int, str, str] 5 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | from enum import IntEnum 9 | 10 | import pytest 11 | 12 | 13 | class PDGIDsEnum(IntEnum): 14 | """Sample of PDGIDs on which to run tests.""" 15 | 16 | # Gauge and Higgs bosons 17 | Gluon = 21 18 | Photon = 22 19 | Z0 = 23 20 | WMinus = -24 21 | HiggsBoson = 25 22 | ZPrime = 32 23 | # Charged leptons 24 | Electron = 11 25 | Positron = -Electron 26 | Muon = 13 27 | AntiMuon = -Muon 28 | Tau = 15 29 | # Neutrinos 30 | Nu_e = 12 31 | NuBar_tau = -16 32 | # Quarks 33 | DQuark = 1 34 | UQuark = 2 35 | SQuark = 3 36 | CQuark = 4 37 | BQuark = 5 38 | TQuark = 6 39 | # 4th generation quarks and leptons 40 | TauPrime = 17 41 | BPrimeQuark = 7 42 | TPrimeQuark = 8 43 | # Quarkonia 44 | jpsi = 443 45 | psi_2S = 100443 46 | psi_3770 = 30443 47 | Upsilon_1S = 553 48 | Upsilon_4S = 300553 49 | Upsilon_3_2D = 100557 50 | h_b_3P = 210553 51 | # Light hadrons 52 | Pi0 = 111 53 | PiPlus = 211 54 | eta = 221 55 | eta_prime = 331 56 | a_0_1450_plus = 10211 57 | KL = 130 58 | KS = 310 59 | KMinus = -321 60 | rho_770_minus = -213 61 | rho_10219_plus = 10219 # unknown particle added for testing purposes 62 | phi = 333 63 | omega = 223 64 | K1_1270_0 = 10313 65 | K1_1400_0 = 20313 66 | K2_1770_minus = -10325 67 | K2_1820_0_bar = -20315 68 | K3_10317_0 = 10317 # unknown particle added for testing purposes 69 | K3_20317_plus = 20317 # unknown particle added for testing purposes 70 | K3_30317_0 = 30317 # unknown particle added for testing purposes 71 | K4_20219_minus = -20219 # unknown particle added for testing purposes 72 | K4_30329_plus = 30329 # unknown particle added for testing purposes 73 | rho_1700_0 = 30113 74 | a2_1320_minus = -215 75 | omega_3_1670 = 227 76 | f_2_30225 = 30225 # unknown particle added for testing purposes 77 | f_4_2050 = 229 78 | f_4_2300 = 9010229 # example of a not-well-known meson 79 | Proton = 2212 80 | AntiNeutron = -2112 81 | Lambda = 3122 82 | Sigma0 = 3212 83 | SigmaPlus = 3222 84 | SigmaMinus = 3112 85 | Xi0 = 3322 86 | AntiXiMinus = -3312 87 | OmegaMinus = 3334 88 | N1650Plus = 32212 89 | N1900BarMinus = -42124 90 | Lambda1810 = 53122 91 | # Charm hadrons 92 | D0 = 421 93 | DPlus = 411 94 | DsPlus = 431 95 | LcPlus = 4122 96 | # Beauty hadrons 97 | B0 = 511 98 | BPlus = 521 99 | Bs = 531 100 | BcPlus = 541 101 | Lb = 5122 102 | # Top hadrons 103 | T0 = 621 104 | LtPlus = 6122 105 | # Special particles 106 | Graviton = 39 107 | Reggeon = 110 108 | Pomeron = 990 109 | Odderon = 9990 110 | # Supersymmetric particles 111 | Gluino = 1000021 112 | Gravitino = 1000039 113 | STildeL = 1000003 114 | CTildeR = 2000004 115 | Neutralino_1 = 1000022 116 | Chargino_1 = 1000024 117 | # R-hadrons 118 | R0_1000017 = 1000017 119 | RPlus_TTildeDbar = 1000612 120 | R0_GTildeG = 1000993 121 | RPlusPlus_GTildeUUU = 1092224 122 | # Q-balls 123 | QBall1 = 10000150 124 | QBall2 = -10000200 125 | # Dyons 126 | DyonSameMagElecChargeSign = 4110010 127 | DyonOppositeMagElecChargeSign = 4120010 128 | # Di-quarks 129 | DD1 = 1103 130 | SD0 = 3101 131 | # Hidden Valley particles 132 | HV_gv = 4900021 133 | # Nuclei 134 | HydrogenNucleus = 1000010010 135 | Carbon12 = 1000060120 136 | # Pentaquarks 137 | AntiUCbarCUDPentaquark = -9422144 138 | # example of spin 3/2 u-cbar-c-u-d pentaquark decaying to J/psi proton 139 | UCbarCUDPentaquark = 9422144 140 | # Technicolor 141 | Pi0TC = 3000111 142 | PiMinusTC = -3000211 143 | # Excited (composite) quarks and leptons 144 | UQuarkStar = 4000002 145 | AntiElectronStar = -4000011 146 | # Generator specific pseudoparticles or concepts 147 | AntiCHadron = -84 148 | GenSpecific910 = 910 149 | GenSpecific999 = 999 150 | GenSpecific1910 = 1910 151 | GenSpecific2910 = 2910 152 | GenSpecific3910 = 3910 153 | OpticalPhoton = 20022 154 | Geantino = 480000000 155 | # Invalid ID 156 | Invalid1 = 0 # illegal ID 157 | Invalid2 = 99999999 # general form is a 7-digit number 158 | 159 | 160 | @pytest.fixture(scope="session") 161 | def PDGIDs(): 162 | return PDGIDsEnum 163 | -------------------------------------------------------------------------------- /tests/converters/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | -------------------------------------------------------------------------------- /tests/converters/test_corsika.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | from particle import PDGID, Corsika7ID, Particle 9 | from particle.converters import Corsika72PDGIDBiMap 10 | 11 | 12 | def test_Corsika72PDGID(): 13 | pdgid = Corsika72PDGIDBiMap[Corsika7ID(5)] 14 | assert pdgid == -13 15 | 16 | cid = Corsika72PDGIDBiMap[PDGID(13)] 17 | assert cid.is_particle() 18 | assert cid == 6 19 | 20 | p = Particle.from_pdgid(cid.to_pdgid()) 21 | # should be muon 22 | assert p.charge == -1 23 | -------------------------------------------------------------------------------- /tests/converters/test_maps.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | from particle import data 11 | from particle.converters.bimap import BiMap, DirectionalMaps 12 | from particle.exceptions import MatchingIDNotFound 13 | from particle.pdgid import PDGID 14 | from particle.pythia import PythiaID 15 | 16 | 17 | def test_BiMap(): 18 | bimap = BiMap(PDGID, PythiaID) 19 | 20 | assert len(bimap) == 540 21 | assert "BiMap(PDGID-PythiaID)" in str(bimap) 22 | 23 | with pytest.raises(MatchingIDNotFound): 24 | bimap[PDGID(9000221)] 25 | 26 | 27 | def test_DirectionalMaps(): 28 | filename = data.basepath / "pdgid_to_pythiaid.csv" 29 | PDG2PyIDMap, Py2PDGIDMap = DirectionalMaps( 30 | "PDGID", "PythiaID", filename=filename, converters=(int, int) 31 | ) 32 | 33 | assert len(PDG2PyIDMap) == 540 34 | assert len(Py2PDGIDMap) == 540 35 | 36 | assert "DirectionalMap(PDGID->PYTHIAID)" in str(PDG2PyIDMap) 37 | assert "DirectionalMap(PYTHIAID->PDGID)" in str(Py2PDGIDMap) 38 | 39 | with pytest.raises(MatchingIDNotFound): 40 | PDG2PyIDMap[PDGID(9000221)] 41 | with pytest.raises(MatchingIDNotFound): 42 | Py2PDGIDMap[PythiaID(9000221)] 43 | -------------------------------------------------------------------------------- /tests/corsika/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | -------------------------------------------------------------------------------- /tests/corsika/test_corsika7id.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import pytest 4 | 5 | from particle.corsika import Corsika7ID 6 | from particle.exceptions import MatchingIDNotFound 7 | from particle.pdgid import PDGID 8 | 9 | 10 | def test_class_string_representations(): 11 | pid = Corsika7ID(1) 12 | assert pid == 1 13 | assert pid.__str__() == "" 14 | 15 | 16 | def test_class_return_type(): 17 | assert isinstance(Corsika7ID(3), Corsika7ID) 18 | 19 | 20 | def test_from_pdgid(): 21 | assert Corsika7ID.from_pdgid(-13) == 5 22 | 23 | assert Corsika7ID.from_pdgid(PDGID(-13)) == 5 24 | assert Corsika7ID.from_pdgid(PDGID(13)) == Corsika7ID(6) 25 | 26 | 27 | def test_from_pdgid_non_matching(): 28 | with pytest.raises(MatchingIDNotFound): 29 | _ = Corsika7ID.from_pdgid(55) 30 | 31 | 32 | def test_to_pdgid(): 33 | cid = Corsika7ID(5) 34 | assert cid.to_pdgid() == -13 35 | assert cid.to_pdgid() == PDGID(-13) 36 | 37 | 38 | def test_to_pdgid_invalid(): 39 | from particle.particle import InvalidParticle # pylint: disable=C0415 40 | 41 | with pytest.raises(InvalidParticle): 42 | _ = Corsika7ID(75).to_pdgid() 43 | 44 | 45 | def test_is_particle(): 46 | cid = Corsika7ID(1) 47 | assert cid.is_particle() 48 | cid = Corsika7ID(75) 49 | assert not cid.is_particle() 50 | 51 | 52 | def test_from_particle_description(): 53 | cid, is_mother = Corsika7ID.from_particle_description(-6001) 54 | assert is_mother 55 | assert cid.is_particle() 56 | cid, is_mother = Corsika7ID.from_particle_description(75001) 57 | assert not is_mother 58 | assert not cid.is_particle() 59 | 60 | # Corsika ID 201 is deuteron 61 | assert Corsika7ID.from_particle_description(-201000)[0].name() == "D2" 62 | 63 | 64 | def test_from_particle_description_non_valid(): 65 | with pytest.raises(MatchingIDNotFound): 66 | _ = Corsika7ID.from_particle_description(0) 67 | 68 | 69 | def test__is_non_particle_id(): 70 | # Muons 71 | assert not Corsika7ID._is_non_particle_id(5) 72 | assert not Corsika7ID._is_non_particle_id(6) 73 | # Additional muon info, which is not a particle 74 | assert Corsika7ID._is_non_particle_id(75) 75 | assert Corsika7ID._is_non_particle_id(76) 76 | # Weights of the MULTITHIN option 77 | assert Corsika7ID._is_non_particle_id(8888420) 78 | # Cherenkov photons on output file 79 | assert Corsika7ID._is_non_particle_id(9900) 80 | 81 | 82 | def test_name(): 83 | # check name from pdgid module 84 | cid = Corsika7ID(5) 85 | assert cid.name() == "mu+" 86 | 87 | # check name for non-particles 88 | cid = Corsika7ID(8888420) 89 | assert cid.name() == "weights of preceding particle (MULTITHIN option)" 90 | 91 | cid = Corsika7ID(9900) 92 | assert cid.name() == "Cherenkov photons on particle output file" 93 | 94 | cid = Corsika7ID(85) 95 | assert cid.name() == "decaying μ+ at start" 96 | 97 | 98 | def test_name_invalid(): 99 | from particle.particle import InvalidParticle # pylint: disable=C0415 100 | 101 | with pytest.raises(InvalidParticle): 102 | _ = Corsika7ID(0).name() 103 | -------------------------------------------------------------------------------- /tests/data/README.rst: -------------------------------------------------------------------------------- 1 | Particle test data folder contents 2 | ================================== 3 | 4 | This folder contains files used for testing purposes. 5 | By construction files can have features, hence not be fully correct. 6 | -------------------------------------------------------------------------------- /tests/data/test_PDG_mcd_file_duplicates.mcd: -------------------------------------------------------------------------------- 1 | * Example PDG particle data file in ".mcd format" for testing purposes. 2 | * File in the very same format as the mass_width_.mcd files. 3 | * Values below come from the 2021 file. 4 | * 5 | * Particle ID(s) Mass (GeV) Errors (GeV) Width (GeV) Errors (GeV) Name Charges 6 | 1 4.67E-03 +0.5E-03 -0.2E-03 d -1/3 7 | 2 2.16E-03 +0.5E-03 -0.3E-03 u +2/3 8 | 3 9.3E-02 +1.1E-02 -5.0E-03 s -1/3 9 | 4 1.27E+00 +2.0E-02 -2.0E-02 c +2/3 10 | 5 4.180E+00 +3.0E-02 -2.0E-02 b -1/3 11 | 6 1.725E+02 +7.0E-01 -7.0E-01 1.42E+00 +1.9E-01 -1.5E-01 t +2/3 12 | 313 8.9555E-01 +2.0E-04 -2.0E-04 4.73E-02 +5.0E-04 -5.0E-04 K*(892) 0 13 | 323 8.9167E-01 +2.6E-04 -2.6E-04 5.14E-02 +8.0E-04 -8.0E-04 K*(892) + 14 | 323 8.955E-01 +8.0E-04 -8.0E-04 4.62E-02 +1.3E-03 -1.3E-03 K*(892) + 15 | 1114 2114 2214 2224 1.2320E+00 +2.0E-03 -2.0E-03 1.170E-01 +3.0E-03 -3.0E-03 Delta(1232) -,0,+,++ 16 | -------------------------------------------------------------------------------- /tests/geant/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | -------------------------------------------------------------------------------- /tests/geant/test_geant3id.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | from particle.exceptions import MatchingIDNotFound 11 | from particle.geant import Geant3ID 12 | from particle.pdgid import PDGID 13 | 14 | 15 | def test_class_string_representations(): 16 | pid = Geant3ID(1) 17 | assert pid == 1 18 | assert pid.__str__() == "" 19 | 20 | 21 | def test_class_return_type(): 22 | assert isinstance(-Geant3ID(3), Geant3ID) 23 | assert isinstance(~Geant3ID(3), Geant3ID) 24 | 25 | 26 | def test_class_inversion(): 27 | assert -Geant3ID(1) == ~Geant3ID(1) 28 | 29 | 30 | def test_from_pdgid(): 31 | assert Geant3ID.from_pdgid(211) == 8 32 | 33 | assert Geant3ID.from_pdgid(PDGID(211)) == 8 34 | assert Geant3ID.from_pdgid(PDGID(211)) == Geant3ID(8) 35 | 36 | 37 | def test_from_pdgid_non_matching(): 38 | with pytest.raises(MatchingIDNotFound): 39 | Geant3ID.from_pdgid(55) 40 | 41 | 42 | def test_to_pdgid(): 43 | gid = Geant3ID(8) 44 | assert gid.to_pdgid() == 211 45 | assert gid.to_pdgid() == PDGID(211) 46 | -------------------------------------------------------------------------------- /tests/lhcb/test_lhcb_name.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | from particle import Particle 11 | from particle.lhcb import from_lhcb_name, to_lhcb_name 12 | 13 | lhcb_style_names = ( 14 | ("nu_tau", 16), 15 | ("nu_tau~", -16), 16 | ("eta_prime", 331), 17 | ("f'_2(1525)", 335), 18 | ("D*_s+", 433), 19 | ("D*_s-", -433), 20 | ("B_s0", 531), 21 | ("B_s~0", -531), 22 | ("Lambda_b0", 5122), 23 | ("Lambda_b~0", -5122), 24 | # ("X_1(3872)", 9920443), 25 | ) 26 | 27 | 28 | @pytest.mark.parametrize(("name", "pid"), lhcb_style_names) 29 | def test_from_lhcb_name(name, pid): 30 | assert from_lhcb_name(name).pdgid == pid 31 | 32 | 33 | @pytest.mark.parametrize(("name", "pid"), lhcb_style_names) 34 | def test_to_lhcb_name(name, pid): 35 | assert to_lhcb_name(Particle.from_pdgid(pid)) == name 36 | -------------------------------------------------------------------------------- /tests/particle/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | -------------------------------------------------------------------------------- /tests/particle/test_convert.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | # Requires pandas 11 | pd = pytest.importorskip("pandas") 12 | 13 | from pathlib import Path 14 | 15 | from particle.particle.convert import get_from_pdg_mcd 16 | 17 | DIR = Path(__file__).parent.resolve() 18 | 19 | 20 | def test_get_from_pdg_mcd(): 21 | with (DIR / "../data/test_PDG_mcd_file_duplicates.mcd").open() as f, pytest.raises( 22 | AssertionError 23 | ): 24 | get_from_pdg_mcd(f) 25 | -------------------------------------------------------------------------------- /tests/particle/test_enums.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from particle.particle.enums import Charge, SpinType 10 | 11 | 12 | def test_enums_Charge(): 13 | assert Charge.p + Charge.m == Charge.o 14 | assert Charge.pp + Charge.mm == Charge.o 15 | 16 | 17 | def test_enums_SpinType(): 18 | assert SpinType.PseudoScalar == -SpinType.Scalar 19 | assert SpinType.Axial == -SpinType.Vector 20 | assert SpinType.PseudoTensor == -SpinType.Tensor 21 | -------------------------------------------------------------------------------- /tests/particle/test_generation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | # Requires pandas 11 | pd = pytest.importorskip("pandas") 12 | 13 | from collections import Counter 14 | 15 | from particle import data 16 | from particle.particle import Particle 17 | from particle.particle.convert import produce_files 18 | from particle.pdgid import ( 19 | is_diquark, 20 | is_dyon, 21 | is_excited_quark_or_lepton, 22 | is_generator_specific, 23 | is_lepton, 24 | is_meson, 25 | is_pentaquark, 26 | is_Qball, 27 | is_quark, 28 | is_Rhadron, 29 | is_sm_lepton, 30 | is_special_particle, 31 | is_SUSY, 32 | is_technicolor, 33 | three_charge, 34 | ) 35 | 36 | FILES = ["particle2023.csv", "particle2024.csv"] 37 | 38 | 39 | def test_generate(tmp_path): 40 | "This verifies that the input and output files match." 41 | 42 | particle2023 = tmp_path / "particle2023.csv" 43 | particle2024 = tmp_path / "particle2024.csv" 44 | 45 | produce_files(particle2023, particle2024, "DUMMY", "2024") 46 | 47 | particle2024_data = data.basepath / "particle2024.csv" 48 | with particle2024.open() as src, particle2024_data.open() as res: 49 | src_filtered = [line for line in src.readlines() if not line.startswith("#")] 50 | res_filtered = [line for line in res.readlines() if not line.startswith("#")] 51 | assert src_filtered == res_filtered 52 | 53 | 54 | @pytest.mark.parametrize("filename", FILES) 55 | def test_csv_file_duplicates(filename): 56 | particle_data = data.basepath / filename 57 | p = pd.read_csv(particle_data, comment="#") 58 | 59 | duplicates = {item for item, count in Counter(p.ID).items() if count > 1} 60 | assert duplicates == set() 61 | 62 | 63 | @pytest.mark.parametrize("filename", FILES) 64 | def test_csv_file_has_latex(filename): 65 | particle_data = data.basepath / filename 66 | p = pd.read_csv(particle_data, comment="#") 67 | 68 | assert p[p.Latex == ""].empty 69 | 70 | 71 | def test_None_masses(): 72 | "Only certain specific particles should have None masses." 73 | none_masses = { 74 | 100321, 75 | -100321, # K(1460)+ 76 | } 77 | for p in Particle.all(): 78 | pdgid = p.pdgid 79 | if pdgid in none_masses: 80 | continue 81 | 82 | if ( 83 | is_Qball(pdgid) 84 | or is_Rhadron(pdgid) 85 | or is_SUSY(pdgid) 86 | or is_diquark(pdgid) 87 | or is_dyon(pdgid) 88 | or is_excited_quark_or_lepton(pdgid) 89 | or is_generator_specific(pdgid) 90 | or (is_lepton(pdgid) and three_charge(pdgid) == 0) 91 | or (is_lepton(pdgid) and not is_sm_lepton(pdgid)) # neutrinos 92 | or ( # 4-th generation leptons 93 | is_meson(pdgid) and (abs(pdgid) // 1000000 % 10 == 9) 94 | ) 95 | or is_pentaquark( # Mesons with PDGIDs of the kind 9XXXXXX are not experimentally well-known 96 | pdgid 97 | ) 98 | or is_quark(pdgid) 99 | or is_special_particle(pdgid) 100 | or is_technicolor(pdgid) 101 | ): 102 | continue 103 | 104 | assert p.mass is not None 105 | 106 | 107 | check_nucleons = ( 108 | (2212, 1000010010), 109 | (-2212, -1000010010), 110 | (2112, 1000000010), 111 | (-2112, -1000000010), 112 | ) 113 | 114 | 115 | @pytest.mark.parametrize(("id_particle", "id_nucleus"), check_nucleons) 116 | def test_nucleon_properties(id_particle, id_nucleus): 117 | """ 118 | Protons and neutrons are both available in the particles table and in the nuclei table 119 | under IDs 2212 and 2112, and 1000010010 and 1000000010, respectively. 120 | This trivial test checks most of what is likely to change between PDG updates, 121 | to ensure consistency. 122 | """ 123 | p_particle = Particle.from_pdgid(id_particle) 124 | p_nucleus = Particle.from_pdgid(id_nucleus) 125 | 126 | # Trivial replacement of IDs to avoid obvious irrelevant differences 127 | assert p_particle.describe().replace( 128 | f"{id_particle:<12}", f"{id_particle:<12}" 129 | ) == p_nucleus.describe().replace(f"{id_nucleus:<12}", f"{id_particle:<12}") 130 | -------------------------------------------------------------------------------- /tests/particle/test_kinematics.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | from hepunits.constants import hbar 10 | from hepunits.units import GeV, MeV, ps 11 | from pytest import approx 12 | 13 | from particle.particle import lifetime_to_width, width_to_lifetime 14 | 15 | 16 | def test_valid_width_lifetime_conversions(): 17 | assert lifetime_to_width(1.5 * ps) / GeV == approx(4.388079676311604e-13) 18 | assert 1.5 * ps * lifetime_to_width(1.5 * ps) == hbar 19 | assert width_to_lifetime(hbar) == 1 * MeV 20 | 21 | 22 | def test_invalid_width_lifetime_conversions(): 23 | with pytest.raises(ValueError, match="Input provided, -1 <= 0!"): 24 | lifetime_to_width(-1) 25 | with pytest.raises(ValueError, match="Input provided, -1 <= 0!"): 26 | width_to_lifetime(-1) 27 | 28 | assert lifetime_to_width(0) == float("inf") 29 | assert width_to_lifetime(0) == float("inf") 30 | -------------------------------------------------------------------------------- /tests/particle/test_literals.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from particle import literals as lp 10 | 11 | 12 | def test_literals_import(): 13 | assert lp is not None 14 | -------------------------------------------------------------------------------- /tests/particle/test_performance.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from particle import Particle, data 4 | 5 | 6 | def test_load_particle_table(benchmark): 7 | benchmark(Particle.load_table, data.basepath / "particle2024.csv") 8 | 9 | 10 | def test_load_nuclei_append(benchmark): 11 | def load_two(): 12 | Particle.load_table(data.basepath / "particle2024.csv") 13 | Particle.load_table(data.basepath / "nuclei2022.csv", append=True) 14 | 15 | benchmark(load_two) 16 | 17 | 18 | def test_from_pdgid(benchmark): 19 | Particle.load_table(data.basepath / "particle2024.csv") 20 | table = [int(s.pdgid) for s in Particle.all()] 21 | 22 | def get_all(listing): 23 | for pdgid in listing: 24 | Particle.from_pdgid(pdgid) 25 | 26 | benchmark(get_all, table) 27 | -------------------------------------------------------------------------------- /tests/particle/test_utilities.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | from particle.particle.utilities import ( 11 | greek_letter_name_to_unicode, 12 | latex_name_unicode, 13 | programmatic_name, 14 | str_with_unc, 15 | ) 16 | 17 | possibilities = ( 18 | # Particles 19 | ("d", "d", False), 20 | ("b~", "b_bar", False), 21 | ("nu(e)~", "nu_e_bar", False), 22 | ("tau+", "tau_plus", False), 23 | ("H0", "H_0", False), 24 | ("a(2)(1320)0", "a_2_1320_0", False), 25 | ("f(2)'(1525)", "f_2p_1525", False), 26 | ("Delta(1232)~--", "Delta_1232_mm_bar", False), 27 | ("a(0)(1450)0", "a_0_1450_0", False), 28 | ("K*(892)0", "Kst_892_0", False), 29 | ("K(2)*(1430)~0", "K_2st_1430_0_bar", False), 30 | ("D(2)*(2460)+", "D_2st_2460_plus", False), 31 | ("B(s2)*(5840)0", "B_s2st_5840_0", False), 32 | ("(dd)(1)", "dd_1", False), 33 | # Nuclei 34 | ("H4", "H4", True), 35 | ("He4", "He4", True), 36 | ("He4~", "He4_bar", True), 37 | ("C10", "C10", True), 38 | ("C10~", "C10_bar", True), 39 | ("Ag100", "Ag100", True), 40 | ("Ag100~", "Ag100_bar", True), 41 | ) 42 | 43 | 44 | @pytest.mark.parametrize(("name", "value", "is_nucleus"), possibilities) 45 | def test_programmatic_name(name, value, is_nucleus): 46 | assert programmatic_name(name, is_nucleus) == value 47 | 48 | 49 | possibilities = ( 50 | (1.234567, 0.01, None, "1.235 ± 0.010"), 51 | (1.234567e-9, 0.01e-9, None, "1.235e-09 ± 1.0e-11"), 52 | (1.234567e9, 0.04e9, None, "1.23e+09 ± 4e+07"), 53 | (0.001, 0.00001, None, "1.000e-03 ± 1.0e-05"), 54 | (0.00099, 0.00001, None, "9.90e-04 ± 1.0e-05"), 55 | (99, 0.24, None, "99.00 ± 0.24"), 56 | (100, 0.25, None, "100.0 ± 0.2"), 57 | (101, 0.26, None, "101.0 ± 0.3"), 58 | (0.00001231, 0.000002, 0.000004, "1.23e-05 + 2.0e-06 - 4.0e-06"), 59 | (1234.5, 0.03, 0.03, "1234.50 ± 0.03"), 60 | (1234.5, 5, 5, "1234 ± 5"), 61 | (1234.5, 2, 2, "1234.5 ± 2.0"), 62 | (1234.5, None, None, "1234.5"), 63 | (1234.5, None, 2, "1234.5"), 64 | ) 65 | 66 | 67 | @pytest.mark.parametrize(("value", "err_u", "err_l", "test_str"), possibilities) 68 | def test_unc_printout(value, err_u, err_l, test_str): 69 | assert str_with_unc(value, err_u, err_l) == test_str 70 | 71 | 72 | possibilities = ( 73 | ("\\omega", "ω"), 74 | ("\\Omega", "Ω"), 75 | ("\\Lambda", "Λ"), 76 | ("\\alpha_{x}^{0}\\beta\\Gamma(1234)\\Omega", "α_{x}^{0}βΓ(1234)Ω"), 77 | ) 78 | 79 | 80 | @pytest.mark.parametrize(("name", "unicode_name"), possibilities) 81 | def test_latex_name_unicode(name, unicode_name): 82 | assert latex_name_unicode(name) == unicode_name 83 | 84 | 85 | def test_greek_letter_name_to_unicode(): 86 | """ 87 | Test the one exception that is not verified 88 | in the test "test_latex_name_unicode" above. 89 | """ 90 | with pytest.raises(KeyError): 91 | _ = greek_letter_name_to_unicode("Lambda") 92 | with pytest.raises(KeyError): 93 | _ = greek_letter_name_to_unicode("NonExistent") 94 | -------------------------------------------------------------------------------- /tests/pdgid/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | -------------------------------------------------------------------------------- /tests/pdgid/test_literals.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from particle.pdgid import literals as lid 10 | 11 | 12 | def test_literals_import(): 13 | assert lid is not None 14 | -------------------------------------------------------------------------------- /tests/pdgid/test_pdgid.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | from particle.pdgid import PDGID 9 | from particle.pdgid import functions as _functions 10 | from particle.pdgid.pdgid import _fnames 11 | 12 | 13 | def test_class_string_representations(): 14 | pid = PDGID(11) 15 | assert pid == 11 16 | assert pid.__str__() == "" 17 | pid = PDGID(-99999999) 18 | assert pid.__str__() == "" 19 | 20 | 21 | def test_class_operations(PDGIDs): 22 | id_electron = PDGID(PDGIDs.Electron) 23 | id_positron = PDGID(PDGIDs.Positron) 24 | assert PDGIDs.Electron == id_electron 25 | assert id_positron == -id_electron 26 | assert PDGIDs.Positron == -id_electron 27 | 28 | 29 | def test_class_return_type(): 30 | assert isinstance(-PDGID(311), PDGID) 31 | assert isinstance(~PDGID(311), PDGID) 32 | 33 | 34 | def test_class_inversion(): 35 | assert -PDGID(311) == ~PDGID(311) 36 | 37 | 38 | def test_nonphysical_pdgids(): 39 | # The negative PDGID of a self-conjugate meson makes no sense 40 | assert not ( 41 | PDGID(-111).is_meson 42 | ) # the "anti-pi0" with opposite PDGID of a pi0 does not exist 43 | assert not ( 44 | PDGID(-443).is_meson 45 | ) # the "anti-J/psi" with opposite PDGID of a J/psi does not exist 46 | 47 | 48 | def test_info(): 49 | __info = """A None 50 | J 1.0 51 | L None 52 | S None 53 | Z None 54 | abspid 22 55 | charge 0.0 56 | has_bottom False 57 | has_charm False 58 | has_down False 59 | has_fundamental_anti False 60 | has_strange False 61 | has_top False 62 | has_up False 63 | is_Qball False 64 | is_Rhadron False 65 | is_SUSY False 66 | is_baryon False 67 | is_diquark False 68 | is_dyon False 69 | is_excited_quark_or_lepton False 70 | is_gauge_boson_or_higgs True 71 | is_generator_specific False 72 | is_hadron False 73 | is_lepton False 74 | is_meson False 75 | is_nucleus False 76 | is_pentaquark False 77 | is_quark False 78 | is_sm_gauge_boson_or_higgs True 79 | is_sm_lepton False 80 | is_sm_quark False 81 | is_special_particle False 82 | is_technicolor False 83 | is_valid True 84 | j_spin 3 85 | l_spin None 86 | s_spin None 87 | three_charge 0 88 | """ 89 | assert PDGID(22).info() == __info 90 | 91 | 92 | def test_decorated_class_methods(PDGIDs): 93 | """ 94 | Check that all particle.pdgid functions decorated in the PDGID class 95 | work as expected for all kinds of PDGIDs. 96 | """ 97 | for m in _fnames: 98 | for pid in PDGIDs: 99 | assert getattr(PDGID(pid), m) == getattr(_functions, m)(pid) 100 | -------------------------------------------------------------------------------- /tests/pythia/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | -------------------------------------------------------------------------------- /tests/pythia/test_pythiaid.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | from particle.exceptions import MatchingIDNotFound 11 | from particle.pdgid import PDGID 12 | from particle.pythia import PythiaID 13 | 14 | 15 | def test_class_string_representations(): 16 | pid = PythiaID(211) 17 | assert pid == 211 18 | assert pid.__str__() == "" 19 | 20 | 21 | def test_class_return_type(): 22 | assert isinstance(-PythiaID(211), PythiaID) 23 | assert isinstance(~PythiaID(211), PythiaID) 24 | 25 | 26 | def test_class_inversion(): 27 | assert -PythiaID(311) == ~PythiaID(311) 28 | 29 | 30 | def test_from_pdgid(): 31 | assert PythiaID.from_pdgid(9010221) == 10221 32 | 33 | assert PythiaID.from_pdgid(PDGID(9010221)) == 10221 34 | assert PythiaID.from_pdgid(PDGID(9010221)) == PythiaID(10221) 35 | 36 | with pytest.raises(MatchingIDNotFound): 37 | PythiaID.from_pdgid(9000221) 38 | 39 | 40 | def test_to_pdgid(): 41 | pythiaid = PythiaID(10331) 42 | assert pythiaid.to_pdgid() == 10221 43 | assert pythiaid.to_pdgid() == PDGID(10221) 44 | -------------------------------------------------------------------------------- /tests/test_module_apis.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import particle 4 | 5 | 6 | def test_top_level_api(): 7 | assert dir(particle) == [ 8 | "Charge", 9 | "Corsika7ID", 10 | "Geant3ID", 11 | "Inv", 12 | "InvalidParticle", 13 | "PDGID", 14 | "Parity", 15 | "Particle", 16 | "ParticleNotFound", 17 | "PythiaID", 18 | "SpinType", 19 | "Status", 20 | "__version__", 21 | "latex_to_html_name", 22 | "lifetime_to_width", 23 | "width_to_lifetime", 24 | ] 25 | 26 | 27 | def test_api_converters(): 28 | assert dir(particle.converters) == [ 29 | "Corsika72PDGIDBiMap", 30 | "EvtGen2PDGNameMap", 31 | "EvtGenName2PDGIDBiMap", 32 | "Geant2PDGIDBiMap", 33 | "PDG2EvtGenNameMap", 34 | "Pythia2PDGIDBiMap", 35 | ] 36 | 37 | 38 | def test_api_corsika(): 39 | assert dir(particle.corsika) == ["Corsika7ID"] 40 | 41 | 42 | def test_api_data(): 43 | assert dir(particle.data) == ["basepath"] 44 | 45 | 46 | def test_api_geant(): 47 | assert dir(particle.geant) == ["Geant3ID"] 48 | 49 | 50 | def test_api_lhcb(): 51 | assert dir(particle.lhcb) == [ 52 | "LHCbName2PDGIDBiMap", 53 | "from_lhcb_name", 54 | "to_lhcb_name", 55 | ] 56 | 57 | 58 | def test_api_lhcb_data(): 59 | assert dir(particle.lhcb.data) == ["basepath"] 60 | 61 | 62 | def test_api_particle(): 63 | assert dir(particle.particle) == [ 64 | "Charge", 65 | "Inv", 66 | "InvalidParticle", 67 | "Parity", 68 | "Particle", 69 | "ParticleNotFound", 70 | "SpinType", 71 | "Status", 72 | "latex_name_unicode", 73 | "latex_to_html_name", 74 | "lifetime_to_width", 75 | "programmatic_name", 76 | "width_to_lifetime", 77 | ] 78 | 79 | 80 | def test_api_pdgid(): 81 | assert dir(particle.pdgid) == sorted( 82 | [ 83 | "PDGID", 84 | "is_valid", 85 | "abspid", 86 | # # 87 | "is_Qball", 88 | "is_Rhadron", 89 | "is_SUSY", 90 | "is_baryon", 91 | "is_diquark", 92 | "is_dyon", 93 | "is_excited_quark_or_lepton", 94 | "is_gauge_boson_or_higgs", 95 | "is_generator_specific", 96 | "is_hadron", 97 | "is_lepton", 98 | "is_meson", 99 | "is_nucleus", 100 | "is_pentaquark", 101 | "is_quark", 102 | "is_sm_gauge_boson_or_higgs", 103 | "is_sm_lepton", 104 | "is_sm_quark", 105 | "is_special_particle", 106 | "is_technicolor", 107 | "has_down", 108 | "has_up", 109 | "has_strange", 110 | "has_charm", 111 | "has_bottom", 112 | "has_top", 113 | "has_fundamental_anti", 114 | "charge", 115 | "three_charge", 116 | "j_spin", 117 | "J", 118 | "s_spin", 119 | "S", 120 | "l_spin", 121 | "L", 122 | "A", 123 | "Z", 124 | ] 125 | ) 126 | 127 | 128 | def test_api_pythia(): 129 | assert dir(particle.pythia) == ["PythiaID"] 130 | -------------------------------------------------------------------------------- /tests/test_package.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2025, Eduardo Rodrigues and Henry Schreiner. 2 | # 3 | # Distributed under the 3-clause BSD license, see accompanying file LICENSE 4 | # or https://github.com/scikit-hep/particle for details. 5 | 6 | from __future__ import annotations 7 | 8 | import particle 9 | 10 | 11 | def test_package_import(): 12 | assert particle is not None 13 | 14 | 15 | def test_load_version(): 16 | assert particle.__version__ 17 | --------------------------------------------------------------------------------