├── tests ├── __init__.py ├── data │ ├── models │ │ ├── model-PYCONT.dec │ │ ├── model-PHSP.dec │ │ ├── model-TAUOLA.dec │ │ ├── model-SLL.dec │ │ ├── model-STS.dec │ │ ├── model-SVS.dec │ │ ├── model-VSS.dec │ │ ├── model-TSS.dec │ │ ├── model-SVP.dec │ │ ├── model-TVP.dec │ │ ├── model-VTOSLL.dec │ │ ├── model-XLL.dec │ │ ├── model-ISGW.dec │ │ ├── model-VSP_PWAVE.dec │ │ ├── model-VVPIPI.dec │ │ ├── model-BC_SMN.dec │ │ ├── model-BC_VMN.dec │ │ ├── model-BTOSLLALI.dec │ │ ├── model-BTOXSGAMMA.dec │ │ ├── model-FLATQ2.dec │ │ ├── model-FLATSQDALITZ.dec │ │ ├── model-ISGW2.dec │ │ ├── model-KNUNU.dec │ │ ├── model-SHD.dec │ │ ├── model-SLN.dec │ │ ├── model-VLL.dec │ │ ├── model-BC_VHAD.dec │ │ ├── model-ETA_DALITZ.dec │ │ ├── model-ETA_LLPIPI.dec │ │ ├── model-MELIKHOV.dec │ │ ├── model-OMEGA_DALITZ.dec │ │ ├── model-PHI_DALITZ.dec │ │ ├── model-PI0_DALITZ.dec │ │ ├── model-SSD_DirectCP.dec │ │ ├── model-TAUSCALARNU.dec │ │ ├── model-TAUVECTORNU.dec │ │ ├── model-BC_TMN.dec │ │ ├── model-BNOCBPTOKSHHH.dec │ │ ├── model-BTOSLLBALL.dec │ │ ├── model-D0GAMMADALITZ.dec │ │ ├── model-ETA2MUMUGAMMA.dec │ │ ├── model-HELAMP.dec │ │ ├── model-HQET2.dec │ │ ├── model-KSTARNUNU_REV.dec │ │ ├── model-PHSPFLATLIFETIME.dec │ │ ├── model-SLBKPOLE.dec │ │ ├── model-VECTORISR.dec │ │ ├── model-ETA_PI0DALITZ.dec │ │ ├── model-LbAmpGen.dec │ │ ├── model-PHSPDECAYTIMECUT.dec │ │ ├── model-BC_VPPHAD.dec │ │ ├── model-BLLNUL.dec │ │ ├── model-B_TO_2BARYON_SCALAR.dec │ │ ├── model-BaryonPCR.dec │ │ ├── model-HQET.dec │ │ ├── model-HypNonLepton.dec │ │ ├── model-PARTWAVE.dec │ │ ├── model-PYTHIA.dec │ │ ├── model-RareLbToLll.dec │ │ ├── model-SVP_HELAMP.dec │ │ ├── model-TAULNUNU.dec │ │ ├── model-VVP.dec │ │ ├── model-BNOCBPTO3HPI0.dec │ │ ├── model-BTOXSLL.dec │ │ ├── model-DToKpienu.dec │ │ ├── model-GOITY_ROBERTS.dec │ │ ├── model-LLSW.dec │ │ ├── model-SSS_CPT.dec │ │ ├── model-THREEBODYPHSP.dec │ │ ├── model-VUB.dec │ │ ├── model-VVPIPI_WEIGHTED.dec │ │ ├── model-VVS_PWAVE.dec │ │ ├── model-SVV_CPLH.dec │ │ ├── model-SVV_HELAMP.dec │ │ ├── model-TVS_PWAVE.dec │ │ ├── model-B_TO_LAMBDA_PBAR_GAMMA.dec │ │ ├── model-D_hhhh.dec │ │ ├── model-KS_PI0MUMU.dec │ │ ├── model-CB3PI-MPP.dec │ │ ├── model-HQET3.dec │ │ ├── model-Lb2Baryonlnu.dec │ │ ├── model-TAUHADNU.dec │ │ ├── model-VSS_MIX.dec │ │ ├── model-YMSTOYNSPIPICLEO.dec │ │ ├── model-CB3PI-P00.dec │ │ ├── model-ETAPRIME_DALITZ.dec │ │ ├── model-SSS_CP.dec │ │ ├── model-BCL.dec │ │ ├── model-BTOXSNUNU_FERMI.dec │ │ ├── model-VSS_BMIX.dec │ │ ├── model-BNOCB0TO4PICP.dec │ │ ├── model-ETA_FULLDALITZ.dec │ │ ├── model-VUB_BLNP.dec │ │ ├── model-BGL.dec │ │ ├── model-YMSTOYNSPIPICLEOBOOST.dec │ │ ├── model-SVS_CP.dec │ │ ├── model-BTO3PI_CP.dec │ │ ├── model-PHSP_BB_MIX.dec │ │ ├── model-PHSP_B_MIX.dec │ │ ├── model-STS_CP.dec │ │ ├── model-SVP_CP.dec │ │ ├── model-BTOXELNU.dec │ │ ├── model-SVVHELCPMIX.dec │ │ ├── model-BToDiBaryonlnupQCD.dec │ │ ├── model-PROPSLPOLE.dec │ │ ├── model-PHSP_CP.dec │ │ ├── model-SSD_CP.dec │ │ ├── model-Lb2plnuLQCD.dec │ │ ├── model-SSS_CP_PNG.dec │ │ ├── model-LNUGAMMA.dec │ │ ├── model-Lb2plnuLCSR.dec │ │ ├── model-SVS_NONCPEIGEN.dec │ │ ├── model-SLPOLE.dec │ │ ├── model-D_DALITZ.dec │ │ ├── model-GENERIC_DALITZ.dec │ │ ├── model-SVS_CPLH.dec │ │ ├── model-BS_MUMUKK.dec │ │ ├── model-SVV_NONCPEIGEN.dec │ │ ├── model-BTODDALITZCPK.dec │ │ ├── model-PVV_CPLH.dec │ │ ├── model-BT02PI_CP_ISO.dec │ │ ├── model-D0MIXDALITZ.dec │ │ ├── model-BSTOGLLMNT.dec │ │ ├── model-SVV_CP.dec │ │ ├── model-SVS_CP_ISO.dec │ │ ├── model-FOURBODYPHSP.dec │ │ ├── model-BTOVLNUBALL.dec │ │ ├── model-BQTOLLLLHYPERCP.dec │ │ ├── model-BTOSLLMS.dec │ │ ├── model-BSTD_2HDMTYPE2.dec │ │ ├── model-BSTOGLLISRFSR.dec │ │ ├── model-BQTOLLLL.dec │ │ ├── model-BSTD.dec │ │ ├── model-BTOSLLMSEXT.dec │ │ └── model-PTO3P.dec │ ├── test_stable-particle.dec │ ├── README.rst │ ├── test_Upsilon4S2B0B0bar.dec │ ├── test_custom_decay_model.dec │ ├── minimalistic.dec │ ├── test_Upsilon2S2UpsilonPiPi.dec │ ├── test_DtoKlnu.dec │ ├── test_Xicc2XicPiPi.dec │ ├── test_Bc2BsPi_Bs2KK.dec │ ├── test_example_Dst.dec │ ├── test_Bd2DmTauNu_Dm23PiPi0_Tau2MuNu.dec │ ├── test_Bd2DDst_Ds2DmPi0.dec │ ├── test_multiline_model.dec │ ├── duplicate-decays.dec │ ├── test_issue90.dec │ ├── test_CopyDecay_RemoveDecay.dec │ ├── test_Bd2DstDst.dec │ ├── test_Bd2DMuNu.dec │ └── test_Bd2Dst0X_D02KPi.dec ├── test_decaylanguage.py ├── dec │ └── test_issues.py ├── test_convert.py ├── test_goofit.py ├── utils │ ├── test_utilities.py │ └── test_particleutils.py ├── decay │ ├── test_descriptor.py │ └── test_viewer.py └── test_dec_full.py ├── src └── decaylanguage │ ├── py.typed │ ├── dec │ ├── py.typed │ ├── __init__.py │ └── enums.py │ ├── decay │ ├── py.typed │ └── __init__.py │ ├── _compat │ ├── __init__.py │ └── typing.py │ ├── modeling │ ├── py.typed │ ├── __init__.py │ ├── ampgentransform.py │ ├── decay.py │ ├── ampgen2goofit.py │ └── amplitudechain.py │ ├── _version.pyi │ ├── data │ ├── __init__.py │ ├── MintDalitzSpecialParticlesLatex.csv │ ├── particle.lark │ ├── README.rst │ ├── ampgen.lark │ ├── decfile.lark │ ├── MintDalitzSpecialParticles.fwf │ └── MintDalitzSpecialParticles.csv │ ├── utils │ ├── errors.py │ ├── __init__.py │ ├── utilities.py │ └── particleutils.py │ ├── __init__.py │ └── __main__.py ├── docs ├── authors.rst ├── readme.rst ├── changelog.rst ├── contributing.rst ├── requirements.txt ├── reference │ ├── index.rst │ ├── decaylanguage.rst │ └── decaylanguage.decay.rst ├── spelling_wordlist.txt ├── installation.rst ├── index.rst ├── usage.rst └── conf.py ├── images ├── DecayLanguage.pdf ├── DecayLanguage.png ├── DecayChain_Dst_stable-D0-and-D+.png ├── DecayLanguage.svg └── DecayLanguage.ink.svg ├── AUTHORS.rst ├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ ├── wheel.yml │ └── ci.yml ├── environment.yml ├── codecov.yml ├── .readthedocs.yml ├── notebooks ├── simple_model.txt └── ExampleDecFileParsingWithLark.ipynb ├── CITATION.cff ├── .gitignore ├── noxfile.py ├── LICENSE ├── .pre-commit-config.yaml ├── CONTRIBUTING.rst ├── .all-contributorsrc └── pyproject.toml /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/decaylanguage/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/decaylanguage/dec/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/decaylanguage/decay/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/decaylanguage/_compat/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/decaylanguage/modeling/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. mdinclude:: ../README.md 2 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. mdinclude:: ../CHANGELOG.md 2 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | -e . 2 | sphinx>=1.3 3 | sphinx-rtd-theme 4 | -------------------------------------------------------------------------------- /images/DecayLanguage.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/decaylanguage/HEAD/images/DecayLanguage.pdf -------------------------------------------------------------------------------- /images/DecayLanguage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/decaylanguage/HEAD/images/DecayLanguage.png -------------------------------------------------------------------------------- /docs/reference/index.rst: -------------------------------------------------------------------------------- 1 | Reference 2 | ========= 3 | 4 | .. toctree:: 5 | :glob: 6 | 7 | decaylanguage* 8 | -------------------------------------------------------------------------------- /images/DecayChain_Dst_stable-D0-and-D+.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scikit-hep/decaylanguage/HEAD/images/DecayChain_Dst_stable-D0-and-D+.png -------------------------------------------------------------------------------- /src/decaylanguage/_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 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | 2 | Authors 3 | ======= 4 | 5 | * Henry Fredrick Schreiner III - https://iscinumpy.gitlab.io 6 | * Eduardo Rodrigues - https://github.com/eduardo-rodrigues/ 7 | -------------------------------------------------------------------------------- /tests/data/models/model-PYCONT.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay vpho 4 | 1.0 PYCONT; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PHSP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay X 4 | 1. A B PHOTOS PHSP; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-TAUOLA.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay tau+ 4 | 1.0 TAUOLA 5; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /docs/spelling_wordlist.txt: -------------------------------------------------------------------------------- 1 | builtin 2 | builtins 3 | classmethod 4 | staticmethod 5 | classmethods 6 | staticmethods 7 | args 8 | kwargs 9 | callstack 10 | Changelog 11 | Indices 12 | -------------------------------------------------------------------------------- /tests/data/models/model-SLL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_s0 4 | 1.0 tau+ tau- SLL; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-STS.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 1.0 chi_c2 K_S0 STS; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SVS.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_c+ 4 | 1.0 rho+ B_s0 SVS; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VSS.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D*+ 4 | 0.6770 D0 pi+ VSS; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/test_stable-particle.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes: 2 | # An empty list of decay modes makes the particle stable! 3 | 4 | Decay K_S0 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /src/decaylanguage/data/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from importlib import resources 4 | 5 | __all__ = ["basepath"] 6 | 7 | 8 | basepath = resources.files(__name__) 9 | -------------------------------------------------------------------------------- /tests/data/models/model-TSS.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay chi_c2 4 | 0.00145 pi+ pi- TSS; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /docs/reference/decaylanguage.rst: -------------------------------------------------------------------------------- 1 | decaylanguage 2 | ============= 3 | 4 | .. testsetup:: 5 | 6 | from decaylanguage import * 7 | 8 | .. automodule:: decaylanguage 9 | :members: 10 | -------------------------------------------------------------------------------- /tests/data/models/model-SVP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay chi_b0 4 | 0.5 gamma Upsilon(2S) SVP; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-TVP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay chi_c2 4 | 1.00 J/psi gamma TVP; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VTOSLL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D*0 4 | 1.0 D0 e+ e- VTOSLL; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-XLL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_s0 4 | 1.0 J/psi K+ K- XLL 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-ISGW.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay anti-B0 4 | 1.0 D*+ e- anti-nu_e ISGW; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VSP_PWAVE.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D*+ 4 | 0.0160 D+ gamma VSP_PWAVE; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VVPIPI.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay psi2S 4 | 1.0 J/psi pi+ pi- VVPIPI; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BC_SMN.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_c+ 4 | 1.000 D0 mu+ nu_mu BC_SMN 2; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BC_VMN.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_c+ 4 | 1.0 D*0 mu+ nu_mu BC_VMN 2; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOSLLALI.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_s0sig 4 | 1.0 phi mu+ mu- BTOSLLALI; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOXSGAMMA.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 0.0003118 Xsu gamma BTOXSGAMMA 2; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-FLATQ2.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+sig 4 | 1.0 MyKst+ mu+ mu- FLATQ2 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-FLATSQDALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 1.000 pi+ K- K+ FLATSQDALITZ; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-ISGW2.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D0 4 | 1.0 K- mu+ nu_mu PHOTOS ISGW2; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-KNUNU.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0sig 4 | 1.0 K0 nu_e anti-nu_e KNUNU; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SHD.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Lambda0sig 4 | 1.0 p+ mu- anti-nu_mu SHD; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SLN.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D_s- 4 | 0.00556 mu- anti-nu_mu PHOTOS SLN; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VLL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | 4 | Decay J/psi 5 | 0.059300000 mu+ mu- PHOTOS VLL; 6 | Enddecay 7 | 8 | End 9 | -------------------------------------------------------------------------------- /tests/data/models/model-BC_VHAD.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_c+ 4 | 1.0 J/psi pi+ pi+ pi- BC_VHAD 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-ETA_DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay eta 4 | 0.227400000 pi- pi+ pi0 ETA_DALITZ; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-ETA_LLPIPI.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay eta 4 | 1.0 mu+ mu- pi+ pi- ETA_LLPIPI; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-MELIKHOV.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay anti-B0 4 | 1.0 D*+ e- anti-nu_e MELIKHOV 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-OMEGA_DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay omega 4 | 0.892000000 pi- pi+ pi0 OMEGA_DALITZ; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PHI_DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay phi 4 | 0.1532 pi+ pi- pi0 PHI_DALITZ; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PI0_DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay pi0 4 | 0.011738247 e+ e- gamma PI0_DALITZ; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SSD_DirectCP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_s0 4 | 1.0 K- pi+ SSD_DirectCP 0.39; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-TAUSCALARNU.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay tau- 4 | 0.109100000 pi- nu_tau TAUSCALARNU; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-TAUVECTORNU.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay tau- 4 | 0.254941 rho- nu_tau TAUVECTORNU; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BC_TMN.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_c+ 4 | 1.0 chi_c2 mu+ nu_mu PHOTOS BC_TMN 3; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BNOCBPTOKSHHH.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 1.0 K+ K- pi+ pi- BNOCBPTOKSHHH; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOSLLBALL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+sig 4 | 1.0 pi+ e+ e- PHOTOS BTOSLLBALL 6; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-D0GAMMADALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay MyD0 4 | 1.0 MyK_S0 pi+ pi- D0GAMMADALITZ; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-ETA2MUMUGAMMA.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay eta 4 | 1.0 mu+ mu- gamma ETA2MUMUGAMMA; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-HELAMP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay h_b(2P) 4 | 0.22 gamma eta_b HELAMP 1.0 0.0 1.0 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-HQET2.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 1.0 D- mu+ nu_mu PHOTOS HQET2 1.18 1.074; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-KSTARNUNU_REV.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 1.0 K*0 nu_e anti-nu_e KSTARNUNU_REV; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PHSPFLATLIFETIME.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_s0 4 | 1.0 phi phi PHSPFLATLIFETIME 12; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SLBKPOLE.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D+ 4 | 0.0013 eta mu+ nu_mu SLBKPOLE 1.0 0.25 1.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VECTORISR.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay vpho 4 | 1.0 Upsilon(4S) gamma VECTORISR -1 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-ETA_PI0DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay eta 4 | 0.325700000 pi0 pi0 pi0 ETA_PI0DALITZ -0.0135; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-LbAmpGen.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D0 4 | 0.667 K- pi+ pi+ pi- LbAmpGen DtoKpipipi ; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PHSPDECAYTIMECUT.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Xi_c+sig 4 | 1.000 p+ K- pi+ PHSPDECAYTIMECUT 0.29; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BC_VPPHAD.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_c+sig 4 | 1.0 MyJ/psi p+ anti-p- pi+ BC_VPPHAD 2; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BLLNUL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 1.000 e- e+ nu_mu mu+ BLLNUL 0.026 0.01 2.9; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-B_TO_2BARYON_SCALAR.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B- 4 | 1.0 Lambda0 anti-p- pi0 B_TO_2BARYON_SCALAR; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BaryonPCR.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Lambda_b0 4 | 1. Lambda_c+ mu- anti-nu_mu BaryonPCR 1 1 1 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-HQET.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay anti-B0 4 | 0.0501 D*+ e- anti-nu_e PHOTOS HQET 0.77 1.33 0.92; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-HypNonLepton.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Lambda0sig 4 | 1.0 p+ pi- HypNonLepton 0.748 -6.5; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PARTWAVE.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Mypsi(2S) 4 | 0.0013 MyJpsi pi0 PARTWAVE 0 0 1 0 0 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PYTHIA.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay tau- 4 | 0.046100000 nu_tau pi- pi+ pi- pi0 PYTHIA 21; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-RareLbToLll.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Lambda_b0 4 | 1.0 Lambda0 mu+ mu- RareLbToLll LQCD; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SVP_HELAMP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay eta' 4 | 1.000 rho0 gamma SVP_HELAMP 1.0 0.0 1.0 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-TAULNUNU.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay tau- 4 | 0.154002925 e- anti-nu_e nu_tau PHOTOS TAULNUNU; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VVP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay chi_c1 4 | 1.0 J/psi gamma VVP 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BNOCBPTO3HPI0.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 1.0 pi+ K- K+ pi0 BNOCBPTO3HPI0 0.0 2.0 0.0 2.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOXSLL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 0.0000025 Xsu mu+ mu- PHOTOS BTOXSLL 4.8 0.2 0.0 0.41; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-DToKpienu.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D+sig 4 | 1.0 K- pi+ mu+ nu_mu PHOTOS DToKpienu; # LHCb model 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-GOITY_ROBERTS.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 0.0015 D- pi0 mu+ nu_mu PHOTOS GOITY_ROBERTS; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-LLSW.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay anti-B0 4 | 0.007040000 D_1+ e- anti-nu_e LLSW 0.71 -1.6 -0.5 2.9; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SSS_CPT.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 1.0 pi+ pi- SSS_CPT 0.0 0.51e12 1.0 0.0 1.0 0.0 0.1 -0.4; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-THREEBODYPHSP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 1.000 J/psi omega K+ THREEBODYPHSP 14.00 16.40; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VUB.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 0.002206 Xu0 e+ nu_e PHOTOS VUB 4.691 1.869 0.22 1 0.28 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VVPIPI_WEIGHTED.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay psi(2S) 4 | 1.0 J/psi pi+ pi- PHOTOS VVPIPI_WEIGHTED; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VVS_PWAVE.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay a_1+ 4 | 1.0 rho0 pi+ VVS_PWAVE 0.9788 0.0 0.0 0.0 0.0212 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | At the command line:: 6 | 7 | pip install decaylanguage 8 | 9 | Or:: 10 | 11 | pip install https://github.com/scikit-hep/decaylanguage.git 12 | -------------------------------------------------------------------------------- /tests/data/models/model-SVV_CPLH.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_s0 4 | 1.0 J/psi phi SVV_CPLH 0.2 2.0e12 1 1.0 0.0 1.0 0.0 1.0 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SVV_HELAMP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 0.002 anti-D_10 D_s*+ SVV_HELAMP 0.48 0.0 0.734 0.0 0.48 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-TVS_PWAVE.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay K_2*- 4 | 0.019050771 anti-K*0 pi- TVS_PWAVE 0 0 1 0 0 0.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-B_TO_LAMBDA_PBAR_GAMMA.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B- 4 | 1.0 Lambda0 anti-p- gamma B_TO_LAMBDA_PBAR_GAMMA; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-D_hhhh.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay My_D0 4 | 1.0 K+ K- pi+ pi- D_hhhh 11; # model in LHCb for MINT program 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-KS_PI0MUMU.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay K_S0 4 | 1.0 pi0 mu+ mu- KS_PI0MUMU 1.2 0.49 -3.9 0.2 2.5; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-CB3PI-MPP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define alpha 1.365 4 | 5 | Decay B+ 6 | 1.0 pi+ pi+ pi- CB3PI-MPP alpha; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-HQET3.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 0.01325 anti-D*0 tau+ nu_tau PHOTOS HQET3 0.920 1.205 1.21 1.404 0.854; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-Lb2Baryonlnu.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Lambda_b0 4 | 0.0730 Lambda_c+ mu- anti-nu_mu PHOTOS Lb2Baryonlnu 1 1 1 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-TAUHADNU.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay tau- 4 | 0.255100000 pi- pi0 nu_tau TAUHADNU -0.108 0.775 0.149 1.364 0.400; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VSS_MIX.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | 5 | Decay Upsilon(4S) 6 | 0.42 B0 anti-B0 VSS_MIX dm; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-YMSTOYNSPIPICLEO.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay Upsilon(2S) 4 | 0.5 Upsilon pi0 pi0 YMSTOYNSPIPICLEO -0.753 0.000; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-CB3PI-P00.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define alpha 1.365 4 | 5 | Decay B- 6 | 0.000026 pi- pi0 pi0 CB3PI-P00 alpha; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-ETAPRIME_DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay eta' 4 | 0.432000000 pi+ pi- eta ETAPRIME_DALITZ -0.047 -0.069 0.0 0.073; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SSS_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | 5 | Decay B0 6 | 1.0 K_S0 pi0 SSS_CP 0.0 dm -1 1.0 0.0 1.0 0.0; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/README.rst: -------------------------------------------------------------------------------- 1 | DecayLanguage test data folder contents 2 | ======================================= 3 | 4 | This folder contains a set of decay files used for testing purposes. 5 | Note that not all decay files and hence fully correct, by construction. 6 | -------------------------------------------------------------------------------- /tests/data/models/model-BCL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+sig 4 | 0.000078 pi0 e+ nu_e PHOTOS BCL 0.419 -0.495 -0.43 0.22 0.510 -1.700 1.53 4.52; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOXSNUNU_FERMI.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0sig 4 | 1.0 Xsd anti-nu_e nu_e BTOXSNUNU_FERMI 0.1 0.0 0.461 1.1 4.68 0.1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VSS_BMIX.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | 5 | Decay Upsilon(4S) 6 | 0.483122645 B0 anti-B0 VSS_BMIX dm; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-BNOCB0TO4PICP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 1.0 pi+ pi- pi+ pi- BNOCB0TO4PICP -1.507964474 0.5065e12 0.0 1.1 0.0 1.86965; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-ETA_FULLDALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay eta 4 | 0.227400000 pi- pi+ pi0 ETA_FULLDALITZ -1.128 0.153 0.0 0.085 0.0 0.173; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-VUB_BLNP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0sig 4 | 0.002050 Xu- mu+ nu_mu PHOTOS VUB_BLNP 4.2281 0.7535 0.4366 1.5 1.5 1 1 1 1 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/test_Upsilon4S2B0B0bar.dec: -------------------------------------------------------------------------------- 1 | # Example decay for testing purposes: 2 | # it checks that variable definitions are understood during parsing. 3 | 4 | Define dm 0.507e12 5 | 6 | Decay Upsilon(4S) 7 | 1.0 B0 anti-B0 VSS_BMIX dm; 8 | Enddecay 9 | -------------------------------------------------------------------------------- /tests/data/test_custom_decay_model.dec: -------------------------------------------------------------------------------- 1 | # Example decfile for testing purposes: 2 | # Simple decay with custom models 3 | 4 | Decay D*+ 5 | 0.5 D+ pi0 CUSTOM_MODEL1; 6 | 0.5 D+ gamma CUSTOM_MODEL2 1 2 3 4; 7 | Enddecay 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BGL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay anti-B0sig 4 | 0.051100000 D*+sig mu- anti-nu_mu BGL 0.02596 -0.06049 0.01311 0.01713 0.00753 -0.09346; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-YMSTOYNSPIPICLEOBOOST.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | 4 | Decay Upsilon(2S) 5 | 0.178500000 Upsilon pi+ pi- YMSTOYNSPIPICLEOBOOST -0.753 0.000; 6 | Enddecay 7 | 8 | End 9 | -------------------------------------------------------------------------------- /tests/data/models/model-SVS_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define beta 0.3814 4 | Define dm 0.507e12 5 | 6 | Decay B0 7 | 1.0 J/psi eta SVS_CP beta dm 1 1 0 1 0; 8 | Enddecay 9 | 10 | End 11 | -------------------------------------------------------------------------------- /tests/data/models/model-BTO3PI_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | Define alpha 1.365 5 | 6 | Decay B0sig 7 | 1.0 pi+ pi- pi0 BTO3PI_CP dm alpha; 8 | Enddecay 9 | 10 | End 11 | -------------------------------------------------------------------------------- /tests/data/models/model-PHSP_BB_MIX.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm_B0 0.5065e12 4 | 5 | Decay Upsilon(5S) 6 | 0.20219 B0heavy anti-B0heavy PHSP_BB_MIX dm_B0 -1; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-PHSP_B_MIX.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm_B0 0.5065e12 4 | 5 | Decay Upsilon(5S) 6 | 0.00013 B0long B- pi+ anti-B0long PHSP_B_MIX dm_B0 ; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-STS_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define alpha 1.365 4 | Define dm 0.507e12 5 | 6 | Decay B0 7 | 1.0 a_2+ pi- STS_CP alpha dm 1 1.0 0.0 1.0 0.0; 8 | Enddecay 9 | 10 | End 11 | -------------------------------------------------------------------------------- /tests/data/models/model-SVP_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | Define beta 0.39 5 | 6 | Decay B0 7 | 1.0 K*0 gamma SVP_CP beta dm 1 0.03 0.0 0.999 0.0; 8 | Enddecay 9 | 10 | End 11 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOXELNU.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B+ 4 | 1.0 rho0 mu+ nu_mu PHOTOS BTOXELNU BCL -0.861 1.444 0.266 0.378 0.165 0.291 0.718 0.384 0.331 -0.876 1.907; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-SVVHELCPMIX.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0s 4 | 1.00 J/psi phi SVVHELCPMIX 1.0 0.0 1.0 0.0 1.0 0.0 8.15e24 17.8e12 65.78e10 8.42e10 0.0 0.025; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 4 10 | charset = utf-8 11 | 12 | [*.{bat,cmd,ps1}] 13 | end_of_line = crlf 14 | -------------------------------------------------------------------------------- /tests/data/minimalistic.dec: -------------------------------------------------------------------------------- 1 | # Example decfile for testing purposes: 2 | 3 | # Line with "End" is strictly speaking not necessary 4 | # Such "empty" files are relevant in LHCb for example when special decays are all defined in Python code 5 | # inserted in commented-out lines 6 | End 7 | # 8 | -------------------------------------------------------------------------------- /tests/data/models/model-BToDiBaryonlnupQCD.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B- 4 | 1.0 p+ anti-p- tau- anti-nu_tau PHOTOS BToDiBaryonlnupQCD 67.7 -280.0 -38.3 -840.0 -10.1 -157.0 800000; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /tests/data/models/model-PROPSLPOLE.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay D+ 4 | 1.0 anti-K*0 e+ nu_e PROPSLPOLE 1.0 -0.558 0.0 1.0 0.85 -0.558 0.0 1.0 1.50 -0.790 0.0 1.0 0.00 -0.558 0.0 1.0; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /tests/data/models/model-PHSP_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define minusTwoBeta -0.78 4 | Define dm 0.507e12 5 | 6 | Decay B0 7 | 1.0 K_S0 K_S0 K_S0 PHSP_CP minusTwoBeta dm 1 1.0 0.0 1.0 0.0; 8 | Enddecay 9 | 10 | End 11 | -------------------------------------------------------------------------------- /tests/data/models/model-SSD_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | Define minusTwoBeta -0.78 5 | 6 | Decay B0 7 | 0.000436500 J/psi K_S0 SSD_CP dm 0.0 1.0 minusTwoBeta 1.0 0.0 -1.0 0.0; 8 | Enddecay 9 | 10 | End 11 | -------------------------------------------------------------------------------- /tests/data/models/model-Lb2plnuLQCD.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Lb -> p mu nu using LQCD form factor predictions 4 | 5 | Decay Lambda_b0 6 | 1.0 p+ mu- anti-nu_mu PHOTOS Lb2plnuLQCD 1 1 1 1; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-SSS_CP_PNG.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | Define beta 0.39 5 | Define gamma 1.387 6 | 7 | Decay B0 8 | 1.0 pi+ pi- SSS_CP_PNG beta gamma 0.1 dm 1.0 1.0 0.2; 9 | Enddecay 10 | 11 | End 12 | -------------------------------------------------------------------------------- /tests/data/models/model-LNUGAMMA.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | # Example taken from the example files in the EvtGen repository https://gitlab.cern.ch/evtgen/evtgen. 3 | 4 | Decay B+ 5 | 1.0 e+ nu_e gamma LNUGAMMA 0.35 3.0 5.0 0; 6 | Enddecay 7 | 8 | End 9 | -------------------------------------------------------------------------------- /tests/data/models/model-Lb2plnuLCSR.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # With Lb -> p form factor predictions from Light Cone Sum Rules 4 | 5 | Decay Lambda_b0 6 | 1.0 p+ mu- anti-nu_mu PHOTOS Lb2plnuLCSR 1 1 1 1; 7 | Enddecay 8 | 9 | End 10 | -------------------------------------------------------------------------------- /tests/data/models/model-SVS_NONCPEIGEN.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define alpha 1.365 4 | Define dm 0.507e12 5 | 6 | Decay B0 7 | 0.5 a_1+ pi- PHOTOS SVS_NONCPEIGEN alpha dm 1.0 3.0 0.0 1.0 0.0 1.0 0.0 3.0 0.0; 8 | Enddecay 9 | 10 | End 11 | -------------------------------------------------------------------------------- /tests/data/models/model-SLPOLE.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B0 4 | 1.0 rho- mu+ nu_mu SLPOLE 0.27 -0.11 -0.75 1.0 0.23 -0.77 5 | -0.40 1.0 0.34 -1.32 0.19 1.0 0.37 -1.42 0.50 1.0; 6 | Enddecay 7 | 8 | End 9 | -------------------------------------------------------------------------------- /tests/data/models/model-D_DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Alias My_D_s- D_s- 4 | Alias My_D_s+ D_s+ 5 | ChargeConj My_D_s- My_D_s+ 6 | 7 | Decay My_D_s+ 8 | 1.0 K+ K- pi+ D_DALITZ; 9 | Enddecay 10 | CDecay My_D_s- 11 | 12 | End 13 | -------------------------------------------------------------------------------- /tests/data/models/model-GENERIC_DALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Generic Dalitz model that uses XML files to configure the resonance amplitude parameters 4 | Decay D+ 5 | 1.0 K- pi+ pi+ GENERIC_DALITZ MyDir/MyDalitzParameters.xml; 6 | Enddecay 7 | 8 | End 9 | -------------------------------------------------------------------------------- /tests/data/models/model-SVS_CPLH.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.472e12 4 | Define dGamma 0.1 5 | Define magqop 1.0 6 | Define argqop 0.7 7 | 8 | Decay B0 9 | 1.0 J/psi K_S0 SVS_CPLH dm dGamma magqop argqop 1.0 0.0 1.0 0.0; 10 | Enddecay 11 | 12 | End 13 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: decaylanguage_demo 2 | dependencies: 3 | - python>=3.9 4 | - pandas>=1 5 | - attrs>=19.2 6 | - pip>=9 7 | - jupyterlab>=0.35 8 | - numpy>=1.19.3 9 | - graphviz>=0.12.0 10 | - plumbum>=1.7.0 11 | - lark>=1.0.0 12 | - RISE 13 | - hepunits>=2.4.0 14 | - particle>=0.26.0 15 | - pip: 16 | - . 17 | -------------------------------------------------------------------------------- /tests/data/models/model-BS_MUMUKK.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Decay B_s0 4 | 1.0 mu+ mu- K+ K- BS_MUMUKK 0., 0., -0.03, 1., 0.11, 3.315, -0.03, 1., 0.5241, 0., -0.03, 1., 0.2504, 0.06159, -0.03, 1., -3.26, -0.03, 1., 0.6603, 0.0805, 17.7, 0.9499, 1.2, 1; 5 | Enddecay 6 | 7 | End 8 | -------------------------------------------------------------------------------- /src/decaylanguage/_compat/typing.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | import typing 5 | 6 | if sys.version_info < (3, 11): 7 | if typing.TYPE_CHECKING: 8 | from typing_extensions import Self 9 | else: 10 | Self = object 11 | else: 12 | from typing import Self 13 | 14 | 15 | __all__ = ["Self"] 16 | -------------------------------------------------------------------------------- /tests/data/models/model-SVV_NONCPEIGEN.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | Define beta 0.39 5 | Define gamma 1.387 6 | 7 | Decay B0 8 | 1.0 rho+ D*- SVV_NONCPEIGEN dm beta gamma 0.322 0.31 0.941 0 0.107 1.42 0.02 0 0.02 0 0.02 0 ; 9 | Enddecay 10 | 11 | End 12 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Contents 3 | ======== 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | readme 9 | installation 10 | usage 11 | reference/index 12 | contributing 13 | authors 14 | changelog 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /tests/data/models/model-BTODDALITZCPK.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # CPV parameters. 4 | Define gamma 1.22 # 70 degrees 5 | Define delta 2.27 # 130 degrees 6 | Define rB 0.10 7 | 8 | Decay B+sig 9 | 1.000 my-anti-D0 K+ BTODDALITZCPK gamma delta rB; 10 | Enddecay 11 | 12 | End 13 | -------------------------------------------------------------------------------- /tests/data/models/model-PVV_CPLH.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define Hp 0.49 4 | Define Hz 0.775 5 | Define Hm 0.4 6 | Define pHp 2.50 7 | Define pHz 0.0 8 | Define pHm -0.17 9 | 10 | Decay B_s0 11 | 1.0 psi(2S) phi PVV_CPLH 0.02 1 Hp pHp Hz pHz Hm pHm; 12 | Enddecay 13 | 14 | End 15 | -------------------------------------------------------------------------------- /tests/data/models/model-BT02PI_CP_ISO.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | Define beta 0.39 5 | Define gamma 1.387 6 | 7 | Decay B0 8 | 1.0 pi+ pi- BT02PI_CP_ISO beta dm 1.0 gamma 1.0 -gamma 9 | 1.0 gamma 1.0 -gamma; 10 | Enddecay 11 | 12 | End 13 | -------------------------------------------------------------------------------- /tests/data/test_Upsilon2S2UpsilonPiPi.dec: -------------------------------------------------------------------------------- 1 | # Example decay for testing purposes: 2 | # This tests whether model names can be substrings of other model names 3 | 4 | Decay Upsilon(2S) 5 | 0.5 Upsilon pi+ pi- YMSTOYNSPIPICLEOBOOST -0.753 0.000; 6 | 0.5 Upsilon pi0 pi0 YMSTOYNSPIPICLEO -0.753 0.000; 7 | Enddecay 8 | -------------------------------------------------------------------------------- /tests/data/models/model-D0MIXDALITZ.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Mixing and CPV in mixing parameters. 4 | Define x 0.00 5 | Define y 0.00 6 | Define reqp 1.00 7 | Define imqp 0.00 8 | Define doKm 0 9 | 10 | Decay my-D0 11 | 1.0 my-K_S0 pi+ pi- D0MIXDALITZ x y reqp imqp doKm; 12 | Enddecay 13 | 14 | End 15 | -------------------------------------------------------------------------------- /tests/data/test_DtoKlnu.dec: -------------------------------------------------------------------------------- 1 | # Example decay for testing purposes: 2 | # This checks whether model aliases are parsed and replaced correctly during parsing 3 | # and if this also works with variable definitions. 4 | 5 | 6 | Define param1 -0.303 7 | 8 | ModelAlias SLBKPOLE_DtoKlnu SLBKPOLE 1.0 param1; 9 | 10 | 11 | Decay D+ 12 | 1.0 anti-K0 e+ nu_e SLBKPOLE_DtoKlnu; 13 | Enddecay 14 | -------------------------------------------------------------------------------- /tests/test_decaylanguage.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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | import decaylanguage 9 | 10 | 11 | def test_main(): 12 | assert decaylanguage is not None 13 | -------------------------------------------------------------------------------- /tests/data/test_Xicc2XicPiPi.dec: -------------------------------------------------------------------------------- 1 | 2 | Alias MyXic+ Xi_c+ 3 | Alias MyantiXic- anti-Xi_c- 4 | ChargeConj MyXic+ MyantiXic- 5 | 6 | Decay Xi_cc+sig 7 | 1.000 MyXic+ pi- pi+ PHSP; 8 | Enddecay 9 | CDecay anti-Xi_cc-sig 10 | 11 | Decay MyXic+ 12 | 1.000 p+ K- pi+ PHSP; 13 | Enddecay 14 | CDecay MyantiXic- 15 | 16 | End 17 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: true 3 | 4 | ignore: 5 | - "src/decaylanguage/__main__.py" 6 | - "src/decaylanguage/__init__.py" 7 | - "src/decaylanguage/*/__init__.py" 8 | - "src/decaylanguage/dec/decparser.py" 9 | - "src/decaylanguage/modeling/*" 10 | - "src/decaylanguage/utils/errors.py" 11 | - "src/decaylanguage/utils/utilities.py" 12 | - "src/decaylanguage/_compat/*" 13 | -------------------------------------------------------------------------------- /tests/data/models/model-BSTOGLLMNT.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define mu 5.0 4 | Define Nf 5 5 | Define res_swch 1 6 | Define ias 1 7 | Define Egamma 0.02 8 | Define A 0.88 9 | Define lambda 0.227 10 | Define barrho 0.22 11 | Define bareta 0.34 12 | 13 | Decay B_s0 14 | 1.000 gamma e+ e- BSTOGLLMNT mu Nf res_swch ias Egamma A lambda barrho bareta; 15 | Enddecay 16 | 17 | End 18 | -------------------------------------------------------------------------------- /src/decaylanguage/utils/errors.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/decaylanguage for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | 10 | class LineFailure(RuntimeError): 11 | def __init__(self, line: str, message: str) -> None: 12 | super().__init__(f"{line}: {message}") 13 | -------------------------------------------------------------------------------- /tests/data/models/model-SVV_CP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define beta 0.39 4 | Define dm 0.507e12 5 | 6 | Define Aplus 0.490 7 | Define Azero 1.10 8 | Define Aminus 0.4 9 | 10 | Define phAplus 2.5 11 | Define phAzero 0.0 12 | Define phAminus -0.17 13 | 14 | Decay B0 15 | 0.00186 J/psi omega SVV_CP beta dm 1 Aplus phAplus Azero phAzero Aminus phAminus; 16 | Enddecay 17 | 18 | End 19 | -------------------------------------------------------------------------------- /src/decaylanguage/modeling/__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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from .amplitudechain import LS, AmplitudeChain 9 | 10 | __all__ = ("LS", "AmplitudeChain") 11 | 12 | 13 | def __dir__() -> tuple[str, ...]: 14 | return __all__ 15 | -------------------------------------------------------------------------------- /src/decaylanguage/dec/__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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from .dec import DecFileParser 9 | from .enums import known_decay_models 10 | 11 | __all__ = ("DecFileParser", "known_decay_models") 12 | 13 | 14 | def __dir__() -> tuple[str, ...]: 15 | return __all__ 16 | -------------------------------------------------------------------------------- /tests/data/models/model-SVS_CP_ISO.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define dm 0.507e12 4 | Define beta 0.39 5 | Define gamma 1.387 6 | 7 | Decay B0 8 | 1.0 a_1- pi+ SVS_CP_ISO beta dm 0.0 1.0 0.0 1.0 0.0 9 | 1.0 0.0 1.0 0.0 10 | 1.0 gamma 3.0 -gamma 11 | 3.0 gamma 1.0 -gamma 12 | 0.0 0.0 0.0 0.0; 13 | Enddecay 14 | 15 | End 16 | -------------------------------------------------------------------------------- /tests/data/models/model-FOURBODYPHSP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Flat phase space in the analysis region of B0 -> D0 D0b. 4 | Define m12_min 1.3 # The model will take at least m1+m2 5 | Define m12_max 2.5 # Must be in GeV/c^2 6 | Define m34_min 1.3 # The model will take at least m1+m2 7 | Define m34_max 2.5 # Must be in GeV/c^2 8 | 9 | Decay B0 10 | 1.0 K+ K- K- pi+ FOURBODYPHSP m12_min m12_max m34_min m34_max; 11 | Enddecay 12 | 13 | End 14 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: docs/conf.py 11 | 12 | # Include PDF and ePub 13 | formats: all 14 | 15 | build: 16 | os: ubuntu-22.04 17 | tools: 18 | python: "3.11" 19 | 20 | python: 21 | install: 22 | - method: pip 23 | path: . 24 | extra_requirements: 25 | - docs 26 | -------------------------------------------------------------------------------- /src/decaylanguage/decay/__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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from .decay import DaughtersDict, DecayChain, DecayMode 9 | from .viewer import DecayChainViewer 10 | 11 | __all__ = ("DaughtersDict", "DecayChain", "DecayChainViewer", "DecayMode") 12 | 13 | 14 | def __dir__() -> tuple[str, ...]: 15 | return __all__ 16 | -------------------------------------------------------------------------------- /notebooks/simple_model.txt: -------------------------------------------------------------------------------- 1 | EventType D0 K- pi+ pi+ pi- 2 | 3 | D0[D]{K*(892)bar0{K-,pi+},rho(770)0{pi+,pi-}} 2 1 0 2 0 0 4 | D0[D]{rho(1450)0{pi+,pi-},K*(892)bar0{K-,pi+}} 0 0.648936 0.0205762 0 -0.271637 0.0342107 5 | D0[P]{K*(892)bar0{K-,pi+},rho(770)0{pi+,pi-}} 0 0.362058 0.00237314 0 -1.79607 0.00663691 6 | D0[P]{rho(1450)0{pi+,pi-},K*(892)bar0{K-,pi+}} 0 0.642781 0.00570074 0 1.69828 0.00900026 7 | 8 | D0_radius 2 0.0037559 0 9 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOVLNUBALL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Documentation: Decay file for [B+ -> (phi(1020) -> K+ K-) mu+ nu_mu]cc, 4 | # using the BToVlnuBall model (for Bs -> phi, lacking an alternative), see https://arxiv.org/pdf/hep-ph/0412079.pdf 5 | # order is r2_A1 mfit2_A1 r1_A2 r2_A2 mfit2_A2 r1_V r2_V mfit2_V 6 | # EndDocumentation 7 | 8 | Decay B+sig 9 | 1.0 MyPhi mu+ nu_mu PHOTOS BTOVLNUBALL 0.308 36.54 -0.054 0.288 48.94 1.484 -1.049 39.52; 10 | Enddecay 11 | 12 | End 13 | -------------------------------------------------------------------------------- /tests/data/test_Bc2BsPi_Bs2KK.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes: 2 | # [B_c+ -> (B_s0 -> K+ K-) pi+]cc 3 | 4 | Alias B_c+sig B_c+ 5 | Alias B_c-sig B_c- 6 | ChargeConj B_c+sig B_c-sig 7 | 8 | Alias MyB_s0 B_s0 9 | Alias Myanti-B_s0 anti-B_s0 10 | ChargeConj MyB_s0 Myanti-B_s0 11 | 12 | Decay B_c+sig 13 | 1.000 MyB_s0 pi+ PHOTOS PHSP; 14 | Enddecay 15 | CDecay B_c-sig 16 | 17 | Decay MyB_s0 18 | 1.000 K+ K- SSD_CP 20.e12 0.1 1.0 0.04 9.6 -0.8 8.4 -0.6; 19 | Enddecay 20 | CDecay Myanti-B_s0 21 | 22 | End 23 | -------------------------------------------------------------------------------- /tests/dec/test_issues.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from pathlib import Path 9 | 10 | import pytest 11 | from lark import UnexpectedToken 12 | 13 | from decaylanguage.dec.dec import DecFileParser 14 | 15 | DIR = Path(__file__).parent.resolve() 16 | 17 | 18 | def test_issue_90(): 19 | p = DecFileParser(DIR / "../data/test_issue90.dec") 20 | with pytest.raises(UnexpectedToken): 21 | p.parse() 22 | -------------------------------------------------------------------------------- /tests/data/models/model-BQTOLLLLHYPERCP.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | Define mS 2.5 4 | Define mP 0.214 5 | Define gammaS 0.0001 6 | Define gammaP 0.0001 7 | Define mLiiLR 1.0 8 | Define Fc 1.0 9 | Define mD23LL 450.0 10 | Define mD23RR 0.0 11 | Define mD32LL 450.0 12 | Define mD32RR 0.0 13 | Define mD13LL 380.0 14 | Define mD13RR 0.0 15 | Define mD31LL 380.0 16 | Define mD31RR 0.0 17 | 18 | Decay B0sig 19 | 1.000 mu+ mu- mu+ mu- BQTOLLLLHYPERCP mS mP gammaS gammaP mLiiLR Fc mD23LL mD23RR mD32LL mD32RR mD13LL mD13RR mD31LL mD31RR; 20 | Enddecay 21 | 22 | End 23 | -------------------------------------------------------------------------------- /src/decaylanguage/data/MintDalitzSpecialParticlesLatex.csv: -------------------------------------------------------------------------------- 1 | pdgid,particle 2 | 998100,\left[\pi^{+}\pi^{-}\right]^{L=0}_{0} 3 | 998101,\left[\pi^{+}\pi^{-}\right]^{L=0}_{1} 4 | 998102,\left[\pi^{+}\pi^{-}\right]^{L=0}_{2} 5 | 998103,\left[\pi^{+}\pi^{-}\right]^{L=0}_{3} 6 | 998104,\left[\pi^{+}\pi^{-}\right]^{L=0}_{4} 7 | 998105,\left[\pi^{+}\pi^{-}\right]^{L=0}_{5} 8 | 998106,\left[\pi^{+}\pi^{-}\right]^{L=0}_{6} 9 | 998110,\left[K^{-}\pi^{+}\right]^{L=0}_{0} 10 | 998111,\left[K^{-}\pi^{+}\right]^{L=0}_{1} 11 | 998112,\left[K^{-}\pi^{+}\right]^{L=0}_{2} 12 | 998113,\left[K^{-}\pi^{+}\right]^{L=0}_{3} 13 | 998114,\left[K^{-}\pi^{+}\right]^{L=0}_{4} 14 | 998115,\left[K^{-}\pi^{+}\right]^{L=0}_{5} 15 | 998116,\left[K^{-}\pi^{+}\right]^{L=0}_{6} 16 | -------------------------------------------------------------------------------- /src/decaylanguage/data/particle.lark: -------------------------------------------------------------------------------- 1 | # Forms: 2 | # ampgen 3 | # decfile 4 | 5 | start : prebar? name family? spin? mass? bar? charge 6 | 7 | name : PNAME 8 | charge : CHARGE 9 | prebar : "anti-" 10 | bar : "~" 11 | 12 | spin : spin_brackets | spin_underscore | spin_star 13 | family : family_brackets | family_underscore 14 | 15 | spin_brackets : "(" DIGIT ")" 16 | spin_underscore : "_" DIGIT 17 | spin_star : "*" 18 | 19 | family_brackets : "(" CNAME ")" 20 | 21 | mass : "(" MASS ")" 22 | 23 | bar : BAR 24 | star : STAR 25 | prime : PRIME 26 | PRIME : "'" 27 | STAR : "*" 28 | 29 | MASS : DIGIT DIGIT+ 30 | BAR : "bar" 31 | PNAME : (LETTER | "/")+ 32 | CHARGE : "--" | "+" | "0" | "-" | "--" 33 | 34 | %import common.CNAME 35 | %import common.DIGIT 36 | -------------------------------------------------------------------------------- /src/decaylanguage/utils/__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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from .errors import LineFailure 9 | from .particleutils import charge_conjugate_name 10 | from .utilities import ( 11 | DescriptorFormat, 12 | filter_lines, 13 | iter_flatten, 14 | split, 15 | ) 16 | 17 | __all__ = ( 18 | "DescriptorFormat", 19 | "LineFailure", 20 | "charge_conjugate_name", 21 | "filter_lines", 22 | "iter_flatten", 23 | "split", 24 | ) 25 | 26 | 27 | def __dir__() -> tuple[str, ...]: 28 | return __all__ 29 | -------------------------------------------------------------------------------- /tests/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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from pathlib import Path 9 | 10 | from decaylanguage.modeling.ampgen2goofit import ampgen2goofit 11 | 12 | DIR = Path(__file__).parent.resolve() 13 | 14 | 15 | def test_full_convert(): 16 | text = ampgen2goofit(DIR / "../models/DtoKpipipi_v2.txt", ret_output=True) 17 | with (DIR / "output/DtoKpipipi_v2.cu").open() as f: 18 | assert {x.strip() for x in text.splitlines() if "Generated on" not in x} == { 19 | x.strip() for x in f.readlines() if "Generated on" not in x 20 | } 21 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: DecayLanguage 3 | message: >- 4 | If you use this software, please cite it using the 5 | metadata from this file. 6 | type: software 7 | abstract: "DecayLanguage is a Python library to describe, manipulate and convert particle decays." 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.3257423 18 | repository-code: "https://github.com/scikit-hep/decaylanguage" 19 | keywords: 20 | - python 21 | - particle decays 22 | - decay files 23 | - scikit-hep 24 | license: "BSD-3-Clause" 25 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Usage 3 | ===== 4 | 5 | Particles are a key component when dealing with decays. 6 | Refer to the `Particle package`_ for how to deal with particles and PDG identification codes. 7 | 8 | 9 | DecFiles 10 | -------- 11 | 12 | DecFiles describe decays. You can read files and query information about them. 13 | 14 | DecayLanguage 15 | ------------- 16 | 17 | The primary way to use ``decaylanguage.decay`` is through the module provided to read in a language file and produce an output. For example, for GooFit, call: 18 | 19 | .. code-block:: bash 20 | 21 | python -m decaylanguage.goofit models/DtoKpipipi_v2.txt 22 | 23 | You can pipe the output to a file. 24 | 25 | Examples of interaction with the API directly are provided in the ``/notebooks`` folder, including svg diagrams of lines. 26 | 27 | .. particle package: https://github.com/scikit-hep/particle 28 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOSLLMS.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Documentation: the B -> phi mu^+ mu^- decay with the transition form factors 4 | # from the paper D.Melikhov, B.Stech, PRD62, 014006 (2000). 5 | # Input parameters - mu - the scale parameter (in GeV's); 6 | # res_swch - resonant switching parameter: 7 | # ias - switching parameter for \alpha_s(M_Z) value: 8 | # Wolfenstein parameterization for CKM matrix: 9 | # EndDocumentation 10 | 11 | Define mu 5.0 12 | Define Nf 5 13 | Define res_swch 0 14 | Define ias 1 15 | Define A 0.88 16 | Define lambda 0.227 17 | Define barrho 0.22 18 | Define bareta 0.34 19 | 20 | Decay B_s0 21 | 1.0000 phi mu+ mu- BTOSLLMS mu Nf res_swch ias A lambda barrho bareta; 22 | Enddecay 23 | 24 | End 25 | -------------------------------------------------------------------------------- /src/decaylanguage/__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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | # Convenient access to the version number 9 | from ._version import version as __version__ 10 | 11 | # Direct access to decay file parsing tools 12 | from .dec import DecFileParser 13 | 14 | # Direct access to decay chain representation classes and visualization tools 15 | from .decay import DaughtersDict, DecayChain, DecayChainViewer, DecayMode 16 | 17 | __all__ = ( 18 | "DaughtersDict", 19 | "DecFileParser", 20 | "DecayChain", 21 | "DecayChainViewer", 22 | "DecayMode", 23 | "__version__", 24 | ) 25 | 26 | 27 | def __dir__() -> tuple[str, ...]: 28 | return __all__ 29 | -------------------------------------------------------------------------------- /docs/reference/decaylanguage.decay.rst: -------------------------------------------------------------------------------- 1 | decaylanguage.decay 2 | =================== 3 | 4 | .. testsetup:: 5 | 6 | from decaylanguage.modeling.amplitudechain import * 7 | from decaylanguage.modeling.goofit import * 8 | from decaylanguage.modeling.decay import * 9 | from decaylanguage.modeling.ampgentransform import * 10 | 11 | decaylanguage.modeling.decay 12 | ------------------------- 13 | 14 | .. automodule:: decaylanguage.modeling.decay 15 | :members: 16 | 17 | decaylanguage.modeling.ampgentransform 18 | ----------------------------------- 19 | 20 | .. automodule:: decaylanguage.modeling.ampgentransform 21 | :members: 22 | 23 | decaylanguage.modeling.amplitudechain 24 | ---------------------------------- 25 | 26 | .. automodule:: decaylanguage.modeling.amplitudechain 27 | :members: 28 | 29 | decaylanguage.modeling.goofit 30 | -------------------------- 31 | 32 | .. automodule:: decaylanguage.modeling.goofit 33 | :members: 34 | -------------------------------------------------------------------------------- /tests/data/test_example_Dst.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes 2 | # Considered by itself, this file in in fact incomplete, 3 | # as there are no instructions on how to decay the anti-D0 and the D-! 4 | 5 | Decay D*+ 6 | 0.677 D0 pi+ VSS; 7 | 0.307 D+ pi0 VSS; 8 | 0.016 D+ gamma VSP_PWAVE; 9 | Enddecay 10 | 11 | Decay D*- 12 | 0.6770 anti-D0 pi- VSS; 13 | 0.3070 D- pi0 VSS; 14 | 0.0160 D- gamma VSP_PWAVE; 15 | Enddecay 16 | 17 | Decay D0 18 | 1.0 K- pi+ PHSP; 19 | Enddecay 20 | 21 | Decay D+ 22 | 1.0 K- pi+ pi+ pi0 PHSP; 23 | Enddecay 24 | 25 | Decay pi0 26 | 0.988228297 gamma gamma PHSP; 27 | 0.011738247 e+ e- gamma PI0_DALITZ; 28 | 0.000033392 e+ e+ e- e- PHSP; 29 | 0.000000065 e+ e- PHSP; 30 | Enddecay 31 | -------------------------------------------------------------------------------- /.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 | .env/ 25 | 26 | # Installer logs 27 | pip-log.txt 28 | 29 | # Unit test / coverage reports 30 | .tox 31 | .coverage 32 | .coverage.* 33 | coverage.xml 34 | coverage* 35 | htmlcov 36 | nosetests.xml 37 | 38 | # Translations 39 | *.mo 40 | 41 | # Mr Developer 42 | .mr.developer.cfg 43 | .project 44 | .pydevproject 45 | .idea 46 | *.iml 47 | *.komodoproject 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 | 73 | /src/decaylanguage/_version.py 74 | -------------------------------------------------------------------------------- /src/decaylanguage/__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/decaylanguage for details. 6 | 7 | 8 | from __future__ import annotations 9 | 10 | from plumbum import cli 11 | 12 | from decaylanguage.modeling.ampgen2goofit import ampgen2goofit, ampgen2goofitpy 13 | 14 | 15 | class DecayLanguageDecay(cli.Application): 16 | generator = cli.SwitchAttr( 17 | ["-G", "--generator"], cli.Set("goofit", "goofitpy"), mandatory=True 18 | ) 19 | 20 | # pylint: disable-next=arguments-differ 21 | def main(self, filename): 22 | if self.generator == "goofit": 23 | ampgen2goofit(filename) 24 | if self.generator == "goofitpy": 25 | ampgen2goofitpy(filename) 26 | 27 | 28 | def main(): 29 | DecayLanguageDecay.run() 30 | 31 | 32 | if __name__ == "__main__": 33 | main() 34 | -------------------------------------------------------------------------------- /tests/test_goofit.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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from particle import Particle 9 | 10 | from decaylanguage.modeling.goofit import GooFitChain 11 | 12 | 13 | def test_simple(): 14 | lines, all_states = GooFitChain.read_ampgen( 15 | text=""" 16 | 17 | # This is a test (should not affect output) 18 | 19 | EventType D0 K- pi+ pi+ pi- 20 | 21 | D0[D]{K*(892)bar0{K-,pi+},rho(770)0{pi+,pi-}} 2 1 0 2 0 0 22 | """ 23 | ) 24 | 25 | assert Particle.from_pdgid(421) == all_states[0] # D0 26 | assert Particle.from_pdgid(-321) == all_states[1] # K- 27 | assert Particle.from_pdgid(211) == all_states[2] # pi+ 28 | assert Particle.from_pdgid(211) == all_states[3] # pi+ 29 | assert Particle.from_pdgid(-211) == all_states[4] # pi- 30 | 31 | assert len(lines) == 1 32 | (_line,) = lines 33 | -------------------------------------------------------------------------------- /.github/workflows/wheel.yml: -------------------------------------------------------------------------------- 1 | name: Wheel and SDist 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | release: 10 | types: 11 | - published 12 | 13 | jobs: 14 | dist: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v5 18 | with: 19 | fetch-depth: 0 20 | 21 | - uses: hynek/build-and-inspect-python-package@v2 22 | 23 | publish: 24 | needs: [dist] 25 | runs-on: ubuntu-latest 26 | if: github.event_name == 'release' && github.event.action == 'published' 27 | environment: pypi 28 | permissions: 29 | id-token: write 30 | attestations: write 31 | 32 | steps: 33 | - uses: actions/download-artifact@v6 34 | with: 35 | name: Packages 36 | path: dist 37 | 38 | - name: Generate artifact attestation for sdist and wheel 39 | uses: actions/attest-build-provenance@v3 40 | with: 41 | subject-path: "dist/*" 42 | 43 | - uses: pypa/gh-action-pypi-publish@release/v1 44 | with: 45 | attestations: true 46 | -------------------------------------------------------------------------------- /tests/data/models/model-BSTD_2HDMTYPE2.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # HQET Form Factor parameters from B->D(*)lnu data 4 | # taken from HFAG End Of Year 2011 5 | # rho_1^2 = 1.186 +/- 0.036 +/- 0.041 6 | # rho_A1^2 = 1.207 +/- 0.015 +/- 0.021 7 | # R_1(1) = 1.403 +/- 0.033 8 | # R_2(1) = 0.854 +/- 0.020 9 | Define rho12 1.186 10 | Define rhoA12 1.207 11 | Define R11 1.403 12 | Define R21 0.854 13 | 14 | # Parameters related to the O(1/m_q) correction in the scalar form factors 15 | # The authors of PRD87,034028 use 1 +/- 1 for these values to take into account the theoretical error. 16 | Define aS1 1.0 17 | Define aR3 1.0 18 | 19 | # quark masses at the m_b scale 20 | # taken from PRD77, 113016 (2008) 21 | # m_b = 4.20+/-0.07 GeV/c^2 22 | # m_c = 0.901+0.111-0.113 GeV/c^2 23 | Define m_b 4.20 24 | Define m_c 0.901 25 | 26 | # (GeV/c^2)^-1 27 | Define tanBeta/m_H+ 0.5 28 | 29 | Decay B0 30 | 0.5 D*- tau+ nu_tau BSTD_2HDMTYPE2 rhoA12 R11 R21 aR3 m_b m_c tanBeta/m_H+; 31 | #0.5 D- tau+ nu_tau BSTD_2HDMTYPE2 rho12 aS1 m_b m_c tanBeta/m_H+; 32 | Enddecay 33 | 34 | End 35 | -------------------------------------------------------------------------------- /tests/data/models/model-BSTOGLLISRFSR.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | 4 | # Documentation: 5 | # ISR contribution only 6 | # Input parameters mu - the scale parameter (in GeV's) 7 | # Nf - number of "effective" flavors (for b-quark Nf=5) 8 | # sr - state radiation type 9 | # res_swch - resonant switching parameter 10 | # ias - switching parameter for \alpha_s(M_Z) value 11 | # Wolfenstein parameterization for CKM matrix 12 | # Egamma - minimum energy of the photon (in GeV) 13 | # mumumass_min - minimum invariant mass of the two muons (in GeV) 14 | # EndDocumentation 15 | Define mu 5.0 16 | Define Nf 5 17 | Define sr 0 18 | Define res_swch 0 19 | Define ias 1 20 | Define Egamma 0.000001 21 | Define A 0.8250 22 | Define lambda 0.22509 23 | Define barrho 0.1598 24 | Define bareta 0.3499 25 | Define mumumass_min 4.5 26 | 27 | Decay B0 28 | 1.000 gamma mu+ mu- BSTOGLLISRFSR mu Nf sr res_swch ias Egamma A lambda barrho bareta mumumass_min; 29 | Enddecay 30 | 31 | End 32 | -------------------------------------------------------------------------------- /tests/data/test_Bd2DmTauNu_Dm23PiPi0_Tau2MuNu.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes: 2 | # Descriptor: [B0 -> (D- -> pi- pi+ pi- pi0) (tau+ -> mu+ nu_mu anti-nu_tau) nu_tau]cc 3 | 4 | Alias B0sig B0 5 | Alias anti-B0sig anti-B0 6 | ChargeConj B0sig anti-B0sig 7 | 8 | Alias MyD+ D+ 9 | Alias MyD- D- 10 | ChargeConj MyD+ MyD- 11 | 12 | Alias Mya_1- a_1- 13 | Alias Mya_1+ a_1+ 14 | ChargeConj Mya_1+ Mya_1- 15 | 16 | Alias MyTau- tau- 17 | Alias MyTau+ tau+ 18 | ChargeConj MyTau- MyTau+ 19 | 20 | Decay B0sig 21 | 1.00 MyD- MyTau+ nu_tau ISGW2; 22 | Enddecay 23 | CDecay anti-B0sig 24 | 25 | Decay MyD- 26 | 0.15 pi- pi+ pi- pi0 PHSP; 27 | 0.60 Mya_1- pi0 SVS; 28 | 0.25 rho- rho0 SVV_HELAMP 1.0 0.0 1.0 0.0 1.0 0.0; 29 | Enddecay 30 | CDecay MyD+ 31 | 32 | Decay MyTau- 33 | 1.00 mu- nu_tau anti-nu_mu PHOTOS TAULNUNU; 34 | Enddecay 35 | CDecay MyTau+ 36 | 37 | Decay Mya_1+ 38 | 1.000 rho0 pi+ VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 39 | Enddecay 40 | CDecay Mya_1- 41 | 42 | End 43 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pathlib import Path 4 | 5 | import nox 6 | 7 | nox.needs_version = ">=2024.4.15" 8 | nox.options.default_venv_backend = "uv|virtualenv" 9 | 10 | ALL_PYTHONS = [ 11 | c.split()[-1] 12 | for c in nox.project.load_toml("pyproject.toml")["project"]["classifiers"] 13 | if c.startswith("Programming Language :: Python :: 3.") 14 | ] 15 | 16 | 17 | @nox.session 18 | def lint(session): 19 | session.install("pre-commit") 20 | session.run("pre-commit", "run", "--all-files", *session.posargs) 21 | 22 | 23 | @nox.session 24 | def pylint(session: nox.Session) -> None: 25 | """ 26 | Run pylint. 27 | """ 28 | 29 | session.install("pylint") 30 | session.install("-e.[dev]") 31 | session.run("pylint", "src", *session.posargs) 32 | 33 | 34 | @nox.session(python=ALL_PYTHONS) 35 | def tests(session): 36 | session.install(".[test]") 37 | session.run("pytest", *session.posargs) 38 | 39 | 40 | @nox.session(default=False) 41 | def build(session): 42 | """ 43 | Build an SDist and wheel. 44 | """ 45 | 46 | session.install("build", "twine", "check-wheel-contents") 47 | session.run("python", "-m", "build") 48 | session.run("twine", "check", "--strict", "dist/*") 49 | session.run( 50 | "check-wheel-contents", str(*Path("dist").glob("*.whl")), "--ignore=W002" 51 | ) 52 | -------------------------------------------------------------------------------- /tests/data/models/model-BQTOLLLL.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Documentation: the B_d0 -> mu^+ mu^- mu^+ mu^- decay based on MNT-model for 4 | # B_d0 -> mu^+ mu^- gamma decay 5 | # mu - the scale parameter (in GeV's); 6 | # Nf - number of "effective" flavors (for b-quark Nf=5); 7 | # res_swch - resonant switching parameter: 8 | # = 0 the resonant contribution switched OFF, 9 | # = 1 the resonant contribution switched ON; 10 | # ias - switching parameter for \alpha_s(M_Z) value: 11 | # = 0 PDG 1sigma minimal alpha_s(M_Z), 12 | # = 1 PDG average value alpha_s(M_Z), 13 | # = 2 PDG 1sigma maximal alpha_s(M_Z). 14 | # Wolfenstein parameterization for CKM matrix: 15 | # A 16 | # lambda 17 | # barrho 18 | # bareta 19 | # EndDocumentation 20 | 21 | Define mu 5.0 22 | Define Nf 5 23 | Define res_swch 0 24 | Define ias 1 25 | Define A 0.88 26 | Define lambda 0.227 27 | Define barrho 0.22 28 | Define bareta 0.34 29 | 30 | Decay B0sig 31 | 1.0 mu+ mu- mu+ mu- BQTOLLLL mu Nf res_swch ias A lambda barrho bareta; 32 | Enddecay 33 | 34 | End 35 | -------------------------------------------------------------------------------- /tests/data/test_Bd2DDst_Ds2DmPi0.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes: 2 | # B0 -> D*- D+, D*- -> D- (pi0, gamma), D- -> K+ pi- pi- or D- -> K+ K- pi- & cc 3 | 4 | # -------------------------------------- 5 | # DEFINE THE ALIASES & CHARGE CONJUGATES 6 | # -------------------------------------- 7 | Alias B0sig B0 8 | Alias anti-B0sig anti-B0 9 | ChargeConj B0sig anti-B0sig 10 | 11 | Alias MyD*- D*- 12 | Alias MyD*+ D*+ 13 | ChargeConj MyD*+ MyD*- 14 | 15 | Alias MyD- D- 16 | Alias MyD+ D+ 17 | ChargeConj MyD+ MyD- 18 | 19 | # --------------- 20 | # DECAY OF THE B0 21 | # --------------- 22 | Decay B0sig 23 | 1.000 MyD*- MyD+ SVS; 24 | Enddecay 25 | CDecay anti-B0sig 26 | 27 | # ---------------- 28 | # DECAY OF THE D*- 29 | # ---------------- 30 | Decay MyD*- 31 | 0.9505 MyD- pi0 VSS; 32 | 0.0495 MyD- gamma VSP_PWAVE; 33 | Enddecay 34 | CDecay MyD*+ 35 | 36 | # --------------- 37 | # DECAY OF THE D- 38 | # --------------- 39 | Decay MyD- 40 | 0.905 K+ pi- pi- D_DALITZ; 41 | 0.095 K+ K- pi- D_DALITZ; 42 | Enddecay 43 | CDecay MyD+ 44 | 45 | # ---------------- 46 | # DECAY OF THE pi0 47 | # ---------------- 48 | Decay pi0 49 | 0.99 gamma gamma PHSP; 50 | 0.01 e+ e- gamma PI0_DALITZ; 51 | Enddecay 52 | 53 | End 54 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | 5 | extensions = [ 6 | "sphinx.ext.autodoc", 7 | "sphinx.ext.autosummary", 8 | "sphinx.ext.coverage", 9 | "sphinx.ext.doctest", 10 | "sphinx.ext.extlinks", 11 | "sphinx.ext.ifconfig", 12 | "sphinx.ext.napoleon", 13 | "sphinx.ext.todo", 14 | "sphinx.ext.viewcode", 15 | ] 16 | if os.getenv("SPELLCHECK"): 17 | extensions += ("sphinxcontrib.spelling",) 18 | spelling_show_suggestions = True 19 | spelling_lang = "en_US" 20 | 21 | source_suffix = ".rst" 22 | main_doc = "index" 23 | project = "decaylanguage" 24 | year = "2018" 25 | author = "Henry Fredrick Schreiner III" 26 | copyright = f"{year}, {author}" 27 | version = release = "0.2.0" 28 | 29 | pygments_style = "trac" 30 | templates_path = ["."] 31 | extlinks = { 32 | "issue": ("https://github.com/scikit-hep/decaylanguage/issues/%s", "#"), 33 | "pr": ("https://github.com/scikit-hep/decaylanguage/pull/%s", "PR #"), 34 | } 35 | # on_rtd is whether we are on readthedocs.org 36 | on_rtd = os.environ.get("READTHEDOCS", None) == "True" 37 | 38 | if not on_rtd: # only set the theme if we're building docs locally 39 | html_theme = "sphinx_rtd_theme" 40 | 41 | html_use_smartypants = True 42 | html_last_updated_fmt = "%b %d, %Y" 43 | html_split_index = False 44 | html_sidebars = { 45 | "**": ["searchbox.html", "globaltoc.html", "sourcelink.html"], 46 | } 47 | html_short_title = f"{project}-{version}" 48 | 49 | napoleon_use_ivar = True 50 | napoleon_use_rtype = False 51 | napoleon_use_param = False 52 | -------------------------------------------------------------------------------- /tests/data/test_multiline_model.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes: 2 | # Test for rather complex models defined in several lines 3 | 4 | Decay B+ 5 | 1.000 K+ K- pi+ PTO3P 6 | MAXPDF 0.09 7 | AMPLITUDE RESONANCE BC K*0 8 | ANGULAR AC 9 | TYPE RBW_ZEMACH 10 | DVFF BLATTWEISSKOPF 4.0 11 | COEFFICIENT POLAR_RAD 1.0 0.0 12 | AMPLITUDE LASS BC 1.412 0.294 2.07 3.32 1.8 13 | COEFFICIENT POLAR_RAD 32.9 -0.38 14 | AMPLITUDE RESONANCE AB phi 15 | ANGULAR CA 16 | TYPE RBW_ZEMACH 17 | DVFF BLATTWEISSKOPF 4.0 18 | COEFFICIENT POLAR_RAD 6.04 2.99 19 | AMPLITUDE RESONANCE AB f_0 0.965 0.695 20 | ANGULAR CA 21 | TYPE FLATTE 0.165 0.13957 0.13957 22 | COEFFICIENT POLAR_RAD 5.28 0.48 23 | AMPLITUDE RESONANCE AB f_0(1500) 1.539 0.257 24 | ANGULAR CA 25 | TYPE RBW_ZEMACH 26 | COEFFICIENT POLAR_RAD 24.0 1.29 27 | AMPLITUDE RESONANCE AB chi_c0 28 | ANGULAR CA 29 | TYPE RBW_ZEMACH 30 | DVFF BLATTWEISSKOPF 4.0 31 | COEFFICIENT POLAR_RAD 0.437 -1.02 32 | AMPLITUDE PHASESPACE 33 | COEFFICIENT POLAR_RAD 6.9 -2.29 34 | ; 35 | Enddecay 36 | -------------------------------------------------------------------------------- /tests/data/duplicate-decays.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. 2 | # Example bug taken from an old DECAY.DEC file ;-) : 3 | # a particle decay is duplicated and the CP conjugate definition with 4 | # 'CDecay anti-Sigma(1775)0' is effectively a different way of defining what is 5 | # already defined via 'Decay anti-Sigma(1775)0' ! 6 | 7 | Decay Sigma(1775)0 8 | 0.215 p+ K- PHSP; 9 | 0.215 n0 anti-K0 PHSP; 10 | 0.20 Lambda0 pi0 PHSP; 11 | 0.02 Sigma+ pi- PHSP; 12 | 0.02 Sigma- pi+ PHSP; 13 | 0.055 Sigma*+ pi- PHSP; 14 | 0.055 Sigma*- pi+ PHSP; 15 | 0.22 Lambda(1520)0 pi0 PHSP; 16 | Enddecay 17 | 18 | Decay anti-Sigma(1775)0 19 | 0.215 anti-p- K+ PHSP; 20 | 0.215 anti-n0 K0 PHSP; 21 | 0.20 anti-Lambda0 pi0 PHSP; 22 | 0.02 anti-Sigma+ pi- PHSP; 23 | 0.02 anti-Sigma- pi+ PHSP; 24 | 0.055 anti-Sigma*+ pi- PHSP; 25 | 0.055 anti-Sigma*- pi+ PHSP; 26 | 0.22 anti-Lambda(1520)0 pi0 PHSP; 27 | Enddecay 28 | 29 | Decay Sigma(1775)0 # PDG 3216 30 | 0.23 Lambda0 pi0 PHSP; 31 | 0.23 Lambda(1405)0 pi0 PHSP; 32 | 0.2 p+ K- PHSP; 33 | 0.1 n0 K_S0 PHSP; 34 | 0.1 n0 K_L0 PHSP; 35 | 0.05 Sigma*+ pi- PHSP; 36 | 0.05 Sigma*- pi+ PHSP; 37 | 0.02 Sigma+ pi- PHSP; 38 | 0.02 Sigma- pi+ PHSP; 39 | Enddecay 40 | CDecay anti-Sigma(1775)0 41 | -------------------------------------------------------------------------------- /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 modification, are permitted provided that the following 7 | conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 12 | disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 18 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 22 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /tests/data/models/model-BSTD.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Wilson coefficients for New Physics contributions 4 | # Each Wilson coefficient is calculated by 5 | # CXX = MagCXX * exp( ArgCXX * i ) 6 | # Negative value of MagCXX is allowed. 7 | # all CXX = 0 --> Standard Model 8 | Define MagCV1 0 9 | Define ArgCV1 0 10 | Define MagCV2 0 11 | Define ArgCV2 0 12 | Define MagCS1 0 13 | Define ArgCS1 0 14 | Define MagCS2 0 15 | Define ArgCS2 0 16 | Define MagCT 0 17 | Define ArgCT 0 18 | 19 | # quark masses at the m_b scale 20 | # taken from PRD77, 113016 (2008) 21 | # m_b = 4.20+/-0.07 GeV/c^2 22 | # m_c = 0.901+0.111-0.113 GeV/c^2 23 | Define m_b 4.20 24 | Define m_c 0.901 25 | 26 | # HQET Form Factor parameters from B->D(*)lnu data 27 | # taken from HFAG End Of Year 2011 28 | # rho_1^2 = 1.186 +/- 0.036 +/- 0.041 29 | # rho_A1^2 = 1.207 +/- 0.015 +/- 0.021 30 | # R_1(1) = 1.403 +/- 0.033 31 | # R_2(1) = 0.854 +/- 0.020 32 | Define rho12 1.186 33 | Define rhoA12 1.207 34 | Define R11 1.403 35 | Define R21 0.854 36 | 37 | # Parameters related to the O(1/m_q) correction in the scalar form factors 38 | # The authors of PRD87,034028 use 1 +/- 1 for these values to take into account the theoretical error. 39 | Define aS1 1.0 40 | Define aR3 1.0 41 | 42 | Decay B- 43 | 0.5 D*0 tau- anti-nu_tau BSTD rhoA12 R11 R21 aR3 m_b m_c MagCV1 ArgCV1 MagCV2 ArgCV2 MagCS1 ArgCS1 MagCS2 ArgCS2 MagCT ArgCT; 44 | #0.5 D0 tau- anti-nu_tau BSTD rho12 aS1 m_b m_c MagCV1 ArgCV1 MagCV2 ArgCV2 MagCS1 ArgCS1 MagCS2 ArgCS2 MagCT ArgCT; 45 | Enddecay 46 | 47 | End 48 | -------------------------------------------------------------------------------- /tests/utils/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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | from decaylanguage import DecayChain, DecayMode 11 | from decaylanguage.utils import DescriptorFormat 12 | 13 | dm1 = DecayMode(0.6770, "D0 pi+") # D*+ 14 | dm2 = DecayMode(0.0124, "K_S0 pi0") # D0 15 | dm3 = DecayMode(0.692, "pi+ pi-") # K_S0 16 | dm4 = DecayMode(0.98823, "gamma gamma") # pi0 17 | 18 | 19 | @pytest.mark.parametrize( 20 | ("decay_pattern", "sub_decay_pattern", "expected"), 21 | [ 22 | ( 23 | "{mother} -> {daughters}", 24 | "({mother} -> {daughters})", 25 | "D*+ -> (D0 -> (K_S0 -> pi+ pi-) (pi0 -> gamma gamma)) pi+", 26 | ), 27 | ( 28 | "{mother} --> {daughters}", 29 | "[{mother} --> {daughters}]", 30 | "D*+ --> [D0 --> [K_S0 --> pi+ pi-] [pi0 --> gamma gamma]] pi+", 31 | ), 32 | ( 33 | "{mother} => {daughters}", 34 | "{mother} (=> {daughters})", 35 | "D*+ => D0 (=> K_S0 (=> pi+ pi-) pi0 (=> gamma gamma)) pi+", 36 | ), 37 | ], 38 | ) 39 | def test_set_descriptor_pattern( 40 | decay_pattern: str, sub_decay_pattern: str, expected: str 41 | ): 42 | dc = DecayChain("D*+", {"D*+": dm1, "D0": dm2, "K_S0": dm3, "pi0": dm4}) 43 | with DescriptorFormat(decay_pattern, sub_decay_pattern): 44 | descriptor = dc.to_string() 45 | assert descriptor == expected 46 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ci: 2 | autoupdate_commit_msg: "chore: 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: v6.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.14.9" 23 | hooks: 24 | - id: ruff-check 25 | args: ["--fix", "--show-fixes"] 26 | - id: ruff-format 27 | 28 | - repo: https://github.com/pre-commit/mirrors-mypy 29 | rev: v1.19.1 30 | hooks: 31 | - id: mypy 32 | files: '^src/decaylanguage/(decay|dec|utils)/' 33 | additional_dependencies: [attrs, particle, importlib_resources, numpy] 34 | 35 | - repo: https://github.com/codespell-project/codespell 36 | rev: v2.4.1 37 | hooks: 38 | - id: codespell 39 | args: ["-L", "vertexes,unkown,te,HEP,hep"] 40 | exclude: '^(.*\.DEC|notebooks/ExampleDecFileParsingWithLark\.ipynb)$' 41 | 42 | - repo: local 43 | hooks: 44 | - id: disallow-caps 45 | name: Disallow improper capitalization 46 | language: pygrep 47 | entry: PyBind|Numpy|Cmake|CCache|Github|PyTest 48 | exclude: .pre-commit-config.yaml 49 | 50 | - repo: https://github.com/pre-commit/pygrep-hooks 51 | rev: "v1.10.0" 52 | hooks: 53 | - id: rst-backticks 54 | - id: rst-directive-colons 55 | - id: rst-inline-touching-normal 56 | -------------------------------------------------------------------------------- /tests/data/models/model-BTOSLLMSEXT.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # Documentation: the B_d^0 -> rho^0 ell^+ ell^- decay with the transition form factors 4 | # from the paper D.Melikhov, B.Stech, PRD62, 014006 (2000). 5 | # mu - the scale parameter (in GeV's); 6 | # Nf - number of "effective" flavors (for b-quark Nf=5); 7 | # res_swch - resonant switching parameter: 8 | # = 0 the resonant contribution switched OFF, 9 | # = 1 the resonant contribution switched ON; 10 | # ias - switching parameter for \alpha_s(M_Z) value: 11 | # = 0 PDG 1sigma minimal alpha_s(M_Z), 12 | # = 1 PDG average value alpha_s(M_Z), 13 | # = 2 PDG 1sigma maximal alpha_s(M_Z). 14 | # Wolfenstein parameterization for CKM matrix: 15 | # A 16 | # lambda 17 | # barrho 18 | # bareta 19 | # Multiplication coefficients 20 | # A7 = ReA7 + i*ImA7 21 | # A10 = ReA10 + i*ImA10 22 | # EndDocumentation 23 | 24 | Define mu 5.0 25 | Define Nf 5 26 | Define res_swch 0 27 | Define ias 1 28 | Define A 0.88 29 | Define lambda 0.227 30 | Define barrho 0.22 31 | Define bareta 0.34 32 | Define ReA7 1.0 33 | Define ImA7 0.0 34 | Define ReA10 -1.0 35 | Define ImA10 0.0 36 | 37 | Decay B0sig 38 | 1.0 MyRho0 mu+ mu- BTOSLLMSEXT mu Nf res_swch ias A lambda barrho bareta ReA7 ImA7 ReA10 ImA10; 39 | Enddecay 40 | 41 | End 42 | -------------------------------------------------------------------------------- /tests/data/models/model-PTO3P.dec: -------------------------------------------------------------------------------- 1 | # File for testing purposes. Contains a single decay mode with a specific model. 2 | 3 | # B+ decay to pi+, K- and K+ with Dalitz model so as to agree roughly with the Dalitz plot distribution 4 | Decay B+ 5 | 1.000 K+ K- pi+ PTO3P 6 | MAXPDF 0.09 7 | #SCANPDF 10000 8 | AMPLITUDE RESONANCE BC K*0 9 | ANGULAR AC 10 | TYPE RBW_ZEMACH 11 | DVFF BLATTWEISSKOPF 4.0 12 | COEFFICIENT POLAR_RAD 1.0 0.0 13 | AMPLITUDE LASS BC 1.412 0.294 2.07 14 | 3.32 1.8 15 | COEFFICIENT POLAR_RAD 32.9 -0.38 16 | AMPLITUDE RESONANCE AB phi 17 | ANGULAR CA 18 | TYPE RBW_ZEMACH 19 | DVFF BLATTWEISSKOPF 4.0 20 | COEFFICIENT POLAR_RAD 6.04 2.99 21 | AMPLITUDE RESONANCE AB f_0 0.965 0.695 22 | ANGULAR CA 23 | TYPE FLATTE 0.165 0.13957 0.13957 24 | COEFFICIENT POLAR_RAD 5.28 0.48 25 | AMPLITUDE RESONANCE AB f_0(1500) 1.539 26 | 0.257 27 | ANGULAR CA 28 | TYPE RBW_ZEMACH 29 | COEFFICIENT POLAR_RAD 24.0 1.29 30 | AMPLITUDE RESONANCE AB chi_c0 31 | ANGULAR CA 32 | TYPE RBW_ZEMACH 33 | DVFF BLATTWEISSKOPF 4.0 34 | COEFFICIENT POLAR_RAD 0.437 -1.02 35 | AMPLITUDE PHASESPACE 36 | COEFFICIENT POLAR_RAD 6.9 -2.29 37 | ; 38 | Enddecay 39 | 40 | End 41 | -------------------------------------------------------------------------------- /tests/decay/test_descriptor.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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | 10 | from decaylanguage import DecayChain, DecayMode 11 | 12 | dm1 = DecayMode(0.6770, "D0 pi+") # D*+ 13 | dm2 = DecayMode(0.0124, "K_S0 pi0") # D0 14 | dm3 = DecayMode(0.692, "pi+ pi-") # K_S0 15 | dm4 = DecayMode(0.98823, "gamma gamma") # pi0 16 | dm5 = DecayMode(0.0105, "D- tau+ nu_tau") # B0 17 | dm6 = DecayMode(0.0938, "K+ pi- pi-") # D- 18 | dm7 = DecayMode(0.0931, "pi+ pi+ pi- anti-nu_tau") # tau+ 19 | dm8 = DecayMode(1.85e-6, "phi phi'") # B_s0 20 | dm9a = DecayMode(0.491, "K+ K-") # phi 21 | dm9b = DecayMode(0.154, "pi+ pi- pi0") # phi 22 | 23 | 24 | @pytest.mark.parametrize( 25 | ("dc", "expected"), 26 | [ 27 | ( 28 | DecayChain("D0", {"D0": dm2, "K_S0": dm3, "pi0": dm4}), 29 | "D0 -> (K_S0 -> pi+ pi-) (pi0 -> gamma gamma)", 30 | ), 31 | ( 32 | DecayChain("D*+", {"D*+": dm1, "D0": dm2, "K_S0": dm3, "pi0": dm4}), 33 | "D*+ -> (D0 -> (K_S0 -> pi+ pi-) (pi0 -> gamma gamma)) pi+", 34 | ), 35 | ( 36 | DecayChain("B0", {"B0": dm5, "D-": dm6, "tau+": dm7}), 37 | "B0 -> (D- -> K+ pi- pi-) (tau+ -> anti-nu_tau pi+ pi+ pi-) nu_tau", 38 | ), 39 | ( 40 | DecayChain("B_s0", {"B_s0": dm8, "phi": dm9a, "phi'": dm9b}), 41 | "B_s0 -> (phi -> K+ K-) (phi' -> pi+ pi- pi0)", 42 | ), 43 | ], 44 | ) 45 | def test_descriptor(dc: DecayChain, expected: str): 46 | descriptor = dc.to_string() 47 | assert descriptor == expected 48 | -------------------------------------------------------------------------------- /src/decaylanguage/data/README.rst: -------------------------------------------------------------------------------- 1 | DecayLanguage data folder contents 2 | ================================== 3 | 4 | You can ``import decaylanguage.data``, then use ``decaylanguage.data.joinpath().open()`` 5 | to access data reliably regardless of how you have installed or are running the package (even from a zip file!). 6 | 7 | 8 | ``DECAY_LHCB.DEC`` 9 | ------------------ 10 | 11 | Copy of the LHCb experiment main decay file for EvtGen, which describes 12 | all generic particle decays. 13 | 14 | 15 | ``decfile.lark`` 16 | ---------------- 17 | Lark parser grammar definition file for parsing .dec decay files. 18 | 19 | 20 | ``MintDalitzSpecialParticles.fwf`` 21 | ---------------------------------- 22 | 23 | An extended PDG data file, prepared by this package's maintainers, 24 | for the definitions of special particles used by the Mint program. 25 | It is similar to the extended PDG data file ``mass_width_2008.fwf``, see 26 | https://github.com/scikit-hep/particle/blob/main/particle/data/README.rst. 27 | 28 | 29 | ``MintDalitzSpecialParticlesLatex.csv`` 30 | --------------------------------------- 31 | 32 | A list of PDG IDs and LaTeX names for the special Mint program particles 33 | defined in the file above. 34 | 35 | 36 | ``MintDalitzSpecialParticles.csv`` 37 | ---------------------------------- 38 | 39 | The combined data file of special particles used by the Mint program, 40 | in a format that is easy for the ``Particle`` class 41 | to read and easy for physicists to extend or edit. 42 | 43 | To regenerate the file from the fixed width file 44 | ``MintDalitzSpecialParticles.fwf`` run 45 | 46 | .. code-block:: bash 47 | 48 | $ python -m particle.particle.convert extended \ 49 | decaylanguage/data/MintDalitzSpecialParticles.fwf \ 50 | decaylanguage/data/MintDalitzSpecialParticlesLatex.csv \ 51 | decaylanguage/data/MintDalitzSpecialParticles.csv 52 | -------------------------------------------------------------------------------- /src/decaylanguage/data/ampgen.lark: -------------------------------------------------------------------------------- 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/decaylanguage for details. 5 | 6 | start : _NEWLINE? (line _NEWLINE)+ 7 | 8 | ?line : cplx_decay_line | cart_decay_line | invert_line | constant | variable | options | event_type 9 | 10 | options : fast_coherent_sum | output | nevents 11 | 12 | fast_coherent_sum : "FastCoherentSum::UseCartesian" INT 13 | output : "Output" ESCAPED_STRING 14 | nevents : "nEvents" INT 15 | event_type : "EventType" particle particle+ 16 | 17 | constant : particle SIGNED_NUMBER 18 | variable : particle fix SIGNED_NUMBER SIGNED_NUMBER 19 | cplx_decay_line : decay fixed_cplx fixed_cplx 20 | cart_decay_line : decay fixed_cplx 21 | 22 | // Particle could have a number in front 23 | // TODO: This could pull out the - or -NUMBER* part 24 | invert_line : particle "=" particle 25 | 26 | fixed_cplx : fix SIGNED_NUMBER SIGNED_NUMBER 27 | 28 | fix : SIGNED_NUMBER -> checkfixed 29 | 30 | 31 | decay : particle ( decaytype? subdecay )? 32 | 33 | decaytype : "[" (spinfactor | lineshape) (";" lineshape)? "]" 34 | 35 | spinfactor : SPIN 36 | lineshape : LINESHAPE 37 | 38 | particle : LABEL 39 | 40 | subdecay : "{" decay "," decay "}" 41 | 42 | // Terminal definitions 43 | 44 | %import common.WS_INLINE 45 | %import common.SIGNED_NUMBER 46 | %import common.DIGIT 47 | %import common.INT 48 | %import common.LETTER 49 | %import common.ESCAPED_STRING 50 | 51 | SPIN : "S" | "P" | "D" 52 | LINESHAPE : CHAR (CHAR | ".")+ 53 | CHAR : LETTER | DIGIT | "_" | "/" 54 | PRIME : "'" 55 | STAR : "*" 56 | PARENS : "(" | ")" 57 | LABEL : ( CHAR | DIGIT | PRIME | STAR | "::" | "+" | "-" | PARENS )+ 58 | COMMENT : /[#][^\n]*/ 59 | _NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+ 60 | 61 | // We should ignore comments 62 | %ignore COMMENT 63 | 64 | // Disregard spaces in text 65 | %ignore WS_INLINE 66 | -------------------------------------------------------------------------------- /tests/data/test_issue90.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain to test issue # 90 2 | # of model that contains a spurious "2", see "VVPIPI;2". 3 | 4 | Decay Upsilon(4S) 5 | 0.515122645 B+ B- VSS; #[Reconstructed PDG2011] 6 | 0.483122645 B0 anti-B0 VSS_BMIX dm; #[Reconstructed PDG2011] 7 | 0.000015583 e+ e- PHOTOS VLL; #[Reconstructed PDG2011] 8 | 0.000015766 mu+ mu- PHOTOS VLL; #[Reconstructed PDG2011] 9 | 0.000015766 tau+ tau- PHOTOS VLL; #[Reconstructed PDG2011] 10 | 0.000084099 Upsilon(2S) pi+ pi- VVPIPI; #[Reconstructed PDG2011] 11 | 0.000044342 Upsilon(2S) pi0 pi0 VVPIPI; #[Reconstructed PDG2011] 12 | 0.000080123 Upsilon pi+ pi- VVPIPI; #[Reconstructed PDG2011] 13 | 0.000044342 Upsilon pi0 pi0 VVPIPI;2 #[Reconstructed PDG2011] 14 | 0.000194392 Upsilon eta PARTWAVE 0.0 0.0 1.0 0.0 0.0 0.0; #[Reconstructed PDG2011] 15 | # BF ~ (2J+1)E^3_gamma; see PRL 94, 032001 16 | # V-> gamma S Partial wave (L,S)=(0,0) 17 | 0.000092625 gamma chi_b0(3P) HELAMP 1. 0. 1. 0.; #[Reconstructed PDG2011] 18 | # V-> gamma V Partial wave (L,S)=(0,1) 19 | 0.000138938 gamma chi_b1(3P) HELAMP 1. 0. 1. 0. -1. 0. -1. 0.; #[Reconstructed PDG2011] 20 | # V-> gamma T Partial wave (L,S)=(0,1) 21 | 0.000129084 gamma chi_b2(3P) HELAMP 2.4494897 0. 1.7320508 0. 1. 0. 1. 0. 1.7320508 0. 2.4494897 0.; #[Reconstructed PDG2011] 22 | # V-> gamma S Partial wave (L,S)=(0,0) 23 | 0.000002956 gamma chi_b0(2P) HELAMP 1. 0. 1. 0.; #[Reconstructed PDG2011] 24 | # V-> gamma V Partial wave (L,S)=(0,1) 25 | 0.000007883 gamma chi_b1(2P) HELAMP 1. 0. 1. 0. -1. 0. -1. 0.; #[Reconstructed PDG2011] 26 | # V-> gamma T Partial wave (L,S)=(0,1) 27 | 0.000011825 gamma chi_b2(2P) HELAMP 2.4494897 0. 1.7320508 0. 1. 0. 1. 0. 1.7320508 0. 2.4494897 0.; #[Reconstructed PDG2011] 28 | 0.000837571 g g g PYTHIA 92; 29 | 0.000039415 gamma g g PYTHIA 92; 30 | Enddecay 31 | -------------------------------------------------------------------------------- /src/decaylanguage/modeling/ampgentransform.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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from collections import OrderedDict 9 | from typing import Any 10 | 11 | from lark import Transformer, Tree 12 | 13 | 14 | def get_from_parser(parser, key): 15 | return [v.children for v in parser.find_data(key)] 16 | 17 | 18 | class AmpGenTransformer(Transformer): 19 | def constant(self, lines): 20 | particle, value = lines 21 | return Tree("constant", [str(particle.children[0]), float(value)]) 22 | 23 | def event_type(self, lines): 24 | return Tree("event_type", [str(p.children[0]) for p in lines]) 25 | 26 | def fixed(self, lines): 27 | return False 28 | 29 | def free(self, lines): 30 | return True 31 | 32 | def checkfixed(self, lines): 33 | val = int(lines[0]) 34 | # AmpGen convention: 0 is free 35 | return val > 0 36 | 37 | def variable(self, lines): 38 | p, fixed, value, error = lines 39 | return Tree("variable", [str(p.children[0]), fixed, float(value), float(error)]) 40 | 41 | def cplx_decay_line(self, lines): 42 | decay, real, imag = lines 43 | real_free, real_val, real_err = real.children 44 | imag_free, imag_val, imag_err = imag.children 45 | 46 | decay["fix"] = not (real_free and imag_free) 47 | decay["amp"] = complex(float(real_val), float(imag_val)) 48 | decay["err"] = complex(float(real_err), float(imag_err)) 49 | 50 | return Tree("cplx_decay_line", decay) 51 | 52 | def decay(self, lines): 53 | (particle,) = lines[0].children 54 | dic: dict[str, Any] = OrderedDict() 55 | dic["name"] = str(particle) 56 | dic["daughters"] = [] 57 | 58 | for line in lines[1:]: 59 | if line.data == "subdecay": 60 | dic["daughters"] += line.children 61 | elif line.data == "decaytype": 62 | for children in line.children: 63 | if children.data == "spinfactor": 64 | (dic["spinfactor"],) = children.children 65 | elif children.data == "lineshape": 66 | (dic["lineshape"],) = children.children 67 | 68 | return dic 69 | -------------------------------------------------------------------------------- /tests/utils/test_particleutils.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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | import pytest 9 | from particle import ParticleNotFound 10 | 11 | from decaylanguage.utils.particleutils import ( 12 | charge_conjugate_name, 13 | particle_from_string_name, 14 | ) 15 | 16 | matches_evtgen = ( 17 | ("pi0", "pi0"), 18 | ("K+", "K-"), 19 | # 'K(S)0' unrecognised in charge conjugation unless specified that these are PDG names 20 | ("K(S)0", "ChargeConj(K(S)0)"), 21 | ("Unknown", "ChargeConj(Unknown)"), 22 | ) 23 | 24 | 25 | matches_pdg = ( 26 | ("pi0", "pi0"), 27 | ("K+", "K-"), 28 | ("K(S)0", "K(S)0"), 29 | ("Unknown", "ChargeConj(Unknown)"), 30 | ) 31 | 32 | 33 | @pytest.mark.parametrize(("p_name", "ccp_name"), matches_evtgen) 34 | def test_charge_conjugate_name_defaults(p_name, ccp_name): 35 | assert charge_conjugate_name(p_name) == ccp_name 36 | 37 | 38 | @pytest.mark.parametrize(("p_name", "ccp_name"), matches_pdg) 39 | def test_charge_conjugate_name_with_pdg_name(p_name, ccp_name): 40 | assert charge_conjugate_name(p_name, pdg_name=True) == ccp_name 41 | 42 | 43 | def test_particle_from_string_name(): 44 | pi = particle_from_string_name("pi+") 45 | assert pi.pdgid == 211 46 | 47 | with pytest.raises(ParticleNotFound): 48 | particle_from_string_name("unknown") 49 | 50 | 51 | def test_fuzzy_string(): 52 | """ 53 | The input name is not specific enough, in which case the search is done 54 | by pdg_name after failing a match by name. 55 | """ 56 | p = particle_from_string_name("a(0)(980)") # all 3 charge stages match 57 | assert p.pdgid == 9000111 58 | 59 | 60 | ampgen_style_names = ( 61 | ("b", 5), 62 | ("b~", -5), 63 | ("pi+", 211), 64 | ("pi-", -211), 65 | ("K~*0", -313), 66 | ("K*(892)bar0", -313), 67 | ("a(1)(1260)+", 20213), 68 | ("rho(1450)0", 100113), 69 | ("rho(770)0", 113), 70 | ("K(1)(1270)bar-", -10323), 71 | # ("K(1460)bar-", -100321), 72 | ("K(2)*(1430)bar-", -325), 73 | ) 74 | 75 | 76 | @pytest.mark.parametrize(("name", "pid"), ampgen_style_names) 77 | def test_ampgen_style_names(name, pid): 78 | particle = particle_from_string_name(name) 79 | 80 | assert particle.pdgid == pid 81 | assert particle == pid 82 | -------------------------------------------------------------------------------- /tests/data/test_CopyDecay_RemoveDecay.dec: -------------------------------------------------------------------------------- 1 | # Example file to test EvtGen's CopyDecay and RemoveDecay keywords. 2 | 3 | # These will all be redefined at the end after Decay definitions 4 | Alias phi_copy phi 5 | Alias f'_0_copy f'_0 6 | 7 | Decay phi 8 | 0.489000000 K+ K- VSS; #[Reconstructed PDG2011] 9 | 0.342000000 K_L0 K_S0 VSS; #[Reconstructed PDG2011] 10 | 0.0425 rho+ pi- VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 11 | 0.0425 rho0 pi0 VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 12 | 0.0425 rho- pi+ VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 13 | 0.0250 pi+ pi- pi0 PHSP; 14 | 0.013090000 eta gamma VSP_PWAVE; #[Reconstructed PDG2011] 15 | 0.000687600 pi0 gamma VSP_PWAVE; #[Reconstructed PDG2011] 16 | 0.000295400 e+ e- PHOTOS VLL; #[Reconstructed PDG2011] 17 | 0.000287000 mu+ mu- PHOTOS VLL; #[Reconstructed PDG2011] 18 | 0.000113000 pi0 pi0 gamma PHSP; #[Reconstructed PDG2011] 19 | 0.000115000 eta e+ e- PHSP; #[Reconstructed PDG2011] 20 | 0.000322000 f_0 gamma PHSP; #[Reconstructed PDG2011] 21 | 0.000074000 pi+ pi- PHSP; #[New mode added] #[Reconstructed PDG2011] 22 | 0.000047000 omega pi0 PHSP; #[New mode added] #[Reconstructed PDG2011] 23 | 0.000041000 pi+ pi- gamma PHSP; #[New mode added] #[Reconstructed PDG2011] 24 | 0.000004000 pi+ pi- pi+ pi- PHSP; #[New mode added] #[Reconstructed PDG2011] 25 | 0.000011200 pi0 e+ e- PHSP; #[New mode added] #[Reconstructed PDG2011] 26 | 0.000072700 pi0 eta gamma PHSP; #[New mode added] #[Reconstructed PDG2011] 27 | 0.000062500 eta' gamma PHSP; #[New mode added] #[Reconstructed PDG2011] 28 | 0.000014000 mu+ mu- gamma PHSP; #[New mode added] #[Reconstructed PDG2011] 29 | Enddecay 30 | 31 | Decay f'_0 32 | 0.5200 pi+ pi- PHSP; 33 | 0.2600 pi0 pi0 PHSP; 34 | 0.0750 pi+ pi+ pi- pi- PHSP; 35 | 0.0750 pi+ pi- pi0 pi0 PHSP; 36 | 0.0350 K+ K- PHSP; 37 | 0.0175 K_S0 K_S0 PHSP; 38 | 0.0175 K_L0 K_L0 PHSP; 39 | Enddecay 40 | 41 | CopyDecay phi_copy phi 42 | CopyDecay f'_0_copy f'_0 43 | 44 | #RemoveDecay phi_copy 45 | #K+ K-; 46 | #Enddecay 47 | #RemoveDecay f'_0_copy 48 | #K+ K-; 49 | #pi+ pi-; 50 | #Enddecay 51 | -------------------------------------------------------------------------------- /tests/data/test_Bd2DstDst.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes: 2 | # [B0 -> D*- D*+]cc 3 | # with 4 | # D*- -> D- (pi0, gamma), D*+ -> D0 pi+ 5 | # and 6 | # D- -> K+ pi- pi- or D- -> K+ K- pi- and D0 -> K- pi- pi+ pi+ 7 | 8 | # ----------------------------------------------- 9 | # DEFINE THE ALIASES & CHARGE CONJUGATES of the B 10 | # ----------------------------------------------- 11 | Alias B0sig B0 12 | Alias anti-B0sig anti-B0 13 | ChargeConj B0sig anti-B0sig 14 | 15 | # -------------------------------------------------- 16 | # DEFINE THE D* decaying to charged D and neutral pi 17 | # -------------------------------------------------- 18 | Alias MyFirstD*- D*- 19 | Alias MyFirstD*+ D*+ 20 | ChargeConj MyFirstD*+ MyFirstD*- 21 | 22 | # -------------------------------------------------- 23 | # DEFINE THE D* decaying to neutral D and charged pi 24 | # -------------------------------------------------- 25 | Alias MySecondD*- D*- 26 | Alias MySecondD*+ D*+ 27 | ChargeConj MySecondD*+ MySecondD*- 28 | 29 | # -------------------- 30 | # DEFINE THE D+ AND D- 31 | # -------------------- 32 | Alias MyD- D- 33 | Alias MyD+ D+ 34 | ChargeConj MyD+ MyD- 35 | 36 | # --------------------- 37 | # DEFINE THE D0 AND D~0 38 | # --------------------- 39 | Alias MyD0 D0 40 | Alias Myanti-D0 anti-D0 41 | ChargeConj MyD0 Myanti-D0 42 | 43 | # --------------- 44 | # DECAY OF THE B0 45 | # --------------- 46 | Decay B0sig 47 | 1.000 MyFirstD*- MySecondD*+ SVV_HELAMP 0.0 0.0 0.0 0.0 1.0 0.0; 48 | Enddecay 49 | CDecay anti-B0sig 50 | 51 | # ------------------------------------------- 52 | # DECAY OF THE D* to charged D and neutral pi 53 | # ------------------------------------------- 54 | Decay MyFirstD*- 55 | 0.9505 MyD- pi0 VSS; 56 | 0.0495 MyD- gamma VSP_PWAVE; 57 | Enddecay 58 | CDecay MyFirstD*+ 59 | 60 | # ------------------------------------------- 61 | # DECAY OF THE D* to neutral D and charged pi 62 | # ------------------------------------------- 63 | Decay MySecondD*+ 64 | 1.000 MyD0 pi+ VSS; 65 | Enddecay 66 | CDecay MySecondD*- 67 | 68 | # --------------- 69 | # DECAY OF THE D- 70 | # --------------- 71 | Decay MyD- 72 | 0.700 K+ pi- pi- D_DALITZ; 73 | 0.300 K+ K- pi- D_DALITZ; 74 | Enddecay 75 | CDecay MyD+ 76 | 77 | # --------------- 78 | # DECAY OF THE D0 79 | # --------------- 80 | Decay MyD0 81 | 1.00 K- pi- pi+ pi+ LbAmpGen DtoKpipipi_v1 ; 82 | Enddecay 83 | CDecay Myanti-D0 84 | 85 | End 86 | -------------------------------------------------------------------------------- /images/DecayLanguage.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 30 | 34 | 44 | Decay 54 | Language 64 | 65 | 66 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | Bug reports 9 | =========== 10 | 11 | When ``reporting a bug ``_ please include: 12 | 13 | * Your operating system name and version. 14 | * Any details about your local setup that might be helpful in troubleshooting. 15 | * Detailed steps to reproduce the bug. 16 | 17 | Documentation improvements 18 | ========================== 19 | 20 | decaylanguage could always use more documentation, whether as part of the 21 | official decaylanguage docs, in docstrings, or even on the web in blog posts, 22 | articles, and such. 23 | 24 | Feature requests and feedback 25 | ============================= 26 | 27 | The best way to send feedback is to file an issue at https://github.com/scikit-hep/decaylanguage/issues. 28 | 29 | If you are proposing a feature: 30 | 31 | * Explain in detail how it would work. 32 | * Keep the scope as narrow as possible, to make it easier to implement. 33 | * Remember that this is a volunteer-driven project, and that code contributions are welcome :) 34 | 35 | Development 36 | =========== 37 | 38 | To set up ``decaylanguage`` for local development: 39 | 40 | 1. Fork ``decaylanguage ``_ 41 | (look for the "Fork" button). 42 | 43 | 2. Clone your fork locally:: 44 | 45 | git clone git@github.com:your_name_here/decaylanguage.git 46 | 47 | 3. Create a branch for local development:: 48 | 49 | git checkout -b name-of-your-bugfix-or-feature 50 | 51 | Now you can make your changes locally. 52 | 53 | 4. When you're done making changes, run all the checks, doc builder and spell checker with ``nox ``_ one command:: 54 | 55 | nox 56 | 57 | 5. Commit your changes and push your branch to GitHub:: 58 | 59 | git add . 60 | git commit -m "Your detailed description of your changes." 61 | git push origin name-of-your-bugfix-or-feature 62 | 63 | 6. Submit a pull request through the GitHub website. 64 | 65 | Pull Request Guidelines 66 | ----------------------- 67 | 68 | If you need some code review or feedback while you're developing the code just make the pull request. 69 | 70 | For merging, you should: 71 | 72 | 1. Include passing tests (run ``nox``) [1]_. 73 | 2. Update documentation when there's new API, functionality etc. 74 | 3. Add a note to ``CHANGELOG.md`` about the changes. 75 | 4. Add yourself to ``AUTHORS.rst``. 76 | 77 | .. [1] If you don't have all the necessary python versions available locally, you can run a specific nox session with ``nox -s tests-3.9``, for example. GitHub Actions will run all the tests whenever a pull request is made, so testing all versions of Python locally is usually not necessary. 78 | 79 | Tips 80 | ---- 81 | 82 | To run a subset of tests:: 83 | 84 | nox -s tests-3.9 -- -k test_myfeature 85 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | pre-commit: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v5 18 | with: 19 | fetch-depth: 0 20 | - uses: actions/setup-python@v6 21 | with: 22 | python-version: "3.x" 23 | - uses: astral-sh/setup-uv@v7 24 | - uses: pre-commit/action@v3.0.1 25 | with: 26 | extra_args: --all-files --hook-stage manual 27 | - name: PyLint 28 | run: uvx nox -s pylint -- --output-format=github 29 | 30 | 31 | checks: 32 | name: Check ${{ matrix.os }} Python ${{ matrix.python-version }} 33 | runs-on: ${{ matrix.os }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [ubuntu-latest] 38 | python-version: ['3.9', '3.11', '3.13', '3.14'] 39 | include: 40 | - {os: macos-15-intel, python-version: '3.9'} 41 | - {os: macos-latest, python-version: '3.13'} 42 | - {os: macos-latest, python-version: '3.14'} 43 | - {os: windows-latest, python-version: '3.9'} 44 | - {os: windows-latest, python-version: '3.13'} 45 | - {os: windows-latest, python-version: '3.14'} 46 | 47 | steps: 48 | - uses: actions/checkout@v5 49 | 50 | - name: Setup Python ${{ matrix.python-version }} 51 | uses: actions/setup-python@v6 52 | with: 53 | python-version: ${{ matrix.python-version }} 54 | allow-prereleases: true 55 | 56 | - uses: astral-sh/setup-uv@v7 57 | 58 | - name: Install package 59 | run: uv pip install --system -e .[test] 60 | 61 | - name: Pytest 62 | if: runner.os == 'Linux' 63 | run: python -m pip install pytest-github-actions-annotate-failures 64 | 65 | - name: Test package 66 | run: python -m pytest ./tests --cov=src/decaylanguage --cov-report=xml 67 | 68 | - name: Test coverage with Codecov 69 | uses: codecov/codecov-action@v5 70 | env: 71 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 72 | 73 | - name: Test docstrings with doctest 74 | if: "runner.os == 'Linux' && matrix.python-version == 3.12" 75 | run: python -m pytest --doctest-modules src/decaylanguage 76 | 77 | notebooks: 78 | runs-on: ubuntu-latest 79 | 80 | steps: 81 | - uses: actions/checkout@v5 82 | with: 83 | fetch-depth: 0 84 | 85 | - uses: actions/setup-python@v6 86 | with: 87 | python-version: "3.x" 88 | 89 | - uses: astral-sh/setup-uv@v7 90 | 91 | - name: Install dot 92 | run: sudo apt-get install graphviz 93 | 94 | - name: Install package 95 | run: uv pip install --system -e .[test] 96 | 97 | - name: Install notebook requirements 98 | run: uv pip install --system nbconvert jupyter_client ipykernel pydot 99 | 100 | - name: Run the notebooks inplace 101 | run: jupyter nbconvert --execute --inplace notebooks/DecayLanguageDemo.ipynb notebooks/ExampleDecFileParsingWithLark.ipynb 102 | -------------------------------------------------------------------------------- /src/decaylanguage/data/decfile.lark: -------------------------------------------------------------------------------- 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/decaylanguage for details. 5 | 6 | start : _NEWLINE* (line _NEWLINE+)* ("End" _NEWLINE+)? 7 | ?line : define | particle_def | pythia_def | jetset_def | ls_def | model_alias | alias | chargeconj | commands | decay | cdecay | copydecay | setlspw | setlsbw | changemasslimit | inc_factor 8 | 9 | pythia_def : LABEL_PYTHIA8_COMMANDS LABEL ":" LABEL "=" (LABEL | SIGNED_NUMBER) // Pythia 8 commands 10 | LABEL_PYTHIA8_COMMANDS : "PythiaAliasParam" | "PythiaBothParam" | "PythiaGenericParam" 11 | 12 | jetset_def : "JetSetPar" LABEL "=" SIGNED_NUMBER // Old Pythia 6 commands 13 | 14 | ls_def : LABEL_LINESHAPE LABEL // Choose a lineshape for a particle 15 | LABEL_LINESHAPE : "LSFLAT" | "LSNONRELBW" | "LSMANYDELTAFUNC" // Lineshape flat | non-relativistic BW, spikes 16 | 17 | inc_factor: LABEL_INCLUDE_FACTOR LABEL BOOLEAN_INCLUDE_FACTOR // Presence of the birth/decay momentum factor and form-factor 18 | LABEL_INCLUDE_FACTOR : "IncludeBirthFactor" | "IncludeDecayFactor" 19 | BOOLEAN_INCLUDE_FACTOR : "yes" | "no" 20 | 21 | setlsbw : "BlattWeisskopf" LABEL SIGNED_NUMBER // Set Blatt-Weisskopf barrier factor for a lineshape 22 | 23 | setlspw : "SetLineshapePW" LABEL LABEL LABEL INT // Redefine Partial Wave for label -> label label 24 | 25 | cdecay : "CDecay" LABEL 26 | 27 | define : "Define" LABEL SIGNED_NUMBER 28 | 29 | particle_def: "Particle" LABEL SIGNED_NUMBER SIGNED_NUMBER? // Set the mass and width (optional) of a particle (in GeV) 30 | 31 | alias : "Alias" LABEL LABEL 32 | 33 | chargeconj : "ChargeConj" LABEL LABEL 34 | 35 | changemasslimit : LABEL_CHANGE_MASS LABEL SIGNED_NUMBER // Set upper/lower mass cuts on a lineshape 36 | LABEL_CHANGE_MASS : "ChangeMassMin" | "ChangeMassMax" 37 | 38 | ?commands : global_photos 39 | 40 | global_photos : boolean_photos 41 | 42 | boolean_photos : "yesPhotos" -> yes 43 | | "noPhotos" -> no 44 | 45 | decay : "Decay" particle _NEWLINE+ decayline* "Enddecay" 46 | decayline : value particle* photos? model _NEWLINE+ 47 | value : SIGNED_NUMBER 48 | photos : "PHOTOS" 49 | 50 | copydecay : "CopyDecay" label label 51 | 52 | label : LABEL 53 | particle : LABEL // Add full particle parsing here 54 | model_label : LABEL 55 | 56 | model_alias : "ModelAlias" model_label model 57 | 58 | model : (model_label | MODEL_NAME model_options?) _SEMICOLON+ 59 | model_options : (value | LABEL | _NEWLINE | _COMMA)+ 60 | 61 | // We must set priorities here to use lalr - match model name above label, and label above something else 62 | // This is supposed to be empty and will be filled via the `edit_terminals` functionality with a list of models 63 | MODEL_NAME.2 : "MODEL_NAME_PLACEHOLDER"/\b/ 64 | 65 | 66 | // Terminal definitions 67 | // To use a fast parser, we need to avoid conflicts 68 | 69 | %import common.WS_INLINE 70 | %import common.INT 71 | %import common.SIGNED_NUMBER 72 | 73 | // Disregard comments, (multiple) newlines and whitespace in parser tree 74 | _NEWLINE: ( /\r?\n[\t ]*/ | COMMENT ) 75 | _SEMICOLON: /;/ 76 | _COMMA: /,/ 77 | _WS: WS_INLINE 78 | 79 | LABEL : /[a-zA-Z0-9\/\-+*_().'~]+/ 80 | COMMENT : /[#][^\n]*/ 81 | 82 | // We should ignore comments 83 | %ignore COMMENT 84 | 85 | // Disregard spaces in text 86 | %ignore WS_INLINE 87 | -------------------------------------------------------------------------------- /src/decaylanguage/dec/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/decaylanguage for details. 5 | 6 | """ 7 | Collection of enums and info to help characterising .dec decay files. 8 | """ 9 | 10 | from __future__ import annotations 11 | 12 | from enum import IntEnum 13 | 14 | 15 | class PhotosEnum(IntEnum): 16 | no = 0 17 | yes = 1 18 | 19 | 20 | # This list should match the list specified in the decay file parser file 21 | # 'decaylanguage/data/decfile.lark'! 22 | known_decay_models = ( 23 | "B_TO_2BARYON_SCALAR", 24 | "B_TO_LAMBDA_PBAR_GAMMA", 25 | "BaryonPCR", 26 | "BC_SMN", 27 | "BC_TMN", 28 | "BC_VHAD", 29 | "BC_VMN", 30 | "BC_VPPHAD", 31 | "BCL", 32 | "BGL", 33 | "BLLNUL", 34 | "BNOCB0TO4PICP", 35 | "BNOCBPTO3HPI0", 36 | "BNOCBPTOKSHHH", 37 | "BSTD_2HDMTYPE2", 38 | "BSTD", 39 | "BS_MUMUKK", 40 | "BSTOGLLISRFSR", 41 | "BSTOGLLMNT", 42 | "BT02PI_CP_ISO", 43 | "BTO3PI_CP", 44 | "BTODDALITZCPK", 45 | "BToDiBaryonlnupQCD", 46 | "BTOSLLALI", 47 | "BTOSLLBALL", 48 | "BTOSLLMS", 49 | "BTOSLLMSEXT", 50 | "BTOVLNUBALL", 51 | "BTOXELNU", 52 | "BTOXSGAMMA", 53 | "BTOXSLL", 54 | "BTOXSNUNU_FERMI", 55 | "BQTOLLLLHYPERCP", 56 | "BQTOLLLL", 57 | "CB3PI-MPP", 58 | "CB3PI-P00", 59 | "D_DALITZ", 60 | "D_hhhh", 61 | "D0GAMMADALITZ", 62 | "D0MIXDALITZ", 63 | "DToKpienu", 64 | "ETA2MUMUGAMMA", 65 | "ETAPRIME_DALITZ", 66 | "ETA_DALITZ", 67 | "ETA_FULLDALITZ", 68 | "ETA_LLPIPI", 69 | "ETA_PI0DALITZ", 70 | "FLATQ2", 71 | "FLATSQDALITZ", 72 | "FOURBODYPHSP", 73 | "GENERIC_DALITZ", 74 | "GOITY_ROBERTS", 75 | "HELAMP", 76 | "HQET3", 77 | "HQET2", 78 | "HQET", 79 | "HypNonLepton", 80 | "ISGW2", 81 | "ISGW", 82 | "KNUNU", 83 | "KSTARNUNU_REV", 84 | "KS_PI0MUMU", 85 | "Lb2Baryonlnu", 86 | "Lb2plnuLCSR", 87 | "Lb2plnuLQCD", 88 | "LbAmpGen", 89 | "LLSW", 90 | "LNUGAMMA", 91 | "MELIKHOV", 92 | "OMEGA_DALITZ", 93 | "PARTWAVE", 94 | "PHI_DALITZ", 95 | "PHSPDECAYTIMECUT", 96 | "PHSPFLATLIFETIME", 97 | "PHSP_BB_MIX", 98 | "PHSP_B_MIX", 99 | "PHSP_CP", 100 | "PHSP", 101 | "PI0_DALITZ", 102 | "PROPSLPOLE", 103 | "PTO3P", 104 | "PVV_CPLH", 105 | "PYCONT", 106 | "PYTHIA", 107 | "RareLbToLll", 108 | "SHD", 109 | "SLBKPOLE", 110 | "SLL", 111 | "SLN", 112 | "SLPOLE", 113 | "SSD_CP", 114 | "SSD_DirectCP", 115 | "SSS_CP_PNG", 116 | "SSS_CP", 117 | "SSS_CPT", 118 | "STS_CP", 119 | "STS", 120 | "SVP_CP", 121 | "SVP_HELAMP", 122 | "SVP", 123 | "SVS_CP_ISO", 124 | "SVS_CPLH", 125 | "SVS_CP", 126 | "SVS_NONCPEIGEN", 127 | "SVS", 128 | "SVV_CPLH", 129 | "SVV_CP", 130 | "SVV_HELAMP", 131 | "SVV_NONCPEIGEN", 132 | "SVVHELCPMIX", 133 | "TAUHADNU", 134 | "TAULNUNU", 135 | "TAUOLA", 136 | "TAUSCALARNU", 137 | "TAUVECTORNU", 138 | "THREEBODYPHSP", 139 | "TSS", 140 | "TVP", 141 | "TVS_PWAVE", 142 | "VECTORISR", 143 | "VLL", 144 | "VSP_PWAVE", 145 | "VSS_BMIX", 146 | "VSS_MIX", 147 | "VSS", 148 | "VTOSLL", 149 | "VUB_BLNP", 150 | "VUB", 151 | "VVPIPI_WEIGHTED", 152 | "VVPIPI", 153 | "VVP", 154 | "VVS_PWAVE", 155 | "XLL", 156 | "YMSTOYNSPIPICLEO", 157 | "YMSTOYNSPIPICLEOBOOST", 158 | ) 159 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitConvention": "angular", 8 | "contributors": [ 9 | { 10 | "login": "eduardo-rodrigues", 11 | "name": "Eduardo Rodrigues", 12 | "avatar_url": "https://avatars.githubusercontent.com/u/5013581?v=4", 13 | "profile": "http://cern.ch/eduardo.rodrigues", 14 | "contributions": [ 15 | "maintenance", 16 | "code", 17 | "doc" 18 | ] 19 | }, 20 | { 21 | "login": "henryiii", 22 | "name": "Henry Schreiner", 23 | "avatar_url": "https://avatars.githubusercontent.com/u/4616906?v=4", 24 | "profile": "http://iscinumpy.dev", 25 | "contributions": [ 26 | "maintenance", 27 | "code", 28 | "doc" 29 | ] 30 | }, 31 | { 32 | "login": "yipengsun", 33 | "name": "Yipeng Sun", 34 | "avatar_url": "https://avatars.githubusercontent.com/u/33738176?v=4", 35 | "profile": "https://github.com/yipengsun", 36 | "contributions": [ 37 | "code" 38 | ] 39 | }, 40 | { 41 | "login": "chrisburr", 42 | "name": "Chris Burr", 43 | "avatar_url": "https://avatars.githubusercontent.com/u/5220533?v=4", 44 | "profile": "https://github.com/chrisburr", 45 | "contributions": [ 46 | "doc" 47 | ] 48 | }, 49 | { 50 | "login": "klieret", 51 | "name": "Kilian Lieret", 52 | "avatar_url": "https://avatars.githubusercontent.com/u/13602468?v=4", 53 | "profile": "https://www.lieret.net", 54 | "contributions": [ 55 | "doc" 56 | ] 57 | }, 58 | { 59 | "login": "sognetic", 60 | "name": "Moritz Bauer", 61 | "avatar_url": "https://avatars.githubusercontent.com/u/10749132?v=4", 62 | "profile": "https://github.com/sognetic", 63 | "contributions": [ 64 | "code" 65 | ] 66 | }, 67 | { 68 | "login": "FlorianReiss", 69 | "name": "FlorianReiss", 70 | "avatar_url": "https://avatars.githubusercontent.com/u/44642966?v=4", 71 | "profile": "https://github.com/FlorianReiss", 72 | "contributions": [ 73 | "code", 74 | "doc" 75 | ] 76 | }, 77 | { 78 | "login": "admorris", 79 | "name": "Adam Morris", 80 | "avatar_url": "https://avatars.githubusercontent.com/u/15155249?v=4", 81 | "profile": "https://gitlab.cern.ch/users/admorris", 82 | "contributions": [ 83 | "code" 84 | ] 85 | }, 86 | { 87 | "login": "ch2ohch2oh", 88 | "name": "Dazhi Wang", 89 | "avatar_url": "https://avatars.githubusercontent.com/u/7986711?v=4", 90 | "profile": "https://github.com/ch2ohch2oh", 91 | "contributions": [ 92 | "code" 93 | ] 94 | }, 95 | { 96 | "login": "manuelfs", 97 | "name": "Manuel Franco Sevilla", 98 | "avatar_url": "https://avatars.githubusercontent.com/u/4977423?v=4", 99 | "profile": "https://github.com/manuelfs", 100 | "contributions": [ 101 | "code" 102 | ] 103 | }, 104 | { 105 | "login": "vvsagar", 106 | "name": "Vidya Sagar", 107 | "avatar_url": "https://avatars.githubusercontent.com/u/14362724?v=4", 108 | "profile": "http://vidyasagarv.com", 109 | "contributions": [ 110 | "code" 111 | ] 112 | } 113 | ], 114 | "contributorsPerLine": 7, 115 | "skipCi": true, 116 | "repoType": "github", 117 | "repoHost": "https://github.com", 118 | "projectName": "decaylanguage", 119 | "projectOwner": "scikit-hep", 120 | "commitType": "docs" 121 | } 122 | -------------------------------------------------------------------------------- /tests/test_dec_full.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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | from typing import ClassVar 9 | 10 | import pytest 11 | from lark import Lark, Transformer, Tree 12 | from particle import ParticleNotFound 13 | 14 | from decaylanguage import data 15 | from decaylanguage.dec import dec 16 | from decaylanguage.dec.enums import PhotosEnum 17 | from decaylanguage.utils.particleutils import particle_from_string_name 18 | 19 | 20 | class TreeToDec(Transformer): 21 | def yes(self, _items): 22 | return True 23 | 24 | def no(self, _items): 25 | return False 26 | 27 | def global_photos(self, items): 28 | (item,) = items 29 | return PhotosEnum.yes if item else PhotosEnum.no 30 | 31 | def value(self, items): 32 | (item,) = items 33 | return float(item) 34 | 35 | def label(self, items): 36 | (item,) = items 37 | return str(item) 38 | 39 | def photos(self, _items): 40 | return PhotosEnum.yes 41 | 42 | 43 | def define(transformed): 44 | return {x.children[0]: x.children[1] for x in transformed.find_data("define")} 45 | 46 | 47 | def pythia_def(transformed): 48 | return [x.children for x in transformed.find_data("pythia_def")] 49 | 50 | 51 | def alias(transformed): 52 | return {x.children[0]: x.children[1] for x in transformed.find_data("alias")} 53 | 54 | 55 | def chargeconj(transformed): 56 | return {x.children[0]: x.children[1] for x in transformed.find_data("chargeconj")} 57 | 58 | 59 | # Commands 60 | def global_photos(transformed): 61 | return { 62 | x.children[0]: x.children[1] for x in transformed.find_data("global_photos") 63 | } 64 | 65 | 66 | def decay(transformed): 67 | return Tree("decay", list(transformed.find_data("decay"))) 68 | 69 | 70 | def cdecay(transformed): 71 | return [x.children[0] for x in transformed.find_data("cdecay")] 72 | 73 | 74 | def setlspw(transformed): 75 | return list(transformed.find_data("setlspw")) 76 | 77 | 78 | class TreeToDec2(Transformer): 79 | missing: ClassVar[str] = set() 80 | keyerrs: ClassVar[str] = set() 81 | 82 | def __init__(self, alias_dict): 83 | self.alias_dict = alias_dict 84 | 85 | def particle(self, items): 86 | (label,) = items 87 | if label in self.alias_dict: 88 | label = self.alias_dict[label] 89 | try: 90 | return particle_from_string_name(str(label)) 91 | except ParticleNotFound: 92 | self.missing.add(str(label)) 93 | return str(label) 94 | except KeyError: 95 | self.keyerrs.add(str(label)) 96 | return str(label) 97 | 98 | 99 | @pytest.mark.skip 100 | def test_dec_full(): 101 | txt = data.basepath.joinpath("DECAY_LHCB.DEC").read_text() 102 | grammar = data.basepath.joinpath("decfile.lark").read_text() 103 | 104 | la = Lark(grammar, parser="lalr", lexer="auto") # , transformer = TreeToDec()) 105 | 106 | parsed = la.parse(txt) 107 | assert bool(parsed) 108 | 109 | transformed = dec.TreeToDec().transform(parsed) 110 | 111 | dec.define(transformed) 112 | pythia_def = dec.pythia_def(transformed) 113 | alias = dec.alias(transformed) 114 | dec.chargeconj(transformed) 115 | dec.global_photos(transformed) 116 | decay = dec.decay(transformed) 117 | dec.cdecay(transformed) 118 | dec.setlspw(transformed) 119 | 120 | for item in pythia_def: 121 | print(item[0], ":", item[1], "=", item[2]) 122 | 123 | TreeToDec2(alias).transform(decay) 124 | 125 | print(TreeToDec2.missing) 126 | print(TreeToDec2.keyerrs) 127 | 128 | assert len(TreeToDec2.missing) == 0 129 | -------------------------------------------------------------------------------- /tests/data/test_Bd2DMuNu.dec: -------------------------------------------------------------------------------- 1 | # 2 | Alias MyD+ D+ 3 | Alias MyD- D- 4 | ChargeConj MyD+ MyD- 5 | # 6 | Alias MyD*- D*- 7 | Alias MyD*+ D*+ 8 | ChargeConj MyD*- MyD*+ 9 | # 10 | Alias MyD_10 D_10 11 | Alias MyAntiD_10 anti-D_10 12 | ChargeConj MyD_10 MyAntiD_10 13 | # 14 | Alias MyD_1+ D_1+ 15 | Alias MyD_1- D_1- 16 | ChargeConj MyD_1+ MyD_1- 17 | # 18 | Alias MyD_0*+ D_0*+ 19 | Alias MyD_0*- D_0*- 20 | ChargeConj MyD_0*+ MyD_0*- 21 | # 22 | Alias MyD_0*0 D_0*0 23 | Alias MyAntiD_0*0 anti-D_0*0 24 | ChargeConj MyD_0*0 MyAntiD_0*0 25 | # 26 | Alias MyD'_10 D'_10 27 | Alias MyAntiD'_10 anti-D'_10 28 | ChargeConj MyD'_10 MyAntiD'_10 29 | # 30 | Alias MyD'_1+ D'_1+ 31 | Alias MyD'_1- D'_1- 32 | ChargeConj MyD'_1+ MyD'_1- 33 | # 34 | Alias MyD_2*+ D_2*+ 35 | Alias MyD_2*- D_2*- 36 | ChargeConj MyD_2*+ MyD_2*- 37 | # 38 | Alias MyD_2*0 D_2*0 39 | Alias MyAntiD_2*0 anti-D_2*0 40 | ChargeConj MyD_2*0 MyAntiD_2*0 41 | # 42 | Alias B0sig B0 43 | Alias anti-B0sig anti-B0 44 | ChargeConj B0sig anti-B0sig 45 | # 46 | Decay B0sig 47 | 0.0018477 MyD_1- mu+ nu_mu PHOTOS ISGW2; 48 | 0.0016516 MyD_2*- mu+ nu_mu PHOTOS ISGW2; 49 | Enddecay 50 | CDecay anti-B0sig 51 | # 52 | Decay MyD+ 53 | 1.000 K- pi+ pi+ PHOTOS D_DALITZ; 54 | Enddecay 55 | CDecay MyD- 56 | # 57 | Decay MyD*+ 58 | 0.3070 MyD+ pi0 PHOTOS VSS; 59 | Enddecay 60 | CDecay MyD*- 61 | # 62 | Decay MyD_0*+ 63 | 0.26667 MyD+ pi0 PHOTOS PHSP; 64 | 0.01292 MyD*+ pi0 pi0 PHOTOS PHSP; 65 | 0.02584 MyD*+ pi+ pi- PHOTOS PHSP; 66 | Enddecay 67 | CDecay MyD_0*- 68 | # 69 | Decay MyD_0*0 70 | 0.55333 MyD+ pi- PHOTOS PHSP; 71 | 0.02584 MyD*+ pi- pi0 PHOTOS PHSP; 72 | Enddecay 73 | CDecay MyAntiD_0*0 74 | # 75 | Decay MyD_1+ 76 | 0.0646 MyD*+ pi0 PHOTOS VVS_PWAVE 0.0 0.0 0.0 0.0 1.0 0.0; 77 | 0.14538 MyD_0*0 pi+ PHOTOS PHSP; 78 | 0.03970 MyD_0*+ pi0 PHOTOS PHSP; 79 | Enddecay 80 | CDecay MyD_1- 81 | # 82 | Decay MyD_10 83 | 0.12920 MyD*+ pi- PHOTOS VVS_PWAVE 0.0 0.0 0.0 0.0 1.0 0.0; 84 | 0.07941 MyD_0*+ pi- PHOTOS PHSP; 85 | 0.07269 MyD_0*0 pi0 PHSP; 86 | Enddecay 87 | CDecay MyAntiD_10 88 | # 89 | Decay MyD'_1+ 90 | 0.08075 MyD*+ pi0 PHOTOS VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 91 | 0.052 MyD+ pi0 pi0 PHOTOS PHSP; 92 | 0.104 MyD+ pi+ pi- PHOTOS PHSP; 93 | Enddecay 94 | CDecay MyD'_1- 95 | # 96 | Decay MyD'_10 97 | 0.1615 MyD*+ pi- PHOTOS VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 98 | 0.104 MyD+ pi- pi0 PHOTOS PHSP; 99 | Enddecay 100 | CDecay MyAntiD'_10 101 | # 102 | Decay MyD_2*+ 103 | 0.02799 MyD*+ pi0 PHOTOS TVS_PWAVE 0.0 0.0 1.0 0.0 0.0 0.0; 104 | 0.13333 MyD+ pi0 PHOTOS TSS; 105 | 0.08201 MyD_0*0 pi+ PHOTOS PHSP; 106 | 0.02240 MyD_0*+ pi0 PHOTOS PHSP; 107 | 0.00129 MyD*+ pi0 pi0 PHOTOS PHSP; 108 | 0.00258 MyD*+ pi+ pi- PHOTOS PHSP; 109 | 0.01600 MyD+ pi0 pi0 PHOTOS PHSP; 110 | 0.03200 MyD+ pi+ pi- PHOTOS PHSP; 111 | Enddecay 112 | CDecay MyD_2*- 113 | # 114 | Decay MyD_2*0 115 | 0.05599 MyD*+ pi- PHOTOS TVS_PWAVE 0.0 0.0 1.0 0.0 0.0 0.0; 116 | 0.26667 MyD+ pi- PHOTOS TSS; 117 | 0.04479 MyD_0*+ pi- PHOTOS PHSP; 118 | 0.04101 MyD_0*0 pi0 PHSP; 119 | 0.00258 MyD*+ pi- pi0 PHOTOS PHSP; 120 | 0.03200 MyD+ pi- pi0 PHOTOS PHSP; 121 | Enddecay 122 | CDecay MyAntiD_2*0 123 | # 124 | End 125 | -------------------------------------------------------------------------------- /src/decaylanguage/modeling/decay.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/decaylanguage for details. 5 | 6 | """ 7 | A general base class representing decays. 8 | """ 9 | 10 | from __future__ import annotations 11 | 12 | import warnings 13 | from itertools import product 14 | 15 | import attr 16 | 17 | from ..utils import iter_flatten 18 | 19 | try: 20 | import graphviz 21 | except ImportError: 22 | graphviz = None 23 | warnings.warn( 24 | "Graphviz is not installed. Line display not available.", stacklevel=1 25 | ) 26 | 27 | 28 | @attr.s(slots=True) 29 | class ModelDecay: 30 | """ 31 | This describes a decay very generally, with search and print features. 32 | Subclassed for further usage. 33 | """ 34 | 35 | particle = attr.ib() 36 | daughters = attr.ib([], converter=lambda x: x if x else []) 37 | name = attr.ib(None) 38 | 39 | def __attrs_post_init__(self): 40 | if self.name is None: 41 | self.name = self.particle.name 42 | 43 | def is_vertex(self): 44 | return len(self) == 2 45 | 46 | def is_strong(self): 47 | if not self.is_vertex(): 48 | return None 49 | return set(self.particle.quarks) == set(self[0].particle.quarks).union( 50 | set(self[1].particle.quarks) 51 | ) 52 | 53 | def __len__(self): 54 | return len(self.daughters) 55 | 56 | def __getitem__(self, item): 57 | return self.daughters[item] 58 | 59 | def _get_html(self): 60 | """ 61 | Get the html dot representation of this node only. Override in subclasses. 62 | """ 63 | return self.particle.html_name 64 | 65 | def _add_nodes(self, drawing): 66 | name = self._get_html() 67 | drawing.node(str(id(self)), "<" + name + ">") 68 | for p in self.daughters: 69 | drawing.edge(str(id(self)), str(id(p))) 70 | p._add_nodes(drawing) 71 | 72 | @property 73 | def vertexes(self): 74 | verts = [] 75 | for d in self.daughters: 76 | if d.is_vertex(): 77 | verts.append(d) 78 | verts += d.vertexes 79 | return verts 80 | 81 | @property 82 | def structure(self): 83 | """ 84 | The structure of the decay chain, simplified to only final state particles 85 | """ 86 | if self.daughters: 87 | return [d.structure for d in self.daughters] 88 | return self.particle 89 | 90 | def list_structure(self, final_states): 91 | """ 92 | The structure in the form [(0,1,2,3)], where the dual-list is used 93 | for permutations for bose symmatrization. 94 | So for final_states=[a,b,c,c], [a,c,[c,b]] would be: 95 | [(0,2,3,1),(0,3,2,1)] 96 | """ 97 | 98 | structure = list(iter_flatten(self.structure)) 99 | 100 | if set(structure) - set(final_states): 101 | raise RuntimeError( 102 | "The final states must encompass all particles in final states!" 103 | ) 104 | 105 | possibilities = [ 106 | [i for i, v in enumerate(final_states) if v == name] for name in structure 107 | ] 108 | return [a for a in product(*possibilities) if len(set(a)) == len(a)] 109 | 110 | def __str__(self): 111 | name = str(self.particle) 112 | 113 | if self.daughters: 114 | name += "{" + ",".join(map(str, self.daughters)) + "}" 115 | return name 116 | 117 | if graphviz: 118 | 119 | def _make_graphviz(self): 120 | d = graphviz.Digraph() 121 | d.attr(labelloc="t", label=str(self)) 122 | self._add_nodes(d) 123 | return d 124 | 125 | def _repr_mimebundle_(self, include=None, exclude=None, **kwargs): 126 | try: 127 | return self._make_graphviz()._repr_mimebundle_( 128 | include=include, exclude=exclude, **kwargs 129 | ) 130 | except AttributeError: 131 | return { 132 | "image/svg+xml": self._make_graphviz()._repr_svg_() 133 | } # for graphviz < 0.19 134 | -------------------------------------------------------------------------------- /src/decaylanguage/data/MintDalitzSpecialParticles.fwf: -------------------------------------------------------------------------------- 1 | *** 2 | * Special particles used to compose "quasi-particles" such as scalar states that are then built from K-matrix poles 3 | * 4 | * 5 | *** 6 | *MASS(MeV) ,Err+ ,Err- ,WIDTH(MeV) ,Err+ ,Err- ,I ,G,J ,P,C,A,PDG-MC ,Chrg,R,S,Name ,Quarks 7 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 9981, 0, ,R,NonResS ,?? 8 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,-,+, , 9991, 0, ,R,NonResP ,?? 9 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,1 ,+, ,F, 9983, 0, ,R,NonResA ,?? 10 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,1 ,-, ,F, 9993, 0, ,R,NonResV ,?? 11 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,2 ,+,+, , 9985, 0, ,S,NonResT ,?? 12 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,2 ,-,+, , 9986, 0, ,S,NonResPT ,?? 13 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998100, 0, ,R,PiPi0 ,x(uU+dD)+y(sS) 14 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998101, 0, ,R,PiPi1 ,x(uU+dD)+y(sS) 15 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998102, 0, ,R,PiPi2 ,x(uU+dD)+y(sS) 16 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998103, 0, ,R,PiPi3 ,x(uU+dD)+y(sS) 17 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998104, 0, ,R,PiPi4 ,x(uU+dD)+y(sS) 18 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998105, 0, ,R,PiPi5 ,x(uU+dD)+y(sS) 19 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998106, 0, ,R,PiPi6 ,x(uU+dD)+y(sS) 20 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998110, 0, ,R,KPi0 ,?? 21 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998111, 0, ,R,KPi1 ,?? 22 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998112, 0, ,R,KPi2 ,?? 23 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998113, 0, ,R,KPi3 ,?? 24 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998114, 0, ,R,KPi4 ,?? 25 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998115, 0, ,R,KPi5 ,?? 26 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998116, 0, ,R,KPi6 ,?? 27 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998120, 0, ,R,KK0 ,x(uU+dD)+y(sS) 28 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998121, 0, ,R,KK1 ,x(uU+dD)+y(sS) 29 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998122, 0, ,R,KK2 ,x(uU+dD)+y(sS) 30 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998123, 0, ,R,KK3 ,x(uU+dD)+y(sS) 31 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998124, 0, ,R,KK4 ,x(uU+dD)+y(sS) 32 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998125, 0, ,R,KK5 ,x(uU+dD)+y(sS) 33 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998126, 0, ,R,KK6 ,x(uU+dD)+y(sS) 34 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998130, 0, ,R,rhoOmega0 ,?? 35 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998131, 0, ,R,rhoOmega1 ,?? 36 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998132, 0, ,R,rhoOmega2 ,?? 37 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998133, 0, ,R,rhoOmega3 ,?? 38 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998134, 0, ,R,rhoOmega4 ,?? 39 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998135, 0, ,R,rhoOmega5 ,?? 40 | 9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998136, 0, ,R,rhoOmega6 ,?? 41 | *** 42 | -------------------------------------------------------------------------------- /images/DecayLanguage.ink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 69 | 80 | Decay 91 | Language 102 | 103 | 104 | -------------------------------------------------------------------------------- /tests/data/test_Bd2Dst0X_D02KPi.dec: -------------------------------------------------------------------------------- 1 | # Example decay chain for testing purposes: 2 | # B0 -> D*0 X, i.e. inclusive production of D*0 mesons 3 | # (sum of exclusive modes), with D0 forced to the K- pi+ final state. 4 | 5 | Alias B0sig B0 6 | Alias anti-B0sig anti-B0 7 | ChargeConj B0sig anti-B0sig 8 | 9 | Alias myD*0 D*0 10 | Alias myanti-D*0 anti-D*0 11 | ChargeConj myD*0 myanti-D*0 12 | 13 | Alias myD0 D0 14 | Alias myanti-D0 anti-D0 15 | ChargeConj myD0 myanti-D0 16 | 17 | Alias myD_1+ D_1+ 18 | Alias myD_1- D_1- 19 | ChargeConj myD_1+ myD_1- 20 | 21 | Alias myD'_1+ D'_1+ 22 | Alias myD'_1- D'_1- 23 | ChargeConj myD'_1- myD'_1+ 24 | 25 | Alias myD_2*+ D_2*+ 26 | Alias myD_2*- D_2*- 27 | ChargeConj myD_2*+ myD_2*- 28 | 29 | Decay anti-B0sig 30 | 0.00346684 myD_1+ e- anti-nu_e PHOTOS ISGW2; 31 | 0.00553361 myD'_1+ e- anti-nu_e PHOTOS ISGW2; 32 | 0.0004807 myD_2*+ e- anti-nu_e PHOTOS ISGW2; 33 | 0.0007 myD*0 pi+ e- anti-nu_e PHOTOS GOITY_ROBERTS; 34 | 35 | 0.00346684 myD_1+ mu- anti-nu_mu PHOTOS ISGW2; 36 | 0.00553361 myD'_1+ mu- anti-nu_mu PHOTOS ISGW2; 37 | 0.0004807 myD_2*+ mu- anti-nu_mu PHOTOS ISGW2; 38 | 0.0007 myD*0 pi+ mu- anti-nu_mu PHOTOS GOITY_ROBERTS; 39 | 40 | 0.00086671 myD_1+ tau- anti-nu_tau ISGW2; 41 | 0.0013334 myD'_1+ tau- anti-nu_tau ISGW2; 42 | 0.000418 myD_2*+ tau- anti-nu_tau ISGW2; 43 | 44 | 0.0004 myD'_1+ D_s- SVS; 45 | 0.0008 myD'_1+ D_s*- SVV_HELAMP 0.48 0.0 0.734 0.0 0.48 0.0; 46 | 0.0008 myD_1+ D_s- SVS; 47 | 0.0016 myD_1+ D_s*- SVV_HELAMP 0.48 0.0 0.734 0.0 0.48 0.0; 48 | 0.0008778 myD_2*+ D_s- STS; 49 | 0.000836 myD_2*+ D_s*- PHSP; 50 | 51 | 0.0049 D+ myanti-D*0 K- PHSP; 52 | 0.0100 D*+ myanti-D*0 K- PHSP; 53 | 54 | 0.0005 myD*0 anti-D0 anti-K0 PHSP; 55 | 0.0015 D0 myanti-D*0 anti-K0 PHSP; 56 | 0.0015 myD*0 anti-D*0 anti-K0 PHSP; 57 | 0.0015 D*0 myanti-D*0 anti-K0 PHSP; 58 | 59 | 0.0025 D+ myanti-D*0 K*- PHSP; 60 | 0.0050 D*+ myanti-D*0 K*- PHSP; 61 | 62 | 0.0005 anti-D0 myD*0 anti-K*0 PHSP; 63 | 0.0005 myanti-D*0 D0 anti-K*0 PHSP; 64 | 0.0010 myanti-D*0 D*0 anti-K*0 PHSP; 65 | 0.0010 anti-D*0 myD*0 anti-K*0 PHSP; 66 | 67 | 0.0003 myD*0 pi+ pi- PHSP; 68 | 0.0005 myD*0 pi0 pi0 PHSP; 69 | 70 | 0.0010 myD*0 pi+ pi- pi0 PHSP; 71 | 0.0001 myD*0 pi0 pi0 pi0 PHSP; 72 | 73 | 0.0004 myD_1+ pi- SVS; 74 | 0.00006667 myD'_1+ pi- SVS; 75 | 0.0001881 myD_2*+ pi- STS; 76 | 0.00026668 myD_1+ rho- PHSP; 77 | 0.00086671 myD'_1+ rho- PHSP; 78 | 0.0004598 myD_2*+ rho- PHSP; 79 | 80 | 0.00004 myD*0 K0 SVS; 81 | 0.00004 myD*0 anti-K*0 SVV_HELAMP 1. 0. 1. 0. 1. 0.; 82 | 0.00001 myanti-D*0 anti-K*0 SVV_HELAMP 1. 0. 1. 0. 1. 0.; 83 | 84 | 0.00027 myD*0 pi0 SVS; 85 | 0.00029 myD*0 rho0 SVV_HELAMP 0.228 0.0 0.932 0.0 0.283 0.0; 86 | 0.00026 myD*0 eta SVS; 87 | 0.00017 myD*0 eta' SVS; 88 | 0.00042 myD*0 omega SVV_HELAMP 0.228 0.0 0.932 0.0 0.283 0.0; 89 | Enddecay 90 | CDecay B0sig 91 | 92 | Decay myD*0 93 | 0.6190 myD0 pi0 VSS; 94 | 0.3810 myD0 gamma VSP_PWAVE; 95 | Enddecay 96 | CDecay myanti-D*0 97 | 98 | Decay myD0 99 | 1.0 K- pi+ PHSP; 100 | Enddecay 101 | CDecay myanti-D0 102 | 103 | Decay myD_1+ 104 | 1.0 myD*0 pi+ VVS_PWAVE 0.0 0.0 0.0 0.0 1.0 0.0; 105 | Enddecay 106 | 107 | Decay myD_1- 108 | 1.0 myanti-D*0 pi- VVS_PWAVE 0.0 0.0 0.0 0.0 1.0 0.0; 109 | Enddecay 110 | 111 | Decay myD'_1+ 112 | 1.0 myD*0 pi+ VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 113 | Enddecay 114 | 115 | Decay myD'_1- 116 | 1.0 myanti-D*0 pi- VVS_PWAVE 1.0 0.0 0.0 0.0 0.0 0.0; 117 | Enddecay 118 | 119 | Decay myD_2*+ 120 | 1.0 myD*0 pi+ TVS_PWAVE 0.0 0.0 1.0 0.0 0.0 0.0; 121 | Enddecay 122 | 123 | Decay myD_2*- 124 | 1.0 myanti-D*0 pi- TVS_PWAVE 0.0 0.0 1.0 0.0 0.0 0.0; 125 | Enddecay 126 | 127 | End 128 | -------------------------------------------------------------------------------- /src/decaylanguage/data/MintDalitzSpecialParticles.csv: -------------------------------------------------------------------------------- 1 | ID,Mass,MassUpper,MassLower,Width,WidthUpper,WidthLower,I,G,P,C,Anti,Charge,Rank,Status,Name,Quarks,Latex 2 | 9981,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,NonResS,??,0^{+} 3 | 9983,9990,10,10,9900000000,30,30,1/2,1,1,5,1,0,0,0,NonResA,??,1^{+} 4 | -9983,9990,10,10,9900000000,30,30,1/2,1,1,5,1,0,0,0,NonResA,??,1^{-} 5 | 9985,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,2,NonResT,??,2^{+} 6 | 9986,9990,10,10,9900000000,30,30,0,1,-1,1,0,0,0,2,NonResPT,??,2^{-} 7 | 9991,9990,10,10,9900000000,30,30,0,1,-1,1,0,0,0,0,NonResP,??,0^{-} 8 | 9993,9990,10,10,9900000000,30,30,1/2,1,-1,5,1,0,0,0,NonResV,??,1^{-} 9 | -9993,9990,10,10,9900000000,30,30,1/2,1,-1,5,1,0,0,0,NonResV,??,1^{+} 10 | 998101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi0,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{0} 11 | 988101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi1,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{1} 12 | 978101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi2,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{2} 13 | 968101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi3,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{3} 14 | 958101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi4,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{4} 15 | 948101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi5,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{5} 16 | 938101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi6,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{6} 17 | 998111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi0,??,\left[K^{-}\pi^{+}\right]^{L=0}_{0} 18 | 988111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi1,??,\left[K^{-}\pi^{+}\right]^{L=0}_{1} 19 | 978111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi2,??,\left[K^{-}\pi^{+}\right]^{L=0}_{2} 20 | 968111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi3,??,\left[K^{-}\pi^{+}\right]^{L=0}_{3} 21 | 958111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi4,??,\left[K^{-}\pi^{+}\right]^{L=0}_{4} 22 | 948111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi5,??,\left[K^{-}\pi^{+}\right]^{L=0}_{5} 23 | 938111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi6,??,\left[K^{-}\pi^{+}\right]^{L=0}_{6} 24 | 998120,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KK0,x(uU+dD)+y(sS), 25 | 998121,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KK1,x(uU+dD)+y(sS), 26 | 998122,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KK2,x(uU+dD)+y(sS), 27 | 998123,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KK3,x(uU+dD)+y(sS), 28 | 998124,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KK4,x(uU+dD)+y(sS), 29 | 998125,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KK5,x(uU+dD)+y(sS), 30 | 998126,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KK6,x(uU+dD)+y(sS), 31 | 998130,9990,10,10,9900000000,30,30,0,1,-1,-1,0,0,0,0,rhoOmega0,??, 32 | 998131,9990,10,10,9900000000,30,30,0,1,-1,-1,0,0,0,0,rhoOmega1,??, 33 | 998132,9990,10,10,9900000000,30,30,0,1,-1,-1,0,0,0,0,rhoOmega2,??, 34 | 998133,9990,10,10,9900000000,30,30,0,1,-1,-1,0,0,0,0,rhoOmega3,??, 35 | 998134,9990,10,10,9900000000,30,30,0,1,-1,-1,0,0,0,0,rhoOmega4,??, 36 | 998135,9990,10,10,9900000000,30,30,0,1,-1,-1,0,0,0,0,rhoOmega5,??, 37 | 998136,9990,10,10,9900000000,30,30,0,1,-1,-1,0,0,0,0,rhoOmega6,??, 38 | ,,,,,,,,,,,,,,,,, 39 | 100321,1482.4,15.63,15.63,335.6,10.64,10.64,1/2,1,-1,1,2,3,0,2,K(1460),uS,K(1460)^{+} 40 | -100321,1482.4,15.63,15.63,335.6,10.64,10.64,1/2,1,-1,-1,2,-3,0,2,K(1460),Us,K(1460)^{-} 41 | -998101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi0bar,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{0} 42 | -988101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi1bar,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{1} 43 | -978101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi2bat,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{2} 44 | -968101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi3bar,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{3} 45 | -958101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi4bar,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{4} 46 | -948101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi5bar,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{5} 47 | -938101,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,PiPi6bar,x(uU+dD)+y(sS),\left[\pi^{+}\pi^{-}\right]^{L=0}_{6} 48 | -998111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi0bar,??,\left[K^{-}\pi^{+}\right]^{L=0}_{0} 49 | -988111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi1bar,??,\left[K^{-}\pi^{+}\right]^{L=0}_{1} 50 | -978111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi2bar,??,\left[K^{-}\pi^{+}\right]^{L=0}_{2} 51 | -968111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi3bar,??,\left[K^{-}\pi^{+}\right]^{L=0}_{3} 52 | -958111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi4bar,??,\left[K^{-}\pi^{+}\right]^{L=0}_{4} 53 | -948111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi5bar,??,\left[K^{-}\pi^{+}\right]^{L=0}_{5} 54 | -938111,9990,10,10,9900000000,30,30,0,1,1,1,0,0,0,0,KPi6bar,??,\left[K^{-}\pi^{+}\right]^{L=0}_{6} 55 | -------------------------------------------------------------------------------- /tests/decay/test_viewer.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/decaylanguage for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | from pathlib import Path 10 | 11 | import pytest 12 | 13 | from decaylanguage.dec.dec import DecFileParser 14 | from decaylanguage.decay.viewer import DecayChainViewer 15 | 16 | DIR = Path(__file__).parent.resolve() 17 | 18 | 19 | def test_single_decay(): 20 | p = DecFileParser(DIR / "../data/test_example_Dst.dec") 21 | p.parse() 22 | 23 | chain = p.build_decay_chains("D*+", stable_particles=["D+", "D0", "pi0"]) 24 | dcv = DecayChainViewer(chain) 25 | graph_output_as_dot = dcv.to_string() 26 | 27 | assert "mother -> dec0 [label=0.677]" in graph_output_as_dot 28 | assert "mother -> dec1 [label=0.307]" in graph_output_as_dot 29 | assert "mother -> dec2 [label=0.016]" in graph_output_as_dot 30 | 31 | 32 | def test_simple_decay_chain(): 33 | p = DecFileParser(DIR / "../data/test_example_Dst.dec") 34 | p.parse() 35 | 36 | chain = p.build_decay_chains("D*+") 37 | dcv = DecayChainViewer(chain) 38 | graph_output_as_dot = dcv.to_string() 39 | 40 | assert "mother -> dec3 [label=0.677]" in graph_output_as_dot 41 | assert "dec3:p0 -> dec4 [label=1.0]" in graph_output_as_dot 42 | assert "mother -> dec5 [label=0.307]" in graph_output_as_dot 43 | assert "dec5:p0 -> dec6 [label=1.0]" in graph_output_as_dot 44 | assert "dec6:p3 -> dec7 [label=0.988228297]" in graph_output_as_dot 45 | 46 | 47 | checklist_decfiles = ( 48 | (DIR / "../data/test_Bc2BsPi_Bs2KK.dec", "B_c+sig", False), 49 | (DIR / "../data/test_Bd2DDst_Ds2DmPi0.dec", "B0sig", True), 50 | (DIR / "../data/test_Bd2DmTauNu_Dm23PiPi0_Tau2MuNu.dec", "B0sig", False), 51 | (DIR / "../data/test_Bd2DMuNu.dec", "anti-B0sig", False), 52 | (DIR / "../data/test_Bd2DstDst.dec", "anti-B0sig", False), 53 | (DIR / "../data/test_example_Dst.dec", "D*+", True), 54 | (DIR / "../data/test_Xicc2XicPiPi.dec", "Xi_cc+sig", False), 55 | ) 56 | 57 | 58 | @pytest.mark.parametrize(("decfilepath", "signal_mother", "dup"), checklist_decfiles) 59 | def test_duplicate_arrows(decfilepath, signal_mother, dup): 60 | """ 61 | This test effectively checks whether any box node (node with subdecays) 62 | gets more than one arrow to it, which would show a bug 63 | in the creation of the DOT file recursively parsing the built decay chain. 64 | """ 65 | p = DecFileParser(decfilepath, DIR / "../../src/decaylanguage/data/DECAY_LHCB.DEC") 66 | 67 | if dup: 68 | with pytest.warns(UserWarning, match="pi0"): 69 | p.parse() 70 | else: 71 | p.parse() 72 | 73 | chain = p.build_decay_chains(signal_mother) 74 | 75 | dcv = DecayChainViewer(chain) 76 | graph_output_as_dot = dcv.to_string() 77 | 78 | ls = [ 79 | i.split(" ")[0] for i in graph_output_as_dot.split("-> dec")[1:] 80 | ] # list of node identifiers 81 | assert len(set(ls)) == len(ls) 82 | 83 | 84 | def test_init_non_defaults_basic(): 85 | p = DecFileParser(DIR / "../data/test_example_Dst.dec") 86 | p.parse() 87 | 88 | chain = p.build_decay_chains("D*+") 89 | dcv = DecayChainViewer(chain, name="TEST", format="pdf") 90 | 91 | assert dcv.graph.name == "TEST" 92 | assert dcv.graph.format == "pdf" 93 | 94 | 95 | def test_init_non_defaults_attributes(): 96 | p = DecFileParser(DIR / "../data/test_example_Dst.dec") 97 | p.parse() 98 | 99 | chain = p.build_decay_chains("D*+") 100 | node_attr = {"shape": "egg"} 101 | edge_attr = {"fontsize": "9"} 102 | graph_attr = {"rankdir": "TB"} 103 | dcv = DecayChainViewer( 104 | chain, node_attr=node_attr, edge_attr=edge_attr, graph_attr=graph_attr 105 | ) 106 | 107 | assert dcv.graph.node_attr == { 108 | "fontname": "Helvetica", 109 | "fontsize": "11", 110 | "shape": "egg", 111 | } 112 | assert dcv.graph.edge_attr == {"fontcolor": "#4c4c4c", "fontsize": "9"} 113 | assert dcv.graph.graph_attr["rankdir"] == "TB" 114 | 115 | 116 | def test_graphs_with_EvtGen_specific_names(): 117 | p = DecFileParser(DIR / "../../src/decaylanguage/data/DECAY_LHCB.DEC") 118 | p.parse() 119 | 120 | # Not setting many of the particles as stable would result in a gargantuesque chain, 121 | # which would also take a fair amount of time to build! 122 | list_stable_particles = [ 123 | "Xi_c0", 124 | "Xi-", 125 | "D0", 126 | "Omega_c0", 127 | "Sigma_c0", 128 | "tau-", 129 | "D_s-", 130 | "J/psi", 131 | "pi0", 132 | "Lambda0", 133 | "psi(2S)", 134 | ] 135 | 136 | chain = p.build_decay_chains("Xi_b-", stable_particles=list_stable_particles) 137 | dcv = DecayChainViewer(chain) 138 | 139 | assert "(cs)0" in dcv.to_string() # not 'cs_0' ;-) 140 | assert "Ξb-" in dcv.to_string() 141 | assert "Ξc0" in dcv.to_string() 142 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "hatchling", 4 | "hatch-vcs" 5 | ] 6 | build-backend = "hatchling.build" 7 | 8 | [project] 9 | name = "decaylanguage" 10 | description = "A language to describe, manipulate and convert particle decays" 11 | readme = "README.md" 12 | requires-python = ">=3.9" 13 | authors = [ 14 | { name = "Eduardo Rodrigues", email = "eduardo.rodrigues@cern.ch" }, 15 | { name = "Henry Schreiner", email = "henryfs@princeton.edu" }, 16 | ] 17 | maintainers = [ 18 | { name = "Scikit-HEP", email = "scikit-hep-admins@googlegroups.com" }, 19 | ] 20 | license = "BSD-3-Clause" 21 | keywords = [ 22 | "HEP", 23 | "chain", 24 | "decay", 25 | "particle", 26 | "representation", 27 | ] 28 | classifiers = [ 29 | "Development Status :: 4 - Beta", 30 | "Intended Audience :: Developers", 31 | "Intended Audience :: Science/Research", 32 | "Operating System :: OS Independent", 33 | "Programming Language :: Python", 34 | "Programming Language :: Python :: 3", 35 | "Programming Language :: Python :: 3 :: Only", 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 | "Programming Language :: Python :: 3.14", 42 | "Topic :: Scientific/Engineering", 43 | ] 44 | dependencies = [ 45 | "attrs>=19.2", 46 | "graphviz>=0.12.0", 47 | "lark>=1.0.0", 48 | "numpy>=1.9.3", 49 | "pandas>=1", 50 | "particle>=0.26.0", 51 | "hepunits>=2.4.0", 52 | "plumbum>=1.7.0", 53 | ] 54 | dynamic = ["version"] 55 | 56 | [project.optional-dependencies] 57 | dev = [ 58 | "pytest>=6", 59 | ] 60 | docs = [ 61 | "sphinx-rtd-theme>=0.5.0", 62 | "sphinx>=4", 63 | ] 64 | test = [ 65 | "pytest-cov", 66 | "pytest>=6", 67 | ] 68 | 69 | [project.urls] 70 | Homepage = "https://github.com/scikit-hep/decaylanguage" 71 | 72 | 73 | [tool.hatch] 74 | version.source = "vcs" 75 | build.hooks.vcs.version-file = "src/decaylanguage/_version.py" 76 | 77 | 78 | [tool.mypy] 79 | files = "src" 80 | exclude = "src/decaylanguage/(data|modeling)" 81 | python_version = "3.10" 82 | warn_unused_configs = true 83 | warn_unused_ignores = true 84 | warn_unreachable = false 85 | enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] 86 | strict = true 87 | 88 | [[tool.mypy.overrides]] 89 | module = [ 90 | "lark", 91 | "graphviz", 92 | "pandas", 93 | "plumbum", 94 | ] 95 | ignore_missing_imports = true 96 | 97 | 98 | [tool.pytest.ini_options] 99 | minversion = "6.0" 100 | testpaths = ["tests"] 101 | addopts = [ 102 | "-ra", 103 | "--doctest-modules", 104 | "--doctest-glob=\\*.rst", 105 | "--strict-markers", 106 | "--strict-config", 107 | ] 108 | log_level = "DEBUG" 109 | filterwarnings = [ 110 | "error", 111 | '''ignore:\s*Pyarrow will become a required dependency of pandas:DeprecationWarning''', 112 | ] 113 | xfail_strict = true 114 | 115 | 116 | [tool.pylint] 117 | py-version = "3.12" 118 | reports.output-format = "colorized" 119 | similarities.ignore-imports = "yes" 120 | jobs = "0" 121 | messages_control.enable = [ 122 | "useless-suppression", 123 | ] 124 | messages_control.disable = [ 125 | "fixme", 126 | "line-too-long", 127 | "missing-class-docstring", 128 | "missing-function-docstring", 129 | "missing-module-docstring", 130 | "too-few-public-methods", 131 | "too-many-arguments", 132 | "too-many-branches", 133 | "too-many-instance-attributes", 134 | "too-many-lines", 135 | "too-many-locals", 136 | "too-many-public-methods", 137 | "too-many-return-statements", 138 | "too-many-statements", 139 | "too-many-positional-arguments", 140 | "wrong-import-position", 141 | "invalid-name", 142 | "consider-using-f-string", # TODO 143 | "broad-except", # TODO 144 | "protected-access", # TODO 145 | "no-member", # TODO 146 | "unused-argument", # covered by Ruff 147 | "duplicate-code", 148 | ] 149 | 150 | [tool.ruff.lint] 151 | extend-select = [ 152 | "B", # flake8-bugbear 153 | "I", # isort 154 | "ARG", # flake8-unused-arguments 155 | "C4", # flake8-comprehensions 156 | "ICN", # flake8-import-conventions 157 | "ISC", # flake8-implicit-str-concat 158 | "PGH", # pygrep-hooks 159 | "PIE", # flake8-pie 160 | "PL", # pylint 161 | "PT", # flake8-pytest-style 162 | "PTH", # flake8-use-pathlib 163 | "RET", # flake8-return 164 | "RUF", # Ruff-specific 165 | "SIM", # flake8-simplify 166 | "T20", # flake8-print 167 | "UP", # pyupgrade 168 | "YTT", # flake8-2020 169 | ] 170 | ignore = [ 171 | "PT013", # Incorrect import of pytest 172 | "PLR2004", # Magic value used in comparison 173 | "PLR09", # Too many X 174 | ] 175 | flake8-unused-arguments.ignore-variadic-names = true 176 | isort.required-imports = ["from __future__ import annotations"] 177 | 178 | [tool.ruff.lint.per-file-ignores] 179 | "tests/**" = ["T20"] 180 | "src/decaylanguage/modeling/*.py" = ["ARG002", "PTH", "T201"] # Should be fixed later 181 | "**.ipynb" = ["T20", "PTH123", "E741"] 182 | -------------------------------------------------------------------------------- /src/decaylanguage/utils/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/decaylanguage for details. 5 | 6 | from __future__ import annotations 7 | 8 | import string 9 | from collections.abc import Iterator 10 | from copy import copy 11 | from re import Pattern 12 | from typing import Any, ClassVar 13 | 14 | 15 | def iter_flatten(iterable: list[str] | tuple[str, ...]) -> Iterator[str]: 16 | """ 17 | Flatten nested tuples and lists 18 | """ 19 | for e in iterable: 20 | if isinstance(e, (list, tuple)): 21 | yield from iter_flatten(e) 22 | else: 23 | yield e 24 | 25 | 26 | def split(x: str) -> list[str]: 27 | """ 28 | Break up a comma separated list, but respect curly brackets. 29 | 30 | For example: 31 | this, that { that { this, that } } 32 | would only break on the first comma, since the second is in a {} list 33 | """ 34 | 35 | c = 0 36 | i = 0 37 | out = [] 38 | while len(x) > 0: 39 | if i + 1 == len(x): 40 | out.append(x[: i + 1]) 41 | return out 42 | if x[i] == "," and c == 0: 43 | out.append(x[:i]) 44 | x = x[i + 1 :] 45 | i = -1 46 | elif x[i] == "{": 47 | c += 1 48 | elif x[i] == "}": 49 | c -= 1 50 | i += 1 51 | return out 52 | 53 | 54 | def filter_lines( 55 | matcher: Pattern[str], inp: list[str] 56 | ) -> tuple[list[dict[str, str | Any]], list[str]]: 57 | """ 58 | Filter out lines into new variable if they match a regular expression 59 | """ 60 | matches = (matcher.match(ln) for ln in inp) 61 | output = [match.groupdict() for match in matches if match is not None] 62 | new_inp = [ln for ln in inp if matcher.match(ln) is None] 63 | return output, new_inp 64 | 65 | 66 | class DescriptorFormat: 67 | """ 68 | Class to help with setting the decay descriptor format. The format is stored as a 69 | class-level variable: ``DescriptorFormat.config``. 70 | 71 | Examples 72 | -------- 73 | >>> from decaylanguage import DecayMode, DecayChain 74 | >>> dm1 = DecayMode(0.6770, "D0 pi+") # D*+ 75 | >>> dm2 = DecayMode(0.0124, "K_S0 pi0") # D0 76 | >>> dm3 = DecayMode(0.692, "pi+ pi-") # K_S0 77 | >>> dm4 = DecayMode(0.98823, "gamma gamma") # pi0 78 | >>> dc = DecayChain("D*+", {"D*+": dm1, "D0": dm2, "K_S0": dm3, "pi0": dm4}) 79 | >>> with DescriptorFormat("{mother} --> {daughters}", "[{mother} --> {daughters}]"): dc.to_string() 80 | ... 81 | 'D*+ --> [D0 --> [K_S0 --> pi+ pi-] [pi0 --> gamma gamma]] pi+' 82 | >>> with DescriptorFormat("{mother} => {daughters}", "{mother} (=> {daughters})"): dc.to_string(); 83 | ... 84 | 'D*+ => D0 (=> K_S0 (=> pi+ pi-) pi0 (=> gamma gamma)) pi+' 85 | >>> dc.to_string() 86 | 'D*+ -> (D0 -> (K_S0 -> pi+ pi-) (pi0 -> gamma gamma)) pi+' 87 | """ 88 | 89 | config: ClassVar[dict[str, str]] = { 90 | "decay_pattern": "{mother} -> {daughters}", 91 | "sub_decay_pattern": "({mother} -> {daughters})", 92 | } 93 | 94 | def __init__(self, decay_pattern: str, sub_decay_pattern: str) -> None: 95 | self.new_config = { 96 | "decay_pattern": decay_pattern, 97 | "sub_decay_pattern": sub_decay_pattern, 98 | } 99 | self.old_config = copy(DescriptorFormat.config) 100 | 101 | def __enter__(self) -> None: 102 | self.set_config(**self.new_config) 103 | 104 | def __exit__(self, *args: list[Any]) -> None: 105 | self.set_config(**self.old_config) 106 | 107 | @staticmethod 108 | def set_config(decay_pattern: str, sub_decay_pattern: str) -> None: 109 | """ 110 | Configure the descriptor patterns after checking that each pattern 111 | has named-wildcards "mother" and "daughters". 112 | 113 | Parameters 114 | ---------- 115 | 116 | decay_pattern: str 117 | Format-string expression for a top-level decay, 118 | e.g. "{mother} -> {daughters}" 119 | sub_decay_pattern: str 120 | Format-string expression for a sub-decay, 121 | e.g. "({mother} -> {daughters}" 122 | """ 123 | new_config = { 124 | "decay_pattern": decay_pattern, 125 | "sub_decay_pattern": sub_decay_pattern, 126 | } 127 | expected_wildcards = {"mother", "daughters"} 128 | for pattern in new_config.values(): 129 | wildcards = { 130 | t[1] for t in string.Formatter().parse(pattern) if isinstance(t[1], str) 131 | } 132 | if wildcards != expected_wildcards: 133 | error_msg = ( 134 | "The pattern should only have the wildcards " 135 | f"{expected_wildcards}, while '{pattern}' has the wildcards " 136 | f"{wildcards}." 137 | ) 138 | raise ValueError(error_msg) 139 | DescriptorFormat.config = new_config 140 | 141 | @staticmethod 142 | def format_descriptor(mother: str, daughters: str, top: bool = True) -> str: 143 | """ 144 | Apply the format to one "layer" of the decay. Does not handle nested 145 | decays itself. It is assumed that the ``daughters`` string already contains 146 | any sub-decays. 147 | 148 | Parameters 149 | ---------- 150 | 151 | mother: str 152 | The decaying particle. 153 | daughters: str 154 | The final-state particles. 155 | """ 156 | args = { 157 | "mother": mother, 158 | "daughters": daughters, 159 | } 160 | if top: 161 | return DescriptorFormat.config["decay_pattern"].format(**args) 162 | return DescriptorFormat.config["sub_decay_pattern"].format(**args) 163 | -------------------------------------------------------------------------------- /src/decaylanguage/modeling/ampgen2goofit.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/decaylanguage for details. 6 | 7 | """ 8 | Function that takes a filename of an AmpGen options file and either prints out or returns 9 | a string output with the converted set of decay chains and variables. 10 | The output is either C++ code (ampgen2goofit) or a Python script (ampgen2goofitpy) 11 | """ 12 | 13 | from __future__ import annotations 14 | 15 | import datetime 16 | from functools import partial 17 | from io import StringIO 18 | 19 | from particle import SpinType 20 | from plumbum import colors 21 | 22 | from decaylanguage.modeling.goofit import GooFitChain, GooFitPyChain, SF_4Body 23 | 24 | 25 | def ampgen2goofit(filename, ret_output=False): 26 | """ 27 | Converts an AmpGen options file to GooFit C++ code. 28 | 29 | Parameters 30 | ---------- 31 | filename: string 32 | Name of AmpGen options file. 33 | ret_output: bool 34 | If True, return output as string. Otherwise print it to terminal. 35 | """ 36 | if ret_output: 37 | output = StringIO() 38 | printer = partial(print, file=output) 39 | else: 40 | printer = print 41 | 42 | lines, all_states = GooFitChain.read_ampgen(str(filename)) 43 | 44 | printer(r"/* Autogenerated file by AmpGen2GooFit") 45 | printer("Generated on ", datetime.datetime.now()) 46 | 47 | printer("\n") 48 | for seen_factor in {p.spindetails() for p in lines}: 49 | my_lines = [p for p in lines if p.spindetails() == seen_factor] 50 | printer(colors.bold | seen_factor, ":", *my_lines[0].spinfactors) 51 | for line in my_lines: 52 | printer(" ", colors.blue | str(line)) 53 | 54 | printer("\n") 55 | for spintype in SpinType: 56 | ps = [ 57 | format(str(p), "11") 58 | for p in sorted(GooFitChain.all_particles) 59 | if p.spin_type == spintype 60 | ] 61 | printer(f"{spintype.name:>12}:", *ps) 62 | 63 | printer("\n") 64 | for n, line in enumerate(lines): 65 | printer( 66 | "{n:2} {line!s:<70} spinfactors: {lensf} L: {line.L} [{Lr[0]}-{Lr[1]}]".format( 67 | n=n, line=line, lensf=len(line.spinfactors), Lr=line.L_range() 68 | ) 69 | ) 70 | 71 | # We can make the GooFit Intro code: 72 | 73 | printer(colors.bold & colors.green | "\n\nAll discovered spin configurations:") 74 | 75 | for line in sorted({iline.spindetails() for iline in lines}): 76 | printer(colors.green | line) 77 | 78 | printer(colors.bold & colors.blue | "\n\nAll known spin configurations:") 79 | 80 | # TODO: 4 body only 81 | for e in SF_4Body: 82 | printer(colors.blue | e.name) 83 | 84 | printer("\n*/\n\n // Intro") 85 | printer(GooFitChain.make_intro(all_states)) 86 | 87 | printer("\n\n // Parameters") 88 | printer(GooFitChain.make_pars()) 89 | 90 | # And the lines can be turned into code, as well: 91 | 92 | printer("\n\n // Lines") 93 | for n, line in enumerate(lines): 94 | printer(" // Line", n) 95 | printer(line.to_goofit(all_states[1:]), end="\n\n\n") 96 | 97 | if ret_output: 98 | return output.getvalue() 99 | return None 100 | 101 | 102 | def ampgen2goofitpy(filename, ret_output=False): 103 | """ 104 | Converts an AmpGen options file to a GooFit Python script. 105 | 106 | Parameters 107 | ---------- 108 | filename: string 109 | Name of AmpGen options file. 110 | ret_output: bool 111 | If True, return output as string. Otherwise print it to terminal. 112 | """ 113 | if ret_output: 114 | output = StringIO() 115 | printer = partial(print, file=output) 116 | else: 117 | printer = print 118 | 119 | lines, all_states = GooFitPyChain.read_ampgen(str(filename)) 120 | 121 | printer(r"'''") 122 | printer("\nAutogenerated file by AmpGen2GooFit\n") 123 | printer("Generated on ", datetime.datetime.now()) 124 | 125 | printer("\n") 126 | for seen_factor in {p.spindetails() for p in lines}: 127 | my_lines = [p for p in lines if p.spindetails() == seen_factor] 128 | printer(colors.bold | seen_factor, ":", *my_lines[0].spinfactors) 129 | for line in my_lines: 130 | printer(" ", colors.blue | str(line)) 131 | 132 | printer("\n") 133 | for spintype in SpinType: 134 | ps = [ 135 | format(str(p), "11") 136 | for p in sorted(GooFitPyChain.all_particles) 137 | if p.spin_type == spintype 138 | ] 139 | printer(f"{spintype.name:>12}:", *ps) 140 | 141 | printer("\n") 142 | for n, line in enumerate(lines): 143 | printer( 144 | "{n:2} {line!s:<70} spinfactors: {lensf} L: {line.L} [{Lr[0]}-{Lr[1]}]".format( 145 | n=n, line=line, lensf=len(line.spinfactors), Lr=line.L_range() 146 | ) 147 | ) 148 | 149 | # We can make the GooFit Intro code: 150 | 151 | printer(colors.bold & colors.green | "\n\nAll discovered spin configurations:") 152 | 153 | for line in sorted({iline.spindetails() for iline in lines}): 154 | printer(colors.green | line) 155 | 156 | printer(colors.bold & colors.blue | "\n\nAll known spin configurations:") 157 | 158 | # TODO: 4 body only 159 | for e in SF_4Body: 160 | printer(colors.blue | e.name) 161 | 162 | print("\n") 163 | printer(r"'''") 164 | print("\n#Intro \n") 165 | printer(GooFitPyChain.make_intro(all_states)) 166 | 167 | printer("\n\n# Parameters") 168 | printer(GooFitPyChain.make_pars()) 169 | 170 | # And the lines can be turned into code, as well: 171 | 172 | printer("\n\n# Lines") 173 | for n, line in enumerate(lines): 174 | printer("# Line", n) 175 | printer(line.to_goofit(all_states[1:]), end="\n\n\n") 176 | print("DK3P_DI.amplitudes = amplitudes_list") 177 | 178 | if ret_output: 179 | return output.getvalue() 180 | return None 181 | -------------------------------------------------------------------------------- /src/decaylanguage/utils/particleutils.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/decaylanguage for details. 5 | 6 | 7 | from __future__ import annotations 8 | 9 | import re 10 | from functools import lru_cache 11 | from typing import Any 12 | 13 | from particle import Particle, ParticleNotFound 14 | from particle.converters import ( 15 | EvtGen2PDGNameMap, 16 | EvtGenName2PDGIDBiMap, 17 | PDG2EvtGenNameMap, 18 | ) 19 | from particle.exceptions import MatchingIDNotFound 20 | from particle.particle.enums import Charge_mapping 21 | 22 | cacher = lru_cache(maxsize=64) 23 | 24 | 25 | @cacher 26 | def charge_conjugate_name(name: str, pdg_name: bool = False) -> str: 27 | """ 28 | Return the charge-conjugate particle name matching the given name. 29 | If no matching is found, return "ChargeConj(pname)". 30 | 31 | Note 32 | ---- 33 | Search/match in order: 34 | 1) Trivial case - does the name correspond to a self-conjugate particle? 35 | Only works for particles in the DB. 36 | 2) Try to match the antiparticle looking for the opposite PDG ID 37 | in the list of PDG IDs - EvtGen names. 38 | This can deal with specific particles or badly-known particles 39 | not in the DB but not so rare in decay files. 40 | 41 | Parameters 42 | ---------- 43 | name: str 44 | Input particle name. 45 | pdg_name: str, optional, default=False 46 | Input particle name is the PDG name, 47 | not the (default) EvtGen name. 48 | 49 | Returns 50 | ------- 51 | out: str 52 | Either the EvtGen or PDG charge-conjugate particle name 53 | depending on the value of parameter ``pdg_name``. 54 | """ 55 | if pdg_name: 56 | try: 57 | ccname = charge_conjugate_name(PDG2EvtGenNameMap[name]) 58 | # Convert the EvtGen name back to a PDG name, to match input type 59 | return EvtGen2PDGNameMap[ccname] 60 | except MatchingIDNotFound: # Catch issue in PDG2EvtGenNameMap matching 61 | return f"ChargeConj({name})" 62 | 63 | # Dealing only with EvtGen names at this stage 64 | try: 65 | return Particle.from_evtgen_name(name).invert().evtgen_name 66 | except Exception: 67 | try: 68 | return EvtGenName2PDGIDBiMap[-EvtGenName2PDGIDBiMap[name]] 69 | except Exception: 70 | return f"ChargeConj({name})" 71 | 72 | 73 | def particle_from_string_name(name: str) -> Particle: 74 | """ 75 | Get a particle from an AmpGen style name. 76 | 77 | Note: the best match is returned. 78 | """ 79 | matches = particle_list_from_string_name(name) 80 | if matches: 81 | return matches[0] 82 | raise ParticleNotFound( 83 | f"Particle with AmpGen style name {name!r} not found in particle table" 84 | ) 85 | 86 | 87 | def particle_list_from_string_name(name: str) -> list[Particle]: 88 | "Get a list of particles from an AmpGen style name." 89 | 90 | # Forcible override 91 | particle = None 92 | 93 | short_name = name 94 | if "~" in name: 95 | short_name = name.replace("~", "") 96 | particle = False 97 | 98 | # Try the simplest searches first 99 | list_can = Particle.findall(name=name, particle=particle) 100 | if list_can: 101 | return list_can 102 | list_can = Particle.findall(pdg_name=short_name, particle=particle) 103 | if list_can: 104 | return list_can 105 | 106 | mat_str = _getname.match(short_name) 107 | 108 | if mat_str is None: 109 | return [] 110 | 111 | mat = mat_str.groupdict() 112 | 113 | if particle is False: 114 | mat["bar"] = "bar" 115 | 116 | try: 117 | return _from_group_dict_list(mat) 118 | except ParticleNotFound: 119 | return [] 120 | 121 | 122 | def _from_group_dict_list(mat: dict[str, Any]) -> list[Particle]: 123 | """ 124 | Internal helper class for the functions ``from_string`` and ``from_string_list`` 125 | for fuzzy finding of particle names used by AmpGen. 126 | """ 127 | kw: dict[str, Any] = { 128 | "particle": ( 129 | False if mat["bar"] is not None else True if mat["charge"] == "0" else None 130 | ) 131 | } 132 | 133 | name = mat["name"] 134 | 135 | if mat["family"]: 136 | if "_" in mat["family"]: 137 | mat["family"] = mat["family"].strip("_") 138 | name += f"({mat['family']})" 139 | if mat["state"]: 140 | name += f"({mat['state']})" 141 | 142 | if mat.get("prime"): 143 | name += "'" 144 | 145 | if mat["star"]: 146 | name += "*" 147 | 148 | if mat["state"] is not None: 149 | kw["J"] = float(mat["state"]) 150 | 151 | maxname = name + f"({mat['mass']})" if mat["mass"] else name 152 | if "charge" in mat and mat["charge"] is not None: 153 | kw["three_charge"] = Charge_mapping[mat["charge"]] 154 | 155 | vals = Particle.findall(name=lambda x: maxname in x, **kw) 156 | if not vals: 157 | vals = Particle.findall(name=lambda x: name in x, **kw) 158 | 159 | if not vals: 160 | raise ParticleNotFound(f"Could not find particle {maxname} or {name}") 161 | 162 | if len(vals) > 1 and mat["mass"] is not None: 163 | vals = [val for val in vals if mat["mass"] in val.latex_name] 164 | 165 | if len(vals) > 1: 166 | return sorted(vals) 167 | 168 | return vals 169 | 170 | 171 | _getname = re.compile( 172 | r""" 173 | ^ # Beginning of string 174 | (?P \w+? ) # One or more characters, non-greedy 175 | (?:\( (?P [udsctb][\w]*) \) )? # Optional family like (s) 176 | (?:\( (?P \d+ ) \) # Optional state in () 177 | (?= \*? \( ) )? # - lookahead for mass 178 | (?P \* )? # Optional star 179 | (?:\( (?P \d+ ) \) )? # Optional mass in () 180 | (?P (bar|~) )? # Optional bar 181 | (?P [0\+\-][+-]?) # Required 0, -, --, or +, ++ 182 | $ # End of string 183 | """, 184 | re.VERBOSE, 185 | ) 186 | -------------------------------------------------------------------------------- /notebooks/ExampleDecFileParsingWithLark.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Example of parsing a .dec decay file with Lark" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "This file demonstrates how to parse a decfile with only the Lark grammar definition. Much of the functionality demonstrated here is already provided as part of decaylanguage in a more thorough and detailed form. This example only serves to show the key data structures used." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "from __future__ import annotations\n", 24 | "\n", 25 | "import re\n", 26 | "\n", 27 | "from lark import Lark, Tree\n", 28 | "\n", 29 | "from decaylanguage import data" 30 | ] 31 | }, 32 | { 33 | "cell_type": "raw", 34 | "metadata": {}, 35 | "source": [ 36 | "Read in the Lark grammar definition file and the input .dec decay file" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "with data.basepath.joinpath(\"decfile.lark\").open() as f:\n", 46 | " grammar = f.read()\n", 47 | "\n", 48 | "with open(\"../tests/data/test_example_Dst.dec\") as f:\n", 49 | " dec_file = f.read()" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "For illustration - the grammar Lark file:" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "print(grammar)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "For illustration - the .dec decay file:" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "print(dec_file)" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "Define a helper function to dynamically load the model names needed to parse the decfile" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "metadata": { 95 | "tags": [] 96 | }, 97 | "outputs": [], 98 | "source": [ 99 | "def edit_model_name_terminals(t) -> None:\n", 100 | " \"\"\"\n", 101 | " Edits the terminals of the grammar to replace the model name placeholder with the actual names of the models.\n", 102 | " \"\"\"\n", 103 | " decay_models = (\"VSS\", \"VSP_PWAVE\", \"PHSP\", \"PI0_DALITZ\")\n", 104 | " modelstr = rf\"(?:{'|'.join(re.escape(dm) for dm in sorted(decay_models, key=len, reverse=True))})\"\n", 105 | " if t.name == \"MODEL_NAME\":\n", 106 | " t.pattern.value = t.pattern.value.replace(\"MODEL_NAME_PLACEHOLDER\", modelstr)" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "Parse the .dec decay file." 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": null, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "l = Lark(grammar, parser=\"lalr\", lexer=\"auto\", edit_terminals=edit_model_name_terminals)\n", 123 | "parsed_dec_file = l.parse(dec_file)" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "def number_of_decays(parsed_file):\n", 133 | " \"\"\"Returns the number of particle decays defined in the parsed .dec file.\"\"\"\n", 134 | " return len(list(parsed_file.find_data(\"decay\")))\n", 135 | "\n", 136 | "\n", 137 | "print(\"# of decays in file =\", number_of_decays(parsed_dec_file))" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": null, 143 | "metadata": {}, 144 | "outputs": [], 145 | "source": [ 146 | "def list_of_decay_trees(parsed_file):\n", 147 | " \"\"\"Return a list of the actual decays defined in the .dec file.\"\"\"\n", 148 | " return list(parsed_file.find_data(\"decay\"))" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [ 157 | "def get_decay_mode_details(decay_mode_Tree):\n", 158 | " \"\"\"Parse a decay mode tree and return the relevant bits of information in it.\"\"\"\n", 159 | " bf = (\n", 160 | " next(iter(decay_mode_Tree.find_data(\"value\"))).children[0].value\n", 161 | " if len(list(decay_mode_Tree.find_data(\"value\"))) == 1\n", 162 | " else None\n", 163 | " )\n", 164 | " bf = float(bf)\n", 165 | " products = tuple(\n", 166 | " [\n", 167 | " p.children[0].value\n", 168 | " for p in decay_mode_Tree.children\n", 169 | " if isinstance(p, Tree) and p.data == \"particle\"\n", 170 | " ]\n", 171 | " )\n", 172 | " model = (\n", 173 | " next(iter(decay_mode_Tree.find_data(\"model\"))).children[0].value\n", 174 | " if len(list(decay_mode_Tree.find_data(\"model\"))) == 1\n", 175 | " else None\n", 176 | " )\n", 177 | " return (bf, products, model)" 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": {}, 183 | "source": [ 184 | "Finally, digest all Lark's Tree objects parsed and collect the information of all defined decays." 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": null, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "decays = {}\n", 194 | "\n", 195 | "for tree in list_of_decay_trees(parsed_dec_file):\n", 196 | " if tree.data == \"decay\":\n", 197 | " if tree.children[0].children[0].value in decays:\n", 198 | " print(\n", 199 | " f\"Decays of particle {tree.children[0].children[0].value} are redefined! Please check your .dec file.\"\n", 200 | " )\n", 201 | " decays[tree.children[0].children[0].value] = []\n", 202 | " for decay_mode in tree.find_data(\"decayline\"):\n", 203 | " decays[tree.children[0].children[0].value].append(\n", 204 | " get_decay_mode_details(decay_mode)\n", 205 | " )" 206 | ] 207 | }, 208 | { 209 | "cell_type": "markdown", 210 | "metadata": {}, 211 | "source": [ 212 | "For illustration - print out the decay modes:" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": null, 218 | "metadata": {}, 219 | "outputs": [], 220 | "source": [ 221 | "def print_decay(dec, final_state):\n", 222 | " \"\"\"Pretty print of the decay modes of a given particle.\"\"\"\n", 223 | " print(dec)\n", 224 | " for fs in final_state:\n", 225 | " print(f\"{fs[0]:12g} : {' '.join(p for p in fs[1]):50s} {fs[2]:15s}\")" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": null, 231 | "metadata": {}, 232 | "outputs": [], 233 | "source": [ 234 | "print_decay(\"pi0\", decays[\"pi0\"])" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "metadata": { 241 | "scrolled": true 242 | }, 243 | "outputs": [], 244 | "source": [ 245 | "for particle, decay_info in decays.items():\n", 246 | " print_decay(particle, decay_info)" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "For illustration - produce a dot plot of a decay Tree:" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": null, 259 | "metadata": { 260 | "tags": [] 261 | }, 262 | "outputs": [], 263 | "source": [ 264 | "from IPython.display import Image\n", 265 | "from lark.tree import pydot__tree_to_png # requires pydot\n", 266 | "\n", 267 | "pydot__tree_to_png(\n", 268 | " list_of_decay_trees(parsed_dec_file)[0], filename=\"decay.png\", rankdir=\"LR\"\n", 269 | ")\n", 270 | "\n", 271 | "Image(filename=\"decay.png\")" 272 | ] 273 | } 274 | ], 275 | "metadata": { 276 | "kernelspec": { 277 | "display_name": "base", 278 | "language": "python", 279 | "name": "python3" 280 | }, 281 | "language_info": { 282 | "codemirror_mode": { 283 | "name": "ipython", 284 | "version": 3 285 | }, 286 | "file_extension": ".py", 287 | "mimetype": "text/x-python", 288 | "name": "python", 289 | "nbconvert_exporter": "python", 290 | "pygments_lexer": "ipython3", 291 | "version": "3.10.13" 292 | } 293 | }, 294 | "nbformat": 4, 295 | "nbformat_minor": 4 296 | } 297 | -------------------------------------------------------------------------------- /src/decaylanguage/modeling/amplitudechain.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/decaylanguage for details. 5 | 6 | """ 7 | A class representing a set of decays. Can be subclassed to provide custom converters. 8 | """ 9 | 10 | from __future__ import annotations 11 | 12 | import os 13 | import re 14 | import sys 15 | from copy import copy 16 | from enum import Enum 17 | from itertools import product 18 | from typing import ClassVar 19 | 20 | import attr 21 | import numpy as np 22 | import pandas as pd 23 | from lark import Lark 24 | from particle import Particle 25 | 26 | from .. import data 27 | from ..utils.particleutils import particle_from_string_name 28 | from .ampgentransform import AmpGenTransformer, get_from_parser 29 | from .decay import ModelDecay 30 | 31 | 32 | class LS(Enum): 33 | "Line shapes supported (currently)" 34 | 35 | RBW = 0 36 | GSpline = 1 37 | kMatrix = 2 38 | FOCUS = 3 39 | 40 | 41 | @attr.s(slots=True) 42 | class AmplitudeChain(ModelDecay): 43 | 'This is a chain of decays (a "line")' 44 | 45 | lineshape = attr.ib(None) 46 | spinfactor = attr.ib(None) 47 | amp = attr.ib( 48 | 1 + 0j, eq=False, order=False, validator=attr.validators.instance_of(complex) 49 | ) 50 | err = attr.ib( 51 | 0 + 0j, eq=False, order=False, validator=attr.validators.instance_of(complex) 52 | ) 53 | fix = attr.ib( 54 | True, eq=False, order=False, validator=attr.validators.instance_of(bool) 55 | ) 56 | name = attr.ib(None) 57 | 58 | # Class members keep track of additions 59 | all_particles: ClassVar[Particle] = set() 60 | final_particles: ClassVar[Particle] = set() 61 | 62 | # This is set class-wide, and only used when a line is made 63 | cartesian = False 64 | 65 | @classmethod 66 | def from_matched_line(cls, mat): 67 | """ 68 | This operates on an already-matched line. 69 | 70 | :param mat: The groupdict output of a match 71 | :return: A new amplitude chain instance 72 | """ 73 | 74 | getall = "all" if hasattr(Particle, "all") else "table" # Support 0.4.4 75 | 76 | # Check to see if new particles loaded; if not, load them. 77 | if 998100 not in getattr(Particle, getall)(): 78 | data_dir = os.path.dirname(os.path.realpath(__file__)) 79 | special_filename = os.path.join( 80 | data_dir, "..", "data", "MintDalitzSpecialParticles.csv" 81 | ) 82 | Particle.load_table(special_filename, append=True) 83 | 84 | try: 85 | mat["particle"] = particle_from_string_name(mat["name"]) 86 | except Exception: 87 | print( 88 | "Failed to find particle", 89 | mat["name"], 90 | "with parsed dictionary:", 91 | mat, 92 | file=sys.stderr, 93 | ) 94 | raise 95 | 96 | if mat["particle"] not in cls.all_particles: 97 | cls.all_particles |= {mat["particle"]} 98 | 99 | if mat["daughters"]: 100 | mat["daughters"] = [cls.from_matched_line(d) for d in mat["daughters"]] 101 | 102 | # if main line only 103 | if "amp" in mat and not cls.cartesian: 104 | A = mat["amp"].real 105 | dA = mat["err"].real 106 | theta = mat["amp"].imag 107 | dtheta = mat["err"].imag 108 | 109 | mat["amp"] = A * np.exp(theta * 1j) 110 | 111 | mat["err"] = (dA * np.cos(theta) + A * np.sin(dtheta)) + ( 112 | dA * np.sin(theta) + A * np.cos(dtheta) 113 | ) * 1j 114 | 115 | return cls(**mat) 116 | 117 | def expand_lines(self, linelist): 118 | """ 119 | Take a DecayTree -> list of DecayTrees with each dead-end daughter 120 | expanded to every possible combination. (recursive) 121 | 122 | """ 123 | 124 | # If the Tree has daughters, run on those 125 | if self.daughters: 126 | dlist = [d.expand_lines(linelist) for d in self.daughters] 127 | retlist = [] 128 | for ds in product(*dlist): 129 | newd = copy(self) 130 | newd.daughters = ds 131 | retlist.append(newd) 132 | return retlist 133 | 134 | # If the tree ends 135 | new_trees = [ 136 | ln 137 | for line in linelist 138 | if line.name == self.name 139 | for ln in line.expand_lines(linelist) 140 | ] 141 | if new_trees: 142 | return new_trees 143 | self.__class__.final_particles |= {self.particle} 144 | return [self] 145 | 146 | @property 147 | def ls_enum(self): 148 | if not self.lineshape: 149 | return LS.RBW 150 | if self.lineshape == "GSpline.EFF": 151 | return LS.GSpline 152 | if self.lineshape.startswith("kMatrix"): 153 | return LS.kMatrix 154 | if self.lineshape.startswith("FOCUS"): 155 | return LS.FOCUS 156 | 157 | raise RuntimeError(f"Unimplemented lineshape {self.lineshape}") 158 | 159 | @property 160 | def full_amp(self): 161 | amp = self.amp 162 | for d in self.daughters: 163 | amp *= d.full_amp 164 | return amp 165 | 166 | def L_range(self, conserveParity=False): 167 | S = self.particle.J 168 | s1 = self[0].particle.J 169 | s2 = self[1].particle.J 170 | min_spin = abs(S - s1 - s2) 171 | min_spin = min(abs(S + s1 - s2), min_spin) 172 | min_spin = min(abs(S - s1 + s2), min_spin) 173 | max_spin = S + s1 + s2 174 | if not conserveParity: 175 | return (min_spin, max_spin) 176 | raise RuntimeError("Strong decays not implemented yet") 177 | 178 | @property 179 | def L(self): 180 | if self.spinfactor: 181 | return ["S", "P", "D", "F"].index(self.spinfactor) 182 | min_L, _ = self.L_range() 183 | return min_L # Ground state unless specified 184 | 185 | def _get_html(self): 186 | name = self.particle.html_name 187 | name = re.sub( 188 | r'(.*)', "\\1\u0305", name 189 | ) 190 | 191 | if self.spinfactor or self.lineshape: 192 | name += "

