atlas-ftag-tools 0.1.13__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.13
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
 
@@ -0,0 +1,23 @@
1
+ ftag/__init__.py,sha256=PN9ZbZHVfxreetH3HnhEbZf1G-J4Up-5si-dQ4rrezg,629
2
+ ftag/cuts.py,sha256=RYAfK3MkEhYhlKQFWQTKu72ZrUwlExFeT8IWLSIgeTU,2798
3
+ ftag/flavour.py,sha256=BLifDbJCoszPzgrU5X3Txff9fTMuVGEjUeU0OtOfllc,2701
4
+ ftag/flavours.yaml,sha256=9ifKyz1_VoHlOaWuf3JEqMLSYyLFedYJf9x1D6dCTnM,5335
5
+ ftag/git_check.py,sha256=TvF502eqDrYzhI-SgruVolx1BPJi-J0mswc4pmgaYY8,1621
6
+ ftag/mock.py,sha256=T2YGeuCkgDEzKPVYwU7Vnq5TNIDrx9eIDVrAQt8s0Mw,4865
7
+ ftag/region.py,sha256=-WxdC0Gy9zz3zEJ2pN779RcxXPG-QEROuMwMoP-Qs0g,353
8
+ ftag/sample.py,sha256=cd-rNHsEY2aWSZdy3V4bOKi3aDMtHTCpjXS8Hl9zwUY,2597
9
+ ftag/transform.py,sha256=uEGGJSnqoKOzLYQv650XdK_kDNw4Aw-5dc60z9Dp_y0,3963
10
+ ftag/vds.py,sha256=PG-NCJdpmK5X2l8i8YWBHx6CY8vosShfqp36facKaYM,3383
11
+ ftag/hdf5/__init__.py,sha256=pZva2TI8nvpBwoawcm_ucVZbGsQJW_u8GGoJgt5mKEw,354
12
+ ftag/hdf5/h5move.py,sha256=1XxiJZ96DYSp8JF0ry3lbRSQaFX72DjUV5vBA6hYw-0,873
13
+ ftag/hdf5/h5reader.py,sha256=et-_LXt942xegqc14bPapUgIO7MUfC2m04uJslLkXxI,13579
14
+ ftag/hdf5/h5split.py,sha256=BlhpsUlqBSDCjVRWuyEq1OImyzwp7VyVkDrCz7pvQKc,2508
15
+ ftag/hdf5/h5utils.py,sha256=wjbAmFY5GoFkWW_AvEKTPbwYMFroHKKFuIcehd91dhM,3222
16
+ ftag/hdf5/h5writer.py,sha256=5jm3vSk4m77lFSUyWm-i_y_USzQRVoKpLL8F_cii65Q,4826
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.13"
4
+ __version__ = "v0.1.16"
5
5
 
6
6
 
7
7
  from ftag import hdf5
ftag/flavour.py CHANGED
@@ -80,9 +80,20 @@ class FlavourContainer:
80
80
  return flavour
81
81
  raise KeyError(f"Flavour with {cuts} not found")
82
82
 
83
+ @classmethod
84
+ def from_yaml(cls, yaml_path: Path | None = None) -> FlavourContainer:
85
+ if yaml_path is None:
86
+ yaml_path = Path(__file__).parent / "flavours.yaml"
83
87
 
84
- with open(Path(__file__).parent / "flavours.yaml") as f:
85
- flavours_yaml = yaml.safe_load(f)
86
- flavours_dict = {f["name"]: Flavour(cuts=Cuts.from_list(f.pop("cuts")), **f) for f in flavours_yaml}
87
- assert len(flavours_dict) == len(flavours_yaml), "Duplicate flavour names detected"
88
- Flavours = FlavourContainer(flavours_dict)
88
+ with open(yaml_path) as f:
89
+ flavours_yaml = yaml.safe_load(f)
90
+
91
+ flavours_dict = {
92
+ f["name"]: Flavour(cuts=Cuts.from_list(f.pop("cuts")), **f) for f in flavours_yaml
93
+ }
94
+ assert len(flavours_dict) == len(flavours_yaml), "Duplicate flavour names detected"
95
+
96
+ return cls(flavours_dict)
97
+
98
+
99
+ Flavours = FlavourContainer.from_yaml()
ftag/flavours.yaml CHANGED
@@ -58,11 +58,6 @@
58
58
  cuts: ["R10TruthLabel_R22v1 == 12"]
