25
25
from hbw .config .hist_hooks import add_hist_hooks
26
26
from hbw .util import timeit_multiple
27
27
28
+ from columnflow .production .cms .electron import ElectronSFConfig
29
+ from columnflow .production .cms .muon import MuonSFConfig
30
+ from columnflow .production .cms .btag import BTagSFConfig
31
+
28
32
thisdir = os .path .dirname (os .path .abspath (__file__ ))
29
33
30
34
logger = law .logger .get_logger (__name__ )
@@ -39,8 +43,6 @@ def add_config(
39
43
limit_dataset_files : int | None = None ,
40
44
add_dataset_extensions : bool = False ,
41
45
) -> od .Config :
42
- # validations
43
- assert campaign .x .year in [2016 , 2017 , 2018 , 2022 ]
44
46
# gather campaign data
45
47
year = campaign .x .year
46
48
year2 = year % 100
@@ -54,9 +56,14 @@ def add_config(
54
56
if not campaign .has_tag ("postEE" ) and not campaign .has_tag ("preEE" ):
55
57
raise ValueError ("2022 campaign must have the 'postEE' or 'preEE' tag" )
56
58
corr_postfix = "postEE" if campaign .has_tag ("postEE" ) else "preEE"
59
+ elif campaign .x .year == 2023 :
60
+ if not campaign .has_tag ("postBPix" ) and not campaign .has_tag ("preBPix" ):
61
+ raise ValueError ("2023 campaign must have the 'postBPix' or 'preBPix' tag" )
62
+ corr_postfix = "postBPix" if campaign .has_tag ("postBPix" ) else "preBPix"
57
63
58
- if campaign .x .year not in [2017 , 2022 ]:
59
- raise NotImplementedError ("For now, only 2017 and 2022 campaign is implemented" )
64
+ implemented_years = [2017 , 2022 , 2023 ]
65
+ if campaign .x .year not in implemented_years :
66
+ raise NotImplementedError (f"For now, only { ', ' .join (implemented_years )} years are implemented" )
60
67
61
68
# create a config by passing the campaign, so id and name will be identical
62
69
# cfg = analysis.add_config(campaign, name=config_name, id=config_id, tags=analysis.tags)
@@ -171,12 +178,12 @@ def if_era(
171
178
})
172
179
elif year == 2023 :
173
180
if campaign .has_tag ("preBPix" ):
174
- cfg .x .luminosity = Number (17.794 , {
181
+ cfg .x .luminosity = Number (17794 , {
175
182
"lumi_13TeV_2023" : 0.01j ,
176
183
"lumi_13TeV_correlated" : 0.006j ,
177
184
})
178
185
elif campaign .has_tag ("postBPix" ):
179
- cfg .x .luminosity = Number (9.451 , {
186
+ cfg .x .luminosity = Number (9451 , {
180
187
"lumi_13TeV_2023" : 0.01j ,
181
188
"lumi_13TeV_correlated" : 0.006j ,
182
189
})
@@ -197,15 +204,22 @@ def if_era(
197
204
# JEC
198
205
# https://twiki.cern.ch/twiki/bin/view/CMS/JECDataMC?rev=201
199
206
jerc_postfix = campaign .x .postfix
200
- if jerc_postfix not in ("" , "APV" , "EE" ):
207
+ if jerc_postfix not in ("" , "APV" , "EE" , "BPix" ):
201
208
raise ValueError (f"Unknown JERC postfix '{ jerc_postfix } '" )
202
209
203
210
if cfg .x .run == 2 :
204
- jerc_campaign = f"Summer19UL{ year2 } { jerc_postfix } "
211
+ jer_campaign = jec_campaign = f"Summer19UL{ year2 } { jerc_postfix } "
205
212
jet_type = "AK4PFchs"
206
213
fatjet_type = "AK8PFchs"
207
214
elif cfg .x .run == 3 :
208
- jerc_campaign = f"Summer{ year2 } { jerc_postfix } _22Sep2023"
215
+ if year == 2022 :
216
+ jer_campaign = jec_campaign = f"Summer{ year2 } { jerc_postfix } _22Sep2023"
217
+ elif year == 2023 :
218
+ # NOTE: this might be totally wrong, ask Daniel
219
+ # TODO: fix for 2023postBPix....
220
+ era = "Cv4" if campaign .has_tag ("preBPix" ) else "D"
221
+ jer_campaign = f"Summer{ year2 } { jerc_postfix } Prompt{ year2 } _Run{ era } "
222
+ jec_campaign = f"Summer{ year2 } { jerc_postfix } Prompt{ year2 } "
209
223
jet_type = "AK4PFPuppi"
210
224
fatjet_type = "AK8PFPuppi"
211
225
@@ -222,17 +236,17 @@ def if_era(
222
236
cfg .x .jec = DotDict .wrap ({
223
237
# NOTE: currently, we set the uncertainty_sources in the calibrator itself
224
238
"Jet" : {
225
- "campaign" : jerc_campaign ,
226
- "version" : {2016 : "V7" , 2017 : "V5" , 2018 : "V5" , 2022 : "V2" }[year ],
239
+ "campaign" : jec_campaign ,
240
+ "version" : {2016 : "V7" , 2017 : "V5" , 2018 : "V5" , 2022 : "V2" , 2023 : "V1" }[year ],
227
241
"jet_type" : jet_type ,
228
242
"external_file_key" : "jet_jerc" ,
229
243
"levels" : ["L1FastJet" , "L2Relative" , "L2L3Residual" , "L3Absolute" ],
230
244
"levels_for_type1_met" : ["L1FastJet" ],
231
245
"uncertainty_sources" : jec_uncertainties ,
232
246
},
233
247
"FatJet" : {
234
- "campaign" : jerc_campaign ,
235
- "version" : {2016 : "V7" , 2017 : "V5" , 2018 : "V5" , 2022 : "V2" }[year ],
248
+ "campaign" : jec_campaign ,
249
+ "version" : {2016 : "V7" , 2017 : "V5" , 2018 : "V5" , 2022 : "V2" , 2023 : "V1" }[year ],
236
250
"jet_type" : fatjet_type ,
237
251
"external_file_key" : "fat_jet_jerc" ,
238
252
"levels" : ["L1FastJet" , "L2Relative" , "L2L3Residual" , "L3Absolute" ],
@@ -245,14 +259,14 @@ def if_era(
245
259
# https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution?rev=107
246
260
cfg .x .jer = DotDict .wrap ({
247
261
"Jet" : {
248
- "campaign" : jerc_campaign ,
249
- "version" : {2016 : "JRV3" , 2017 : "JRV2" , 2018 : "JRV2" , 2022 : "JRV1" }[year ],
262
+ "campaign" : jer_campaign ,
263
+ "version" : {2016 : "JRV3" , 2017 : "JRV2" , 2018 : "JRV2" , 2022 : "JRV1" , 2023 : "JRV1" }[year ],
250
264
"jet_type" : jet_type ,
251
265
"external_file_key" : "jet_jerc" ,
252
266
},
253
267
"FatJet" : {
254
- "campaign" : jerc_campaign ,
255
- "version" : {2016 : "JRV3" , 2017 : "JRV2" , 2018 : "JRV2" , 2022 : "JRV1" }[year ],
268
+ "campaign" : jer_campaign ,
269
+ "version" : {2016 : "JRV3" , 2017 : "JRV2" , 2018 : "JRV2" , 2022 : "JRV1" , 2023 : "JRV1" }[year ],
256
270
# "jet_type": "fatjet_type",
257
271
# JER info only for AK4 jets, stored in AK4 file
258
272
"jet_type" : jet_type ,
@@ -328,11 +342,28 @@ def if_era(
328
342
})
329
343
330
344
# b-tag configuration. Potentially overwritten by the jet Selector.
331
- cfg .x .b_tagger = {
332
- 2 : "deepjet" ,
333
- 3 : "particlenet" ,
334
- }[cfg .x .run ]
345
+ if cfg .x .run == 2 :
346
+ cfg .x .b_tagger = "deepjet"
347
+ cfg .x .btag_sf = BTagSFConfig (
348
+ correction_set = "deepJet_shape" ,
349
+ jec_sources = cfg .x .btag_sf_jec_sources ,
350
+ discriminator = "btagDeepFlavB" ,
351
+ # corrector_kwargs=...,
352
+ )
353
+ elif cfg .x .run == 3 :
354
+ cfg .x .b_tagger = "particlenet"
355
+ cfg .x .btag_sf = BTagSFConfig (
356
+ correction_set = "particleNet_shape" ,
357
+ jec_sources = cfg .x .btag_sf_jec_sources ,
358
+ discriminator = "btagPNetB" ,
359
+ # corrector_kwargs=...,
360
+ )
361
+
362
+ cfg .x .btag_column = cfg .x .btag_sf .discriminator
335
363
cfg .x .btag_wp = "medium"
364
+ cfg .x .btag_wp_score = (
365
+ cfg .x .btag_working_points [cfg .x .b_tagger ][cfg .x .btag_wp ]
366
+ )
336
367
337
368
# met configuration
338
369
cfg .x .met_name = {
@@ -390,29 +421,49 @@ def if_era(
390
421
if cfg .x .run == 2 :
391
422
# names of electron correction sets and working points
392
423
# (used in the electron_sf producer)
393
- cfg .x .electron_sf_names = ("UL-Electron-ID-SF" , f"{ cfg .x .cpn_tag } " , "Tight" )
424
+ cfg .x .electron_sf_names = ElectronSFConfig (
425
+ correction = "UL-Electron-ID-SF" ,
426
+ campaign = f"{ cfg .x .cpn_tag } " ,
427
+ working_point = "Tight" ,
428
+ )
394
429
395
430
# names of muon correction sets and working points
396
431
# (used in the muon producer)
397
- cfg .x .muon_sf_names = ("NUM_TightRelIso_DEN_TightIDandIPCut" , f"{ cfg .x .cpn_tag } _UL" )
398
432
cfg .x .muon_id_sf_names = ("NUM_TightID_DEN_TrackerMuons" , f"{ cfg .x .cpn_tag } _UL" )
399
433
cfg .x .muon_iso_sf_names = ("NUM_TightRelIso_DEN_TightIDandIPCut" , f"{ cfg .x .cpn_tag } _UL" )
400
434
401
435
elif cfg .x .run == 3 :
436
+ electron_sf_campaign = {
437
+ "2022postEE" : "2022Re-recoE+PromptFG" ,
438
+ "2022preEE" : "2022Re-recoBCD" ,
439
+ "2023postBPix" : "2023PromptD" ,
440
+ "2023preBPix" : "2023PromptC" ,
441
+ }[cfg .x .cpn_tag ]
442
+
443
+ cfg .x .electron_sf_names = ElectronSFConfig (
444
+ correction = "Electron-ID-SF" ,
445
+ campaign = electron_sf_campaign ,
446
+ working_point = "Tight" ,
447
+ )
402
448
# names of electron correction sets and working points
403
449
# (used in the electron_sf producer)
404
450
if cfg .x .cpn_tag == "2022postEE" :
405
- # TODO: we need to use different SFs for control regions
451
+ # TODO: we might need to use different SFs for control regions
406
452
cfg .x .electron_sf_names = ("Electron-ID-SF" , "2022Re-recoE+PromptFG" , "Tight" )
407
453
elif cfg .x .cpn_tag == "2022preEE" :
408
454
cfg .x .electron_sf_names = ("Electron-ID-SF" , "2022Re-recoBCD" , "Tight" )
409
455
410
456
# names of muon correction sets and working points
411
457
# (used in the muon producer)
412
- # TODO: we need to use different SFs for control regions
413
- cfg .x .muon_sf_names = ("NUM_TightPFIso_DEN_TightID" , f"{ cfg .x .cpn_tag } " )
414
- cfg .x .muon_id_sf_names = ("NUM_TightID_DEN_TrackerMuons" , f"{ cfg .x .cpn_tag } " )
415
- cfg .x .muon_iso_sf_names = ("NUM_TightPFIso_DEN_TightID" , f"{ cfg .x .cpn_tag } " )
458
+ # TODO: we might need to use different SFs for control regions
459
+ cfg .x .muon_id_sf_names = MuonSFConfig (
460
+ correction = "NUM_TightID_DEN_TrackerMuons" ,
461
+ campaign = f"{ cfg .x .cpn_tag } " ,
462
+ )
463
+ cfg .x .muon_iso_sf_names = MuonSFConfig (
464
+ correction = "NUM_TightPFIso_DEN_TightID" ,
465
+ campaign = f"{ cfg .x .cpn_tag } " ,
466
+ )
416
467
417
468
# central trigger SF, only possible for SL
418
469
if cfg .x .lepton_tag == "sl" :
@@ -592,12 +643,12 @@ def add_external(name, value):
592
643
value = DotDict .wrap (value )
593
644
cfg .x .external_files [name ] = value
594
645
595
- json_mirror = "/afs/cern.ch/user/m/mfrahm/public/mirrors/jsonpog-integration-a332cfa "
646
+ json_mirror = "/afs/cern.ch/user/m/mfrahm/public/mirrors/jsonpog-integration-cb90b1e8 "
596
647
if cfg .x .run == 2 :
597
648
# json_mirror = "/afs/cern.ch/user/m/mrieger/public/mirrors/jsonpog-integration-9ea86c4c"
598
649
corr_tag = f"{ cfg .x .cpn_tag } _UL"
599
650
elif cfg .x .run == 3 :
600
- corr_tag = f"{ year } _Summer22 { jerc_postfix } "
651
+ corr_tag = f"{ year } _Summer { year2 } { jerc_postfix } "
601
652
602
653
# pileup weight correction
603
654
add_external ("pu_sf" , (f"{ json_mirror } /POG/LUM/{ corr_tag } /puWeights.json.gz" , "v1" ))
@@ -608,24 +659,21 @@ def add_external(name, value):
608
659
add_external ("jet_veto_map" , (f"{ json_mirror } /POG/JME/{ corr_tag } /jetvetomaps.json.gz" , "v1" ))
609
660
# electron scale factors
610
661
add_external ("electron_sf" , (f"{ json_mirror } /POG/EGM/{ corr_tag } /electron.json.gz" , "v1" ))
611
- add_external ("electron_ss" , (f"{ json_mirror } /POG/EGM/{ corr_tag } /electronSS.json.gz" , "v1" ))
662
+ # add_external("electron_ss", (f"{json_mirror}/POG/EGM/{corr_tag}/electronSS.json.gz", "v1"))
612
663
# muon scale factors
613
664
add_external ("muon_sf" , (f"{ json_mirror } /POG/MUO/{ corr_tag } /muon_Z.json.gz" , "v1" ))
614
665
# trigger_sf from Balduin
615
- # # files with uncertainties, not loadable because there are some NaNs in the json :/
616
- # trigger_sf_path = "/afs/desy.de/user/f/frahmmat/Projects/hh2bbww/data/software/trig_sf"
617
- # add_external("trigger_sf_ee", (f"{trigger_sf_path}/sf_ee+Ele50_CaloI+DoubleEle33_mli_lep_pt-trig_ids.json", "v1"))
618
- # add_external("trigger_sf_mm", (f"{trigger_sf_path}/sf_mm_mli_lep_pt-trig_ids.json", "v1"))
619
- # add_external("trigger_sf_mixed", (f"{trigger_sf_path}/sf_mixed+Ele50_CaloI+DoubleEle33_mli_lep_pt-trig_ids.json", "v1")) # noqa: E501
620
-
621
- # files without uncertainties and with wrong triggers
622
- trigger_sf_path = "/nfs/dust/cms/user/letzerba/hh2bbww/data/cf_store/hbw_dl/cf.CalculateTriggerScaleFactors/c22post/nominal/calib__with_b_reg/sel__dl1_no_triggerV11__steps_no_trigger/prod__event_weightsV2__trigger_prodV2__pre_ml_catsV1__dl_ml_inputsV1/weight__ref_cut/datasets_4_10839b14e3/prod3/" # noqa: E501
623
- add_external ("trigger_sf_ee" , (f"{ trigger_sf_path } /sf_ee_mli_lep_pt-trig_ids.json" , "v1" ))
624
- add_external ("trigger_sf_mm" , (f"{ trigger_sf_path } /sf_mm_mli_lep_pt-trig_ids.json" , "v1" ))
625
- add_external ("trigger_sf_mixed" , (f"{ trigger_sf_path } /sf_mixed_mli_lep_pt-trig_ids.json" , "v1" )) # noqa: E501
666
+
667
+ trigger_sf_path = f"{ json_mirror } /data/trig_sf_v0"
668
+ # add_external("trigger_sf_ee", (f"{trigger_sf_path}/sf_ee+Ele50_CaloI+DoubleEle33_mli_lep_pt-trig_ids_statanda.json", "v2")) # noqa: E501
669
+ # add_external("trigger_sf_mm", (f"{trigger_sf_path}/sf_mm_mli_lep_pt-trig_ids_statanda.json", "v2")) # noqa: E501
670
+ # add_external("trigger_sf_mixed", (f"{trigger_sf_path}/sf_mixed+Ele50_CaloI+DoubleEle33_mli_lep_pt-trig_ids_statanda.json", "v2")) # noqa: E501
671
+ add_external ("trigger_sf_ee" , (f"{ trigger_sf_path } /sf_ee_mli_lep_pt-trig_ids.json" , "v2" ))
672
+ add_external ("trigger_sf_mm" , (f"{ trigger_sf_path } /sf_mm_mli_lep_pt-trig_ids.json" , "v2" ))
673
+ add_external ("trigger_sf_mixed" , (f"{ trigger_sf_path } /sf_mixed_mli_lep_pt-trig_ids.json" , "v2" )) # noqa: E501
626
674
627
675
# btag scale factor
628
- add_external ("btag_sf_corr" , (f"{ json_mirror } /POG/BTV/{ corr_tag } /btagging.json.gz" , "v1 " ))
676
+ add_external ("btag_sf_corr" , (f"{ json_mirror } /POG/BTV/{ corr_tag } /btagging.json.gz" , "v2 " ))
629
677
# V+jets reweighting (derived for 13 TeV, custom json converted from ROOT, not centrally produced)
630
678
# ROOT files (eej.root and aj.root) taken from here:
631
679
# https://github.com/UHH2/2HDM/tree/ultra_legacy/data/ScaleFactors/VJetsCorrections
@@ -660,7 +708,7 @@ def add_external(name, value):
660
708
}
661
709
662
710
# external files with more complex year dependence
663
- if year not in (2017 , 2022 ):
711
+ if year not in (2017 , 2022 , 2023 ):
664
712
raise NotImplementedError ("TODO: generalize external files to different years than 2017" )
665
713
666
714
if year == 2017 :
@@ -727,6 +775,8 @@ def add_external(name, value):
727
775
# isolations for testing
728
776
"Electron.{pfRelIso03_all,miniPFRelIso_all,mvaIso,mvaTTH}" ,
729
777
"Muon.{pfRelIso03_all,miniPFRelIso_all,mvaMuID,mvaTTH}" ,
778
+ # Taus
779
+ "VetoTau.{pt,eta,phi,mass,decayMode}" ,
730
780
# MET
731
781
"{MET,PuppiMET}.{pt,phi}" ,
732
782
# all columns added during selection using a ColumnCollection flag, but skip cutflow ones
@@ -769,6 +819,7 @@ def add_external(name, value):
769
819
# sanity check: sometimes the process is not the same as the one in the dataset
770
820
p1 = cfg .get_process ("dy_m50toinf" )
771
821
p2 = campaign .get_dataset ("dy_m50toinf_amcatnlo" ).processes .get_first ()
822
+ # if repr(p1) != repr(p2):
772
823
if p1 != p2 :
773
824
raise Exception (f"Processes are not the same: { repr (p1 )} != { repr (p2 )} " )
774
825
0 commit comments