SND@LHC Software
Loading...
Searching...
No Matches
makeCascade.py
Go to the documentation of this file.
1from __future__ import print_function
2from __future__ import division
3import ROOT,time,os,sys,random,getopt,copy
4from array import array
5import rootUtils as ut
6ROOT.gROOT.LoadMacro("$VMCWORKDIR/gconfig/basiclibs.C")
7ROOT.basiclibs()
8timer = ROOT.TStopwatch()
9timer.Start()
10
11R = ''
12#generate ccbar (msel=4) or bbbar(msel=5)
13mselcb=4
14pbeamh=400.
15storePrimaries = False
16nevgen=100000
17Fntuple='Cascade100k-parp16-MSTP82-1-MSEL'+str(mselcb)+'-ntuple.root'
18
19print("usage: python $FAIRSHIP/macro/makeCascade.py -n (20000) -msel (4) -E (400)")
20
21try:
22 opts, args = getopt.getopt(sys.argv[1:], "s:t:H:n:E:m:P",[\
23 "msel=","seed=","beam="])
24except getopt.GetoptError:
25 # print help information and exit:
26 print(' enter -n: number of events to produce, default 20000')
27 print(' -m --msel=4 (5): charm (beauty) production, default charm')
28 print(' -E --beam=: energy of beam, default 400 GeV')
29 print(' -t: name of ntuple output file, default: Cascade20k-parp16-MSTP82-1-MSEL"+msel+"-ntuple.root')
30 print(' -s --seed: random number seed, integer, if not given, current time will be used.')
31 print(' -P : store all particles produced together with charm')
32 sys.exit()
33for o, a in opts:
34 if o in ("-n",):
35 nevgen = int(a)
36 if o in ("-E","--beam"):
37 pbeamh = float(a)
38 if o in ("-m","--msel"):
39 mselcb = int(a)
40 if o in ("-t",):
41 Fntuple = a
42 if o in ("-s","--seed"):
43 R = int(a)
44 if o in ("-P",):
45 storePrimaries = True
46print('Generate ',nevgen,' p.o.t. with msel=',mselcb,' proton beam ',pbeamh,'GeV')
47print('Output ntuples written to: ',Fntuple)
48
49
50#some parameters for generating the chi (sigma(signal)/sigma(total) as a function of momentum
51# event/momentum, and number of momentum points taken to calculate sig/sigtot
52nev=5000
53nrpoints=20
54# cascade beam particles, anti-particles are generated automatically if they exist.
55idbeam=[2212,211,2112,321,130,310]
56target=['p+','n0']
57print('Chi generation with ',nev,' events/point, nr points=',nrpoints)
58print('Cascade beam particle: ',idbeam)
59
60# Assume Molybdum target, fracp is the fraction of protons in nucleus, i.e. 42/98.
61# Used to average chi on p and n target in Pythia.
62fracp=0.43
63#
64print('Target particles: ',target,' fraction of protons in Mo=',fracp)
65
66# lower/upper momentum limit for beam, depends on msel..
67# signal particles wanted (and their antis), which could decay semi-leptonically.
68if mselcb==4:
69 pbeaml=34.
70 idsig=[411, 421, 431,4122,4132,4232,4332,4412,4414,4422,4424,4432,4434,4444]
71elif mselcb==5:
72 pbeaml=130.
73 idsig=[511, 521, 531, 541,5122,5132,5142,5232,5242,5332,5342,5412,5414,5422,5424,5432,5434,5442,5444,5512,5514,5522,5524,5532,5534,5542,5544,5554]
74else:
75 print('Error: msel is unknown',mselcb,' STOP program')
76 sys.exit('ERROR on input, exit')
77
78PDG = ROOT.TDatabasePDG.Instance()
79myPythia = ROOT.TPythia6()
80tp = ROOT.tPythia6Generator()
81
82# Pythia6 can only accept names below in pyinit, hence reset PDG table:
83PDG.GetParticle(2212).SetName('p+')
84PDG.GetParticle(-2212).SetName('pbar-')
85PDG.GetParticle(2112).SetName('n0')
86PDG.GetParticle(-2112).SetName('nbar0')
87PDG.GetParticle(130).SetName('KL0')
88PDG.GetParticle(310).SetName('KS0')
89#lower lowest sqrt(s) allowed for generating events
90myPythia.SetPARP(2,2.)
91
93# settings with default Pythia6 pdf, based on getting <pt> at 500 GeV pi-
94# same as that of E791: http://arxiv.org/pdf/hep-ex/9906034.pdf
95 print(' ')
96 print('********** PoorE791_tune **********')
97 #change pt of D's to mimic E791 data.
98 P6.SetPARP(91,1.6)
99 print('PARP(91)=',P6.GetPARP(91))
100 #what PDFs etc.. are being used:
101 print('MSTP PDF info, i.e. (51) and (52)=',P6.GetMSTP(51),P6.GetMSTP(52))
102 #set multiple interactions equal to Fortran version, i.e.=1, default=4, and adapt parp(89) accordingly
103 P6.SetMSTP(82,1)
104 P6.SetPARP(89,1000.)
105 print('And corresponding multiple parton stuff, i.e. MSTP(82),PARP(81,89,90)=',P6.GetMSTP(82),P6.GetPARP(81),P6.GetPARP(89),P6.GetPARP(90))
106 print('********** PoorE791_tune **********')
107 print(' ')
108
109def LHCb_tune(P6):
110# settings by LHCb for Pythia 6.427
111# https://twiki.cern.ch/twiki/bin/view/LHCb/SettingsSim08
112 print(' ')
113 print('********** LHCb_tune **********')
114 #P6.SetCKIN(41,3.0)
115 P6.SetMSTP(2, 2)
116 P6.SetMSTP(33, 3)
117 #P6.SetMSTP(128, 2) #store or not store
118 P6.SetMSTP(81, 21)
119 P6.SetMSTP(82, 3)
120 P6.SetMSTP(52, 2)
121 P6.SetMSTP(51, 10042)# (ie CTEQ6 LO fit, with LOrder alpha_S PDF from LHAPDF)
122 P6.SetMSTP(142, 0) #do not weigh events
123 P6.SetPARP(67, 1.0)
124 P6.SetPARP(82, 4.28)
125 P6.SetPARP(89, 14000)
126 P6.SetPARP(90, 0.238)
127 P6.SetPARP(85, 0.33)
128 P6.SetPARP(86, 0.66)
129 P6.SetPARP(91, 1.0)
130 P6.SetPARP(149, 0.02)
131 P6.SetPARP(150, 0.085)
132 P6.SetPARJ(11, 0.4)
133 P6.SetPARJ(12, 0.4)
134 P6.SetPARJ(13, 0.769)
135 P6.SetPARJ(14, 0.09)
136 P6.SetPARJ(15, 0.018)
137 P6.SetPARJ(16, 0.0815)
138 P6.SetPARJ(17, 0.0815)
139 P6.SetMSTJ(26, 0)
140 P6.SetPARJ(33, 0.4)
141 print('********** LHCb_tune **********')
142 print(' ')
143
144def fillp1(hist):
145# scan filled bins in hist, and fill intermediate bins with lineair interpolation
146 nb=hist.GetNbinsX()
147 i1=hist.FindBin(pbeaml,0.,0.)
148 y1=hist.GetBinContent(i1)
149 p1=hist.GetBinCenter(i1)
150 for i in range(i1+1,nb+1):
151 if hist.GetBinContent(i)>0.:
152 y2=hist.GetBinContent(i)
153 p2=hist.GetBinCenter(i)
154 tg=(y2-y1)/(p2-p1)
155 for ib in range(i1+1,i):
156 px=hist.GetBinCenter(ib)
157 yx=(px-p1)*tg+y1
158 hist.Fill(px,yx)
159 i1=i
160 y1=y2
161 p1=p2
162
163
164#choose the Pythia tune:
165PoorE791_tune(myPythia)
166#LHCb_tune(myPythia)
167#avoid any printing to the screen, only when LHAPDF is used, i.e. LHCb tune.
168#myPythia.OpenFortranFile(6, os.devnull)
169
170# Pythia output to dummy (11) file (to screen use 6)
171myPythia.OpenFortranFile(11, os.devnull)
172myPythia.SetMSTU(11, 11)
173
174
175#start with different random number for each run...
176if R == '': R = int(time.time()*100000000%900000000)
177print('Setting random number seed =',R)
178myPythia.SetMRPY(1,R)
179
180#histogram helper
181h={}
182
183# initalise phase, determine chi=sigma(signal)/sigma(total) for many beam momenta.
184# loop over beam particles
185id=0
186nb=400
187t0=time.time()
188idhist=len(idbeam)*4*[0]
189print('Get chi vs momentum for all beam+target particles')
190for idp in range(0,len(idbeam)):
191# particle or antiparticle
192 for idpm in range(-1,3,2):
193 idw=idbeam[idp]*idpm
194 if PDG.GetParticle(idw)!=None:
195 name=PDG.GetParticle(idw).GetName()
196# particle exists, book hists etc..
197 id=id+1
198 for idnp in range(2):
199 idb=id*10+idnp*4
200 ut.bookHist(h,str(idb+1),'sigma vs p, '+name+'->'+target[idnp],nb,0.5,pbeamh+0.5)
201 ut.bookHist(h,str(idb+2),'sigma-tot vs p, '+name+'->'+target[idnp],nb,0.5,pbeamh+0.5)
202 ut.bookHist(h,str(idb+3),'chi vs p, '+name+'->'+target[idnp],nb,0.5,pbeamh+0.5)
203 ut.bookHist(h,str(idb+4),'Prob(normalised), '+name+'->'+target[idnp],nb,0.5,pbeamh+0.5)
204# keep track of histogram<->Particle id relation.
205 idhist[id]=idw
206# target is proton or neutron
207 for idpn in range(2):
208 idadd=idpn*4
209# loop over beam momentum
210 print(name,'+',target[idpn],' for chi, seconds:',time.time()-t0)
211 for ipbeam in range(nrpoints):
212 pbw=ipbeam*(pbeamh-pbeaml)/(nrpoints-1)+pbeaml
213# convert to center of a bin
214 ibin=h[str(id*10+1+idadd)].FindBin(pbw,0.,0.)
215 pbw=h[str(id*10+1+idadd)].GetBinCenter(ibin)
216# new particle/momentum, init again, first signal run.
217 myPythia.SetMSEL(mselcb) # set forced ccbar or bbbar generation
218 myPythia.Initialize('FIXT',name,target[idpn],pbw)
219 for iev in range(nev):
220 myPythia.GenerateEvent()
221# signal run finished, get cross-section
222 h[str(id*10+1+idadd)].Fill(pbw,tp.getPyint5_XSEC(2,0))
223# now total cross-section, i.e. msel=2
224 myPythia.SetMSEL(2)
225 myPythia.Initialize('FIXT',name,target[idpn],pbw)
226 for iev in range(nev//10):
227# if iev%100==0: print 'generated mbias events',iev,' seconds:',time.time()-t0
228 myPythia.GenerateEvent()
229# get cross-section
230 h[str(id*10+2+idadd)].Fill(pbw,tp.getPyint5_XSEC(2,0))
231# for this beam particle, do arithmetics to get chi.
232 h[str(id*10+3+idadd)].Divide(h[str(id*10+1+idadd)],h[str(id*10+2+idadd)],1.,1.)
233# fill with lineair function between evaluated momentum points.
234 fillp1(h[str(id*10+3+idadd)])
235
236# collected all, now re-scale to make max chi at 400 Gev==1.
237chimx=0.
238for i in range(1,id+1):
239 for idpn in range(2):
240 idw=i*10+idpn*4+3
241 ibh=h[str(idw)].FindBin(pbeamh)
242 print('beam id, momentum,chi,chimx=',i,idw,idhist[i],pbeamh,h[str(idw)].GetBinContent(ibh),chimx)
243 if h[str(idw)].GetBinContent(ibh)>chimx: chimx=h[str(idw)].GetBinContent(ibh)
244chimx=1./chimx
245for i in range(1,id+1):
246 for idpn in range(2):
247 idw=i*10+idpn*4+3
248 h[str(idw+1)].Add(h[str(idw)],h[str(idw)],chimx,0.)
249
250# switch output printing OFF for generation phase.
251# Generate ccbar (or bbbar) pairs according to probability in hists i*10+8.
252# some check histos
253ut.bookHist(h,str(1),'E of signals',100,0.,400.)
254ut.bookHist(h,str(2),'nr signal per cascade depth',50,0.5,50.5)
255ut.bookHist(h,str(3),'D0 pt**2',40,0.,4.)
256ut.bookHist(h,str(4),'D0 pt**2',100,0.,18.)
257ut.bookHist(h,str(5),'D0 pt',100,0.,10.)
258ut.bookHist(h,str(6),'D0 XF',100,-1.,1.)
259
260ftup = ROOT.TFile.Open(Fntuple, 'RECREATE')
261Ntup = ROOT.TNtuple("pythia6","pythia6 heavy flavour",\
262 "id:px:py:pz:E:M:mid:mpx:mpy:mpz:mE:mM:k:a0:a1:a2:a3:a4:a5:a6:a7:a8:a9:a10:a11:a12:a13:a14:a15:\
263s0:s1:s2:s3:s4:s5:s6:s7:s8:s9:s10:s11:s12:s13:s14:s15")
264
265#make sure all particles for cascade production are stable
266for kf in idbeam:
267 kc = myPythia.Pycomp(kf)
268 myPythia.SetMDCY(kc,1,0)
269# make charm or beauty signal hadrons stable
270for kf in idsig:
271 kc = myPythia.Pycomp(kf)
272 myPythia.SetMDCY(kc,1,0)
273
274#declare the stack for the cascade particles
275stack=1000*[0]
276for iev in range(nevgen):
277 if iev%1000==0: print('Generate event ',iev)
278#put 400. GeV proton on the stack
279 nstack=0
280# stack: PID,px,py,pz,cascade depth,nstack of mother
281 stack[nstack]=[2212,0.,0.,pbeamh,1,100*[0],100*[0]]
282 stack[nstack][5][0]=2212
283 while nstack>=0:
284# generate a signal based on probabilities in hists i*10+8?
285 ptot=ROOT.TMath.Sqrt(stack[nstack][1]**2+stack[nstack][2]**2+stack[nstack][3]**2)
286 prbsig=0.
287 for i in range(1,id+1):
288# get hist id for this beam particle
289 if stack[nstack][0]==idhist[i]:
290 idpn=0
291# decide on p or n target in Mo
292 if random.random>fracp: idpn=1
293 idw=i*10+idpn*4+4
294 ib=h[str(idw)].FindBin(ptot,0.,0.)
295 prbsig=h[str(idw)].GetBinContent(ib)
296 if prbsig>random.random():
297# last particle on the stack as beam particle
298 for k in range(1,4):
299 myPythia.SetP(1,k,stack[nstack][k])
300 myPythia.SetP(2,k,0.)
301# new particle/momentum, init again: signal run.
302 myPythia.SetMSEL(mselcb) # set forced ccbar or bbbar generation
303 myPythia.Initialize('3MOM',PDG.GetParticle(stack[nstack][0]).GetName(),target[idpn],0.)
304 myPythia.GenerateEvent()
305# look for the signal particles
306 charmFound = []
307 for itrk in range(1,myPythia.GetN()+1):
308 idabs = ROOT.TMath.Abs(myPythia.GetK(itrk,2))
309 if idabs in idsig:
310 #signal found store in ntuple
311 vl=array('f')
312 vl.append(float(myPythia.GetK(itrk,2)))
313 for i in range(1,6):
314 vl.append(float(myPythia.GetP(itrk,i)))
315 vl.append(float(myPythia.GetK(1,2)))
316 for i in range(1,6):
317 vl.append(float(myPythia.GetP(1,i)))
318 vl.append(float(stack[nstack][4]))
319 for i in range(16):
320 vl.append(float(stack[nstack][5][i]))
321 nsub=stack[nstack][4]-1
322 if nsub>15: nsub=15
323 for i in range(nsub):
324 vl.append(float(stack[nstack][6][i]))
325 vl.append(float(myPythia.GetMSTI(1)))
326 for i in range(nsub+1,16):
327 vl.append(float(0))
328 Ntup.Fill(vl)
329 charmFound.append(itrk)
330 h['1'].Fill(myPythia.GetP(itrk,4))
331 h['2'].Fill(stack[nstack][4])
332 if idabs==421 and stack[nstack][4]==1 :
333# some checking hist to monitor pt**2, XF of prompt D^0
334 pt2=myPythia.GetP(itrk,1)**2+myPythia.GetP(itrk,2)**2
335 h['3'].Fill(pt2)
336 h['4'].Fill(pt2)
337 h['5'].Fill(ROOT.TMath.Sqrt(pt2))
338# boost to Cm frame for XF ccalculation of D^0
339 beta=pbeamh/(myPythia.GetP(1,4)+myPythia.GetP(2,5))
340 gamma=(1-beta**2)**-0.5
341 pbcm=-gamma*beta*myPythia.GetP(1,4)+gamma*myPythia.GetP(1,3)
342 pDcm=-gamma*beta*myPythia.GetP(itrk,4)+gamma*myPythia.GetP(itrk,3)
343 xf=pDcm/pbcm
344 h['6'].Fill(xf)
345 if len(charmFound)>0 and storePrimaries:
346 for itP in range(1,myPythia.GetN()+1):
347 if itP in charmFound: continue
348 if myPythia.GetK(itP,1)==1:
349# store only undecayed particle and no charm found
350# ***WARNING****: with new with new ancestor and process info (a0-15, s0-15) add to ntuple, might not work???
351 Ntup.Fill(float(myPythia.GetK(itP,2)),float(myPythia.GetP(itP,1)),float(myPythia.GetP(itP,2)),float(myPythia.GetP(itP,3)),\
352 float(myPythia.GetP(itP,4)),float(myPythia.GetP(itP,5)),-1,\
353 float(myPythia.GetV(itP,1)-myPythia.GetV(charmFound[0],1)),\
354 float(myPythia.GetV(itP,2)-myPythia.GetV(charmFound[0],2)),\
355 float(myPythia.GetV(itP,3)-myPythia.GetV(charmFound[0],3)),0,0,stack[nstack][4])
356
357# now generate msel=2 to add new cascade particles to the stack
358 for k in range(1,4):
359 myPythia.SetP(1,k,stack[nstack][k])
360 myPythia.SetP(2,k,0.)
361# new particle/momentum, init again, generate total cross-section event
362 myPythia.SetMSEL(2) # mbias event
363 idpn=0
364 if random.random()>fracp: idpn=1
365 myPythia.Initialize('3MOM',PDG.GetParticle(stack[nstack][0]).GetName(),target[idpn],0.)
366 myPythia.GenerateEvent()
367# remove used particle from the stack, before adding new
368# first store its history: cascade depth and ancestors-list
369 icas=stack[nstack][4]+1
370 if icas>98: icas=98
371 anclist=copy.copy(stack[nstack][5])
372 sublist=copy.copy(stack[nstack][6])
373 #fill in interaction process of first proton
374 if nstack==0: sublist[0]=myPythia.GetMSTI(1)
375 nstack=nstack-1
376 for itrk in range(1,myPythia.GetN()+1):
377 if myPythia.GetK(itrk,1)==1:
378 ptot=ROOT.TMath.Sqrt(myPythia.GetP(itrk,1)**2+myPythia.GetP(itrk,2)**2+myPythia.GetP(itrk,3)**2)
379 if ptot>pbeaml:
380# produced particle is stable and has enough momentum, is it in the wanted list?
381 for isig in range(len(idbeam)):
382 if ROOT.TMath.Abs(myPythia.GetK(itrk,2))==idbeam[isig] and nstack<999:
383 if nstack<999: nstack+=1
384 #update ancestor list
385 tmp=copy.copy(anclist)
386 tmp[icas-1]=myPythia.GetK(itrk,2)
387 stmp=copy.copy(sublist)
388 #Pythia interaction process identifier
389 stmp[icas-1]=myPythia.GetMSTI(1)
390 stack[nstack]=[myPythia.GetK(itrk,2),myPythia.GetP(itrk,1),myPythia.GetP(itrk,2),myPythia.GetP(itrk,3),icas,tmp,stmp]
391
392print('Now at Ntup.Write()')
393Ntup.Write()
394for akey in h: h[akey].Write()
395ftup.Close()
396
397timer.Stop()
398rtime = timer.RealTime()
399ctime = timer.CpuTime()
400print(' ')
401print("Macro finished succesfully.")
402print("Output file is ", ftup.GetName())
403print("Real time ",rtime, " s, CPU time ",ctime,"s")
404
PoorE791_tune(P6)