59
59
  colour: "#B45F06"
60
60
  category: xbb
61
- - name: tqqb
62
- label: Fully Contained Top
63
- cuts: ["R10TruthLabel_R22v1 == 1"]
64
- colour: "#A300A3"
65
- category: xbb
66
61
  - name: top
67
62
  label: Inclusive Top
68
63
  cuts: ["R10TruthLabel_R22v1 in (1,6,7)"]
@@ -74,6 +69,23 @@
74
69
  colour: "#38761D"
75
70
  category: xbb
76
71
 
72
+ # extended Xbb tagging
73
+ - name: tqqb
74
+ label: Fully Contained Top
75
+ cuts: ["R10TruthLabel_R22v1 == 1"]
76
+ colour: "#A300A3"
77
+ category: xbb-extended
78
+ - name: wqq_from_t
79
+ label: Fully Contained W->qq from Top
80
+ cuts: ["R10TruthLabel_R22v1 == 6"]
81
+ colour: "indigo"
82
+ category: xbb-extended
83
+ - name: other_from_t
84
+ label: Other Matched from Top
85
+ cuts: ["R10TruthLabel_R22v1 == 7"]
86
+ colour: "purple"
87
+ category: xbb-extended
88
+
77
89
  # partonic labelling
78
90
  - name: upjets
79
91
  label: $u$-jets
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/hdf5/h5split.py CHANGED
@@ -9,7 +9,8 @@ import h5py
9
9
  from ftag.hdf5 import H5Reader, H5Writer
10
10
 
11
11
 
12
- class HelpFormatter(argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter): ...
12
+ class HelpFormatter(argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter):
13
+ ...
13
14
 
14
15
 
15
16
  def parse_args(args):
ftag/mock.py CHANGED
@@ -21,6 +21,7 @@ JET_VARS = [
21
21
  ("n_tracks", "i4"),
22
22
  ("HadronConeExclTruthLabelID", "i4"),
23
23
  ("HadronConeExclTruthLabelPt", "f4"),
24
+ ("R10TruthLabel_R22v1", "i4"),
24
25
  ("n_truth_promptLepton", "i4"),
25
26
  ("flavour_label", "i4"),
26
27
  ]
@@ -71,6 +72,23 @@ def get_mock_scores(labels: np.ndarray):
71
72
  return u2s(scores, dtype=np.dtype([(name, "f4") for name in cols]))
72
73
 
73
74
 
