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.
@@ -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.3
1
+ Metadata-Version: 2.4
2
2
  Name: atlas-schema
3
- Version: 0.1.0
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.8
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-copybutton; extra == 'docs'
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.0
252
+ # atlas-schema v0.2.1
248
253
 
249
254
  [![Actions Status][actions-badge]][actions-link]
250
255
  [![Documentation Status][rtd-badge]][rtd-link]
@@ -1,4 +1,4 @@
1
- # atlas-schema v0.1.0
1
+ # atlas-schema v0.2.1
2
2
 
3
3
  [![Actions Status][actions-badge]][actions-link]
4
4
  [![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.8"
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
- "sphinx_copybutton",
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.8"
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.8"
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
- __all__ = ["__version__", "ParticleOrigin", "PhotonID"]
14
+ warnings.filterwarnings("ignore", module="coffea.*")
15
+
16
+ __all__ = ["ParticleOrigin", "PhotonID", "__version__"]
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1.0'
16
- __version_tuple__ = version_tuple = (0, 1, 0)
15
+ __version__ = version = '0.2.1'
16
+ __version_tuple__ = version_tuple = (0, 2, 1)
@@ -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 Dict, Type
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 = Dict[str, Type[awkward.Record]]
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