Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trigger sf #48

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
17769a5
update 2022 pre trigger bits to last version from cclub, except jet l…
nprouvost Oct 11, 2024
3019586
update trigger infos, add new configs for sfs
nprouvost Nov 15, 2024
bbbf60d
add start of custom trigger sf
nprouvost Nov 15, 2024
7ccb331
linting, change name tau_trigger_sf producer, add missing producers a…
nprouvost Nov 15, 2024
b3de8a3
Merge branch 'master' into trigger_sf
nprouvost Nov 15, 2024
11c3444
add functions for MC efficiency calculations and calculate SFs for mu…
nprouvost Nov 22, 2024
263ba62
add SF configs, complete and harmonize custom_trigger_sf and tau scripts
nprouvost Nov 27, 2024
e61f41e
Merge branch 'master' into trigger_sf
nprouvost Dec 6, 2024
d8ae788
merge branch 'master' into 'trigger_sf'
nprouvost Feb 3, 2025
1c4b505
merge branch 'master' into 'trigger_sf'
nprouvost Feb 3, 2025
bee7b9e
remove wrong double definitions due to auto-merging
nprouvost Feb 4, 2025
1cb89e0
start implementation ee, mumu and emu
nprouvost Feb 5, 2025
dd42902
Merge branch 'master' into trigger_sf
nprouvost Feb 5, 2025
6076430
add control regions trigger SFs (columnflow update needed)
nprouvost Feb 6, 2025
e20259e
merge branch 'master' into branch 'trigger_sf'
nprouvost Feb 6, 2025
35d6775
first draft reimplement etau and mutau with correct tau trigger sfs
nprouvost Feb 11, 2025
af1e630
Merge branch 'master' into trigger_sf
nprouvost Feb 11, 2025
9f9b59d
first working version of etau, mutau
nprouvost Feb 11, 2025
a2b0be5
update columnflow for working electron weights
nprouvost Feb 11, 2025
483cf20
correct tautau mask in tau sf producer, start tautau sf producer
nprouvost Feb 11, 2025
c05f8ca
correct error selected electron and muons in control channels
nprouvost Feb 14, 2025
4f44385
add tautau channel, correct etau and mutau tau variations, put all ch…
nprouvost Feb 14, 2025
1b13c24
add forgotten jet producer
nprouvost Feb 14, 2025
161e5eb
add shifts and weights trigger sfs
nprouvost Feb 24, 2025
9ab13b4
update selections to conserve correct trigger ids, update emu selecti…
nprouvost Feb 24, 2025
df6241b
update names trigger weights, stil one TODO
nprouvost Feb 24, 2025
788f5b6
lepton selection debugging finished
nprouvost Feb 24, 2025
ec62ec2
correct jet matching selection, add matched trigger ids, change tau s…
nprouvost Feb 28, 2025
f5b70e3
correct wrong sf variations columns, needs cf update once PR merged
nprouvost Feb 28, 2025
96a251b
merge branch 'master' into branch 'trigger_sf'
nprouvost Feb 28, 2025
37fec2e
update columnflow
nprouvost Feb 28, 2025
e045d24
add trigger dependent eta cut for muons
nprouvost Mar 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 82 additions & 15 deletions hbt/config/configs_hbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,9 @@ def if_not_era(*, values: list[str | None] | None = None, **kwargs) -> list[str]
},
})

# trigger sf corrector
cfg.x.jet_trigger_corrector = "jetlegSFs"

################################################################################################
# tau settings
################################################################################################
Expand Down Expand Up @@ -802,6 +805,10 @@ def if_not_era(*, values: list[str | None] | None = None, **kwargs) -> list[str]
"trigger_corr": "VVLoose",
})

# tau trigger correctors
cfg.x.tau_trigger_corrector = "tau_trigger"
cfg.x.cclub_tau_corrector = "tauTriggerSF"

################################################################################################
# electron settings
################################################################################################
Expand All @@ -828,6 +835,31 @@ def if_not_era(*, values: list[str | None] | None = None, **kwargs) -> list[str]
campaign=cmpgn,
working_point="wp80iso",
)
cfg.x.electron_trigger_sf_names = ElectronSFConfig(
correction="Electron-HLT-SF",
campaign=cmpgn,
hlt_path="HLT_SF_Ele30_TightID",
)
cfg.x.single_trigger_electron_data_effs_names = ElectronSFConfig(
correction="Electron-HLT-DataEff",
campaign=cmpgn,
hlt_path="HLT_SF_Ele30_TightID",
)
cfg.x.single_trigger_electron_mc_effs_names = ElectronSFConfig(
correction="Electron-HLT-McEff",
campaign=cmpgn,
hlt_path="HLT_SF_Ele30_TightID",
)
cfg.x.cross_trigger_electron_data_effs_names = ElectronSFConfig(
correction="Electron-HLT-DataEff",
campaign=cmpgn,
hlt_path="HLT_SF_Ele24_TightID",
)
cfg.x.cross_trigger_electron_mc_effs_names = ElectronSFConfig(
correction="Electron-HLT-McEff",
campaign=cmpgn,
hlt_path="HLT_SF_Ele24_TightID",
)
else:
assert False