" 193 | if self.spinfactor: 194 | name += '[' + self.spinfactor + "]" 195 | if self.lineshape: 196 | name += '[' + self.lineshape + "]" 197 | return name 198 | 199 | def __str__(self): 200 | name = str(self.particle) 201 | if self.lineshape and self.spinfactor: 202 | name += "[" + self.spinfactor + ";" + self.lineshape + "]" 203 | elif self.lineshape: 204 | name += "[" + self.lineshape + "]" 205 | elif self.spinfactor: 206 | name += "[" + self.spinfactor + "]" 207 | if self.daughters: 208 | name += "{" + ",".join(map(str, self.daughters)) + "}" 209 | return name 210 | 211 | @classmethod 212 | def read_ampgen( 213 | cls, filename=None, text=None, grammar=None, parser="lalr", **kargs 214 | ): 215 | """ 216 | Read in an ampgen file 217 | 218 | :param filename: Filename to read 219 | :param text: Text to read (use instead of filename) 220 | :return: array of AmplitudeChains, parameters, constants, event type 221 | """ 222 | 223 | if grammar is None: 224 | grammar = data.basepath.joinpath("ampgen.lark").read_text() 225 | 226 | # Read the file in, ignore empty lines and comments 227 | if filename is not None: 228 | with open(filename, encoding="utf_8") as f: 229 | text = f.read() 230 | elif text is None: 231 | raise RuntimeError("Must have filename or text") 232 | 233 | lark = Lark(grammar, parser=parser, transformer=AmpGenTransformer(), **kargs) 234 | parsed = lark.parse(text) 235 | 236 | (event_type,) = get_from_parser(parsed, "event_type") 237 | 238 | # invert_lines = get_from_parser(parsed, "invert_line") 239 | cplx_decay_lines = get_from_parser(parsed, "cplx_decay_line") 240 | # cart_decay_lines = get_from_parser(parsed, "cart_decay_line") 241 | variables = get_from_parser(parsed, "variable") 242 | constants = get_from_parser(parsed, "constant") 243 | 244 | try: 245 | all_states = [particle_from_string_name(n) for n in event_type] 246 | except Exception: 247 | print("Did not find at least one of the state particles from", *event_type) 248 | raise 249 | 250 | fcs = get_from_parser(parsed, "fast_coherent_sum") 251 | if fcs: 252 | (fcs,) = fcs 253 | (fcs,) = fcs.children 254 | cls.cartesian = bool(fcs) 255 | 256 | # TODO: re-enable this 257 | # Combine dual line Cartesian lines into traditional cartesian lines 258 | # for a, b in combinations(cart_decay_lines, 2): 259 | # if a['name'] == b['name']: 260 | # if a['cart'] == 'Re' and b['cart'] == 'Im': 261 | # pass 262 | # elif a['cart'] == 'Im' and b['cart'] == 'Re': 263 | # a, b = b, a 264 | # else: 265 | # raise RuntimeError("Can't process a line with *both* components Re or Im") 266 | # new_string = "{a[name]} {a[fix]} {a[amp]} {a[err]} {b[fix]} {b[amp]} {b[err]}".format( 267 | # a=a, b=b) 268 | # real_lines.append(ampline.dual.match(new_string).groupdict()) 269 | 270 | # Make the partial lines and constants as dataframes 271 | parameters = pd.DataFrame( 272 | variables, columns=["name", "fix", "value", "error"] 273 | ).set_index("name") 274 | 275 | constants = pd.DataFrame(constants, columns=["name", "value"]).set_index("name") 276 | 277 | # Convert the matches into AmplitudeChains 278 | line_arr = [cls.from_matched_line(c) for c in cplx_decay_lines] 279 | 280 | # Expand partial lines into complete lines 281 | new_line_arr = [ 282 | ln 283 | for line in line_arr 284 | if line.particle == all_states[0] 285 | for ln in line.expand_lines(line_arr) 286 | ] 287 | 288 | # Return 289 | return new_line_arr, parameters, constants, all_states 290 | --------------------------------------------------------------------------------