FairShip
Loading...
Searching...
No Matches
runPythia8.py
Go to the documentation of this file.
1# SPDX-License-Identifier: LGPL-3.0-or-later
2# SPDX-FileCopyrightText: Copyright CERN for the benefit of the SHiP Collaboration
3
4
5import ROOT
6import rootUtils as ut
7
8# PYTHIA8 requires Random:seed to be in range [0, 900000000]
9# When theSeed=0, ROOT generates a seed from system time which can exceed this limit
10theSeed = 0
11h = {}
12ROOT.gRandom.SetSeed(0) # Generate time-based seed
13theSeed = ROOT.gRandom.GetSeed()
14# Clamp to PYTHIA8's maximum allowed seed value
15if theSeed > 900000000:
16 theSeed = theSeed % 900000000
17ROOT.gRandom.SetSeed(theSeed)
18ROOT.gSystem.Load("libpythia8")
19
20from argparse import ArgumentParser
21
22parser = ArgumentParser()
23parser.add_argument("-b", "--heartbeat", dest="heartbeat", type=int, help="progress report", default=10000)
24parser.add_argument("-n", "--pot", dest="NPoT", type=int, help="protons on target", default=1000000)
25parser.add_argument("-r", "--run", dest="run", type=int, help="production sequence number", default=0)
26parser.add_argument("-M", "--Emin", dest="Emin", type=float, help="cutOff", default=1.0)
27parser.add_argument("-E", "--Beam", dest="fMom", type=float, help="beam momentum", default=400.0)
28parser.add_argument("-J", "--Jpsi-mainly", action="store_true", dest="JpsiMainly", default=False)
29parser.add_argument("-Y", "--DrellYan", action="store_true", dest="DrellYan", default=False)
30parser.add_argument("-P", "--PhotonCollision", action="store_true", dest="PhotonCollision", default=False)
31parser.add_argument("-C", "--charm", action="store_true", dest="charm", default=False)
32parser.add_argument("-X", "--PDFpSet", dest="PDFpSet", type=str, help="PDF pSet to use", default="13")
33parser.add_argument("-u", "--uOnly", action="store_true", dest="uOnly", default=False)
34
35# for lhapdf, -X LHAPDF6:cteq6
36
37options = parser.parse_args()
38print("start IGNOREIGNOREIGNOREIGNOREIGNOREIGNOREIGNOREIGNOREIGNORE")
39X = ROOT.FixedTargetGenerator()
40print("end IGNOREIGNOREIGNOREIGNOREIGNOREIGNOREIGNOREIGNOREIGNORE")
41
42
43def yBeam(Mproton: float = 0.938272081, pbeam: float = 400.0):
44 Ebeam = ROOT.TMath.Sqrt(pbeam**2 + Mproton**2)
45 betaCM = pbeam / (Ebeam + Mproton)
46 y_beam = 0.5 * ROOT.TMath.Log((1 + betaCM) / (1 - betaCM)) # https://arxiv.org/pdf/1604.02651.pdf
47 return y_beam
48
49
50generators = {"p": ROOT.Pythia8.Pythia(), "n": ROOT.Pythia8.Pythia()}
51generators["p"].settings.mode("Beams:idB", 2212)
52generators["n"].settings.mode("Beams:idB", 2112)
53
54for g in generators:
55 ut.bookHist(h, "xsec_" + g, " total cross section", 1, 0.0, 1.0)
56 ut.bookHist(h, "M_" + g, " N mu+mu-;M [GeV/c^{2}];y_{CM}", 500, 0.0, 10.0, 120, -3.0, 3.0, 100, 0.0, 5.0)
57 ut.bookHist(h, "cosCS_" + g, " N cosCS;cosCS;y_{CM}", 100, -1.0, 1.0, 120, -3.0, 3.0, 100, 0.0, 5.0)
58 ut.bookHist(h, "cosCSJpsi_" + g, " N cosCS 2.9<M<4.5;cosCS;y_{CM}", 100, -1.0, 1.0, 120, -3.0, 3.0, 100, 0.0, 5.0)
59 generators[g].settings.mode("Next:numberCount", options.heartbeat)
60 generators[g].settings.mode("Beams:idA", 2212)
61 generators[g].settings.mode("Beams:frameType", 2)
62 generators[g].settings.parm("Beams:eA", options.fMom) # codespell:ignore parm
63 generators[g].settings.parm("Beams:eB", 0.0) # codespell:ignore parm
64 generators[g].readString("PDF:pSet = " + options.PDFpSet)
65 if options.DrellYan:
66 generators[g].readString("WeakSingleBoson:ffbar2gmZ = on")
67 if options.uOnly:
68 generators[g].readString("23:onMode = off")
69 generators[g].readString("23:onIfAll = 13 13")
70 generators[g].readString("23:mMin = " + str(options.Emin))
71 generators[g].readString("PhaseSpace:mHatMin = " + str(options.Emin))
72 # generators[g].readString("BeamRemnants:primordialKThard = 0.8")
73 generators[g].readString("PartonLevel:FSR = on")
74 elif options.JpsiMainly:
75 # use this for all onia productions
76 generators[g].readString("Onia:all(3S1) = on")
77 if options.uOnly:
78 generators[g].readString("443:onMode = off")
79 generators[g].readString("443:onIfAll = 13 13")
80 generators[g].readString("553:onMode = off")
81 generators[g].readString("553:onIfAll = 13 13")
82 elif options.PhotonCollision:
83 generators[g].readString("PhotonCollision:gmgm2mumu = on")
84 generators[g].readString("PhaseSpace:mHatMin = " + str(options.Emin))
85 elif options.charm:
86 generators[g].readString("HardQCD:hardccbar = on")
87 else:
88 generators[g].readString("SoftQCD:inelastic = on")
89 generators[g].init()
90
91rc = generators["p"].next()
92processes = generators["p"].info.codesHard()
93hname = (
94 "pythia8_PDFpset"
95 + options.PDFpSet
96 + "_Emin"
97 + str(options.Emin)
98 + "_"
99 + generators["p"].info.nameProc(processes[0])
100)
101hname = hname.replace("*", "star")
102hname = hname.replace("->", "to")
103hname = hname.replace("/", "")
104
105f = ROOT.TFile("ntuple-" + hname + ".root", "RECREATE")
106signal = ROOT.TNtuple("ntuple", "ntuple", "M:P:Pt:y:p1x:p1y:p1z:p2x:p2y:p2z:cosCS")
107
108timer = ROOT.TStopwatch()
109timer.Start()
110
111ntagged = {"p": 0, "n": 0}
112ybeam = yBeam(pbeam=options.fMom)
113for n in range(int(options.NPoT)):
114 for g in generators:
115 py = generators[g]
116 rc = py.next()
117 nmu = {}
118 for ii in range(1, len(py.event)):
119 if options.DrellYan and py.event[ii].id() != 23:
120 continue
121 if options.PhotonCollision and py.event[ii].id() != 22:
122 continue
123 for m in py.event.daughterList(ii):
124 if abs(py.event[m].id()) == 13:
125 nmu[m] = ii
126 if len(nmu) == 2:
127 ntagged[g] += 1
128 ks = list(nmu)
129 if options.DrellYan:
130 Zstar = py.event[nmu[ks[0]]]
131 rc = h["M_" + g].Fill(Zstar.m(), py.event[nmu[ks[0]]].y() - ybeam, py.event[nmu[ks[0]]].pT())
132 # what about polarization?
133 ii = nmu[ks[0]]
134 d0 = py.event.daughterList(ii)[0]
135 d1 = py.event.daughterList(ii)[1]
136 if py.event[d0].id() < 0:
137 nlep = py.event[d0]
138 nantilep = py.event[d1]
139 else:
140 nlep = py.event[d1]
141 nantilep = py.event[d0]
142 P1pl = nlep.e() + nlep.pz()
143 P2pl = nantilep.e() + nantilep.pz()
144 P1mi = nlep.e() - nlep.pz()
145 P2mi = nantilep.e() - nantilep.pz()
146 A = P1pl * P2mi - P2pl * P1mi
147 cosCS = (
148 Zstar.pz() / abs(Zstar.pz()) * 1.0 / Zstar.m() / ROOT.TMath.Sqrt(Zstar.m2() + Zstar.pT() ** 2) * A
149 )
150 rc = h["cosCS_" + g].Fill(cosCS, Zstar.y() - ybeam, py.event[nmu[ks[0]]].pT())
151 if Zstar.m() > 2.9 and Zstar.m() < 4.5:
152 rc = h["cosCSJpsi_" + g].Fill(cosCS, py.event[nmu[ks[0]]].y() - ybeam, py.event[nmu[ks[0]]].pT())
153 rc = signal.Fill(
154 Zstar.m(),
155 Zstar.pAbs(),
156 Zstar.pT(),
157 Zstar.y(),
158 nlep.px(),
159 nlep.py(),
160 nlep.pz(),
161 nantilep.px(),
162 nantilep.py(),
163 nantilep.pz(),
164 cosCS,
165 )
166 if options.PhotonCollision:
167 M = {}
168 k = 0
169 for m in ks:
170 M[k] = ROOT.TLorentzVector(py.event[m].px(), py.event[m].py(), py.event[m].pz(), py.event[m].e())
171 k += 1
172 G = M[0] + M[1]
173 rc = h["M_" + g].Fill(G.M(), G.Rapidity() - ybeam, G.Pt())
174
175
176print(">>>> proton statistics, ntagged=", ntagged["p"])
177generators["p"].stat()
178print(">>>> neutron statistics, ntagged=", ntagged["n"])
179generators["n"].stat()
180
181timer.Stop()
182rtime = timer.RealTime()
183ctime = timer.CpuTime()
184print("run ", options.run, " PoT ", options.NPoT, " Real time ", rtime, " s, CPU time ", ctime, "s")
185signal.Write()
186for g in generators:
187 sigma = generators[g].info.sigmaGen(processes[0])
188 h["xsec_" + g].SetBinContent(1, sigma)
189ut.writeHists(h, hname + ".root")
190
191
192def na50(online: bool = True) -> None:
193 for g in generators:
194 if online:
195 processes = generators[g].info.codesHard()
196 name = generators[g].info.nameProc(processes[0])
197 sigma = generators[g].info.sigmaGen(processes[0])
198 else:
199 name = ""
200 sigma = h["xsec_" + g].GetBinContent(1)
201 yax = h["M_" + g].GetYaxis()
202 xax = h["M_" + g].GetXaxis()
203 Mmin = xax.FindBin(2.9)
204 Mmax = xax.FindBin(4.5)
205 Ymin = yax.FindBin(-0.425)
206 Ymax = yax.FindBin(0.575)
207 h["MA"] = h["M_" + g].ProjectionX("MA")
208 h["M"] = h["M_" + g].ProjectionX("M", Ymin, Ymax)
209 print("generator sigma mumu-ratio in-mass-range in-y-range")
210 print(
211 "%s %s %6.2F nbarn, %5.2F, %5.2G, %5.2F "
212 % (
213 g,
214 name,
215 sigma * 1e6,
216 float(h["MA"].GetEntries()) / options.NPoT,
217 h["MA"].Integral(Mmin, Mmax) / float(h["MA"].GetEntries()),
218 h["M"].GetEntries() / float(h["MA"].GetEntries()),
219 )
220 )
221 fraction = h["M"].Integral(Mmin, Mmax) / options.NPoT
222 # multiply with 0.5 assuming no polarization -0.5 < cosCS < 0.5
223 print(f"cross section a la NA50 for : {g} {0.5 * fraction * sigma * 1e9:5.2F} pb")
224 # via cosCS
225 for g in generators:
226 if online:
227 processes = generators[g].info.codesHard()
228 name = generators[g].info.nameProc(processes[0])
229 sigma = generators[g].info.sigmaGen(processes[0])
230 else:
231 name = ""
232 sigma = h["xsec_" + g].GetBinContent(1)
233 yax = h["cosCSJpsi_" + g].GetYaxis()
234 xax = h["cosCSJpsi_" + g].GetXaxis()
235 Mmin = xax.FindBin(-0.5)
236 Mmax = xax.FindBin(0.5)
237 Ymin = yax.FindBin(-0.425)
238 Ymax = yax.FindBin(0.575)
239 h["MA"] = h["cosCSJpsi_" + g].ProjectionX("MA")
240 h["M"] = h["cosCSJpsi_" + g].ProjectionX("M", Ymin, Ymax)
241 print("generator sigma mumu-in-mass-range% cosCS in-y-range")
242 print(
243 "%s %s %6.2F nbarn, %5.2F, %5.2F, %5.2F "
244 % (
245 g,
246 name,
247 sigma * 1e6,
248 float(h["MA"].GetEntries()) / options.NPoT * 100.0,
249 h["MA"].Integral(Mmin, Mmax) / float(h["MA"].GetEntries()),
250 h["M"].GetEntries() / float(h["MA"].GetEntries()),
251 )
252 )
253 fraction = h["M"].Integral(Mmin, Mmax) / options.NPoT
254 # taking polarization into account.
255 print("cross section a la NA50, -0.5<cosCS<0.5: %5.2F pb" % (fraction * sigma * 1e9))
256
257
258def muflux() -> None:
259 Z_Mo = 96.0
260 P_Mo = 42
261 fraction = {}
262 for g in generators:
263 processes = generators[g].info.codesHard()
264 name = generators[g].info.nameProc(processes[0])
265 sigma = generators[g].info.sigmaGen(processes[0])
266 yax = h["M_" + g].GetYaxis()
267 xax = h["M_" + g].GetXaxis()
268 Mmin = xax.FindBin(0.0)
269 Mmax = xax.FindBin(5.0)
270 Ymin = yax.FindBin(0.3)
271 Ymax = yax.FindBin(3.0)
272 h["MA"] = h["M_" + g].ProjectionX("MA")
273 h["M"] = h["M_" + g].ProjectionX("M", Ymin, Ymax)
274 print(
275 g,
276 name,
277 sigma,
278 float(h["MA"].GetEntries()) / options.NPoT,
279 h["MA"].Integral(Mmin, Mmax) / float(h["MA"].GetEntries()),
280 h["M"].GetEntries() / float(h["MA"].GetEntries()),
281 )
282 fraction[g] = h["M"].Integral(Mmin, Mmax) / options.NPoT
283 meanFraction = (fraction["p"] * P_Mo + fraction["n"] * (Z_Mo - P_Mo)) / Z_Mo * sigma
284 print("cross section a la muflux: %5.2F pb" % (0.5 * meanFraction * 1e9))
285
286
287def debugging(g) -> None:
288 generators[g].settings.listAll()
def yBeam(float Mproton=0.938272081, float pbeam=400.0)
Definition: runPythia8.py:43
None debugging(g)
Definition: runPythia8.py:287
None muflux()
Definition: runPythia8.py:258
None na50(bool online=True)
Definition: runPythia8.py:192