SND@LHC Software
Loading...
Searching...
No Matches
scifiSimAna.py
Go to the documentation of this file.
1import ROOT
2import rootUtils as ut
3import shipunit as u
4from array import array
5
6from argparse import ArgumentParser
7parser = ArgumentParser()
8parser.add_argument("-f", "--inputFile", dest="inputFile", help="single input file", required=False, default="sndLHC.Ntuple-TGeant4_dig.root")
9parser.add_argument("-g", "--geoFile", dest="geoFile", help="geofile", required=False, default="geofile_full.Ntuple-TGeant4.root")
10parser.add_argument("-n", "--nEvents", dest="nEvents", help="number of events to process", default=100000)
11parser.add_argument("-d", "--Debug", dest="debug", help="debug", default=False)
12parser.add_argument("-s", "--start", dest="start", type=int,help="file name with $*$", required=False,default=False)
13parser.add_argument("-e", "--end", dest="end", type=int,help="file name with $*$", required=False,default=False)
14
15options = parser.parse_args()
16debug = options.debug
17h={}
18
19fgeo = ROOT.TFile.Open(options.geoFile)
20from ShipGeoConfig import ConfigRegistry
21from rootpyPickler import Unpickler
22#load geo dictionary
23upkl = Unpickler(fgeo)
24snd_geo = upkl.load('ShipGeo')
25
26# -----Create geometry----------------------------------------------
27import shipLHC_conf as sndDet_conf
28
29run = ROOT.FairRunSim()
30run.SetName("TGeant4") # Transport engine
31run.SetSink(ROOT.FairRootFileSink(ROOT.TMemFile('output', 'recreate'))) # Output file
32run.SetUserConfig("g4Config_basic.C") # geant4 transport not used
33rtdb = run.GetRuntimeDb()
34modules = sndDet_conf.configure(run,snd_geo)
35sGeo = fgeo.FAIRGeom
36nav = sGeo.GetCurrentNavigator()
37top = sGeo.GetTopVolume()
38scifi = modules['Scifi']
39scifi.SiPMmapping()
40
41ut.bookHist(h,'S','stations',7,-0.5,6.5)
42ut.bookHist(h,'O','orientation',7,-0.5,6.5)
43ut.bookHist(h,'M','mat',7,-0.5,6.5)
44ut.bookHist(h,'R','row',7,-0.5,6.5)
45ut.bookHist(h,'N','fibre',1000,-0.5,999.5)
46
47for s in range(1,6):
48 ut.bookHist(h,'Sxy'+str(s),'XY',50,-50.,0.,50,10.,60.)
49 for o in range(2):
50 for m in range(1,4):
51 for r in range(1,7):
52 ut.bookHist(h,'N'+str(s)+str(o)+str(m)+str(r),'fibre',1000,-0.5,999.5)
53ut.bookHist(h,'E','dE',100,0.0,300.)
54ut.bookHist(h,'Edigi_all','digitized signal',150,0.0,150.)
55ut.bookHist(h,'Edigi','digitized valid signal',150,0.0,150.)
56ut.bookHist(h,'Edigi_muon','digitized valid signal',150,0.0,150.)
57ut.bookHist(h,'Ecluster','cluster energy',150,0.0,150.)
58ut.bookHist(h,'clusterSize','cluster size',20,-0.5,19.5)
59ut.bookHist(h,'clusterSize_muon','cluster size',20,-0.5,19.5)
60ut.bookHist(h,'doca','closest distance;[micron]',100,-500.,500.)
61ut.bookHist(h,'doca_muon','closest distance; [micron] ',100,-500.,500.)
62ut.bookHist(h,'docaCl','closest distance;[micron]',100,-500.,500.)
63ut.bookHist(h,'docaCl_muon','closest distance; [micron] ',100,-500.,500.)
64ut.bookHist(h,'pangle','angle of particle entering;mrad',100,-10.,10.)
65ut.bookHist(h,'pangle_muon','angle of particle entering;mrad',100,-10.,10.)
66
67ut.bookHist(h,'pdoca_muon','closest distance',100,0.0,0.02)
68ut.bookHist(h,'pdx_muon','closest distance',100,-0.02,0.02)
69
70ut.bookHist(h,'nMCpoints','hits per event',5000,-0.5,4999.5)
71ut.bookHist(h,'nDigihits','hits per event',5000,-0.5,4999.5)
72ut.bookHist(h,'nDigihits_muon','hits per event directly from muon',100,-0.5,99.5)
73ut.bookHist(h,'in_muon','p of incoming muon in Scifi',1000,0.0,2000.)
74
75def siPMPosCPP(scifi):
76 P=scifi.GetSiPMPos()
77 Pos = {}
78 for x in P:
79 Pos[x.first]=x.second
80 return Pos
81
82def docaLinePoint(A,B,p):
83 n = B-A
84 tmp = (A-p).Cross(n)
85 return tmp.Mag()/n.Mag()
86def docaLine(a,b,c,d):
87 u = b-a
88 v = d-c
89 n = u.Cross(v)
90 ac = a-c
91 if n.Mag()==0:
92 dist = ROOT.TMath.Sqrt(ac.Mag2()+3*(ac.Dot(u))**2/u.Mag2())
93 else:
94 dist = n.Dot(ac)/n.Mag()
95 return dist
96
97
98A=ROOT.TVector3()
99B=ROOT.TVector3()
100
101tchain = ROOT.TChain("cbmsim")
102if options.inputFile.find("XXX")<0:
103 tchain.Add(options.inputFile)
104else:
105 for i in range(options.start,options.end+1):
106 aFile = options.inputFile.replace("XXX",str(i))
107 tchain.Add(aFile)
108
109for x in h: h[x].Reset()
110for sTree in tchain:
111 L = sTree.Digi_ScifiHits2MCPoints[0]
112 w = sTree.MCTrack[0].GetWeight() # assume these are muon background events.
113 # to be multiplied with normalization[1] = 5.83388*137.13/78. = 10.26 to get rates in second.
114 rc = h['nMCpoints'].Fill(sTree.ScifiPoint.GetEntries(),w)
115 rc = h['nDigihits'].Fill(sTree.Digi_ScifiHits.GetEntries(),w)
116#
117 first = True
118 for p in sTree.ScifiPoint:
119 if p.GetDetectorID()==0:
120 print('?')
121 continue
122 rc = h['S'].Fill(p.station(),w)
123 rc = h['O'].Fill(p.orientation(),w)
124 rc = h['M'].Fill(p.mat(),w)
125 rc = h['R'].Fill(p.row(),w)
126 rc = h['N'].Fill(p.fibreN(),w)
127 rc = h['Sxy'+str(p.station())].Fill(p.GetX(),p.GetY(),w)
128 rc = h['N'+str(p.GetDetectorID()//1000)].Fill(p.fibreN(),w)
129 rc = h['E'].Fill(p.GetEnergyLoss()*1E6,w)
130 if p.GetTrackID()==0: # incoming muon
131 scifi.GetPosition(p.GetDetectorID(),A,B)
132 impactPoint = ROOT.TVector3(p.GetX(),p.GetY(),p.GetZ())
133 D = docaLinePoint(A,B,impactPoint)
134 rc = h['pdoca_muon'].Fill(D)
135 if p.orientation()==1:
136 rc = h['pdx_muon'].Fill(A[0]-impactPoint[0])
137 else:
138 rc = h['pdx_muon'].Fill(A[1]-impactPoint[1])
139 if first:
140 first = False
141 P = ROOT.TVector3(p.GetPx(),p.GetPy(),p.GetPz())
142 rc = h['in_muon'].Fill(P.Mag(),w)
143#
144 hitDict = {}
145 for k in range(sTree.Digi_ScifiHits.GetEntries()):
146 d = sTree.Digi_ScifiHits[k]
147 rc = h['Edigi_all'].Fill(d.GetEnergy())
148 if not d.isValid(): continue
149 rc = h['Edigi'].Fill(d.GetEnergy())
150 hitDict[d.GetDetectorID()] = k
151 NmuonHit = 0
152 for cl in sTree.Cluster_Scifi:
153 rc = h['Ecluster'].Fill(cl.GetEnergy())
154 isMuon = True
155 meanImpact = ROOT.TVector3(0,0,0)
156 nPoints = 0
157 first = cl.GetFirst()
158 cl_size = cl.GetN()
159 for c in range(first,cl_size+first):
160 # origin of digis:
161 points = L.wList(c)
162 for p in points:
163 scifiPoint = sTree.ScifiPoint[p[0]]
164 trackKey = scifiPoint.GetTrackID()
165 pid = -1
166 if not trackKey<0: pid = sTree.MCTrack[trackKey].GetPdgCode()
167 rc = h['pangle'].Fill(ROOT.TMath.ATan2(scifiPoint.GetPx(),scifiPoint.GetPz())*1000)
168 if abs(pid)==13: rc = h['pangle_muon'].Fill(ROOT.TMath.ATan2(scifiPoint.GetPx(),scifiPoint.GetPz())*1000)
169 if abs(pid)!=13: isMuon = False
170 meanImpact+=ROOT.TVector3(scifiPoint.GetX(),scifiPoint.GetY(),scifiPoint.GetZ())
171 nPoints+=1
172 w = 1./nPoints
173 meanImpact=meanImpact*w
174 rc = h['clusterSize'].Fill(cl_size)
175 if isMuon:
176 NmuonHit +=1
177 rc = h['clusterSize_muon'].Fill(cl_size)
178 for hitID in range(first,first+cl_size):
179 d = sTree.Digi_ScifiHits[hitDict[hitID]]
180 r = h['Edigi_muon'].Fill(d.GetEnergy())
181 # goto local coordinates in detector plane
182 vertical = int(first/100000)%10 == 1
183 cl.GetPosition(A,B)
184 locCluster = scifi.GetLocalPos(first,A)
185 locPart = scifi.GetLocalPos(first,meanImpact)
186#
187 if vertical: delta = locCluster[0]-locPart[0]
188 else: delta = locCluster[1]-locPart[1]
189 rc = h['docaCl'].Fill(delta/u.um)
190 if isMuon:
191 rc = h['docaCl_muon'].Fill(delta/u.um)
192 if debug:
193 print('delta ',delta/u.um,cl_size)
194 locPart.Print()
195 locCluster.Print()
196#
197 docaMax = 0
198 for aHit in range(first,cl_size+first):
199 scifi.GetSiPMPosition(aHit, A, B)
200 loc = scifi.GetLocalPos(aHit,A)
201 if vertical: delta = loc[0]-locPart[0]
202 else: delta = loc[1]-locPart[1]
203 rc = h['doca'].Fill(delta/u.um)
204 if isMuon:
205 rc = h['doca_muon'].Fill(delta/u.um)
206 if debug:
207 print('------------ ',aHit,delta/u.um)
208 loc.Print()
209 if abs(delta/u.um) > docaMax: docaMax = abs(delta/u.um)
210 if debug:
211 print(docaMax)
212 if docaMax>300: 1/0
213 rc = h['nDigihits_muon'].Fill(NmuonHit,w)
214
215# test position
216import SciFiMapping
217from array import array
218loc = array('d',[0,0,0])
219glob = array('d',[0,0,0])
220
221def testPosition()
222 F = SciFiMapping.getFibre2SiPMCPP(modules)
223 Finv = SciFiMapping.getSiPM2FibreCPP(modules)
224 print("================================================")
225 scifi.GetPosition(1011001,A,B)
226 print("horizontal mat")
227 A.Print()
228 B.Print()
229 print("vertical mat")
230 scifi.GetPosition(1111001,A,B)
231 A.Print()
232 B.Print()
233
234from array import array
235class Tracking(ROOT.FairTask):
236 " Tracking "
237 def InitTask(self,event):
238 geoMat = ROOT.genfit.TGeoMaterialInterface()
239 bfield = ROOT.genfit.ConstField(0,0,0) # constant field of zero
240 fM = ROOT.genfit.FieldManager.getInstance()
241 fM.init(bfield)
242 ROOT.genfit.MaterialEffects.getInstance().init(geoMat)
243 ROOT.genfit.MaterialEffects.getInstance().setNoEffects()
244 self.fitter = ROOT.genfit.KalmanFitter()
245 self.fitter.setMaxIterations(50)
246 self.sigma_spatial = 100.*u.mu
247 self.Debug = True
248 self.event = event
249
250 def FinishEvent(self):
251 pass
252
253 def ExecuteTask(self,option=''):
254 self.clusters = self.scifiCluster()
255 self.trackCandidates = self.patternReco()
256 self.event.fittedTracks = []
257 for aTrack in self.trackCandidates:
258 rc = self.fitTrack(aTrack)
259 if type(rc)==type(1):
260 print('trackfit failed',rc,aTrack)
261 else:
262 self.event.fittedTracks.append(aTrack)
263
264 def scifiCluster(self):
265 clusters = []
266 hitDict = {}
267 for k in range(event.Digi_ScifiHits.GetEntries()):
268 d = event.Digi_ScifiHits[k]
269 if not d.isValid(): continue
270 hitDict[d.GetDetectorID()] = k
271 hitList = list(hitDict.keys())
272 if len(hitList)>0:
273 hitList.sort()
274 tmp = [ hitList[0] ]
275 cprev = hitList[0]
276 ncl = 0
277 last = len(hitList)-1
278 hitlist = ROOT.std.vector("sndScifiHit*")()
279 for i in range(len(hitList)):
280 if i==0 and len(hitList)>1: continue
281 c=hitList[i]
282 if (c-cprev)==1:
283 tmp.append(c)
284 if (c-cprev)!=1 or c==hitList[last]:
285 first = tmp[0]
286 N = len(tmp)
287 hitlist.clear()
288 for aHit in tmp: hitlist.push_back( event.Digi_ScifiHits[hitDict[aHit]])
289 aCluster = ROOT.sndCluster(first,N,hitlist)
290 clusters.append(aCluster)
291 if c!=hitList[last]:
292 ncl+=1
293 tmp = [c]
294 cprev = c
295 return clusters
296
297 def patternReco():
298# very simple for the moment, take all scifi clusters
299 trackCandidates = []
300 hitlist = {}
301 for cl in self.clusters:
302 hitlist.append(cl)
303 trackCandidates.append(hitlist)
304 return trackCandidates
305
306 def fitTrack(hitlist):
307# hitlist: clusterID: [A,B] endpoints of scifiCluster
308 hitPosLists={}
309 trID = 0
310
311 posM = ROOT.TVector3(0, 0, 0.)
312 momM = ROOT.TVector3(0,0,100.) # default track with high momentum
313
314# approximate covariance
315 covM = ROOT.TMatrixDSym(6)
316 res = self.sigma_spatial
317 for i in range(3): covM[i][i] = res*res
318 for i in range(3,6): covM[i][i] = ROOT.TMath.Power(res / (4.*2.) / ROOT.TMath.Sqrt(3), 2)
319 rep = ROOT.genfit.RKTrackRep(13)
320
321# start state
322 state = ROOT.genfit.MeasuredStateOnPlane(rep)
323 rep.setPosMomCov(state, posM, momM, covM)
324
325# create track
326 seedState = ROOT.TVectorD(6)
327 seedCov = ROOT.TMatrixDSym(6)
328 rep.get6DStateCov(state, seedState, seedCov)
329 theTrack = ROOT.genfit.Track(rep, seedState, seedCov)
330
331# make measurements sorted in z
332 unSortedList = {}
333 tmpList = {}
334 A,B = ROOT.TVector3(),ROOT.TVector3()
335 for k in range(hitlist):
336 aCl = hitlist[k]
337 detID = aHit.GetDetectorID()
338 aCl.GetPosition(A,B)
339 distance = 0
340 tmp = array('d',[A[0],A[1],A[2],B[0],B[1],B[2],distance])
341 unSortedList[A[2]] = [ROOT.TVectorD(7,tmp),detID,k]
342 sorted_z=list(unSortedList.keys())
343 sorted_z.sort()
344 for z in sorted_z:
345 tp = ROOT.genfit.TrackPoint() # note how the point is told which track it belongs to
346 hitCov = ROOT.TMatrixDSym(7)
347 hitCov[6][6] = resolution*resolution
348 measurement = ROOT.genfit.WireMeasurement(unSortedList[z][0],hitCov,1,6,tp) # the measurement is told which trackpoint it belongs to
349 measurement.setMaxDistance(0.1)
350 measurement.setDetId(unSortedList[z][1])
351 measurement.setHitId(unSortedList[z][2])
352 tp.addRawMeasurement(measurement) # package measurement in the TrackPoint
353 theTrack.insertPoint(tp) # add point to Track
354 if not theTrack.checkConsistency():
355 print("track not consistent")
356 theTrack.Delete()
357 return -2
358# do the fit
359 self.fitter.processTrack(theTrack) # processTrackWithRep(theTrack,rep,True)
360 fitStatus = theTrack.getFitStatus()
361 if self.Debug: print("Fit result: converged chi2 Ndf",fitStatus.isFitConverged(),fitStatus.getChi2(),fitStatus.getNdf())
362 if not fitStatus.isFitConverged():
363 theTrack.Delete()
364 return -1
365 if self.Debug:
366 chi2 = fitStatus.getChi2()/fitStatus.getNdf()
367 fittedState = theTrack.getFittedState()
368 P = fittedState.getMomMag()
369 print("track fitted Ndf #Meas P",fitStatus.getNdf(), theTrack.getNumPointsWithMeasurement(),P)
370 for p in theTrack.getPointsWithMeasurement():
371 rawM = p.getRawMeasurement()
372 info = p.getFitterInfo()
373 if not info: continue
374 detID = rawM.getDetId()
375 print(detID,"weights",info.getWeights()[0],info.getWeights()[1],fitStatus.getNdf())
376 return theTrack
377
378
getSiPM2FibreCPP(scifi)
docaLinePoint(A, B, p)
siPMPosCPP(scifi)
docaLine(a, b, c, d)