atlas-ftag-tools 0.1.14__py3-none-any.whl → 0.1.16__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atlas-ftag-tools
3
- Version: 0.1.14
3
+ Version: 0.1.16
4
4
  Summary: ATLAS Flavour Tagging Tools
5
5
  Author: Sam Van Stroud, Philipp Gadow
6
6
  License: MIT
@@ -102,6 +102,19 @@ By default the working points are printed to the terminal, but you can save the
102
102
 
103
103
  See `wps --help` for more options and information.
104
104
 
105
+ ## Calculate efficiency at discriminant cut
106
+
107
+ The same script can be used to calculate the efficiency and rejection values at a given discriminant cut value.
108
+ The script `working_points.py` can be run after intalling this package as follows
109
+
110
+ ```
111
+ wps \
112
+ --ttbar "path/to/ttbar/*.h5" \
113
+ --tagger GN120220509 \
114
+ --fx 0.1
115
+ --disc_cuts 1.0 1.5
116
+ ```
117
+ The `--tagger`, `--fx`, and `--outfile` follow the same procedure as in the 'Calculate WPs' script as described above.
105
118
 
106
119
  ## H5 Utils
107
120
 
@@ -1,4 +1,4 @@
1
- ftag/__init__.py,sha256=cFcVSJvJIJEYUcFPAaSn0xuKE5lytiF-E3jcbnG6Hpo,629
1
+ ftag/__init__.py,sha256=PN9ZbZHVfxreetH3HnhEbZf1G-J4Up-5si-dQ4rrezg,629
2
2
  ftag/cuts.py,sha256=RYAfK3MkEhYhlKQFWQTKu72ZrUwlExFeT8IWLSIgeTU,2798
3
3
  ftag/flavour.py,sha256=BLifDbJCoszPzgrU5X3Txff9fTMuVGEjUeU0OtOfllc,2701
4
4
  ftag/flavours.yaml,sha256=9ifKyz1_VoHlOaWuf3JEqMLSYyLFedYJf9x1D6dCTnM,5335
@@ -7,17 +7,17 @@ ftag/mock.py,sha256=T2YGeuCkgDEzKPVYwU7Vnq5TNIDrx9eIDVrAQt8s0Mw,4865
7
7
  ftag/region.py,sha256=-WxdC0Gy9zz3zEJ2pN779RcxXPG-QEROuMwMoP-Qs0g,353
8
8
  ftag/sample.py,sha256=cd-rNHsEY2aWSZdy3V4bOKi3aDMtHTCpjXS8Hl9zwUY,2597
9
9
  ftag/transform.py,sha256=uEGGJSnqoKOzLYQv650XdK_kDNw4Aw-5dc60z9Dp_y0,3963
10
- ftag/vds.py,sha256=l2JttxscusBWUSog8SjSkhPn-4lhOLzZmLaqe4hGiS0,2929
10
+ ftag/vds.py,sha256=PG-NCJdpmK5X2l8i8YWBHx6CY8vosShfqp36facKaYM,3383
11
11
  ftag/hdf5/__init__.py,sha256=pZva2TI8nvpBwoawcm_ucVZbGsQJW_u8GGoJgt5mKEw,354
12
12
  ftag/hdf5/h5move.py,sha256=1XxiJZ96DYSp8JF0ry3lbRSQaFX72DjUV5vBA6hYw-0,873
13
- ftag/hdf5/h5reader.py,sha256=D3a9l4jVnvJPlp9fprvnlp2arHPRl_1PT5SEDFO0i_U,13390
13
+ ftag/hdf5/h5reader.py,sha256=et-_LXt942xegqc14bPapUgIO7MUfC2m04uJslLkXxI,13579
14
14
  ftag/hdf5/h5split.py,sha256=BlhpsUlqBSDCjVRWuyEq1OImyzwp7VyVkDrCz7pvQKc,2508
15
15
  ftag/hdf5/h5utils.py,sha256=wjbAmFY5GoFkWW_AvEKTPbwYMFroHKKFuIcehd91dhM,3222
16
16
  ftag/hdf5/h5writer.py,sha256=5jm3vSk4m77lFSUyWm-i_y_USzQRVoKpLL8F_cii65Q,4826
