atlas-schema 0.1.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/.gitignore +7 -0
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/PKG-INFO +11 -6
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/README.md +1 -1
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/pyproject.toml +9 -6
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/src/atlas_schema/__init__.py +5 -1
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/src/atlas_schema/_version.py +2 -2
- atlas_schema-0.2.1/src/atlas_schema/enums.py +123 -0
- atlas_schema-0.2.1/src/atlas_schema/methods.py +241 -0
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/src/atlas_schema/typing_compat.py +2 -7
- atlas_schema-0.1.0/src/atlas_schema/enums.py +0 -116
- atlas_schema-0.1.0/src/atlas_schema/methods.py +0 -181
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/LICENSE +0 -0
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/src/atlas_schema/_version.pyi +0 -0
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/src/atlas_schema/py.typed +0 -0
- {atlas_schema-0.1.0 → atlas_schema-0.2.1}/src/atlas_schema/schema.py +0 -0
@@ -70,6 +70,7 @@ instance/
|
|
70
70
|
|
71
71
|
# Sphinx documentation
|
72
72
|
docs/_build/
|
73
|
+
docs/_generated/
|
73
74
|
|
74
75
|
# PyBuilder
|
75
76
|
.pybuilder/
|
@@ -156,3 +157,9 @@ Thumbs.db
|
|
156
157
|
# Common editor files
|
157
158
|
*~
|
158
159
|
*.swp
|
160
|
+
|
161
|
+
# pyenv
|
162
|
+
.python-version
|
163
|
+
|
164
|
+
# root files
|
165
|
+
*.root
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: atlas-schema
|
3
|
-
Version: 0.1
|
3
|
+
Version: 0.2.1
|
4
4
|
Summary: Helper python package for ATLAS Common NTuple Analysis work.
|
5
5
|
Project-URL: Homepage, https://github.com/scipp-atlas/atlas-schema
|
6
6
|
Project-URL: Bug Tracker, https://github.com/scipp-atlas/atlas-schema/issues
|
@@ -209,6 +209,7 @@ License:
|
|
209
209
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
210
210
|
See the License for the specific language governing permissions and
|
211
211
|
limitations under the License.
|
212
|
+
License-File: LICENSE
|
212
213
|
Classifier: Development Status :: 1 - Planning
|
213
214
|
Classifier: Intended Audience :: Developers
|
214
215
|
Classifier: Intended Audience :: Science/Research
|
@@ -217,23 +218,27 @@ Classifier: Operating System :: OS Independent
|
|
217
218
|
Classifier: Programming Language :: Python
|
218
219
|
Classifier: Programming Language :: Python :: 3
|
219
220
|
Classifier: Programming Language :: Python :: 3 :: Only
|
220
|
-
Classifier: Programming Language :: Python :: 3.8
|
221
221
|
Classifier: Programming Language :: Python :: 3.9
|
222
222
|
Classifier: Programming Language :: Python :: 3.10
|
223
223
|
Classifier: Programming Language :: Python :: 3.11
|
224
224
|
Classifier: Programming Language :: Python :: 3.12
|
225
225
|
Classifier: Topic :: Scientific/Engineering
|
226
226
|
Classifier: Typing :: Typed
|
227
|
-
Requires-Python: >=3.
|
227
|
+
Requires-Python: >=3.9
|
228
228
|
Requires-Dist: coffea[dask]>=2024.4.1
|
229
|
+
Requires-Dist: particle>=0.25.0
|
229
230
|
Provides-Extra: dev
|
230
231
|
Requires-Dist: pytest-cov>=3; extra == 'dev'
|
231
232
|
Requires-Dist: pytest>=6; extra == 'dev'
|
232
233
|
Provides-Extra: docs
|
233
234
|
Requires-Dist: furo>=2023.08.17; extra == 'docs'
|
235
|
+
Requires-Dist: intersphinx-registry>=0.2411.17; extra == 'docs'
|
236
|
+
Requires-Dist: ipywidgets; extra == 'docs'
|
234
237
|
Requires-Dist: myst-parser>=0.13; extra == 'docs'
|
235
238
|
Requires-Dist: sphinx-autodoc-typehints; extra == 'docs'
|
236
|
-
Requires-Dist: sphinx-
|
239
|
+
Requires-Dist: sphinx-click; extra == 'docs'
|
240
|
+
Requires-Dist: sphinx-copybutton!=0.5.1,>=0.3.2; extra == 'docs'
|
241
|
+
Requires-Dist: sphinx-issues; extra == 'docs'
|
237
242
|
Requires-Dist: sphinx>=7.0; extra == 'docs'
|
238
243
|
Provides-Extra: test
|
239
244
|
Requires-Dist: build; extra == 'test'
|
@@ -244,7 +249,7 @@ Requires-Dist: tbump>=6.7.0; extra == 'test'
|
|
244
249
|
Requires-Dist: twine; extra == 'test'
|
245
250
|
Description-Content-Type: text/markdown
|
246
251
|
|
247
|
-
# atlas-schema v0.1
|
252
|
+
# atlas-schema v0.2.1
|
248
253
|
|
249
254
|
[![Actions Status][actions-badge]][actions-link]
|
250
255
|
[![Documentation Status][rtd-badge]][rtd-link]
|
@@ -10,7 +10,7 @@ authors = [
|
|
10
10
|
description = "Helper python package for ATLAS Common NTuple Analysis work."
|
11
11
|
readme = "README.md"
|
12
12
|
license.file = "LICENSE"
|
13
|
-
requires-python = ">=3.
|
13
|
+
requires-python = ">=3.9"
|
14
14
|
classifiers = [
|
15
15
|
"Development Status :: 1 - Planning",
|
16
16
|
"Intended Audience :: Science/Research",
|
@@ -20,7 +20,6 @@ classifiers = [
|
|
20
20
|
"Programming Language :: Python",
|
21
21
|
"Programming Language :: Python :: 3",
|
22
22
|
"Programming Language :: Python :: 3 :: Only",
|
23
|
-
"Programming Language :: Python :: 3.8",
|
24
23
|
"Programming Language :: Python :: 3.9",
|
25
24
|
"Programming Language :: Python :: 3.10",
|
26
25
|
"Programming Language :: Python :: 3.11",
|
@@ -29,7 +28,7 @@ classifiers = [
|
|
29
28
|
"Typing :: Typed",
|
30
29
|
]
|
31
30
|
dynamic = ["version"]
|
32
|
-
dependencies = ["coffea[dask] >= 2024.4.1"]
|
31
|
+
dependencies = ["coffea[dask] >= 2024.4.1", "particle >= 0.25.0"]
|
33
32
|
|
34
33
|
[project.optional-dependencies]
|
35
34
|
test = [
|
@@ -48,9 +47,13 @@ dev = [
|
|
48
47
|
docs = [
|
49
48
|
"sphinx>=7.0",
|
50
49
|
"myst_parser>=0.13",
|
51
|
-
"
|
50
|
+
"sphinx-copybutton>=0.3.2,!=0.5.1",
|
52
51
|
"sphinx_autodoc_typehints",
|
53
52
|
"furo>=2023.08.17",
|
53
|
+
"sphinx-click",
|
54
|
+
"ipywidgets",
|
55
|
+
"intersphinx_registry>=0.2411.17",
|
56
|
+
"sphinx-issues",
|
54
57
|
]
|
55
58
|
|
56
59
|
[project.urls]
|
@@ -111,7 +114,7 @@ report.exclude_also = [
|
|
111
114
|
|
112
115
|
[tool.mypy]
|
113
116
|
files = ["src", "tests"]
|
114
|
-
python_version = "3.
|
117
|
+
python_version = "3.9"
|
115
118
|
warn_unused_configs = true
|
116
119
|
strict = true
|
117
120
|
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
|
@@ -182,7 +185,7 @@ typing-modules = ["atlas_schema.typing_compat"]
|
|
182
185
|
|
183
186
|
|
184
187
|
[tool.pylint]
|
185
|
-
py-version = "3.
|
188
|
+
py-version = "3.9"
|
186
189
|
ignore-paths = [".*/_version.py"]
|
187
190
|
reports.output-format = "colorized"
|
188
191
|
similarities.ignore-imports = "yes"
|
@@ -6,7 +6,11 @@ atlas_schema: Collection of utilities and helper functions for HEP ATLAS analyse
|
|
6
6
|
|
7
7
|
from __future__ import annotations
|
8
8
|
|
9
|
+
import warnings
|
10
|
+
|
9
11
|
from atlas_schema._version import version as __version__
|
10
12
|
from atlas_schema.enums import ParticleOrigin, PhotonID
|
11
13
|
|
12
|
-
|
14
|
+
warnings.filterwarnings("ignore", module="coffea.*")
|
15
|
+
|
16
|
+
__all__ = ["ParticleOrigin", "PhotonID", "__version__"]
|
@@ -0,0 +1,123 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from enum import IntEnum
|
4
|
+
|
5
|
+
|
6
|
+
class ParticleType(IntEnum):
|
7
|
+
"""
|
8
|
+
Taken from `ATLAS Truth Utilities for ParticleType <https://gitlab.cern.ch/atlas/athena/-/blob/74f43ff0910edb2a2bd3778880ccbdad648dc037/Generators/TruthUtils/TruthUtils/TruthClasses.h#L8-49>`_.
|
9
|
+
"""
|
10
|
+
|
11
|
+
Unknown = 0
|
12
|
+
UnknownElectron = 1
|
13
|
+
IsoElectron = 2
|
14
|
+
NonIsoElectron = 3
|
15
|
+
BkgElectron = 4
|
16
|
+
UnknownMuon = 5
|
17
|
+
IsoMuon = 6
|
18
|
+
NonIsoMuon = 7
|
19
|
+
BkgMuon = 8
|
20
|
+
UnknownTau = 9
|
21
|
+
IsoTau = 10
|
22
|
+
NonIsoTau = 11
|
23
|
+
BkgTau = 12
|
24
|
+
UnknownPhoton = 13
|
25
|
+
IsoPhoton = 14
|
26
|
+
NonIsoPhoton = 15
|
27
|
+
BkgPhoton = 16
|
28
|
+
Hadron = 17
|
29
|
+
Neutrino = 18
|
30
|
+
NuclFrag = 19
|
31
|
+
NonPrimary = 20
|
32
|
+
GenParticle = 21
|
33
|
+
SUSYParticle = 22
|
34
|
+
OtherBSMParticle = 39
|
35
|
+
BBbarMesonPart = 23
|
36
|
+
BottomMesonPart = 24
|
37
|
+
CCbarMesonPart = 25
|
38
|
+
CharmedMesonPart = 26
|
39
|
+
BottomBaryonPart = 27
|
40
|
+
CharmedBaryonPart = 28
|
41
|
+
StrangeBaryonPart = 29
|
42
|
+
LightBaryonPart = 30
|
43
|
+
StrangeMesonPart = 31
|
44
|
+
LightMesonPart = 32
|
45
|
+
BJet = 33
|
46
|
+
CJet = 34
|
47
|
+
LJet = 35
|
48
|
+
GJet = 36
|
49
|
+
TauJet = 37
|
50
|
+
UnknownJet = 38
|
51
|
+
|
52
|
+
|
53
|
+
class ParticleOrigin(IntEnum):
|
54
|
+
"""
|
55
|
+
Taken from `ATLAS Truth Utilities for ParticleOrigin <https://gitlab.cern.ch/atlas/athena/-/blob/74f43ff0910edb2a2bd3778880ccbdad648dc037/Generators/TruthUtils/TruthUtils/TruthClasses.h#L51-103>`_.
|
56
|
+
"""
|
57
|
+
|
58
|
+
NonDefined = 0
|
59
|
+
SingleElec = 1
|
60
|
+
SingleMuon = 2
|
61
|
+
SinglePhot = 3
|
62
|
+
SingleTau = 4
|
63
|
+
PhotonConv = 5
|
64
|
+
DalitzDec = 6
|
65
|
+
ElMagProc = 7
|
66
|
+
Mu = 8
|
67
|
+
TauLep = 9
|
68
|
+
top = 10
|
69
|
+
QuarkWeakDec = 11
|
70
|
+
WBoson = 12
|
71
|
+
ZBoson = 13
|
72
|
+
Higgs = 14
|
73
|
+
HiggsMSSM = 15
|
74
|
+
HeavyBoson = 16
|
75
|
+
WBosonLRSM = 17
|
76
|
+
NuREle = 18
|
77
|
+
NuRMu = 19
|
78
|
+
NuRTau = 20
|
79
|
+
LQ = 21
|
80
|
+
SUSY = 22
|
81
|
+
OtherBSM = 46
|
82
|
+
LightMeson = 23
|
83
|
+
StrangeMeson = 24
|
84
|
+
CharmedMeson = 25
|
85
|
+
BottomMeson = 26
|
86
|
+
CCbarMeson = 27
|
87
|
+
JPsi = 28
|
88
|
+
BBbarMeson = 29
|
89
|
+
LightBaryon = 30
|
90
|
+
StrangeBaryon = 31
|
91
|
+
CharmedBaryon = 32
|
92
|
+
BottomBaryon = 33
|
93
|
+
PionDecay = 34
|
94
|
+
KaonDecay = 35
|
95
|
+
BremPhot = 36
|
96
|
+
PromptPhot = 37
|
97
|
+
UndrPhot = 38
|
98
|
+
ISRPhot = 39
|
99
|
+
FSRPhot = 40
|
100
|
+
NucReact = 41
|
101
|
+
PiZero = 42
|
102
|
+
DiBoson = 43
|
103
|
+
ZorHeavyBoson = 44
|
104
|
+
MultiBoson = 47
|
105
|
+
QCD = 45
|
106
|
+
|
107
|
+
|
108
|
+
class PhotonID(IntEnum):
|
109
|
+
"""
|
110
|
+
Taken from the `EGamma Identification CP group's twiki <https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/EGammaIdentificationRun2#Photon_isEM_word>`_.
|
111
|
+
"""
|
112
|
+
|
113
|
+
Rhad = 10 # ClusterHadronicLeakage_Photon
|
114
|
+
E277 = 11 # ClusterMiddleEnergy_Photon
|
115
|
+
Reta = 12 # ClusterMiddleEratio37_Photon
|
116
|
+
Rphi = 13 # ClusterMiddleEratio33_Photon
|
117
|
+
Weta2 = 14 # ClusterMiddleWidth_Photon
|
118
|
+
f1 = 15 # ClusterStripsEratio_Photon
|
119
|
+
DeltaE = 17 # ClusterStripsDeltaE_Photon
|
120
|
+
Wstot = 18 # ClusterStripsWtot_Photon
|
121
|
+
fside = 19 # ClusterStripsFracm_Photon
|
122
|
+
Ws3 = 20 # ClusterStripsWeta1c_Photon
|
123
|
+
ERatio = 21 # ClusterStripsDEmaxs1_Photon
|
@@ -0,0 +1,241 @@
|
|
1
|
+
"""Mixins for the Ntuple schema"""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from functools import reduce
|
6
|
+
from operator import ior
|
7
|
+
|
8
|
+
import awkward
|
9
|
+
import particle
|
10
|
+
from coffea.nanoevents.methods import base, candidate, vector
|
11
|
+
from dask_awkward import dask_method
|
12
|
+
|
13
|
+
from atlas_schema.enums import PhotonID
|
14
|
+
from atlas_schema.typing_compat import Behavior
|
15
|
+
|
16
|
+
behavior: Behavior = {}
|
17
|
+
behavior.update(base.behavior)
|
18
|
+
# vector behavior is included in candidate behavior
|
19
|
+
behavior.update(candidate.behavior)
|
20
|
+
|
21
|
+
|
22
|
+
class NtupleEvents(behavior["NanoEvents"]): # type: ignore[misc, valid-type, name-defined]
|
23
|
+
def __repr__(self):
|
24
|
+
return f"<event {getattr(self, 'runNumber', '??')}:\
|
25
|
+
{getattr(self, 'eventNumber', '??')}:\
|
26
|
+
{getattr(self, 'mcChannelNumber', '??')}>"
|
27
|
+
|
28
|
+
|
29
|
+
behavior["NanoEvents"] = NtupleEvents
|
30
|
+
|
31
|
+
|
32
|
+
def _set_repr_name(classname):
|
33
|
+
def namefcn(_self):
|
34
|
+
return classname
|
35
|
+
|
36
|
+
behavior[("__typestr__", classname)] = classname[0].lower() + classname[1:]
|
37
|
+
behavior[classname].__repr__ = namefcn
|
38
|
+
|
39
|
+
|
40
|
+
@awkward.mixin_class(behavior)
|
41
|
+
class Weight(base.NanoCollection, base.Systematic): ...
|
42
|
+
|
43
|
+
|
44
|
+
_set_repr_name("Weight")
|
45
|
+
|
46
|
+
|
47
|
+
@awkward.mixin_class(behavior)
|
48
|
+
class Pass(base.NanoCollection, base.Systematic): ...
|
49
|
+
|
50
|
+
|
51
|
+
_set_repr_name("Pass")
|
52
|
+
|
53
|
+
behavior.update(
|
54
|
+
awkward._util.copy_behaviors("PtEtaPhiMLorentzVector", "Particle", behavior)
|
55
|
+
)
|
56
|
+
|
57
|
+
|
58
|
+
@awkward.mixin_class(behavior)
|
59
|
+
class Particle(vector.PtEtaPhiMLorentzVector):
|
60
|
+
"""Generic particle collection that has Lorentz vector properties
|
61
|
+
|
62
|
+
Also handles the following additional branches:
|
63
|
+
- '{obj}_select'
|
64
|
+
"""
|
65
|
+
|
66
|
+
@property
|
67
|
+
def mass(self):
|
68
|
+
r"""Invariant mass (+, -, -, -)
|
69
|
+
|
70
|
+
:math:`\sqrt{t^2-x^2-y^2-z^2}`
|
71
|
+
"""
|
72
|
+
return self["mass"] / 1.0e3
|
73
|
+
|
74
|
+
@dask_method
|
75
|
+
def passes(self, name):
|
76
|
+
return self[f"select_{name}"] == 1
|
77
|
+
|
78
|
+
@passes.dask
|
79
|
+
def passes(self, dask_array, name):
|
80
|
+
return dask_array[f"select_{name}"] == 1
|
81
|
+
|
82
|
+
# NB: fields with the name 'pt' take precedence over this
|
83
|
+
# @dask_property
|
84
|
+
# def pt(self):
|
85
|
+
# print('inside non-dask prop')
|
86
|
+
# return self["pt_NOSYS"]
|
87
|
+
|
88
|
+
# @pt.dask
|
89
|
+
# def pt(self, dask_array):
|
90
|
+
# branch = 'pt'
|
91
|
+
# print('inside dask prop')
|
92
|
+
# variation = dask_array._events().metadata.get("systematic", "NOSYS")
|
93
|
+
# with contextlib.suppress(Exception):
|
94
|
+
# return dask_array[f"{branch}_{variation}"]
|
95
|
+
|
96
|
+
# if variation != "NOSYS":
|
97
|
+
# with contextlib.suppress(Exception):
|
98
|
+
# return dask_array[f"{branch}_NOSYS"]
|
99
|
+
|
100
|
+
# return dask_array[branch]
|
101
|
+
|
102
|
+
|
103
|
+
_set_repr_name("Particle")
|
104
|
+
|
105
|
+
ParticleArray.ProjectionClass2D = vector.TwoVectorArray # noqa: F821
|
106
|
+
ParticleArray.ProjectionClass3D = vector.ThreeVectorArray # noqa: F821
|
107
|
+
ParticleArray.ProjectionClass4D = ParticleArray # noqa: F821
|
108
|
+
ParticleArray.MomentumClass = vector.LorentzVectorArray # noqa: F821
|
109
|
+
|
110
|
+
|
111
|
+
behavior.update(awkward._util.copy_behaviors("PolarTwoVector", "MissingET", behavior))
|
112
|
+
|
113
|
+
|
114
|
+
@awkward.mixin_class(behavior)
|
115
|
+
class MissingET(vector.PolarTwoVector, base.NanoCollection, base.Systematic):
|
116
|
+
@property
|
117
|
+
def r(self):
|
118
|
+
"""Distance from origin in XY plane"""
|
119
|
+
return self["met"]
|
120
|
+
|
121
|
+
|
122
|
+
_set_repr_name("MissingET")
|
123
|
+
|
124
|
+
MissingETArray.ProjectionClass2D = MissingETArray # noqa: F821
|
125
|
+
MissingETArray.ProjectionClass3D = vector.SphericalThreeVectorArray # noqa: F821
|
126
|
+
MissingETArray.ProjectionClass4D = vector.LorentzVectorArray # noqa: F821
|
127
|
+
MissingETArray.MomentumClass = MissingETArray # noqa: F821
|
128
|
+
|
129
|
+
behavior.update(awkward._util.copy_behaviors("Particle", "Photon", behavior))
|
130
|
+
|
131
|
+
|
132
|
+
@awkward.mixin_class(behavior)
|
133
|
+
class Photon(Particle, base.NanoCollection, base.Systematic):
|
134
|
+
@property
|
135
|
+
def mass(self):
|
136
|
+
"""Return zero mass for photon."""
|
137
|
+
return awkward.zeros_like(self.pt)
|
138
|
+
|
139
|
+
@property
|
140
|
+
def charge(self):
|
141
|
+
"""Return zero charge for photon."""
|
142
|
+
return awkward.zeros_like(self.pt)
|
143
|
+
|
144
|
+
@property
|
145
|
+
def isEM(self):
|
146
|
+
return self.isEM_syst.NOSYS == 0
|
147
|
+
|
148
|
+
def pass_isEM(self, words: list[PhotonID]):
|
149
|
+
# 0 is pass, 1 is fail
|
150
|
+
return (
|
151
|
+
self.isEM_syst.NOSYS & reduce(ior, (1 << word.value for word in words))
|
152
|
+
) == 0
|
153
|
+
|
154
|
+
|
155
|
+
_set_repr_name("Photon")
|
156
|
+
|
157
|
+
PhotonArray.ProjectionClass2D = vector.TwoVectorArray # noqa: F821
|
158
|
+
PhotonArray.ProjectionClass3D = vector.ThreeVectorArray # noqa: F821
|
159
|
+
PhotonArray.ProjectionClass4D = PhotonArray # noqa: F821
|
160
|
+
PhotonArray.MomentumClass = vector.LorentzVectorArray # noqa: F821
|
161
|
+
|
162
|
+
behavior.update(awkward._util.copy_behaviors("Particle", "Electron", behavior))
|
163
|
+
|
164
|
+
|
165
|
+
@awkward.mixin_class(behavior)
|
166
|
+
class Electron(Particle, base.NanoCollection, base.Systematic):
|
167
|
+
@property
|
168
|
+
def mass(self):
|
169
|
+
"""Electron mass in GeV"""
|
170
|
+
return particle.literals.e_minus.mass / 1.0e3
|
171
|
+
|
172
|
+
|
173
|
+
_set_repr_name("Electron")
|
174
|
+
|
175
|
+
ElectronArray.ProjectionClass2D = vector.TwoVectorArray # noqa: F821
|
176
|
+
ElectronArray.ProjectionClass3D = vector.ThreeVectorArray # noqa: F821
|
177
|
+
ElectronArray.ProjectionClass4D = ElectronArray # noqa: F821
|
178
|
+
ElectronArray.MomentumClass = vector.LorentzVectorArray # noqa: F821
|
179
|
+
|
180
|
+
behavior.update(awkward._util.copy_behaviors("Particle", "Muon", behavior))
|
181
|
+
|
182
|
+
|
183
|
+
@awkward.mixin_class(behavior)
|
184
|
+
class Muon(Particle, base.NanoCollection, base.Systematic):
|
185
|
+
@property
|
186
|
+
def mass(self):
|
187
|
+
"""Muon mass in GeV"""
|
188
|
+
return particle.literals.mu_minus.mass / 1.0e3
|
189
|
+
|
190
|
+
|
191
|
+
_set_repr_name("Muon")
|
192
|
+
|
193
|
+
MuonArray.ProjectionClass2D = vector.TwoVectorArray # noqa: F821
|
194
|
+
MuonArray.ProjectionClass3D = vector.ThreeVectorArray # noqa: F821
|
195
|
+
MuonArray.ProjectionClass4D = MuonArray # noqa: F821
|
196
|
+
MuonArray.MomentumClass = vector.LorentzVectorArray # noqa: F821
|
197
|
+
|
198
|
+
behavior.update(awkward._util.copy_behaviors("Particle", "Tau", behavior))
|
199
|
+
|
200
|
+
|
201
|
+
@awkward.mixin_class(behavior)
|
202
|
+
class Tau(Particle, base.NanoCollection, base.Systematic):
|
203
|
+
@property
|
204
|
+
def mass(self):
|
205
|
+
"""Tau mass in GeV"""
|
206
|
+
return particle.literals.tau_minus.mass / 1.0e3
|
207
|
+
|
208
|
+
|
209
|
+
_set_repr_name("Tau")
|
210
|
+
|
211
|
+
TauArray.ProjectionClass2D = vector.TwoVectorArray # noqa: F821
|
212
|
+
TauArray.ProjectionClass3D = vector.ThreeVectorArray # noqa: F821
|
213
|
+
TauArray.ProjectionClass4D = TauArray # noqa: F821
|
214
|
+
TauArray.MomentumClass = vector.LorentzVectorArray # noqa: F821
|
215
|
+
|
216
|
+
|
217
|
+
behavior.update(awkward._util.copy_behaviors("Particle", "Jet", behavior))
|
218
|
+
|
219
|
+
|
220
|
+
@awkward.mixin_class(behavior)
|
221
|
+
class Jet(Particle, base.NanoCollection, base.Systematic): ...
|
222
|
+
|
223
|
+
|
224
|
+
_set_repr_name("Jet")
|
225
|
+
|
226
|
+
JetArray.ProjectionClass2D = vector.TwoVectorArray # noqa: F821
|
227
|
+
JetArray.ProjectionClass3D = vector.ThreeVectorArray # noqa: F821
|
228
|
+
JetArray.ProjectionClass4D = JetArray # noqa: F821
|
229
|
+
JetArray.MomentumClass = vector.LorentzVectorArray # noqa: F821
|
230
|
+
|
231
|
+
__all__ = [
|
232
|
+
"Electron",
|
233
|
+
"Jet",
|
234
|
+
"MissingET",
|
235
|
+
"Muon",
|
236
|
+
"NtupleEvents",
|
237
|
+
"Particle",
|
238
|
+
"Pass",
|
239
|
+
"Photon",
|
240
|
+
"Weight",
|
241
|
+
]
|
@@ -5,15 +5,10 @@ Typing helpers.
|
|
5
5
|
from __future__ import annotations
|
6
6
|
|
7
7
|
import sys
|
8
|
-
from typing import
|
8
|
+
from typing import Annotated
|
9
9
|
|
10
10
|
import awkward
|
11
11
|
|
12
|
-
if sys.version_info >= (3, 9):
|
13
|
-
from typing import Annotated
|
14
|
-
else:
|
15
|
-
from typing_extensions import Annotated
|
16
|
-
|
17
12
|
if sys.version_info >= (3, 10):
|
18
13
|
from typing import TypeAlias
|
19
14
|
else:
|
@@ -24,6 +19,6 @@ if sys.version_info >= (3, 11):
|
|
24
19
|
else:
|
25
20
|
from typing_extensions import Self
|
26
21
|
|
27
|
-
Behavior: TypeAlias =
|
22
|
+
Behavior: TypeAlias = dict[str, type[awkward.Record]]
|
28
23
|
|
29
24
|
__all__ = ("Annotated", "Behavior", "Self")
|
@@ -1,116 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from enum import IntEnum
|
4
|
-
|
5
|
-
from atlas_schema.typing_compat import Annotated
|
6
|
-
|
7
|
-
|
8
|
-
# https://gitlab.cern.ch/atlas/athena/-/blob/74f43ff0910edb2a2bd3778880ccbdad648dc037/Generators/TruthUtils/TruthUtils/TruthClasses.h#L51-103
|
9
|
-
class ParticleType(IntEnum):
|
10
|
-
Unknown: Annotated[int, "Unknown"] = 0
|
11
|
-
UnknownElectron: Annotated[int, "UnknownElectron"] = 1
|
12
|
-
IsoElectron: Annotated[int, "IsoElectron"] = 2
|
13
|
-
NonIsoElectron: Annotated[int, "NonIsoElectron"] = 3
|
14
|
-
BkgElectron: Annotated[int, "BkgElectron"] = 4
|
15
|
-
UnknownMuon: Annotated[int, "UnknownMuon"] = 5
|
16
|
-
IsoMuon: Annotated[int, "IsoMuon"] = 6
|
17
|
-
NonIsoMuon: Annotated[int, "NonIsoMuon"] = 7
|
18
|
-
BkgMuon: Annotated[int, "BkgMuon"] = 8
|
19
|
-
UnknownTau: Annotated[int, "UnknownTau"] = 9
|
20
|
-
IsoTau: Annotated[int, "IsoTau"] = 10
|
21
|
-
NonIsoTau: Annotated[int, "NonIsoTau"] = 11
|
22
|
-
BkgTau: Annotated[int, "BkgTau"] = 12
|
23
|
-
UnknownPhoton: Annotated[int, "UnknownPhoton"] = 13
|
24
|
-
IsoPhoton: Annotated[int, "IsoPhoton"] = 14
|
25
|
-
NonIsoPhoton: Annotated[int, "NonIsoPhoton"] = 15
|
26
|
-
BkgPhoton: Annotated[int, "BkgPhoton"] = 16
|
27
|
-
Hadron: Annotated[int, "Hadron"] = 17
|
28
|
-
Neutrino: Annotated[int, "Neutrino"] = 18
|
29
|
-
NuclFrag: Annotated[int, "NuclFrag"] = 19
|
30
|
-
NonPrimary: Annotated[int, "NonPrimary"] = 20
|
31
|
-
GenParticle: Annotated[int, "GenParticle"] = 21
|
32
|
-
SUSYParticle: Annotated[int, "SUSYParticle"] = 22
|
33
|
-
OtherBSMParticle: Annotated[int, "OtherBSMParticle"] = 39
|
34
|
-
BBbarMesonPart: Annotated[int, "BBbarMesonPart"] = 23
|
35
|
-
BottomMesonPart: Annotated[int, "BottomMesonPart"] = 24
|
36
|
-
CCbarMesonPart: Annotated[int, "CCbarMesonPart"] = 25
|
37
|
-
CharmedMesonPart: Annotated[int, "CharmedMesonPart"] = 26
|
38
|
-
BottomBaryonPart: Annotated[int, "BottomBaryonPart"] = 27
|
39
|
-
CharmedBaryonPart: Annotated[int, "CharmedBaryonPart"] = 28
|
40
|
-
StrangeBaryonPart: Annotated[int, "StrangeBaryonPart"] = 29
|
41
|
-
LightBaryonPart: Annotated[int, "LightBaryonPart"] = 30
|
42
|
-
StrangeMesonPart: Annotated[int, "StrangeMesonPart"] = 31
|
43
|
-
LightMesonPart: Annotated[int, "LightMesonPart"] = 32
|
44
|
-
BJet: Annotated[int, "BJet"] = 33
|
45
|
-
CJet: Annotated[int, "CJet"] = 34
|
46
|
-
LJet: Annotated[int, "LJet"] = 35
|
47
|
-
GJet: Annotated[int, "GJet"] = 36
|
48
|
-
TauJet: Annotated[int, "TauJet"] = 37
|
49
|
-
UnknownJet: Annotated[int, "UnknownJet"] = 38
|
50
|
-
|
51
|
-
|
52
|
-
# https://gitlab.cern.ch/atlas/athena/-/blob/74f43ff0910edb2a2bd3778880ccbdad648dc037/Generators/TruthUtils/TruthUtils/TruthClasses.h#L51-103
|
53
|
-
class ParticleOrigin(IntEnum):
|
54
|
-
NonDefined: Annotated[int, "NonDefined"] = 0
|
55
|
-
SingleElec: Annotated[int, "SingleElec"] = 1
|
56
|
-
SingleMuon: Annotated[int, "SingleMuon"] = 2
|
57
|
-
SinglePhot: Annotated[int, "SinglePhot"] = 3
|
58
|
-
SingleTau: Annotated[int, "SingleTau"] = 4
|
59
|
-
PhotonConv: Annotated[int, "PhotonConv"] = 5
|
60
|
-
DalitzDec: Annotated[int, "DalitzDec"] = 6
|
61
|
-
ElMagProc: Annotated[int, "ElMagProc"] = 7
|
62
|
-
Mu: Annotated[int, "Mu"] = 8
|
63
|
-
TauLep: Annotated[int, "TauLep"] = 9
|
64
|
-
top: Annotated[int, "top"] = 10
|
65
|
-
QuarkWeakDec: Annotated[int, "QuarkWeakDec"] = 11
|
66
|
-
WBoson: Annotated[int, "WBoson"] = 12
|
67
|
-
ZBoson: Annotated[int, "ZBoson"] = 13
|
68
|
-
Higgs: Annotated[int, "Higgs"] = 14
|
69
|
-
HiggsMSSM: Annotated[int, "HiggsMSSM"] = 15
|
70
|
-
HeavyBoson: Annotated[int, "HeavyBoson"] = 16
|
71
|
-
WBosonLRSM: Annotated[int, "WBosonLRSM"] = 17
|
72
|
-
NuREle: Annotated[int, "NuREle"] = 18
|
73
|
-
NuRMu: Annotated[int, "NuRMu"] = 19
|
74
|
-
NuRTau: Annotated[int, "NuRTau"] = 20
|
75
|
-
LQ: Annotated[int, "LQ"] = 21
|
76
|
-
SUSY: Annotated[int, "SUSY"] = 22
|
77
|
-
OtherBSM: Annotated[int, "OtherBSM"] = 46
|
78
|
-
LightMeson: Annotated[int, "LightMeson"] = 23
|
79
|
-
StrangeMeson: Annotated[int, "StrangeMeson"] = 24
|
80
|
-
CharmedMeson: Annotated[int, "CharmedMeson"] = 25
|
81
|
-
BottomMeson: Annotated[int, "BottomMeson"] = 26
|
82
|
-
CCbarMeson: Annotated[int, "CCbarMeson"] = 27
|
83
|
-
JPsi: Annotated[int, "JPsi"] = 28
|
84
|
-
BBbarMeson: Annotated[int, "BBbarMeson"] = 29
|
85
|
-
LightBaryon: Annotated[int, "LightBaryon"] = 30
|
86
|
-
StrangeBaryon: Annotated[int, "StrangeBaryon"] = 31
|
87
|
-
CharmedBaryon: Annotated[int, "CharmedBaryon"] = 32
|
88
|
-
BottomBaryon: Annotated[int, "BottomBaryon"] = 33
|
89
|
-
PionDecay: Annotated[int, "PionDecay"] = 34
|
90
|
-
KaonDecay: Annotated[int, "KaonDecay"] = 35
|
91
|
-
BremPhot: Annotated[int, "BremPhot"] = 36
|
92
|
-
PromptPhot: Annotated[int, "PromptPhot"] = 37
|
93
|
-
UndrPhot: Annotated[int, "UndrPhot"] = 38
|
94
|
-
ISRPhot: Annotated[int, "ISRPhot"] = 39
|
95
|
-
FSRPhot: Annotated[int, "FSRPhot"] = 40
|
96
|
-
NucReact: Annotated[int, "NucReact"] = 41
|
97
|
-
PiZero: Annotated[int, "PiZero"] = 42
|
98
|
-
DiBoson: Annotated[int, "DiBoson"] = 43
|
99
|
-
ZorHeavyBoson: Annotated[int, "ZorHeavyBoson"] = 44
|
100
|
-
MultiBoson: Annotated[int, "MultiBoson"] = 47
|
101
|
-
QCD: Annotated[int, "QCD"] = 45
|
102
|
-
|
103
|
-
|
104
|
-
# https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/EGammaIdentificationRun2#Photon_isEM_word
|
105
|
-
class PhotonID(IntEnum):
|
106
|
-
Rhad: Annotated[int, "ClusterHadronicLeakage_Photon"] = 10
|
107
|
-
E277: Annotated[int, "ClusterMiddleEnergy_Photon"] = 11
|
108
|
-
Reta: Annotated[int, "ClusterMiddleEratio37_Photon"] = 12
|
109
|
-
Rphi: Annotated[int, "ClusterMiddleEratio33_Photon"] = 13
|
110
|
-
Weta2: Annotated[int, "ClusterMiddleWidth_Photon"] = 14
|
111
|
-
f1: Annotated[int, "ClusterStripsEratio_Photon"] = 15
|
112
|
-
DeltaE: Annotated[int, "ClusterStripsDeltaE_Photon"] = 17
|
113
|
-
Wstot: Annotated[int, "ClusterStripsWtot_Photon"] = 18
|
114
|
-
fside: Annotated[int, "ClusterStripsFracm_Photon"] = 19
|
115
|
-
Ws3: Annotated[int, "ClusterStripsWeta1c_Photon"] = 20
|
116
|
-
ERatio: Annotated[int, "ClusterStripsDEmaxs1_Photon"] = 21
|
@@ -1,181 +0,0 @@
|
|
1
|
-
"""Mixins for the Ntuple schema"""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from functools import reduce
|
6
|
-
from operator import ior
|
7
|
-
|
8
|
-
import awkward
|
9
|
-
from coffea.nanoevents.methods import base, candidate, vector
|
10
|
-
from dask_awkward import dask_method
|
11
|
-
|
12
|
-
from atlas_schema.enums import PhotonID
|
13
|
-
from atlas_schema.typing_compat import Behavior
|
14
|
-
|
15
|
-
behavior: Behavior = {}
|
16
|
-
behavior.update(base.behavior)
|
17
|
-
# vector behavior is included in candidate behavior
|
18
|
-
behavior.update(candidate.behavior)
|
19
|
-
|
20
|
-
|
21
|
-
class NtupleEvents(behavior["NanoEvents"]): # type: ignore[misc, valid-type, name-defined]
|
22
|
-
def __repr__(self):
|
23
|
-
return f"<event {getattr(self,'runNumber','??')}:\
|
24
|
-
{getattr(self,'eventNumber','??')}:\
|
25
|
-
{getattr(self,'mcChannelNumber','??')}>"
|
26
|
-
|
27
|
-
|
28
|
-
behavior["NanoEvents"] = NtupleEvents
|
29
|
-
|
30
|
-
|
31
|
-
def _set_repr_name(classname):
|
32
|
-
def namefcn(_self):
|
33
|
-
return classname
|
34
|
-
|
35
|
-
behavior[("__typestr__", classname)] = classname[0].lower() + classname[1:]
|
36
|
-
behavior[classname].__repr__ = namefcn
|
37
|
-
|
38
|
-
|
39
|
-
@awkward.mixin_class(behavior)
|
40
|
-
class Weight(base.NanoCollection, base.Systematic): ...
|
41
|
-
|
42
|
-
|
43
|
-
_set_repr_name("Weight")
|
44
|
-
|
45
|
-
|
46
|
-
@awkward.mixin_class(behavior)
|
47
|
-
class Pass(base.NanoCollection, base.Systematic): ...
|
48
|
-
|
49
|
-
|
50
|
-
_set_repr_name("Pass")
|
51
|
-
|
52
|
-
|
53
|
-
@awkward.mixin_class(behavior)
|
54
|
-
class Particle(vector.PtEtaPhiMLorentzVector):
|
55
|
-
"""Generic particle collection that has Lorentz vector properties
|
56
|
-
|
57
|
-
Also handles the following additional branches:
|
58
|
-
- '{obj}_select'
|
59
|
-
"""
|
60
|
-
|
61
|
-
@property
|
62
|
-
def mass(self):
|
63
|
-
r"""Invariant mass (+, -, -, -)
|
64
|
-
|
65
|
-
:math:`\sqrt{t^2-x^2-y^2-z^2}`
|
66
|
-
"""
|
67
|
-
return self["mass"] / 1.0e3
|
68
|
-
|
69
|
-
@dask_method
|
70
|
-
def passes(self, name):
|
71
|
-
return self[f"select_{name}"] == 1
|
72
|
-
|
73
|
-
@passes.dask
|
74
|
-
def passes(self, dask_array, name):
|
75
|
-
return dask_array[f"select_{name}"] == 1
|
76
|
-
|
77
|
-
# NB: fields with the name 'pt' take precedence over this
|
78
|
-
# @dask_property
|
79
|
-
# def pt(self):
|
80
|
-
# print('inside non-dask prop')
|
81
|
-
# return self["pt_NOSYS"]
|
82
|
-
|
83
|
-
# @pt.dask
|
84
|
-
# def pt(self, dask_array):
|
85
|
-
# branch = 'pt'
|
86
|
-
# print('inside dask prop')
|
87
|
-
# variation = dask_array._events().metadata.get("systematic", "NOSYS")
|
88
|
-
# with contextlib.suppress(Exception):
|
89
|
-
# return dask_array[f"{branch}_{variation}"]
|
90
|
-
|
91
|
-
# if variation != "NOSYS":
|
92
|
-
# with contextlib.suppress(Exception):
|
93
|
-
# return dask_array[f"{branch}_NOSYS"]
|
94
|
-
|
95
|
-
# return dask_array[branch]
|
96
|
-
|
97
|
-
|
98
|
-
_set_repr_name("Particle")
|
99
|
-
|
100
|
-
|
101
|
-
@awkward.mixin_class(behavior)
|
102
|
-
class MasslessParticle(Particle, base.NanoCollection):
|
103
|
-
@property
|
104
|
-
def mass(self):
|
105
|
-
r"""Invariant mass (+, -, -, -)
|
106
|
-
|
107
|
-
:math:`\sqrt{t^2-x^2-y^2-z^2}`
|
108
|
-
"""
|
109
|
-
return 0.0 * self.pt
|
110
|
-
|
111
|
-
|
112
|
-
_set_repr_name("MasslessParticle")
|
113
|
-
|
114
|
-
|
115
|
-
@awkward.mixin_class(behavior)
|
116
|
-
class MissingET(MasslessParticle, base.NanoCollection, base.Systematic):
|
117
|
-
@property
|
118
|
-
def pt(self):
|
119
|
-
"""Alias for `r`"""
|
120
|
-
return self["met"] / 1.0e3
|
121
|
-
|
122
|
-
@property
|
123
|
-
def eta(self):
|
124
|
-
r"""Pseudorapidity
|
125
|
-
|
126
|
-
:math:`-\ln\tan(\theta/2) = \text{arcsinh}(z/r)`
|
127
|
-
"""
|
128
|
-
return 0.0 * self.pt
|
129
|
-
|
130
|
-
|
131
|
-
_set_repr_name("MissingET")
|
132
|
-
|
133
|
-
|
134
|
-
@awkward.mixin_class(behavior)
|
135
|
-
class Photon(MasslessParticle, base.NanoCollection, base.Systematic):
|
136
|
-
@property
|
137
|
-
def isEM(self):
|
138
|
-
return self.isEM_syst.NOSYS == 0
|
139
|
-
|
140
|
-
def pass_isEM(self, words: list[PhotonID]):
|
141
|
-
# 0 is pass, 1 is fail
|
142
|
-
return (
|
143
|
-
self.isEM_syst.NOSYS & reduce(ior, (1 << word.value for word in words))
|
144
|
-
) == 0
|
145
|
-
|
146
|
-
|
147
|
-
_set_repr_name("Photon")
|
148
|
-
|
149
|
-
|
150
|
-
@awkward.mixin_class(behavior)
|
151
|
-
class Electron(MasslessParticle, base.NanoCollection, base.Systematic): ...
|
152
|
-
|
153
|
-
|
154
|
-
_set_repr_name("Electron")
|
155
|
-
|
156
|
-
|
157
|
-
@awkward.mixin_class(behavior)
|
158
|
-
class Muon(MasslessParticle, base.NanoCollection, base.Systematic): ...
|
159
|
-
|
160
|
-
|
161
|
-
_set_repr_name("Muon")
|
162
|
-
|
163
|
-
|
164
|
-
@awkward.mixin_class(behavior)
|
165
|
-
class Jet(Particle, base.NanoCollection, base.Systematic): ...
|
166
|
-
|
167
|
-
|
168
|
-
_set_repr_name("Jet")
|
169
|
-
|
170
|
-
|
171
|
-
__all__ = [
|
172
|
-
"NtupleEvents",
|
173
|
-
"Weight",
|
174
|
-
"Pass",
|
175
|
-
"MissingET",
|
176
|
-
"Particle",
|
177
|
-
"Photon",
|
178
|
-
"Electron",
|
179
|
-
"Muon",
|
180
|
-
"Jet",
|
181
|
-
]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|