Expand All @@ -846,6 +878,22 @@ def if_not_era(*, values: list[str | None] | None = None, **kwargs) -> list[str]
cfg.x.muon_sf_names = MuonSFConfig(
correction="NUM_TightPFIso_DEN_TightID",
)
cfg.x.muon_trigger_sf_names = MuonSFConfig(
correction="NUM_IsoMu24_DEN_CutBasedIdTight_and_PFIsoTight",
)
cfg.x.single_trigger_muon_data_effs_names = MuonSFConfig(
correction="NUM_IsoMu24_DEN_CutBasedIdTight_and_PFIsoTight_DATAeff",
)
cfg.x.single_trigger_muon_mc_effs_names = MuonSFConfig(
correction="NUM_IsoMu24_DEN_CutBasedIdTight_and_PFIsoTight_MCeff",
)
cfg.x.cross_trigger_muon_data_effs_names = MuonSFConfig(
correction="NUM_IsoMu20_DEN_CutBasedIdTight_and_PFIsoTight_DATAeff",
)
cfg.x.cross_trigger_muon_mc_effs_names = MuonSFConfig(
correction="NUM_IsoMu20_DEN_CutBasedIdTight_and_PFIsoTight_MCeff",
)

else:
assert False

Expand Down Expand Up @@ -1089,20 +1137,6 @@ def if_not_era(*, values: list[str | None] | None = None, **kwargs) -> list[str]
cfg.add_shift(name=f"tau_{unc}_down", id=51 + 2 * i, type="shape")
add_shift_aliases(cfg, f"tau_{unc}", {"tau_weight": f"tau_weight_{unc}_" + "{direction}"})

cfg.add_shift(name="tautau_trigger_up", id=80, type="shape")
cfg.add_shift(name="tautau_trigger_down", id=81, type="shape")
add_shift_aliases(cfg, "tautau_trigger", {"tau_trigger_weight": "tau_trigger_weight_tautau_{direction}"})
cfg.add_shift(name="etau_trigger_up", id=82, type="shape")
cfg.add_shift(name="etau_trigger_down", id=83, type="shape")
add_shift_aliases(cfg, "etau_trigger", {"tau_trigger_weight": "tau_trigger_weight_etau_{direction}"})
cfg.add_shift(name="mutau_trigger_up", id=84, type="shape")
cfg.add_shift(name="mutau_trigger_down", id=85, type="shape")
add_shift_aliases(cfg, "mutau_trigger", {"tau_trigger_weight": "tau_trigger_weight_mutau_{direction}"})
# no uncertainty for di-tau VBF trigger existing yet
# cfg.add_shift(name="mutau_trigger_up", id=86, type="shape")
# cfg.add_shift(name="tautauvbf_trigger_down", id=86, type="shape")
# add_shift_aliases(cfg, "tautauvbf_trigger", {"tau_trigger_weight": "tau_trigger_weight_tautauvbf_{direction}"})

cfg.add_shift(name="e_up", id=90, type="shape")
cfg.add_shift(name="e_down", id=91, type="shape")
add_shift_aliases(cfg, "e", {"electron_weight": "electron_weight_{direction}"})
Expand Down Expand Up @@ -1177,6 +1211,13 @@ def if_not_era(*, values: list[str | None] | None = None, **kwargs) -> list[str]
},
)

# trigger scale factors
trigger_legs = ["e", "mu", "tau_dm0", "tau_dm1", "tau_dm10", "tau_dm11", "jet"]
for i, leg in enumerate(trigger_legs):
cfg.add_shift(name=f"trigger_{leg}_up", id=150 + 2 * i, type="shape")
cfg.add_shift(name=f"trigger_{leg}_down", id=151 + 2 * i, type="shape")
add_shift_aliases(cfg, f"trigger_{leg}", {"trigger_weight": f"trigger_weight_{leg}_{{direction}}"})

