FairShip
Loading...
Searching...
No Matches
makeDecay.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# Use Pythia8 to decay the signals (Charm/Beauty) as produced by makeCascade.
5# Output is an ntuple with muon/neutrinos
6import getopt
7import os
8import sys
9
10import ROOT
11import rootUtils as ut
12
13ROOT.gROOT.LoadMacro("$VMCWORKDIR/gconfig/basiclibs.C")
14ROOT.basiclibs()
15
16# latest production May 2016,76 M pot which produce a charm event equivalent,roughly 150 M charm hadrons
17fname = "/eos/experiment/ship/data/Charm/Cascade-parp16-MSTP82-1-MSEL4-76Mpot_1"
18
19nrpotspill = 5.0e13 # number of pot/spill
20chicc = 1.7e-3 # prob to produce primary ccbar pair/pot
21chibb = 1.6e-7 # prob to produce primary bbbar pair/pot
22setByHand = False
23
24print("usage: python $FAIRSHIP/macro/makeDecay.py -f ")
25
26try:
27 opts, args = getopt.getopt(sys.argv[1:], "f:p:c:", ["pot=", "chicc="])
28except getopt.GetoptError:
29 # print help information and exit:
30 print(" enter -f: input file with charm hadrons")
31 print(" for experts: p pot= number of protons on target per spill to normalize on")
32 print(" : c chicc= ccbar over mbias cross section")
33 sys.exit()
34for o, a in opts:
35 if o in ("-f",):
36 fname = a.replace(".root", "")
37 if o in ("-p", "--pot"):
38 nrpotspill = float(a)
39 if o in ("-c", "--chicc"):
40 chicc = float(a)
41 setByHand = True
42
43FIN = fname + ".root"
44tmp = os.path.abspath(FIN).split("/")
45FOUT = "Decay-" + tmp[len(tmp) - 1]
46if FIN.find("eos") < 0:
47 fin = ROOT.TFile(FIN)
48else:
49 fin = ROOT.TFile.Open(ROOT.gSystem.Getenv("EOSSHIP") + FIN)
50sTree = fin.FindObjectAny("pythia6")
51nEvents = sTree.GetEntries()
52
53# Calculate weights, for the whole file.
54# get histogram with number of pot to normalise
55hc = {}
56if fin.GetKey("2"):
57 hc["2"] = fin.Get("2")
58else:
59 fhin = ROOT.TFile(FIN.replace("ntuple", "hists"))
60 hc["2"] = fhin.Get("2")
61
62# pot are counted double, i.e. for each signal, i.e. pot/2.
63nrcpot = hc["2"].GetBinContent(1) / 2.0
64print("Input file: ", FIN, " with ", nEvents, " entries, corresponding to nr-pot=", nrcpot)
65# nEvents=100
66print("Output ntuples written to: ", FOUT)
67
68P8gen = ROOT.TPythia8()
69P8 = P8gen.Pythia8()
70P8.readString("ProcessLevel:all = off")
71
72# let strange particle decay in Geant4
73n = 1
74while n != 0:
75 n = P8.particleData.nextId(n)
76 p = P8.particleData.particleDataEntryPtr(n)
77 if p.tau0() > 1:
78 command = str(n) + ":mayDecay = false"
79 P8.readString(command)
80 print("Pythia8 configuration: Made %s stable for Pythia, should decay in Geant4", p.name())
81P8.init()
82
83
84# output ntuple:
85ftup = ROOT.TFile.Open(FOUT, "RECREATE")
86Ntup = ROOT.TNtuple("Decay", "pythia8 heavy flavour decays", "id:px:py:pz:E:M:weight:mid:mpx:mpy:mpz:mE:pot:ptGM:pzGM")
87
88h = {}
89# book hists for Genie neutrino momentum distrubition, just as check
90# type of neutrino
91PDG = ROOT.TDatabasePDG.Instance()
92for idnu in range(12, 18, 2):
93 # nu or anti-nu
94 for idadd in range(-1, 3, 2):
95 idhnu = 1000 + idnu
96 idw = idnu
97 if idadd == -1:
98 idhnu += 1000
99 idw = -idnu
100 name = PDG.GetParticle(idw).GetName()
101 ut.bookHist(h, str(idhnu), name + " momentum (GeV)", 400, 0.0, 400.0)
102 ut.bookHist(h, str(idhnu + 100), name + " log10-p vs log10-pt", 100, -0.3, 1.7, 100, -2.0, 0.5)
103 ut.bookHist(h, str(idhnu + 200), name + " log10-p vs log10-pt", 25, -0.3, 1.7, 100, -2.0, 0.5)
104
105pot = 0.0
106# Determine fDs on this file for primaries
107nDsprim = 0
108ntotprim = 0
109
110for n in range(nEvents):
111 rc = sTree.GetEvent(n)
112 # check if we deal with charm or beauty:
113 if n == 0:
114 if not setByHand and sTree.M > 5:
115 chicc = chibb
116 print("automatic detection of beauty, configured for beauty")
117 print("bb cross section / mbias ", chicc)
118 else:
119 print("cc cross section / mbias ", chicc)
120 # convert pot to weight corresponding to one spill of 5e13 pot
121 print("weights: ", nrpotspill, " p.o.t. per spill")
122 print(" ")
123 wspill = nrpotspill * chicc / nrcpot
124 # sanity check, count number of p.o.t. on input file.
125 pt = ROOT.TMath.Sqrt(sTree.mpx**2 + sTree.mpy**2)
126 # every event appears twice, i.e.
127 if pt < 1.0e-5 and int(sTree.mid) == 2212:
128 pot = pot + 0.5
129 ntotprim += 1
130 idabs = int(abs(sTree.id))
131 if idabs == 431:
132 nDsprim += 1
133 P8.event.reset()
134 P8.event.append(int(sTree.id), 1, 0, 0, sTree.px, sTree.py, sTree.pz, sTree.E, sTree.M, 0.0, 9.0)
135 next(P8)
136 # P8.event.list()
137 for n in range(len(P8.event)):
138 # ask for stable particles
139 if P8.event[n].isFinal():
140 # select neutrinos and mu
141 idabs = int(abs(P8.event[n].id()))
142 if idabs > 11 and idabs < 17:
143 par = P8.event[n]
144 ptGM = ROOT.TMath.Sqrt(sTree.mpx * sTree.mpx + sTree.mpy * sTree.mpy)
145 Ntup.Fill(
146 par.id(),
147 par.px(),
148 par.py(),
149 par.pz(),
150 par.e(),
151 par.m(),
152 wspill,
153 sTree.id,
154 sTree.px,
155 sTree.py,
156 sTree.pz,
157 sTree.E,
158 sTree.M,
159 ptGM,
160 sTree.mpz,
161 )
162 # count total muons from charm/spill, and within some angular range..
163 if idabs == 16 or idabs == 14 or idabs == 12:
164 idhnu = idabs + 1000
165 if par.id() < 0:
166 idhnu += 1000
167 pt2 = par.px() ** 2 + par.py() ** 2
168 ptot = ROOT.TMath.Sqrt(pt2 + par.pz() ** 2)
169 l10ptot = min(max(ROOT.TMath.Log10(ptot), -0.3), 1.69999)
170 l10pt = min(max(ROOT.TMath.Log10(ROOT.TMath.Sqrt(pt2)), -2.0), 0.4999)
171 h[str(idhnu)].Fill(ptot, wspill)
172 h[str(idhnu + 100)].Fill(l10ptot, l10pt, wspill)
173 h[str(idhnu + 200)].Fill(l10ptot, l10pt, wspill)
174
175print("Now at Ntup.Write() for pot=", pot, nrcpot)
176if (1.0 - pot / nrcpot) < 1.0e-2:
177 print("write ntuple, weight/event=", nrpotspill, "x", chicc, "/", nrcpot, "=", wspill)
178 Ntup.Write()
179 for akey in h:
180 h[akey].Write()
181 ftup.Close()
182 print("Neutrino statistics/spill of 5.e15 pot:")
183 for idnu in range(12, 18, 2):
184 # nu or anti-nu
185 for idadd in range(-1, 3, 2):
186 idhnu = 1000 + idnu
187 idw = idnu
188 if idadd == -1:
189 idhnu += 1000
190 idw = -idnu
191 print(idhnu, h[str(idhnu)].GetTitle(), ("%8.3E " % (h[str(idhnu)].Integral())))
192
193 fDsP6 = 1.0 * nDsprim / ntotprim
194 fDs = 0.077 # Used in TP..
195 print(" ")
196 print("fDs of primary proton interactions in P6=", fDsP6, " should be ", fDs)
197
198else:
199 print("*********** WARNING ***********")
200 print("number of POT does not agree between ntuple and hists, i.e.:", pot, "<>", nrcpot)
201 print("mu/neutrino ntuple has NOT been written")
202#