17
- ftag/wps/discriminant.py,sha256=CnRr1GwfT12GYEI8i-iJxmBLavZN6ZAcv2NIeBP-Xqc,2258
18
- ftag/wps/working_points.py,sha256=BdVpAh9nPyb2B90Pr48RD_7A17_PzofIojS1iHs5th0,5601
19
- atlas_ftag_tools-0.1.14.dist-info/METADATA,sha256=3pMQRYJl1OiE2MGMzYM_PMnb8B6D14I7ALfJEnIBMdI,4591
20
- atlas_ftag_tools-0.1.14.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
21
- atlas_ftag_tools-0.1.14.dist-info/entry_points.txt,sha256=LfVLsZHQolqbPnwPgtmc5IQTh527BKkN2v-IpXWTNHw,137
22
- atlas_ftag_tools-0.1.14.dist-info/top_level.txt,sha256=qiYQuKcAvMim-31FwkT3MTQu7WQm0s58tPAia5KKWqs,5
23
- atlas_ftag_tools-0.1.14.dist-info/RECORD,,
17
+ ftag/wps/discriminant.py,sha256=0YmI3-ieSWReO_uY4-3Sc_85hLVpoCHQ7LfuU1SC_Sg,2318
18
+ ftag/wps/working_points.py,sha256=pLoe8RaVmbtiGM9TxMtWocMohBWrY6JcMCLE_e3XtVY,8033
19
+ atlas_ftag_tools-0.1.16.dist-info/METADATA,sha256=H547FpfWZ6plg5PXm7E9SJhppKGWM8iKM_EpFJaUNJs,5064
20
+ atlas_ftag_tools-0.1.16.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
21
+ atlas_ftag_tools-0.1.16.dist-info/entry_points.txt,sha256=LfVLsZHQolqbPnwPgtmc5IQTh527BKkN2v-IpXWTNHw,137
22
+ atlas_ftag_tools-0.1.16.dist-info/top_level.txt,sha256=qiYQuKcAvMim-31FwkT3MTQu7WQm0s58tPAia5KKWqs,5
23
+ atlas_ftag_tools-0.1.16.dist-info/RECORD,,
ftag/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """atlas-ftag-tools - Common tools for ATLAS flavour tagging software."""
2
2
  from __future__ import annotations
3
3
 
4
- __version__ = "v0.1.14"
4
+ __version__ = "v0.1.16"
5
5
 
6
6
 
7
7
  from ftag import hdf5
ftag/hdf5/h5reader.py CHANGED
@@ -354,6 +354,11 @@ class H5Reader:
354
354
  int
355
355
  Estimated number of jets available after selection cuts, rounded down.
356
356
  """
357
+ # reset rngs to ensure same jets are used for each sample
358
+ self.rng = np.random.default_rng(42)
359
+ for r in self.readers:
360
+ r.rng = np.random.default_rng(42)
361
+
357
362
  # if equal jets is True, available jets is based on the smallest sample
358
363
  if self.equal_jets:
359
364
  num_jets = []
ftag/vds.py CHANGED
@@ -62,10 +62,24 @@ def create_virtual_file(
62
62
  if not overwrite and out_fname.is_file():
63
63
  return out_fname
64
64
 
65
+ # identify common groups across all files
66
+ common_groups: set[str] = set()
67
+ for fname in fnames:
68
+ with h5py.File(fname) as f:
69
+ groups = set(f.keys())
70
+ common_groups = groups if not common_groups else common_groups.intersection(groups)
71
+
72
+ if not common_groups:
73
+ raise ValueError("No common groups found across files")
74
+
75
+ print("Common groups found:")
76
+ for group in common_groups:
77
+ print(f" {group}")
78
+
65
79
  # create virtual file
66
80
  out_fname.parent.mkdir(exist_ok=True)
67
81
  with h5py.File(out_fname, "w") as f:
68
- for group in h5py.File(fnames[0]):
82
+ for group in common_groups:
69
83
  layout = get_virtual_layout(fnames, group)
70
84
  f.create_virtual_dataset(group, layout)
71
85
  attrs_dict: dict = {}
ftag/wps/discriminant.py CHANGED
@@ -58,6 +58,8 @@ def get_discriminant(
58
58
  np.ndarray
59
59
  Array of discriminant values.
60
60
  """
61
+ if not isinstance(fx, tuple | list):
62
+ fx = (fx,)
61
63
  tagger_funcs = {
62
64
  "bjets": btag_discriminant,
63
65
  "cjets": ctag_discriminant,
@@ -36,7 +36,6 @@ def parse_args(args):
36
36
  nargs="+",
37
37
  type=float,
38
38
  help="efficiency working point(s). If -r is specified, values should be 1/efficiency",
39
- default=[60, 70, 77, 85],
40
39
  )