################################################################################################
# external files
################################################################################################
Expand All @@ -1198,6 +1239,17 @@ def add_external(name, value):
elif run == 3:
json_pog_era = f"{year}_Summer{year2}{campaign.x.postfix}"
json_mirror = "/afs/cern.ch/user/m/mrieger/public/mirrors/jsonpog-integration-377439e8"
trigger_json_mirror = "/data/dust/user/prouvost/cclub_gitlab/AnalysisCore/data/TriggerScaleFactors"
cfg.x.campaign_tag = ""
for tag in ("preEE", "postEE", "preBPix", "postBPix"):
if campaign.has_tag(tag, mode=any):
if cfg.x.campaign_tag:
raise ValueError(f"Multiple campaign tags found: {cfg.x.campaign_tag} and {tag}")
cfg.x.campaign_tag = tag
cclub_eras = (
f"{year}"
f"{cfg.x.campaign_tag}"
)
else:
assert False

Expand Down Expand Up @@ -1254,8 +1306,14 @@ def add_external(name, value):
elif run == 3:
# muon scale factors
add_external("muon_sf", (f"{json_mirror}/POG/MUO/{json_pog_era}/muon_Z.json.gz", "v1"))
# muon trigger scale factors
add_external("muon_trigger_sf", (f"{trigger_json_mirror}/{cclub_eras}/temporary_MuHlt_abseta_pt.json", "v1")) # noqa
add_external("cross_trigger_muon_sf", (f"{trigger_json_mirror}/{cclub_eras}/CrossMuTauHlt.json", "v1"))
# electron scale factors
add_external("electron_sf", (f"{json_mirror}/POG/EGM/{json_pog_era}/electron.json.gz", "v1"))
# electron trigger scale factors
add_external("electron_trigger_sf", (f"{trigger_json_mirror}/{cclub_eras}/electronHlt.json", "v1"))
add_external("cross_trigger_electron_sf", (f"{trigger_json_mirror}/{cclub_eras}/CrossEleTauHlt.json", "v1"))
# hh-btag repository with TF saved model directories trained on 22+23 samples using pnet
add_external("hh_btag_repo", ("https://gitlab.cern.ch/hh/bbtautau/hh-btag/-/archive/master/hh-btag-master.tar.gz", "v3")) # noqa

Expand All @@ -1270,11 +1328,20 @@ def add_external(name, value):
json_mirror_tau_pog = "/afs/cern.ch/work/m/mrieger/public/mirrors/jsonpog-integration-taupog"
if year == 2022:
tau_pog_era = f"{year}_{'pre' if campaign.has_tag('preEE') else 'post'}EE"
tau_pog_era_cclub = f"{year}{'pre' if campaign.has_tag('preEE') else 'post'}EE"
tau_pog_dir = tau_pog_era
elif year == 2023:
tau_pog_era = f"{year}_{'pre' if campaign.has_tag('preBPix') else 'post'}BPix"
tau_pog_era_cclub = f"{year}{'pre' if campaign.has_tag('preBPix') else 'post'}BPix"
tau_pog_dir = str(year) # yes, it's inconsistent w.r.t. 2022
add_external("tau_sf", (f"{json_mirror_tau_pog}/POG/TAU/{tau_pog_dir}/tau_DeepTau2018v2p5_{tau_pog_era}.json.gz", "v1")) # noqa
# tau trigger scale factors
add_external("tau_trigger_sf", (f"{trigger_json_mirror}/{cclub_eras}/tau_trigger_DeepTau2018v2p5_{tau_pog_era_cclub}.json", "v1")) # noqa

jet_tag = "preEE" if campaign.has_tag('preEE') else "postEE" if campaign.has_tag('postEE') else "preBPix" if campaign.has_tag('preBPix') else "postBPix" # noqa
# jet trigger scale factors
add_external("jet_trigger_sf", (f"{trigger_json_mirror}/{cclub_eras}/ditaujet_jetleg_SFs_{jet_tag}.json", "v1")) # noqa

else:
assert False

Expand Down Expand Up @@ -1336,7 +1403,7 @@ def add_external(name, value):
"electron_weight": get_shifts("e"),
"muon_weight": get_shifts("mu"),
"tau_weight": get_shifts(*(f"tau_{unc}" for unc in cfg.x.tau_unc_names)),
"tau_trigger_weight": get_shifts("etau_trigger", "mutau_trigger", "tautau_trigger"),
"trigger_weight": get_shifts(*(f"trigger_{leg}" for leg in trigger_legs)),
})

# define per-dataset event weights
Expand Down
3 changes: 2 additions & 1 deletion hbt/production/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
normalized_pu_weight, normalized_pdf_weight, normalized_murmuf_weight,
)
from hbt.production.btag import normalized_btag_weights_deepjet, normalized_btag_weights_pnet
from hbt.production.tau import tau_weights, trigger_weights
from hbt.production.tau import tau_weights
from hbt.production.trigger_sf import trigger_weights
from hbt.util import IF_DATASET_HAS_LHE_WEIGHTS, IF_RUN_3

