-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathprocesses.py
187 lines (160 loc) · 6.49 KB
/
processes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# coding: utf-8
"""
Configuration of the Run 2 HH -> bbWW processes.
"""
import cmsdb
import order as od
from scinum import Number
from cmsdb.util import add_decay_process
def add_parent_process(config: od.Config, child_procs: list[od.Process], **kwargs):
"""
Helper function to create processes from multiple processes *child_procs*
"""
if "id" not in kwargs:
raise ValueError("A field 'id' is required to create a process")
if "name" not in kwargs:
raise ValueError("A field 'name' is required to create a process")
proc_kwargs = kwargs.copy()
if "xsecs" not in kwargs:
# set the xsec as sum of all xsecs when the ecm key exists for all processes
valid_ecms = set.intersection(*[set(proc.xsecs.keys()) for proc in child_procs])
proc_kwargs["xsecs"] = {ecm: sum([proc.get_xsec(ecm) for proc in child_procs]) for ecm in valid_ecms}
parent_process = config.add_process(**proc_kwargs)
# add child processes to parent
for child_proc in child_procs:
parent_process.add_process(child_proc)
return parent_process
def add_dummy_xsecs(config: od.Config, dummy_xsec: float = 0.1):
""" Helper that adds some dummy xsecs when missing for the campaign's correspondign ecm """
ecm = config.campaign.ecm
process_insts = [
process_inst
for process_inst, _, _ in config.walk_processes()
if process_inst.is_mc
]
for process_inst in process_insts:
if not process_inst.xsecs.get(ecm, None):
# print(f"TODO: xsecs for {ecm} TeV, process {process_inst.name}")
process_inst.xsecs[ecm] = Number(dummy_xsec)
# # temporary xsecs from XSDB
# config.get_process("dy").xsecs[13.6] = Number(67710.0) # https://xsdb-temp.app.cern.ch/xsdb/?columns=37814272¤tPage=0&pageSize=10&searchQuery=DAS%3DWtoLNu-2Jets_TuneCP5_13p6TeV_amcatnloFXFX-pythia8 # noqa
# config.get_process("w_lnu").xsecs[13.6] = Number(5558.0) # https://xsdb-temp.app.cern.ch/xsdb/?columns=37814272¤tPage=0&ordDirection=1&ordFieldName=process_name&pageSize=10&searchQuery=DAS%3DWtoLNu-2Jets_TuneCP5_13p6TeV_amcatnloFXFX-pythia8 # noqa
# temporary xsecs that were missing in xsdb
# for proc in ("qcd_mu_pt170to300", "qcd_mu_pt470to600", "qcd_mu_pt1000"):
# proc_inst = config.get_process(proc)
# proc_inst.set_xsec(13.6, proc_inst.get_xsec(13))
def configure_hbw_processes(config: od.Config):
# add main HH process
config.add_process(cmsdb.processes.hh_ggf.copy())
# Set dummy xsec for all processes if missing
add_dummy_xsecs(config)
# QCD process customization
qcd_mu = config.get_process("qcd_mu", default=None)
if qcd_mu:
qcd_mu = "QCD Muon enriched"
# add custom qcd_ele process
qcd_em = config.get_process("qcd_em", default=None)
qcd_bctoe = config.get_process("qcd_bctoe", default=None)
if qcd_em and qcd_bctoe:
qcd_ele = add_parent_process( # noqa
config,
[qcd_em, qcd_bctoe],
name="qcd_ele",
id=31199,
label="QCD Electron enriched",
)
elif qcd_em:
qcd_ele = add_parent_process( # noqa
config,
[qcd_em],
name="qcd_ele",
id=31199,
label="QCD Electron enriched",
)
# custom v_lep process for ML Training, combining W+DY
w_lnu = config.get_process("w_lnu", default=None)
dy = config.get_process("dy", default=None)
if w_lnu and dy:
v_lep = add_parent_process( # noqa
config,
[w_lnu, dy],
name="v_lep",
id=64575573, # random number
label="W and DY",
)
# Custom t_bkg process for ML Training, combining tt+st
st = config.get_process("st", default=None)
tt = config.get_process("tt", default=None)
if st and tt:
t_bkg = add_parent_process( # noqa
config,
[st, tt],
name="t_bkg",
id=97842611, # random number
label="tt + st",
)
if config.has_tag("is_dl") and config.has_tag("is_nonresonant") and config.x.run == 2:
# Custom signal process for ML Training, combining multiple kl signal samples
# NOTE: only built for run 2 because kl variations are missing in run 3
signal_processes = [
config.get_process(f"hh_ggf_hbb_hvv2l2nu_kl{kl}_kt1", deep=True)
for kl in [0, 1, "2p45"]
]
sig = config.add_process(
name="sig",
id=75835213, # random number
xsecs={
13: sum([proc.get_xsec(13) for proc in signal_processes]),
},
label="signal",
)
for proc in signal_processes:
try:
sig.add_process(proc)
except Exception:
# this also adds 'sig' as parent to 'proc', but sometimes this is happening
# multiple times, since we create multiple configs
pass
# add auxiliary information if process is signal
for proc_inst, _, _ in config.walk_processes():
is_signal = any([
signal_tag in proc_inst.name
for signal_tag in ("hh_vbf", "hh_ggf", "radion", "gravition")
])
if is_signal:
proc_inst.add_tag("is_signal")
decay_map = {
"lf": {
"name": "lf",
"id": 50,
"label": "(lf)",
"br": -1,
},
"hf": {
"name": "hf",
"id": 60,
"label": "(hf)",
"br": -1,
},
}
# add heavy flavour and light flavour dy processes
for proc in (
"dy",
"dy_m4to10", "dy_m10to50",
"dy_m50toinf",
"dy_m50toinf_0j", "dy_m50toinf_1j", "dy_m50toinf_2j",
):
dy_proc_inst = config.get_process(proc, default=None)
if dy_proc_inst:
add_production_mode_parent = proc != "dy"
for flavour in ("hf", "lf"):
# the 'add_decay_process' function helps us to create all parent-daughter relationships
add_decay_process(
dy_proc_inst,
decay_map[flavour],
add_production_mode_parent=add_production_mode_parent,
name_func=lambda parent_name, decay_name: f"{parent_name}_{decay_name}",
label_func=lambda parent_label, decay_label: f"{parent_label} {decay_label}",
xsecs=None,
aux={"flavour": flavour},
)