SND@LHC Software
Loading...
Searching...
No Matches
run_fixedTarget.py
Go to the documentation of this file.
1#!/usr/bin/env python
2from __future__ import print_function
3import ROOT,os,sys,getopt,time,shipRoot_conf
4import shipunit as u
5from ShipGeoConfig import ConfigRegistry
6
7mcEngine = "TGeant4"
8simEngine = "Pythia8"
9runnr = 1
10nev = 1000
11checkOverlap = True
12G4only = False
13storeOnlyMuons = False
14skipNeutrinos = False
15withEvtGen = True
16boostDiMuon = 1.
17boostFactor = 1.
18charm = False
19beauty = False
20chicc = 1.7e-3
21chibb = 1.6e-7
22npot = 5E13
23nStart = 0
24
25charmInputFile = ROOT.gSystem.Getenv("EOSSHIP")+"/eos/experiment/ship/data/Charm/Cascade-parp16-MSTP82-1-MSEL4-76Mpot_1.root"
26nStart = 0
27
28outputDir = "."
29work_dir = "./"
30ecut = 0.5 # GeV with 1 : ~1sec / event, with 2: 0.4sec / event, 10: 0.13sec
31
32dy = 10.
33dv = 6 # 4=TP elliptical tank design, 5 = optimized conical rectangular design, 6=5 without segment-1
34ds = 9 # 5=TP muon shield, 6=magnetized hadron, 7=short magnet design, 9=optimised with T4 as constraint, 8=requires config file
35nud = 3 # 0=TP, 1=new magnet option for short muon shield, 2= no magnet surrounding neutrino detector
36
37# example for primary interaction, nobias: python $FAIRSHIP/muonShieldOptimization/run_fixedTarget.py -n 10000 -e 10 -f -r 10
38# 10000 events, energy cut 10GeV, run nr 10, override existing output folder
39# example for charm decays, python $FAIRSHIP/muonShieldOptimization/run_fixedTarget.py -C -M -n 10000 -e 10 -r 60 -b 50 -f
40# 10000 events, charm decays, energy cut 10GeV, run nr 60, override existing output folder
41# increase di-muon BRs for resonances < 1.1GeV by a factor 50
42
43#----------------------------- Yandex production ------------------------------
44import shutil
45import argparse
46import logging
47logging.info("")
48logger = logging.getLogger(os.path.splitext(os.path.basename(os.sys.argv[0]))[0])
49logger.setLevel(logging.INFO)
50
51
52def get_work_dir(run_number,tag=None):
53 import socket
54 host = socket.gethostname()
55 job_base_name = os.path.splitext(os.path.basename(os.sys.argv[0]))[0]
56 if tag: out_dir = "{host}_{base}_{runnr}_{comment}".format(host=host, base=job_base_name, runnr=run_number, comment=tag)
57 else: out_dir = "{host}_{base}_{runnr}".format(host=host, base=job_base_name, runnr=run_number)
58 return out_dir
59
60
61def init():
62 global runnr, nev, ecut, G4only, tauOnly,JpsiMainly, work_dir,Debug,withEvtGen,boostDiMuon,\
63 boostFactor,charm,beauty,charmInputFile,nStart,storeOnlyMuons,chicc,chibb,npot,nStart,skipNeutrinos,FourDP
64 logger.info("SHiP proton-on-taget simulator (C) Thomas Ruf, 2017")
65
66 ap = argparse.ArgumentParser(
67 description='Run SHiP "pot" simulation')
68 ap.add_argument('-d', '--debug', action='store_true', dest='debug')
69 ap.add_argument('-f', '--force', action='store_true', help="force overwriting output directory")
70 ap.add_argument('-r', '--run-number', type=int, dest='runnr', default=runnr)
71 ap.add_argument('-e', '--ecut', type=float, help="energy cut", dest='ecut', default=ecut)
72 ap.add_argument('-n', '--num-events', type=int, help="number of events to generate", dest='nev', default=nev)
73 ap.add_argument('-G', '--G4only', action='store_true', dest='G4only', default=False, help="use Geant4 directly, no Pythia8")
74 ap.add_argument('-P', '--PythiaDecay', action='store_true', dest='pythiaDecay', default=False, help="use Pythia8 for decays")
75 ap.add_argument('-V', '--EvtGen', action='store_true', dest='withEvtGen', default=withEvtGen, help="use EvtGen for decays")
76 ap.add_argument('-t', '--tau-only', action='store_true', dest='tauOnly', default=False)
77 ap.add_argument('-J', '--Jpsi-mainly', action='store_true', dest='JpsiMainly', default=False)
78 ap.add_argument('-b', '--boostDiMuon', type=float, dest='boostDiMuon', default=boostDiMuon, help="boost Di-muon branching ratios")
79 ap.add_argument('-X', '--boostFactor', type=float, dest='boostFactor', default=boostFactor, help="boost Di-muon prod cross sections")
80 ap.add_argument('-C', '--charm', action='store_true', dest='charm', default=charm, help="generate charm decays")
81 ap.add_argument('-B', '--beauty', action='store_true', dest='beauty', default=beauty, help="generate beauty decays")
82 ap.add_argument('-M', '--storeOnlyMuons', action='store_true', dest='storeOnlyMuons', default=storeOnlyMuons, help="store only muons, ignore neutrinos")
83 ap.add_argument('-N', '--skipNeutrinos', action='store_true', dest='skipNeutrinos', default=False, help="skip neutrinos")
84 ap.add_argument('-D', '--4darkPhoton', action='store_true', dest='FourDP', default=False, help="enable ntuple production")
85# for charm production
86 ap.add_argument('-cc','--chicc',action='store_true', dest='chicc', default=chicc, help="ccbar over mbias cross section")
87 ap.add_argument('-bb','--chibb',action='store_true', dest='chibb', default=chibb, help="bbbar over mbias cross section")
88 ap.add_argument('-p','--pot',action='store_true', dest='npot', default=npot, help="number of protons on target per spill to normalize on")
89 ap.add_argument('-S', '--nStart', type=int, help="first event of input file to start", dest='nStart', default=nStart)
90 ap.add_argument('-I', '--InputFile', type=str, dest='charmInputFile', default=charmInputFile, help="input file for charm/beauty decays")
91 ap.add_argument('-o','--output' , type=str, help="output directory", dest='work_dir', default=None)
92 ap.add_argument('-rs','--seed', type=int, help="random seed; default value is 0, see TRrandom::SetSeed documentation", dest='seed', default=0)
93 args = ap.parse_args()
94 if args.debug:
95 logger.setLevel(logging.DEBUG)
96 runnr = args.runnr
97 nev = args.nev
98 ecut = args.ecut
99 tauOnly = args.tauOnly
100 JpsiMainly = args.JpsiMainly
101 G4only = args.G4only
102 boostFactor = args.boostFactor
103 boostDiMuon = args.boostDiMuon
104 storeOnlyMuons = args.storeOnlyMuons
105 skipNeutrinos = args.skipNeutrinos
106 FourDP = args.FourDP
107 if G4only:
108 args.charm = False
109 args.beauty = False
110 args.withEvtGen = False
111 args.pythiaDecay = False
112 elif args.pythiaDecay:
113 withEvtGen = False
114 args.withEvtGen = False
115 logger.info("use Pythia8 as primary decayer")
116 else:
117 withEvtGen = True
118 logger.info("use EvtGen as primary decayer")
119 withEvtGen = args.withEvtGen
120 charm = args.charm
121 beauty = args.beauty
122 if charm and beauty:
123 logger.warn("charm and beauty decays are set! Beauty gets priority")
124 charm = False
125 charmInputFile = args.charmInputFile
126 nStart = int(args.nStart)
127 Debug = args.debug
128 if args.work_dir is None:
129 if charm: args.work_dir = get_work_dir(runnr,"charm")
130 if beauty: args.work_dir = get_work_dir(runnr,"beauty")
131 else: args.work_dir = get_work_dir(runnr)
132 work_dir = args.work_dir
133 logger.debug("work_dir: %s" % work_dir)
134 logger.debug("command line arguments: %s", args)
135 if os.path.exists(work_dir):
136 logger.warn("output directory '%s' already exists." % work_dir)
137 if args.force:
138 logger.warn("...cleaning")
139 for root, dirs, files in os.walk(work_dir):
140 for f in files:
141 os.unlink(os.path.join(root, f))
142 for d in dirs:
143 shutil.rmtree(os.path.join(root, d))
144 else:
145 logger.warn("...use '-f' option to overwrite it")
146 else:
147 os.makedirs(work_dir)
148 return args
149
150args = init()
151os.chdir(work_dir)
152# -------------------------------------------------------------------
153ROOT.gRandom.SetSeed(args.seed) # this should be propagated via ROOT to Pythia8 and Geant4VMC
154shipRoot_conf.configure() # load basic libraries, prepare atexit for python
155ship_geo = ConfigRegistry.loadpy("$FAIRSHIP/geometry/geometry_config.py", Yheight = dy, tankDesign = dv, muShieldDesign = ds, nuTauTargetDesign=nud)
156
157txt = 'pythia8_Geant4_'
158if withEvtGen: txt = 'pythia8_evtgen_Geant4_'
159outFile = outputDir+'/'+txt+str(runnr)+'_'+str(ecut)+'.root'
160parFile = outputDir+'/ship.params.'+txt+str(runnr)+'_'+str(ecut)+'.root'
161
162# -----Timer--------------------------------------------------------
163timer = ROOT.TStopwatch()
164timer.Start()
165
166# -----Create simulation run----------------------------------------
167run = ROOT.FairRunSim()
168run.SetName(mcEngine) # Transport engine
169run.SetOutputFile(outFile) # Output file
170run.SetUserConfig("g4Config.C") # user configuration file default g4Config.C
171rtdb = run.GetRuntimeDb()
172
173# -----Materials----------------------------------------------
174run.SetMaterials("media.geo")
175# -----Create geometry----------------------------------------------
176cave= ROOT.ShipCave("CAVE")
177cave.SetGeometryFileName("caveWithAir.geo")
178run.AddModule(cave)
179
180TargetStation = ROOT.ShipTargetStation("TargetStation",ship_geo.target.length,ship_geo.hadronAbsorber.length,
181 ship_geo.target.z,ship_geo.hadronAbsorber.z,ship_geo.targetOpt,ship_geo.target.sl)
182slices_length = ROOT.std.vector('float')()
183slices_material = ROOT.std.vector('std::string')()
184for i in range(1,ship_geo.targetOpt+1):
185 slices_length.push_back( eval("ship_geo.target.L"+str(i)))
186 slices_material.push_back(eval("ship_geo.target.M"+str(i)))
187TargetStation.SetLayerPosMat(ship_geo.target.xy,slices_length,slices_material)
188
189run.AddModule(TargetStation)
190MuonShield = ROOT.ShipMuonShield("MuonShield",ship_geo.muShieldDesign,"ShipMuonShield",ship_geo.muShield.z,ship_geo.muShield.dZ0,ship_geo.muShield.dZ1,\
191 ship_geo.muShield.dZ2,ship_geo.muShield.dZ3,ship_geo.muShield.dZ4,ship_geo.muShield.dZ5,ship_geo.muShield.dZ6,\
192 ship_geo.muShield.dZ7,ship_geo.muShield.dZ8,ship_geo.muShield.dXgap,ship_geo.muShield.LE,ship_geo.Yheight*4./10.,0.)
193MuonShield.SetSupports(False) # otherwise overlap with sensitive Plane
194run.AddModule(MuonShield) # needs to be added because of magn hadron shield.
195sensPlane = ROOT.exitHadronAbsorber()
196sensPlane.SetEnergyCut(ecut*u.GeV)
197if storeOnlyMuons: sensPlane.SetOnlyMuons()
198if skipNeutrinos: sensPlane.SkipNeutrinos()
199if FourDP: sensPlane.SetOpt4DP() # in case a ntuple should be filled with pi0,etas,omega
200# sensPlane.SetZposition(0.*u.cm) # if not using automatic positioning behind default magnetized hadron absorber
201run.AddModule(sensPlane)
202
203# -----Create PrimaryGenerator--------------------------------------
204primGen = ROOT.FairPrimaryGenerator()
205P8gen = ROOT.FixedTargetGenerator()
206P8gen.SetTarget("/TargetArea_1",0.,0.) # will distribute PV inside target, beam offset x=y=0.
207P8gen.SetMom(400.*u.GeV)
208P8gen.SetEnergyCut(ecut*u.GeV)
209P8gen.SetDebug(Debug)
210P8gen.SetHeartBeat(100000)
211if G4only: P8gen.SetG4only()
212if JpsiMainly: P8gen.SetJpsiMainly()
213if tauOnly: P8gen.SetTauOnly()
214if withEvtGen: P8gen.WithEvtGen()
215if boostDiMuon > 1:
216 P8gen.SetBoost(boostDiMuon) # will increase BR for rare eta,omega,rho ... mesons decaying to 2 muons in Pythia8
217 # and later copied to Geant4
218P8gen.SetSeed(args.seed)
219# for charm/beauty
220# print ' for experts: p pot= number of protons on target per spill to normalize on'
221# print ' : c chicc= ccbar over mbias cross section'
222if charm or beauty:
223 print("--- process heavy flavours ---")
224 P8gen.InitForCharmOrBeauty(charmInputFile,nev,npot,nStart)
225primGen.AddGenerator(P8gen)
226#
227run.SetGenerator(primGen)
228# -----Initialize simulation run------------------------------------
229run.Init()
230
231gMC = ROOT.TVirtualMC.GetMC()
232fStack = gMC.GetStack()
233fStack.SetMinPoints(1)
234fStack.SetEnergyCut(-1.)
235#
236import AddDiMuonDecayChannelsToG4
238
239# boost gamma2muon conversion
240if boostFactor > 1:
241 ROOT.gROOT.ProcessLine('#include "Geant4/G4ProcessTable.hh"')
242 ROOT.gROOT.ProcessLine('#include "Geant4/G4AnnihiToMuPair.hh"')
243 ROOT.gROOT.ProcessLine('#include "Geant4/G4GammaConversionToMuons.hh"')
244 gProcessTable = ROOT.G4ProcessTable.GetProcessTable()
245 procAnnihil = gProcessTable.FindProcess(ROOT.G4String('AnnihiToMuPair'),ROOT.G4String('e+'))
246 procGMuPair = gProcessTable.FindProcess(ROOT.G4String('GammaToMuPair'),ROOT.G4String('gamma'))
247 procGMuPair.SetCrossSecFactor(boostFactor)
248 procAnnihil.SetCrossSecFactor(boostFactor)
249
250# -----Start run----------------------------------------------------
251run.Run(nev)
252
253# -----Finish-------------------------------------------------------
254timer.Stop()
255rtime = timer.RealTime()
256ctime = timer.CpuTime()
257print(' ')
258print("Macro finished succesfully.")
259print("Output file is ", outFile)
260print("Real time ",rtime, " s, CPU time ",ctime,"s")
261# ---post processing--- remove empty events --- save histograms
262tmpFile = outFile+"tmp"
263if ROOT.gROOT.GetListOfFiles().GetEntries()>0:
264 fin = ROOT.gROOT.GetListOfFiles()[0]
265else:
266 fin = ROOT.TFile.Open(outFile)
267fHeader = fin.FileHeader
268fHeader.SetRunId(runnr)
269if charm or beauty:
270# normalization for charm
271 poteq = P8gen.GetPotForCharm()
272 info = "POT equivalent = %7.3G"%(poteq)
273else:
274 info = "POT = "+str(nev)
275
276conditions = " with ecut="+str(ecut)
277if JpsiMainly: conditions+=" J"
278if tauOnly: conditions+=" T"
279if withEvtGen: conditions+=" V"
280if boostDiMuon > 1: conditions+=" diMu"+str(boostDiMuon)
281if boostFactor > 1: conditions+=" X"+str(boostFactor)
282
283info += conditions
284fHeader.SetTitle(info)
285print("Data generated ", fHeader.GetTitle())
286
287nt = fin.Get('4DP')
288if nt:
289 tf = ROOT.TFile('FourDP.root','recreate')
290 tnt = nt.CloneTree(0)
291 for i in range(nt.GetEntries()):
292 rc = nt.GetEvent(i)
293 rc = tnt.Fill(nt.id,nt.px,nt.py,nt.pz,nt.x,nt.y,nt.z)
294 tnt.Write()
295 tf.Close()
296
297t = fin.cbmsim
298fout = ROOT.TFile(tmpFile,'recreate' )
299sTree = t.CloneTree(0)
300nEvents = 0
301for n in range(t.GetEntries()):
302 rc = t.GetEvent(n)
303 if t.vetoPoint.GetEntries()>0:
304 rc = sTree.Fill()
305 nEvents+=1
306 #t.Clear()
307fout.cd()
308for k in fin.GetListOfKeys():
309 x = fin.Get(k.GetName())
310 className = x.Class().GetName()
311 if className.find('TTree')<0 and className.find('TNtuple')<0:
312 xcopy = x.Clone()
313 rc = xcopy.Write()
314sTree.AutoSave()
315ff = fin.FileHeader.Clone(fout.GetName())
316fout.cd()
317ff.Write("FileHeader", ROOT.TObject.kSingleKey)
318sTree.Write()
319fout.Close()
320
321rc1 = os.system("rm "+outFile)
322rc2 = os.system("mv "+tmpFile+" "+outFile)
323print("removed out file, moved tmpFile to out file",rc1,rc2)
324fin.SetWritable(False) # bpyass flush error
325
326print("Number of events produced with activity after hadron absorber:",nEvents)
327
328if checkOverlap:
329 sGeo = ROOT.gGeoManager
330 sGeo.CheckOverlaps()
331 sGeo.PrintOverlaps()
332 run.CreateGeometryFile("%s/geofile_full.root" % (outputDir))
333 import saveBasicParameters
334 saveBasicParameters.execute("%s/geofile_full.root" % (outputDir),ship_geo)
335
get_work_dir(run_number, tag=None)
execute(f, ox, name='ShipGeo')
configure(darkphoton=None)