ak = maybe_import("awkward")
Expand Down
134 changes: 134 additions & 0 deletions hbt/production/jet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# coding: utf-8

"""
Jet scale factor production.
"""

from __future__ import annotations

import functools

from columnflow.production import Producer, producer
from columnflow.util import maybe_import, InsertableDict
from columnflow.columnar_util import set_ak_column, flat_np_view, layout_ak_array


ak = maybe_import("awkward")
np = maybe_import("numpy")

# helper
set_ak_column_f32 = functools.partial(set_ak_column, value_type=np.float32)


@producer(
uses={
"channel_id", "HHBJet.{pt,eta}",
},
produces={
f"ditaujet_trigger_jet_weight_{corrtype_}" for corrtype_ in ["eff_data", "eff_mc"]
} | {
f"ditaujet_trigger_jet_weight_{corrtype_}_{direction}"
for direction in ["up", "down"]
for corrtype_ in ["eff_data", "eff_mc"]
},
# only run on mc
mc_only=True,
# function to determine the correction file
get_jet_file=(lambda self, external_files: external_files.jet_trigger_sf),
get_jet_corrector=(lambda self: self.config_inst.x.jet_trigger_corrector),
weight_name="ditaujet_trigger_jet_weight",
)
def jet_trigger_weights(
self: Producer,
events: ak.Array,
jet_mask: ak.Array | type(Ellipsis) = Ellipsis,
**kwargs,
) -> ak.Array:
"""
Producer for trigger scale factors derived by the CCLUB group. Requires an external file in the
config under ``jet_trigger_sf``:

.. code-block:: python

cfg.x.external_files = DotDict.wrap({
"jet_trigger_sf": (f"{trigger_json_mirror}/{cclub_eras}/ditaujet_jetleg_SFs_{jet_tag}.json", "v1"), # noqa
})

*get_jet_file* can be adapted in a subclass in case it is stored differently in the external
files. A correction set named ``"jet_trigger_corrector"`` is extracted from it.

Resources:
https://gitlab.cern.ch/cclubbtautau/AnalysisCore/-/blob/59ae66c4a39d3e54afad5733895c33b1fb511c47/data/TriggerScaleFactors/2023postBPix/ditaujet_jetleg_SFs_postBPix.json
"""

# flat absolute eta and pt views
abs_eta = flat_np_view(abs(events.HHBJet.eta[jet_mask]), axis=1)
pt = flat_np_view(events.HHBJet.pt[jet_mask], axis=1)

variable_map = {
"pt": pt,
"abseta": abs_eta,
}

# loop over efficiency type
for corrtype_name, corrtype in [("data", "eff_data"), ("mc", "eff_mc")]:
# loop over systematics
for syst, postfix in [
("nom", ""),
("up", "_up"),
("down", "_down"),
]:
# get the inputs for this type of variation
variable_map_syst = {
**variable_map,
"syst": syst,
"data_or_mc": corrtype_name,
}
inputs = [variable_map_syst[inp.name] for inp in self.jet_trig_corrector.inputs]
sf_flat = self.jet_trig_corrector(*inputs)

# add the correct layout to it
sf = layout_ak_array(sf_flat, events.HHBJet.pt[jet_mask])

# create the product over all muons in one event
weight = ak.prod(sf, axis=1, mask_identity=False)

# store it
events = set_ak_column(events, f"{self.weight_name}_{corrtype}{postfix}", weight, value_type=np.float32)

return events


@jet_trigger_weights.requires
def jet_trigger_weights_requires(self: Producer, reqs: dict) -> None:
if "external_files" in reqs:
return

from columnflow.tasks.external import BundleExternalFiles
reqs["external_files"] = BundleExternalFiles.req(self.task)


@jet_trigger_weights.setup
def jet_trigger_weights_setup(self: Producer, reqs: dict, inputs: dict, reader_targets: InsertableDict) -> None:
bundle = reqs["external_files"]

# create the trigger and id correctors
import correctionlib
correctionlib.highlevel.Correction.__call__ = correctionlib.highlevel.Correction.evaluate

# load the correction set
jet_file = self.get_jet_file(bundle.files)
if jet_file.ext() == "json":
correction_set = correctionlib.CorrectionSet.from_file(
self.get_jet_file(bundle.files).abspath,
)
else:
correction_set = correctionlib.CorrectionSet.from_string(
self.get_jet_file(bundle.files).load(formatter="gzip").decode("utf-8"),
)

corrector_string = self.get_jet_corrector()
self.jet_trig_corrector = correction_set[corrector_string]

# check versions
assert self.jet_trig_corrector.version in [0, 1]
Loading