41
40
  parser.add_argument(
42
41
  "-t",
@@ -69,6 +68,13 @@ def parse_args(args):
69
68
  choices=["ujets", "cjets", "bjets", "hbb", "hcc", "top", "qcd"],
70
69
  help="use rejection of specified background class to determine working points",
71
70
  )
71
+ parser.add_argument(
72
+ "-d",
73
+ "--disc_cuts",
74
+ nargs="+",
75
+ type=float,
76
+ help="D_x value(s) to calculate efficiency at",
77
+ )
72
78
  parser.add_argument(
73
79
  "-n",
74
80
  "--num_jets",
@@ -116,8 +122,6 @@ def get_eff_rej(jets, disc, wp, flavs):
116
122
 
117
123
 
118
124
  def get_working_points(args=None):
119
- args = parse_args(args)
120
-
121
125
  if args.xbb:
122
126
  if len(args.fx) != 2 * len(args.tagger):
123
127
  raise ValueError("For Xbb tagging, each tagger must have two fx values")
@@ -180,10 +184,76 @@ def get_working_points(args=None):
180
184
  return out
181
185
 
182
186
 
183
- def main():
184
- out = get_working_points()
187
+ def get_rej_eff_at_disc(jets, tagger, signal, fx, disc_cuts):
188
+ disc = get_discriminant(jets, tagger, signal, fx)
189
+ d = {}
190
+ flavs = Flavours.by_category("single-btag")
191
+ for dcut in disc_cuts:
192
+ d[str(dcut)] = {"eff": {}, "rej": {}}
193
+ for f in flavs:
194
+ e_discs = disc[f.cuts(jets).idx]
195
+ eff = sum(e_discs > dcut) / len(e_discs)
196
+ d[str(dcut)]["eff"][str(f)] = float(f"{eff:.3g}")
197
+ d[str(dcut)]["rej"][str(f)] = 1 / float(f"{eff:.3g}")
198
+ return d
199
+
200
+
201
+ def get_efficiencies(args=None):
202
+ if len(args.tagger) != len(args.fx):
203
+ raise ValueError("Must provide fb/fc for each tagger")
204
+
205
+ fx_values = [(fx,) for fx in args.fx]
206
+ # setup cuts and variables
207
+ flavs = Flavours.by_category("single-btag")
208
+ default_cuts = Cuts.from_list(["eta > -2.5", "eta < 2.5"])
209
+ ttbar_cuts = Cuts.from_list(args.ttbar_cuts) + default_cuts
210
+ zprime_cuts = Cuts.from_list(args.zprime_cuts) + default_cuts
211
+ all_vars = next(iter(flavs)).cuts.variables
212
+ for tagger in args.tagger:
213
+ all_vars += [f"{tagger}_{f.px}" for f in flavs if "tau" not in f.px]
214
+
215
+ # load jets
216
+ reader = H5Reader(args.ttbar)
217
+ jets = reader.load({"jets": all_vars}, args.num_jets, cuts=ttbar_cuts)["jets"]
218
+ if args.zprime:
219
+ zp_reader = H5Reader(args.zprime)
220
+ zp_jets = zp_reader.load({"jets": all_vars}, args.num_jets, cuts=zprime_cuts)["jets"]
221
+
222
+ # loop over taggers
223
+ out = {}
224
+ for tagger, fx in zip(args.tagger, fx_values):
225
+ out[tagger] = {"signal": args.signal, "fx": fx}
226
+
227
+ out[tagger]["ttbar"] = get_rej_eff_at_disc(jets, tagger, args.signal, fx, args.disc_cuts)
228
+ if args.zprime:
229
+ out[tagger]["zprime"] = get_rej_eff_at_disc(
230
+ zp_jets, tagger, args.signal, fx, args.disc_cuts
231
+ )
232
+
233
+ if args.outfile:
234
+ with open(args.outfile, "w") as f:
235
+ yaml.dump(out, f, sort_keys=False)
236
+ return None
237
+ else:
238
+ return out
239
+
240
+
241
+ def main(args=None):
242
+ args = parse_args(args)
243
+
244
+ if args.effs and args.disc_cuts:
245
+ raise ValueError("Cannot specify both --effs and --disc_cuts")
246
+
247
+ if args.effs:
248
+ out = get_working_points(args)
249
+ elif args.disc_cuts:
250
+ out = get_efficiencies(args)
251
+ else:
252
+ raise ValueError("Must specify either --effs or --disc_cuts")
185
253
  if out:
186
254
  print(yaml.dump(out, sort_keys=False))
255
+ return out
256
+ return None
187
257
 
188
258
 
189
259
  if __name__ == "__main__":