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.
- {atlas_ftag_tools-0.1.13.dist-info → atlas_ftag_tools-0.1.16.dist-info}/METADATA +14 -1
- atlas_ftag_tools-0.1.16.dist-info/RECORD +23 -0
- ftag/__init__.py +1 -1
- ftag/flavour.py +16 -5
- ftag/flavours.yaml +17 -5
- ftag/hdf5/h5reader.py +5 -0
- ftag/hdf5/h5split.py +2 -1
- ftag/mock.py +21 -1
- ftag/vds.py +15 -1
- ftag/wps/discriminant.py +41 -11
- ftag/wps/working_points.py +94 -12
- atlas_ftag_tools-0.1.13.dist-info/RECORD +0 -23
- {atlas_ftag_tools-0.1.13.dist-info → atlas_ftag_tools-0.1.16.dist-info}/WHEEL +0 -0
- {atlas_ftag_tools-0.1.13.dist-info → atlas_ftag_tools-0.1.16.dist-info}/entry_points.txt +0 -0
- {atlas_ftag_tools-0.1.13.dist-info → atlas_ftag_tools-0.1.16.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: atlas-ftag-tools
|
3
|
-
Version: 0.1.
|
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
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(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
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
|
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(
|
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(
|
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,
|
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
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
ftag/wps/working_points.py
CHANGED
@@ -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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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,
|
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
|
172
|
-
|
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,,
|
File without changes
|
File without changes
|
File without changes
|