75
+ def get_mock_xbb_scores(labels: np.ndarray):
76
+ rng = np.random.default_rng(42)
77
+ scores = np.zeros((len(labels), 4))
78
+ for label, count in zip(*np.unique(labels, return_counts=True)):
79
+ if label == 11:
80
+ scores[labels == label] = rng.normal(loc=[1, 0, 0, 0], scale=1, size=(count, 4))
81
+ elif label == 12:
82
+ scores[labels == label] = rng.normal(loc=[0, 1, 0, 0], scale=1, size=(count, 4))
83
+ elif label == 1:
84
+ scores[labels == label] = rng.normal(loc=[0, 0, 1, 0], scale=1, size=(count, 4))
85
+ elif label == 10:
86
+ scores[labels == label] = rng.normal(loc=[0, 0, 0, 1], scale=1, size=(count, 4))
87
+ scores = softmax(scores, axis=1)
88
+ cols = [f"MockXbbTagger_p{x}" for x in ["hbb", "hcc", "top", "qcd"]]
89
+ return u2s(scores, dtype=np.dtype([(name, "f4") for name in cols]))
90
+
91
+
74
92
  def get_mock_file(
75
93
  num_jets=1000,
76
94
  fname: str | None = None,
@@ -83,6 +101,7 @@ def get_mock_file(
83
101
  jets = u2s(rng.random((num_jets, len(JET_VARS))), jets_dtype)
84
102
  jets["HadronConeExclTruthLabelID"] = rng.choice([0, 4, 5, 15], size=num_jets)
85
103
  jets["flavour_label"] = rng.choice([0, 4, 5], size=num_jets)
104
+ jets["R10TruthLabel_R22v1"] = rng.choice([1, 10, 11, 12], size=num_jets)
86
105
  jets["pt"] *= 400e3
87
106
  jets["mass"] *= 50e3
88
107
  jets["eta"] = (jets["eta"] - 0.5) * 6.0
@@ -91,7 +110,8 @@ def get_mock_file(
91
110
 
92
111
  # add tagger scores
93
112
  scores = get_mock_scores(jets["HadronConeExclTruthLabelID"])
94
- jets = join_structured_arrays([jets, scores])
113
+ xbb_scores = get_mock_xbb_scores(jets["R10TruthLabel_R22v1"])
114
+ jets = join_structured_arrays([jets, scores, xbb_scores])
95
115
 
96
116
  # create a tempfile in a new folder
97
117
  if fname is None:
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
@@ -5,16 +5,38 @@ import numpy as np
5
5
  from ftag.flavour import Flavour, Flavours
6
6
 
7
7
 
8
- def btag_discriminant(pb, pc, pu, fc=0.1, epsilon=1e-10):
8
+ def btag_discriminant(jets, tagger, fc=0.1, epsilon=1e-10):
9
+ pb, pc, pu = (jets[f"{tagger}_pb"], jets[f"{tagger}_pc"], jets[f"{tagger}_pu"])
9
10
  return np.log((pb + epsilon) / ((1.0 - fc) * pu + fc * pc + epsilon))
10
11
 
11
12
 
12
- def ctag_discriminant(pb, pc, pu, fb=0.2, epsilon=1e-10):
13
+ def ctag_discriminant(jets, tagger, fb=0.2, epsilon=1e-10):
14
+ pb, pc, pu = (jets[f"{tagger}_pb"], jets[f"{tagger}_pc"], jets[f"{tagger}_pu"])
13
15
  return np.log((pc + epsilon) / ((1.0 - fb) * pu + fb * pb + epsilon))
14
16
 
15
17
 
18
+ def hbb_discriminant(jets, tagger, ftop=0.25, fhcc=0.02, epsilon=1e-10):
19
+ phbb = jets[f"{tagger}_phbb"]
20
+ phcc = jets[f"{tagger}_phcc"]
21
+ ptop = jets[f"{tagger}_ptop"]
22
+ pqcd = jets[f"{tagger}_pqcd"]
23
+ return np.log(phbb / (ftop * ptop + fhcc * phcc + (1 - ftop - fhcc) * pqcd + epsilon))
24
+
25
+
26
+ def hcc_discriminant(jets, tagger, ftop=0.25, fhbb=0.3, epsilon=1e-10):
27
+ phbb = jets[f"{tagger}_phbb"]
28
+ phcc = jets[f"{tagger}_phcc"]
29
+ ptop = jets[f"{tagger}_ptop"]
30
+ pqcd = jets[f"{tagger}_pqcd"]
31
+ return np.log(phcc / (ftop * ptop + fhbb * phbb + (1 - ftop - fhbb) * pqcd + epsilon))
32
+
33
+
16
34
  def get_discriminant(
17
- jets: np.ndarray, tagger: str, signal: Flavour | str, fx: float, epsilon: float = 1e-10
35
+ jets: np.ndarray,
36
+ tagger: str,
37
+ signal: Flavour | str,
38
+ fx: float | tuple[float, ...],
39
+ epsilon: float = 1e-10,
18
40
  ):
19
41
  """Calculate the b-tag or c-tag discriminant for a given tagger.
20
42
 
@@ -25,9 +47,9 @@ def get_discriminant(
25
47
  tagger : str
26
48
  Name of the tagger
27
49
  signal : Flavour
28
- Signal flavour (bjets or cjets)
50
+ Signal flavour (bjets/cjets or hbb/hcc)
29
51
  fx : float, optional
30
- Value fb or fc
52
+ Value fb or fc (fhbb or fhcc and ftop for Xbb)
31
53
  epsilon : float, optional
32
54
  Small number to avoid division by zero, by default 1e-10
33
55
 
@@ -36,9 +58,17 @@ def get_discriminant(
36
58
  np.ndarray
37
59
  Array of discriminant values.
38
60
  """
39
- pb, pc, pu = (jets[f"{tagger}_pb"], jets[f"{tagger}_pc"], jets[f"{tagger}_pu"])
40
- if Flavours[signal] == Flavours.bjets:
41
- return btag_discriminant(pb, pc, pu, fx, epsilon)
42
- if Flavours[signal] == Flavours.cjets:
43
- return ctag_discriminant(pb, pc, pu, fx, epsilon)
44
- raise ValueError(f"Signal flavour must be bjets or cjets, not {signal}")
61
+ if not isinstance(fx, tuple | list):
62
+ fx = (fx,)
63
+ tagger_funcs = {
64
+ "bjets": btag_discriminant,
65
+ "cjets": ctag_discriminant,
66
+ "hbb": hbb_discriminant,
67
+ "hcc": hcc_discriminant,
68
+ }
69
+
70
+ func = tagger_funcs.get(str(Flavours[signal]), None)
71
+ if func is None:
72
+ raise ValueError(f"Signal flavour must be among {list(tagger_funcs.keys())}, not {signal}")
73
+
74
+ return func(jets, tagger, *fx, epsilon) # type: ignore
@@ -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",
@@ -58,17 +57,24 @@ def parse_args(args):
58
57
  "-s",
59
58
  "--signal",
60
59
  default="bjets",
61
- choices=["bjets", "cjets"],
60
+ choices=["bjets", "cjets", "hbb", "hcc"],
62
61
  type=str,
63
- help='signal flavour ("bjets" or "cjets")',
62
+ help='signal flavour ("bjets" or "cjets" for b-tagging, "hbb" or "hcc" for Xbb)',
64
63
  )
65
64
  parser.add_argument(
66
65
  "-r",
67
66
  "--rejection",
68
67
  default=None,
69
- choices=["ujets", "cjets", "bjets"],
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",
@@ -96,6 +102,11 @@ def parse_args(args):
96
102
  type=Path,
97
103
  help="save results to yaml instead of printing",
98
104
  )
105
+ parser.add_argument(
106
+ "--xbb",
107
+ action="store_true",
108
+ help="Enable Xbb tagging which expects two fx values ftop and fhcc/fhbb for each tagger",
109
+ )
99
110
 
100
111
  return parser.parse_args(args)
101
112
 
@@ -111,13 +122,18 @@ def get_eff_rej(jets, disc, wp, flavs):
111
122
 
112
123
 
113
124
  def get_working_points(args=None):
114
- args = parse_args(args)
115
-
116
- if len(args.tagger) != len(args.fx):
117
- raise ValueError("Must provide fb/fc for each tagger")
125
+ if args.xbb:
126
+ if len(args.fx) != 2 * len(args.tagger):
127
+ raise ValueError("For Xbb tagging, each tagger must have two fx values")
128
+ fx_values = list(zip(args.fx[::2], args.fx[1::2]))
129
+ else:
130
+ if len(args.fx) != len(args.tagger):
131
+ raise ValueError("Number of taggers must match number of fx values")
132
+ fx_values = [(fx,) for fx in args.fx]
118
133
 
119
134
  # setup cuts and variables
120
- flavs = Flavours.by_category("single-btag")
135
+ flavs = Flavours.by_category("single-btag") if not args.xbb else Flavours.by_category("xbb")
136
+
121
137
  default_cuts = Cuts.from_list(["eta > -2.5", "eta < 2.5"])
122
138
  ttbar_cuts = Cuts.from_list(args.ttbar_cuts) + default_cuts
123
139
  zprime_cuts = Cuts.from_list(args.zprime_cuts) + default_cuts
@@ -134,7 +150,7 @@ def get_working_points(args=None):
134
150
 
135
151
  # loop over taggers
136
152
  out = {}
137
- for tagger, fx in zip(args.tagger, args.fx):
153
+ for tagger, fx in zip(args.tagger, fx_values):
138
154
  out[tagger] = {"signal": args.signal, "fx": fx}
139
155
 
140
156
  # calculate discriminant
@@ -168,10 +184,76 @@ def get_working_points(args=None):
168
184
  return out
169
185
 
170
186
 
171
- def main():
172
- 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")
173
253
  if out:
174
254
  print(yaml.dump(out, sort_keys=False))
255
+ return out
256
+ return None
175
257
 
176
258
 
177
259
  if __name__ == "__main__":
@@ -1,23 +0,0 @@
1
- ftag/__init__.py,sha256=gcWw-kYu7WI13uQZ_ulcS2T--iUjHXXFUb4ZaDzASBs,629
2
- ftag/cuts.py,sha256=RYAfK3MkEhYhlKQFWQTKu72ZrUwlExFeT8IWLSIgeTU,2798
3
- ftag/flavour.py,sha256=qvAPWPDdFGoTsADhqUB1PEFHrM2NekiDlLM0Tlx9w0E,2456
4
- ftag/flavours.yaml,sha256=RT1LooN-75MlZ6k1RhFZySickv1er_1qIxoa94HTGy4,5028
5
- ftag/git_check.py,sha256=TvF502eqDrYzhI-SgruVolx1BPJi-J0mswc4pmgaYY8,1621
6
- ftag/mock.py,sha256=EZ-2YtFf36mL95cLzoezxzH2p4WfG6Nad6gM9f6nlsM,3828
7
- ftag/region.py,sha256=-WxdC0Gy9zz3zEJ2pN779RcxXPG-QEROuMwMoP-Qs0g,353
8
- ftag/sample.py,sha256=cd-rNHsEY2aWSZdy3V4bOKi3aDMtHTCpjXS8Hl9zwUY,2597
9
- ftag/transform.py,sha256=uEGGJSnqoKOzLYQv650XdK_kDNw4Aw-5dc60z9Dp_y0,3963
10
- ftag/vds.py,sha256=l2JttxscusBWUSog8SjSkhPn-4lhOLzZmLaqe4hGiS0,2929
11
- ftag/hdf5/__init__.py,sha256=pZva2TI8nvpBwoawcm_ucVZbGsQJW_u8GGoJgt5mKEw,354
12
- ftag/hdf5/h5move.py,sha256=1XxiJZ96DYSp8JF0ry3lbRSQaFX72DjUV5vBA6hYw-0,873
13
- ftag/hdf5/h5reader.py,sha256=D3a9l4jVnvJPlp9fprvnlp2arHPRl_1PT5SEDFO0i_U,13390
14
- ftag/hdf5/h5split.py,sha256=QICjC41GyXCQkaP6AqBjVxicmP2yEULVVHktvkq9bY4,2504
15
- ftag/hdf5/h5utils.py,sha256=wjbAmFY5GoFkWW_AvEKTPbwYMFroHKKFuIcehd91dhM,3222
16
- ftag/hdf5/h5writer.py,sha256=5jm3vSk4m77lFSUyWm-i_y_USzQRVoKpLL8F_cii65Q,4826
17
- ftag/wps/discriminant.py,sha256=b41PrrGSRwYKsqBaQgbi6wGLGJHnm-tYEpvyszQPy_4,1364
18
- ftag/wps/working_points.py,sha256=70UU4xlwkTRKX2HXZ9VE2tjcwWj0GuFrl-a01SvEnSY,5006
19
- atlas_ftag_tools-0.1.13.dist-info/METADATA,sha256=ahnqgms5ZEIkV_YDa6LWwCPYoPy3dwbLSijWgXQhvWA,4591
20
- atlas_ftag_tools-0.1.13.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
21
- atlas_ftag_tools-0.1.13.dist-info/entry_points.txt,sha256=LfVLsZHQolqbPnwPgtmc5IQTh527BKkN2v-IpXWTNHw,137
22
- atlas_ftag_tools-0.1.13.dist-info/top_level.txt,sha256=qiYQuKcAvMim-31FwkT3MTQu7WQm0s58tPAia5KKWqs,5
23
- atlas_ftag_tools-0.1.13.dist-info/RECORD,,