File: | libraries/PID/DParticleID.cc |
Location: | line 571, column 7 |
Description: | Value stored to 'myphi' is never read |
1 | // $Id$ |
2 | // |
3 | // File: DParticleID.cc |
4 | // Created: Mon Feb 28 14:48:56 EST 2011 |
5 | // Creator: staylor (on Linux ifarml1 2.6.18-128.el5 x86_64) |
6 | // |
7 | |
8 | #include "DParticleID.h" |
9 | #include <TRACKING/DTrackFitter.h> |
10 | #include <TMath.h> |
11 | #include "FCAL/DFCALGeometry.h" |
12 | |
13 | #define C_EFFECTIVE15. 15. // start counter light propagation speed |
14 | #define OUT_OF_TIME_CUT200. 200. |
15 | |
16 | // Routine for sorting dEdx data |
17 | bool static DParticleID_dedx_cmp(DParticleID::dedx_t a,DParticleID::dedx_t b){ |
18 | return a.dEdx < b.dEdx; |
19 | } |
20 | |
21 | // Routine for sorting hypotheses according to FOM |
22 | bool static DParticleID_hypothesis_cmp(const DTrackTimeBased *a, |
23 | const DTrackTimeBased *b){ |
24 | return (a->FOM>b->FOM); |
25 | } |
26 | |
27 | |
28 | //--------------------------------- |
29 | // DParticleID (Constructor) |
30 | //--------------------------------- |
31 | DParticleID::DParticleID(JEventLoop *loop) |
32 | { |
33 | |
34 | DApplication* dapp = dynamic_cast<DApplication*>(loop->GetJApplication()); |
35 | if(!dapp){ |
36 | _DBG_std::cerr<<"DParticleID.cc"<<":"<<36<< " "<<"Cannot get DApplication from JEventLoop! (are you using a JApplication based program?)"<<endl; |
37 | return; |
38 | } |
39 | const DRootGeom *RootGeom = dapp->GetRootGeom(); |
40 | bfield = dapp->GetBfield(); |
41 | stepper= new DMagneticFieldStepper(bfield); |
42 | |
43 | // Get material properties for chamber gas |
44 | double rho_Z_over_A_LnI=0,radlen=0; |
45 | |
46 | RootGeom->FindMat("CDchamberGas", dRhoZoverA_CDC, rho_Z_over_A_LnI, radlen); |
47 | dLnI_CDC = rho_Z_over_A_LnI/dRhoZoverA_CDC; |
48 | dKRhoZoverA_CDC = 0.1535E-3*dRhoZoverA_CDC; |
49 | |
50 | RootGeom->FindMat("FDchamberGas", dRhoZoverA_FDC, rho_Z_over_A_LnI, radlen); |
51 | dLnI_FDC = rho_Z_over_A_LnI/dRhoZoverA_FDC; |
52 | dKRhoZoverA_FDC = 0.1535E-3*dRhoZoverA_FDC; |
53 | |
54 | // Get the geometry |
55 | geom = dapp->GetDGeometry(loop->GetJEvent().GetRunNumber()); |
56 | |
57 | vector<double>sc_origin; |
58 | geom->Get("//posXYZ[@volume='StartCntr']/@X_Y_Z",sc_origin); |
59 | |
60 | //vector<double>sc_light_guide(3); |
61 | //geom->Get("//tubs[@name='STLG']/@Rio_Z",sc_light_guide); |
62 | //sc_light_guide_length=sc_light_guide[2]; |
63 | |
64 | vector<vector<double> > sc_rioz; |
65 | geom->GetMultiple("//pgon[@name='STRC']/polyplane/@Rio_Z", sc_rioz); |
66 | |
67 | for (unsigned int k=0;k<sc_rioz.size()-1;k++){ |
68 | DVector3 pos((sc_rioz[k][0]+sc_rioz[k][1])/2.,0.,sc_rioz[k][2]+sc_origin[2]); |
69 | DVector3 dir(sc_rioz[k+1][2]-sc_rioz[k][2],0, |
70 | -sc_rioz[k+1][0]+sc_rioz[k][0]); |
71 | dir.SetMag(1.); |
72 | |
73 | sc_pos.push_back(pos); |
74 | sc_norm.push_back(dir); |
75 | } |
76 | // sc_leg_tcor=(sc_light_guide[2]-sc_pos[0].z())/C_EFFECTIVE; |
77 | sc_leg_tcor=-sc_pos[0].z()/C_EFFECTIVE15.; |
78 | double theta=sc_norm[sc_norm.size()-1].Theta(); |
79 | sc_angle_cor=1./cos(M_PI3.14159265358979323846-theta); |
80 | |
81 | //Get calibration constants |
82 | map<string, double> locPIDParams; |
83 | if ( !loop->GetCalib("PID/photon_track_matching", locPIDParams)){ |
84 | cout<<"DParticleID: loading values from PID data base"<<endl; |
85 | DELTA_R_BCAL = locPIDParams["DELTA_R_BCAL"]; |
86 | DELTA_R_FCAL = locPIDParams["DELTA_R_FCAL"]; |
87 | } else { |
88 | cout << "DParticleID: Error loading values from PID data base" <<endl; |
89 | DELTA_R_BCAL = 15.0; |
90 | DELTA_R_FCAL = 15.0; |
91 | } |
92 | |
93 | dTargetZCenter = 0.0; |
94 | geom->GetTargetZ(dTargetZCenter); |
95 | } |
96 | |
97 | //--------------------------------- |
98 | // ~DParticleID (Destructor) |
99 | //--------------------------------- |
100 | DParticleID::~DParticleID() |
101 | { |
102 | if (stepper) delete stepper; |
103 | } |
104 | |
105 | // Group fitted tracks according to candidate id |
106 | jerror_t DParticleID::GroupTracks(vector<const DTrackTimeBased *> &tracks, |
107 | vector<vector<const DTrackTimeBased*> >&grouped_tracks){ |
108 | if (tracks.size()==0) return RESOURCE_UNAVAILABLE; |
109 | |
110 | JObject::oid_t old_id=tracks[0]->candidateid; |
111 | vector<const DTrackTimeBased *>hypotheses; |
112 | for (unsigned int i=0;i<tracks.size();i++){ |
113 | const DTrackTimeBased *track=tracks[i]; |
114 | |
115 | if (old_id != track->candidateid){ |
116 | // Sort according to FOM |
117 | sort(hypotheses.begin(),hypotheses.end(),DParticleID_hypothesis_cmp); |
118 | |
119 | // Add to the grouped_tracks vector |
120 | grouped_tracks.push_back(hypotheses); |
121 | |
122 | // Clear the hypothesis list for the next track |
123 | hypotheses.clear(); |
124 | } |
125 | hypotheses.push_back(track); |
126 | old_id=track->candidateid; |
127 | } |
128 | // Final set |
129 | sort(hypotheses.begin(),hypotheses.end(),DParticleID_hypothesis_cmp); |
130 | grouped_tracks.push_back(hypotheses); |
131 | |
132 | return NOERROR; |
133 | } |
134 | |
135 | // Compute the energy losses and the path lengths in the chambers for each hit |
136 | // on the track. Returns a list of dE and dx pairs with the momentum at the |
137 | // hit. |
138 | jerror_t DParticleID::GetDCdEdxHits(const DTrackTimeBased *track, vector<dedx_t>& dEdxHits_CDC, vector<dedx_t>& dEdxHits_FDC){ |
139 | // Position and momentum |
140 | DVector3 pos,mom; |
141 | |
142 | //dE and dx pairs |
143 | pair<double,double>de_and_dx; |
144 | |
145 | // We cast away the const-ness of the reference trajectory so that we can use the DisToRT method |
146 | DReferenceTrajectory *my_rt=const_cast<DReferenceTrajectory*>(track->rt); |
147 | |
148 | //Get the list of cdc hits used in the fit |
149 | vector<const DCDCTrackHit*>cdchits; |
150 | track->GetT(cdchits); |
151 | |
152 | // Loop over cdc hits |
153 | for (unsigned int i=0;i<cdchits.size();i++){ |
154 | double locReturnValue = my_rt->DistToRT(cdchits[i]->wire); |
155 | if(!((locReturnValue >= 0.0) || (locReturnValue <= 0.0))) |
156 | continue; //NaN |
157 | |
158 | my_rt->GetLastDOCAPoint(pos, mom); |
159 | |
160 | // Create the dE,dx pair from the position and momentum using a helical approximation for the path |
161 | // in the straw and keep track of the momentum in the active region of the detector |
162 | if (CalcdEdxHit(mom,pos,cdchits[i],de_and_dx)==NOERROR) |
163 | dEdxHits_CDC.push_back(dedx_t(de_and_dx.first, de_and_dx.second, mom.Mag())); |
164 | } |
165 | |
166 | //Get the list of fdc hits used in the fit |
167 | vector<const DFDCPseudo*>fdchits; |
168 | track->GetT(fdchits); |
169 | |
170 | // loop over fdc hits |
171 | for (unsigned int i=0;i<fdchits.size();i++){ |
172 | double locReturnValue = my_rt->DistToRT(fdchits[i]->wire); |
173 | if(!((locReturnValue >= 0.0) || (locReturnValue <= 0.0))) |
174 | continue; //NaN |
175 | my_rt->GetLastDOCAPoint(pos, mom); |
176 | |
177 | double gas_thickness = 1.0; // cm |
178 | dEdxHits_FDC.push_back(dedx_t(fdchits[i]->dE, gas_thickness/cos(mom.Theta()), mom.Mag())); |
179 | } |
180 | |
181 | // Sort the dEdx entries from smallest to largest |
182 | sort(dEdxHits_FDC.begin(),dEdxHits_FDC.end(),DParticleID_dedx_cmp); |
183 | sort(dEdxHits_CDC.begin(),dEdxHits_CDC.end(),DParticleID_dedx_cmp); |
184 | |
185 | return NOERROR; |
186 | } |
187 | |
188 | jerror_t DParticleID::CalcDCdEdx(const DTrackTimeBased *locTrackTimeBased, double& locdEdx_FDC, double& locdx_FDC, double& locdEdx_CDC, double& locdx_CDC, unsigned int& locNumHitsUsedFordEdx_FDC, unsigned int& locNumHitsUsedFordEdx_CDC){ |
189 | vector<dedx_t> locdEdxHits_CDC, locdEdxHits_FDC; |
190 | jerror_t locReturnStatus = GetDCdEdxHits(locTrackTimeBased, locdEdxHits_CDC, locdEdxHits_FDC); |
191 | if(locReturnStatus != NOERROR){ |
192 | locdEdx_FDC = NaNstd::numeric_limits<double>::quiet_NaN(); |
193 | locdx_FDC = NaNstd::numeric_limits<double>::quiet_NaN(); |
194 | locNumHitsUsedFordEdx_FDC = 0; |
195 | locdEdx_CDC = NaNstd::numeric_limits<double>::quiet_NaN(); |
196 | locdx_CDC = NaNstd::numeric_limits<double>::quiet_NaN(); |
197 | locNumHitsUsedFordEdx_CDC = 0; |
198 | return locReturnStatus; |
199 | } |
200 | return CalcDCdEdx(locTrackTimeBased, locdEdxHits_CDC, locdEdxHits_FDC, locdEdx_FDC, locdx_FDC, locdEdx_CDC, locdx_CDC, locNumHitsUsedFordEdx_FDC, locNumHitsUsedFordEdx_CDC); |
201 | } |
202 | |
203 | jerror_t DParticleID::CalcDCdEdx(const DTrackTimeBased *locTrackTimeBased, const vector<dedx_t>& locdEdxHits_CDC, const vector<dedx_t>& locdEdxHits_FDC, double& locdEdx_FDC, double& locdx_FDC, double& locdEdx_CDC, double& locdx_CDC, unsigned int& locNumHitsUsedFordEdx_FDC, unsigned int& locNumHitsUsedFordEdx_CDC){ |
204 | locdx_CDC = 0.0; |
205 | locdEdx_CDC = 0.0; |
206 | locNumHitsUsedFordEdx_CDC = locdEdxHits_CDC.size()/2; |
207 | if(locNumHitsUsedFordEdx_CDC > 0){ |
208 | for(unsigned int loc_i = 0; loc_i < locNumHitsUsedFordEdx_CDC; ++loc_i){ |
209 | locdEdx_CDC += locdEdxHits_CDC[loc_i].dE; //weight is ~ #e- (scattering sites): dx! |
210 | locdx_CDC += locdEdxHits_CDC[loc_i].dx; |
211 | } |
212 | locdEdx_CDC /= locdx_CDC; |
213 | } |
214 | |
215 | locdx_FDC = 0.0; |
216 | locdEdx_FDC = 0.0; |
217 | locNumHitsUsedFordEdx_FDC = locdEdxHits_FDC.size()/2; |
218 | if(locNumHitsUsedFordEdx_FDC > 0){ |
219 | for(unsigned int loc_i = 0; loc_i < locNumHitsUsedFordEdx_FDC; ++loc_i){ |
220 | locdEdx_FDC += locdEdxHits_FDC[loc_i].dE; //weight is ~ #e- (scattering sites): dx! |
221 | locdx_FDC += locdEdxHits_FDC[loc_i].dx; |
222 | } |
223 | locdEdx_FDC /= locdx_FDC; //weight is dx/dx_total |
224 | } |
225 | return NOERROR; |
226 | } |
227 | |
228 | // Calculate the path length for a single hit in a straw and return ds and the |
229 | // energy deposition in the straw. It returns dE as the first element in the |
230 | // dedx pair and ds as the second element in the dedx pair. |
231 | jerror_t DParticleID::CalcdEdxHit(const DVector3 &mom, |
232 | const DVector3 &pos, |
233 | const DCDCTrackHit *hit, |
234 | pair <double,double> &dedx){ |
235 | if (hit==NULL__null || hit->wire==NULL__null) return RESOURCE_UNAVAILABLE; |
236 | |
237 | // Track direction parameters |
238 | double phi=mom.Phi(); |
239 | double lambda=M_PI_21.57079632679489661923-mom.Theta(); |
240 | double cosphi=cos(phi); |
241 | double sinphi=sin(phi); |
242 | double tanl=tan(lambda); |
243 | |
244 | //Position relative to wire origin |
245 | double dz=pos.z()-hit->wire->origin.z(); |
246 | double dx=pos.x()-hit->wire->origin.x(); |
247 | double dy=pos.y()-hit->wire->origin.y(); |
248 | |
249 | // square of straw radius |
250 | double rs2=0.776*0.776; |
251 | |
252 | // Useful temporary variables related to the direction of the wire |
253 | double ux=hit->wire->udir.x(); |
254 | double uy=hit->wire->udir.y(); |
255 | double uz=hit->wire->udir.z(); |
256 | double A=1.-ux*ux; |
257 | double B=-2.*ux*uy; |
258 | double C=-2.*ux*uz; |
259 | double D=-2.*uy*uz; |
260 | double E=1.-uy*uy; |
261 | double F=1.-uz*uz; |
262 | |
263 | // The path length in the straw is given by s=sqrt(b*b-4*a*c)/a/cosl. |
264 | // a, b, and c follow. |
265 | double a=A*cosphi*cosphi+B*cosphi*sinphi+C*cosphi*tanl+D*sinphi*tanl |
266 | +E*sinphi*sinphi+F*tanl*tanl; |
267 | double b=2.*A*dx*cosphi+B*dx*sinphi+B*dy*cosphi+C*dx*tanl+C*cosphi*dz |
268 | +D*dy*tanl+D*sinphi*dz+2.*E*dy*sinphi+2.*F*dz*tanl; |
269 | double c=A*dx*dx+B*dx*dy+C*dx*dz+D*dy*dz+E*dy*dy+F*dz*dz-rs2; |
270 | |
271 | // Check for valid arc length and compute dEdx |
272 | double temp=b*b-4.*a*c; |
273 | if (temp>0){ |
274 | double cosl=fabs(cos(lambda)); |
275 | // double gas_density=0.0018; |
276 | |
277 | // arc length and energy deposition |
278 | //dedx.second=gas_density*sqrt(temp)/a/cosl; // g/cm^2 |
279 | dedx.second=sqrt(temp)/a/cosl; |
280 | dedx.first=hit->dE; //GeV |
281 | |
282 | return NOERROR; |
283 | } |
284 | |
285 | return VALUE_OUT_OF_RANGE; |
286 | } |
287 | |
288 | //------------------ |
289 | // MatchToTOF |
290 | //------------------ |
291 | // Loop over TOF points, looking for minimum distance of closest approach |
292 | // of track to a point in the TOF and using this to check for a match. |
293 | // |
294 | // NOTE: an initial guess for tproj is expected as input so that out-of-time |
295 | // hits can be skipped |
296 | jerror_t DParticleID::MatchToTOF(const DReferenceTrajectory *rt, DTrackFitter::fit_type_t fit_type, vector<const DTOFPoint*>&tof_points, double &tproj, unsigned int &tof_match_id, double &locPathLength, double &locFlightTime){ |
297 | //tproj=NaN; |
298 | tof_match_id=0; |
299 | if (tof_points.size()==0){ |
300 | tproj=NaNstd::numeric_limits<double>::quiet_NaN(); |
301 | return RESOURCE_UNAVAILABLE; |
302 | } |
303 | |
304 | double dmin=10000.; |
305 | // loop over tof points |
306 | double locTempPathLength; |
307 | for (unsigned int k=0;k<tof_points.size();k++){ |
308 | |
309 | // Get the TOF cluster position and normal vector for the TOF plane |
310 | DVector3 tof_pos=tof_points[k]->pos; |
311 | DVector3 norm(0,0,1); |
312 | DVector3 proj_pos,dir; |
313 | |
314 | // Find the distance of closest approach between the track trajectory |
315 | // and the tof cluster position, looking for the minimum |
316 | double locTempFlightTime=0.; |
317 | rt->GetIntersectionWithPlane(tof_pos,norm,proj_pos,dir,&locTempPathLength,&locTempFlightTime); |
318 | double d=(tof_pos-proj_pos).Mag(); |
319 | |
320 | // Check that the hit is not out of time with respect to the track |
321 | if (fabs(tof_points[k]->t - locTempFlightTime - tproj) > OUT_OF_TIME_CUT200.) continue; |
322 | |
323 | if (d<dmin){ |
324 | dmin=d; |
325 | locPathLength = locTempPathLength; |
326 | locFlightTime = locTempFlightTime; |
327 | tof_match_id=k; |
328 | } |
329 | } |
330 | |
331 | // Check for a match |
332 | // double p=rt->swim_steps[0].mom.Mag(); |
333 | double match_cut=0.; |
334 | match_cut = 6.15; //current dPositionMatchCut_DoubleEnded variable in DTOFPoint_factory.cc |
335 | // if (fit_type==DTrackFitter::kTimeBased) match_cut=3.624+0.488/p; |
336 | // else match_cut=4.0+0.488/p; |
337 | if (dmin<match_cut){ |
338 | // Projected time at the target |
339 | tproj=tof_points[tof_match_id]->t - locFlightTime; |
340 | |
341 | return NOERROR; |
342 | } |
343 | |
344 | tproj=NaNstd::numeric_limits<double>::quiet_NaN(); |
345 | return VALUE_OUT_OF_RANGE; |
346 | } |
347 | |
348 | //------------------ |
349 | // MatchToBCAL |
350 | //------------------ |
351 | // Loop over bcal clusters, looking for minimum distance of closest approach |
352 | // of track to a cluster and using this to check for a match. |
353 | // |
354 | // NOTE: an initial guess for tproj is expected as input so that out-of-time |
355 | // hits can be skipped |
356 | jerror_t DParticleID::MatchToBCAL(const DReferenceTrajectory *rt, const vector<const DBCALShower*>& locInputBCALShowers, vector<const DBCALShower*>& locMatchedBCALShowers, double& locProjectedTime, double& locPathLength, double& locFlightTime){ |
357 | if (locInputBCALShowers.size() == 0){ |
358 | locProjectedTime = NaNstd::numeric_limits<double>::quiet_NaN(); |
359 | return RESOURCE_UNAVAILABLE; |
360 | } |
361 | |
362 | //Loop over bcal showers |
363 | double locTempPathLength, dphi, dz; |
364 | double locLargestShowerEnergy = -1.0; |
365 | int locBestShowerMatchIndex = -1, locBestShowerMatchIndexInMatchVector = -1; |
366 | for (unsigned int k = 0; k < locInputBCALShowers.size(); ++k){ |
367 | // Get the BCAL cluster position and normal |
368 | const DBCALShower *shower = locInputBCALShowers[k]; |
369 | DVector3 bcal_pos(shower->x, shower->y, shower->z); |
370 | DVector3 proj_pos; |
371 | // and the bcal cluster position, looking for the minimum |
372 | double locTempFlightTime = 0.0; |
373 | double d = rt->DistToRTwithTime(bcal_pos, &locTempPathLength, &locTempFlightTime); |
374 | if(!finite(d)) |
375 | continue; |
376 | // Check that the hit is not out of time with respect to the track |
377 | if (fabs(locInputBCALShowers[k]->t - locTempFlightTime - locProjectedTime) > OUT_OF_TIME_CUT200.) continue; |
378 | |
379 | proj_pos = rt->GetLastDOCAPoint(); |
380 | |
381 | dz = proj_pos.z() - bcal_pos.z(); |
382 | dphi = proj_pos.Phi() - bcal_pos.Phi(); |
383 | double p = rt->swim_steps[0].mom.Mag(); |
384 | dphi += 0.002 + 8.314e-3/(p + 0.3788)/(p + 0.3788); |
385 | while(dphi > TMath::Pi()) |
386 | dphi -= 2.0*TMath::Pi(); |
387 | while(dphi < -1.0*TMath::Pi()) |
388 | dphi += 2.0*TMath::Pi(); |
389 | double phi_sigma = 0.025 + 5.8e-4/(p*p*p); |
390 | if (fabs(dz) < 10. && fabs(dphi) < 3.*phi_sigma){ |
391 | locMatchedBCALShowers.push_back(shower); |
392 | if(shower->E > locLargestShowerEnergy){ |
393 | locLargestShowerEnergy = shower->E; |
394 | locPathLength = locTempPathLength; |
395 | locFlightTime = locTempFlightTime; |
396 | locBestShowerMatchIndex = k; |
397 | locBestShowerMatchIndexInMatchVector = locMatchedBCALShowers.size() - 1; |
398 | } |
399 | } |
400 | } |
401 | |
402 | if(locBestShowerMatchIndexInMatchVector > 0){ //move highest energy shower to the front of the list |
403 | locMatchedBCALShowers.erase(locMatchedBCALShowers.begin() + locBestShowerMatchIndexInMatchVector); |
404 | locMatchedBCALShowers.insert(locMatchedBCALShowers.begin(), locInputBCALShowers[locBestShowerMatchIndex]); |
405 | } |
406 | |
407 | if(locMatchedBCALShowers.size() > 0){ |
408 | // Projected time at the target |
409 | locProjectedTime = locMatchedBCALShowers[0]->t - locFlightTime; |
410 | // locProjectedTime += 0.03; // correction determined from observation of simulated data //Paul Mattione |
411 | return NOERROR; |
412 | } |
413 | |
414 | locProjectedTime = NaNstd::numeric_limits<double>::quiet_NaN(); |
415 | return VALUE_OUT_OF_RANGE; |
416 | } |
417 | |
418 | //------------------ |
419 | // MatchToFCAL |
420 | //------------------ |
421 | // Loop over fcal clusters, looking for minimum distance of closest approach |
422 | // of track to a cluster and using this to check for a match. |
423 | // |
424 | // NOTE: an initial guess for locProjectedTime is expected as input so that out-of-time |
425 | // hits can be skipped |
426 | jerror_t DParticleID::MatchToFCAL(const DReferenceTrajectory *rt, const vector<const DFCALShower*>& locInputFCALShowers, vector<const DFCALShower*>& locMatchedFCALShowers, double& locProjectedTime, double& locPathLength, double& locFlightTime){ |
427 | if (locInputFCALShowers.size() == 0){ |
428 | locProjectedTime = NaNstd::numeric_limits<double>::quiet_NaN(); |
429 | return RESOURCE_UNAVAILABLE; |
430 | } |
431 | |
432 | // Set minimum matching distance to a large default value |
433 | double locLargestShowerEnergy = -1.0; |
434 | // loop over clusters |
435 | double locTempPathLength; |
436 | int locBestShowerMatchIndex = -1, locBestShowerMatchIndexInMatchVector = -1; |
437 | for (unsigned int k = 0;k < locInputFCALShowers.size(); k++){ |
438 | |
439 | // Get the FCAL cluster position and normal vector for the FCAL plane |
440 | DVector3 fcal_pos = locInputFCALShowers[k]->getPosition(); |
441 | // This is a bit of a kludge... |
442 | //fcal_pos.SetZ(DFCALGeometry::fcalFaceZ()); |
443 | DVector3 norm(0,0,1); |
444 | DVector3 proj_pos, dir; |
445 | |
446 | // Find the distance of closest approach between the track trajectory |
447 | // and the tof cluster position, looking for the minimum |
448 | double locTempFlightTime = 0.; |
449 | rt->GetIntersectionWithPlane(fcal_pos, norm, proj_pos, dir, &locTempPathLength, &locTempFlightTime); |
450 | double d = (fcal_pos - proj_pos).Mag(); |
451 | // Check that the hit is not out of time with respect to the track |
452 | if (fabs(locInputFCALShowers[k]->getTime() - locTempFlightTime - locProjectedTime) > OUT_OF_TIME_CUT200.) continue; |
453 | if(d < DELTA_R_FCAL){ |
454 | locMatchedFCALShowers.push_back(locInputFCALShowers[k]); |
455 | if(locInputFCALShowers[k]->getEnergy() > locLargestShowerEnergy){ |
456 | locLargestShowerEnergy = locInputFCALShowers[k]->getEnergy(); |
457 | locPathLength = locTempPathLength; |
458 | locFlightTime = locTempFlightTime; |
459 | locBestShowerMatchIndex = k; |
460 | locBestShowerMatchIndexInMatchVector = locMatchedFCALShowers.size() - 1; |
461 | } |
462 | } |
463 | } |
464 | |
465 | if(locBestShowerMatchIndexInMatchVector > 0){ //move highest energy shower to the front of the list |
466 | locMatchedFCALShowers.erase(locMatchedFCALShowers.begin() + locBestShowerMatchIndexInMatchVector); |
467 | locMatchedFCALShowers.insert(locMatchedFCALShowers.begin(), locInputFCALShowers[locBestShowerMatchIndex]); |
468 | } |
469 | |
470 | // Check for a match |
471 | if(locMatchedFCALShowers.size() > 0){ |
472 | locProjectedTime = locMatchedFCALShowers[0]->getTime() - locFlightTime; |
473 | locProjectedTime -= 2.218; // correction determined from fit to simulated data |
474 | return NOERROR; |
475 | } |
476 | |
477 | locProjectedTime = NaNstd::numeric_limits<double>::quiet_NaN(); |
478 | return VALUE_OUT_OF_RANGE; |
479 | } |
480 | |
481 | //------------------ |
482 | // MatchToSC |
483 | //------------------ |
484 | // Match track to the start counter paddles with hits. If a match |
485 | // is found, use the z-position of the track projection to the start counter |
486 | // planes to correct for the light propagation within the scintillator and |
487 | // estimate the "vertex" time. |
488 | // |
489 | // Unlike the next method, this method does not use the reference trajectory. |
490 | // |
491 | // NOTE: an initial guess for tproj is expected as input so that out-of-time |
492 | // hits can be skipped |
493 | jerror_t DParticleID::MatchToSC(const DKinematicData &parms, |
494 | vector<const DSCHit*>&sc_hits, |
495 | double &tproj,unsigned int &sc_match_id){ |
496 | sc_match_id=0; |
497 | if (sc_hits.size()==0){ |
498 | tproj=NaNstd::numeric_limits<double>::quiet_NaN(); |
499 | return RESOURCE_UNAVAILABLE; |
500 | } |
501 | double myz=0.; |
502 | double dphi_min=10000.,myphi=0.; |
503 | unsigned int num=sc_norm.size()-1; |
504 | |
505 | DVector3 pos(parms.position()); |
506 | DVector3 mom(parms.momentum()); |
507 | stepper->SetCharge(parms.charge()); |
508 | |
509 | // Swim to barrel representing the start counter straight portion |
510 | double ds=0.,myds=0; |
511 | if (stepper->SwimToRadius(pos,mom,sc_pos[1].x(),&ds)){ |
512 | tproj=NaNstd::numeric_limits<double>::quiet_NaN(); |
513 | return VALUE_OUT_OF_RANGE; |
514 | } |
515 | // Change the sign of ds -- most of the time we will need to add a small |
516 | // amount of time to the time calculated at the start counter |
517 | ds*=-1.; |
518 | |
519 | // Position along z and phi at intersection |
520 | double proj_z=pos.z(); |
521 | double proj_phi=pos.Phi(); |
522 | if (proj_phi<0) proj_phi+=2.*M_PI3.14159265358979323846; |
523 | |
524 | // Position of transition between start counter nose and leg |
525 | double sc_pos1=sc_pos[1].z(); |
526 | // position in z at the end of the nose |
527 | double sc_posn=sc_pos[num].z(); |
528 | |
529 | // loop over sc hits, looking for the one with closest phi value to the |
530 | // projected phi value |
531 | for (unsigned int i=0;i<sc_hits.size();i++){ |
532 | // Check that the hit is not out of time with respect to the track |
533 | if (fabs(tproj-sc_hits[i]->t)>OUT_OF_TIME_CUT200.) continue; |
534 | |
535 | double phi=(6.0+12.*(sc_hits[i]->sector-1))*M_PI3.14159265358979323846/180.; |
536 | double dphi=phi-proj_phi; |
537 | |
538 | // If the z position is in the nose region, match to the appropriate start |
539 | // counter plane |
540 | if (proj_z>sc_pos1){ |
541 | double cosphi=cos(phi); |
542 | double sinphi=sin(phi); |
543 | for (unsigned int i=1;i<num;i++){ |
544 | DVector3 mymom=(-1.)*mom; |
545 | DVector3 mypos=pos; |
546 | double xhat=sc_norm[i].x(); |
547 | double r=sc_pos[i].X(); |
548 | double x=r*cosphi; |
549 | double y=r*sinphi; |
550 | double z=sc_pos[i].z(); |
551 | DVector3 norm(x*xhat,y*xhat,z); |
552 | DVector3 plane(x,y,z); |
553 | double ds2=0.; |
554 | if (stepper->SwimToPlane(mypos,mymom,plane,norm,&ds2)) continue; |
555 | |
556 | proj_z=mypos.z(); |
557 | if (proj_z<sc_pos[i+1].z()){ |
558 | proj_phi=mypos.Phi(); |
559 | if (proj_phi<0) proj_phi+=2.*M_PI3.14159265358979323846; |
560 | dphi=proj_phi-phi; |
561 | ds+=ds2; |
562 | |
563 | break; |
564 | } |
565 | } |
566 | } |
567 | |
568 | // Look for smallest difference in phi |
569 | if (fabs(dphi)<dphi_min){ |
570 | dphi_min=fabs(dphi); |
571 | myphi=phi; |
Value stored to 'myphi' is never read | |
572 | myz=proj_z; |
573 | myds=ds; |
574 | sc_match_id=i; |
575 | } |
576 | } |
577 | |
578 | // Look for a match in phi |
579 | if (dphi_min<0.16){ |
580 | // Find the time at the start counter, before correcting for position |
581 | // along the start counter |
582 | tproj=sc_hits[sc_match_id]->t-sc_leg_tcor; |
583 | |
584 | // Check position along z |
585 | if (myz<sc_pos[0].z()) myz=sc_pos[0].z(); |
586 | if (myz<sc_pos1){ |
587 | // Leg region |
588 | tproj-=myz/C_EFFECTIVE15.; |
589 | } |
590 | else if (myz<sc_posn){ |
591 | // Nose region |
592 | tproj-=((myz-sc_pos1)*sc_angle_cor+sc_pos1)/C_EFFECTIVE15.; |
593 | } |
594 | else{ |
595 | // Assume that the particle hit the most downstream z position of the |
596 | // start counter |
597 | tproj-=((sc_posn-sc_pos1)*sc_angle_cor+sc_pos1)/C_EFFECTIVE15.; |
598 | } |
599 | |
600 | // Adjust for flight time to the position pos |
601 | double mass=parms.mass(); |
602 | double p2=mom.Mag2(); |
603 | double one_over_beta=sqrt(1.+mass*mass/p2); |
604 | tproj += myds*one_over_beta/SPEED_OF_LIGHT29.9792; |
605 | |
606 | return NOERROR; |
607 | } |
608 | |
609 | tproj=NaNstd::numeric_limits<double>::quiet_NaN(); |
610 | return VALUE_OUT_OF_RANGE; |
611 | |
612 | } |
613 | |
614 | |
615 | //------------------ |
616 | // MatchToSC |
617 | //------------------ |
618 | // Match track to the start counter paddles with hits. If a match |
619 | // is found, use the z-position of the track projection to the start counter |
620 | // planes to correct for the light propagation within the scintillator and |
621 | // estimate the "vertex" time. |
622 | // |
623 | // NOTE: an initial guess for tproj is expected as input so that out-of-time |
624 | // hits can be skipped |
625 | jerror_t DParticleID::MatchToSC(const DReferenceTrajectory *rt, DTrackFitter::fit_type_t fit_type, vector<const DSCHit*>&sc_hits, double &tproj,unsigned int &sc_match_id, double &locPathLength, double &locFlightTime){ |
626 | |
627 | //tproj=NaN; |
628 | sc_match_id=0; |
629 | if (sc_hits.size()==0){ |
630 | tproj=NaNstd::numeric_limits<double>::quiet_NaN(); |
631 | return RESOURCE_UNAVAILABLE; |
632 | } |
633 | double myz=0.; |
634 | double dphi_min=10000.,myphi=0.; |
635 | double locTempPathLength, locTempFlightTime = 0.0; |
636 | DVector3 proj_pos; |
637 | |
638 | // Find intersection with a "barrel" approximation for the start counter |
639 | rt->GetIntersectionWithRadius(sc_pos[1].x(),proj_pos,&locTempPathLength,&locTempFlightTime); |
640 | double proj_phi=proj_pos.Phi(); |
641 | if (proj_phi<0) proj_phi+=2.*M_PI3.14159265358979323846; |
642 | |
643 | // loop over sc hits, looking for the one with closest phi value to the |
644 | // projected phi value |
645 | for (unsigned int i=0;i<sc_hits.size();i++){ |
646 | // Check that the hit is not out of time with respect to the track |
647 | if (fabs(tproj-sc_hits[i]->t)>OUT_OF_TIME_CUT200.) continue; |
648 | |
649 | double phi=(6.0+12.*(sc_hits[i]->sector-1))*M_PI3.14159265358979323846/180.; |
650 | double dphi=phi-proj_phi; |
651 | |
652 | if (fabs(dphi)<dphi_min){ |
653 | dphi_min=fabs(dphi); |
654 | myphi=phi; |
655 | myz=proj_pos.z(); |
656 | sc_match_id=i; |
657 | } |
658 | } |
659 | // Look for a match in phi |
660 | if (dphi_min<0.21){ |
661 | // Now check to see if the intersection is in the nose region and find the |
662 | // start time |
663 | tproj=sc_hits[sc_match_id]->t-sc_leg_tcor; |
664 | if (myz<sc_pos[0].z()) myz=sc_pos[0].z(); |
665 | if (myz>sc_pos[1].z()){ |
666 | unsigned int num=sc_norm.size()-1; |
667 | for (unsigned int i=1;i<num;i++){ |
668 | double xhat=sc_norm[i].x(); |
669 | DVector3 norm(cos(myphi)*xhat,sin(myphi)*xhat,sc_norm[i].z()); |
670 | double r=sc_pos[i].X(); |
671 | DVector3 pos(r*cos(myphi),r*sin(myphi),sc_pos[i].z()); |
672 | rt->GetIntersectionWithPlane(pos,norm,proj_pos,&locTempPathLength,&locTempFlightTime); |
673 | myz=proj_pos.z(); |
674 | if (myz<sc_pos[i+1].z()) |
675 | break; |
676 | } |
677 | double sc_pos1=sc_pos[1].z(); |
678 | if (myz<sc_pos1){ |
679 | tproj-=locTempFlightTime+sc_pos1/C_EFFECTIVE15.; |
680 | locFlightTime = locTempFlightTime; |
681 | locPathLength = locTempPathLength; |
682 | }else if (myz>sc_pos[num].z()){ |
683 | // Assume that the particle hit the most downstream z position of the |
684 | // start counter |
685 | double costheta=rt->swim_steps[0].mom.CosTheta(); |
686 | double s=(sc_pos[num].z()-rt->swim_steps[0].origin.z())/costheta; |
687 | double mass=rt->GetMass(); |
688 | double p2=rt->swim_steps[0].mom.Mag2(); |
689 | double one_over_beta=sqrt(1.+mass*mass/p2); |
690 | |
691 | tproj -= s*one_over_beta/SPEED_OF_LIGHT29.9792 + ((sc_pos[num].z()-sc_pos1)*sc_angle_cor+sc_pos1)/C_EFFECTIVE15.; |
692 | locFlightTime = s*one_over_beta/SPEED_OF_LIGHT29.9792; |
693 | locPathLength = s; |
694 | }else{ |
695 | tproj-=locTempFlightTime+((myz-sc_pos1)*sc_angle_cor+sc_pos1)/C_EFFECTIVE15.; |
696 | locFlightTime = locTempFlightTime; |
697 | locPathLength = locTempPathLength; |
698 | } |
699 | }else{ |
700 | tproj-=locTempFlightTime+myz/C_EFFECTIVE15.; |
701 | locFlightTime = locTempFlightTime; |
702 | locPathLength = locTempPathLength; |
703 | } |
704 | return NOERROR; |
705 | } |
706 | |
707 | tproj=NaNstd::numeric_limits<double>::quiet_NaN(); |
708 | return VALUE_OUT_OF_RANGE; |
709 | } |
710 | |
711 | void DParticleID::Calc_TimingChiSq(DChargedTrackHypothesis* locChargedTrackHypothesis, double locRFTime, double locRFBunchFrequency) |
712 | { |
713 | if((locChargedTrackHypothesis->t0_detector() == SYS_NULL) || (locChargedTrackHypothesis->t1_detector() == SYS_NULL) || (locChargedTrackHypothesis->t1_detector() == SYS_START)) |
714 | { |
715 | //uncertainty so huge on SYS_START that for t1() it won't help distinguish PID anyway |
716 | locChargedTrackHypothesis->dChiSq_Timing = 0.0; |
717 | locChargedTrackHypothesis->dNDF_Timing = 0; |
718 | return; |
719 | } |
720 | |
721 | // Use ST hit to select RF beam bucket |
722 | double locPropagatedRFTime = locRFTime + (locChargedTrackHypothesis->z() - dTargetZCenter)/SPEED_OF_LIGHT29.9792; |
723 | double locSTRFTimeDifference = locChargedTrackHypothesis->t0() - locPropagatedRFTime; |
724 | while(fabs(locSTRFTimeDifference) > locRFBunchFrequency/2.0){ |
725 | locPropagatedRFTime += (locSTRFTimeDifference > 0.0) ? locRFBunchFrequency : -1.0*locRFBunchFrequency; |
726 | locSTRFTimeDifference = locChargedTrackHypothesis->t0() - locPropagatedRFTime; |
727 | } |
728 | |
729 | // Compare time difference between RF & TOF/BCAL/FCAL times at the vertex |
730 | double locTimeDifference = locPropagatedRFTime - locChargedTrackHypothesis->dProjectedStartTime; |
731 | |
732 | // Calculate ChiSq, FOM |
733 | double locTUncertainty = locChargedTrackHypothesis->dProjectedStartTimeUncertainty; |
734 | double locTimingChiSq = locTimeDifference*locTimeDifference/(locTUncertainty*locTUncertainty); |
735 | locChargedTrackHypothesis->dChiSq_Timing = locTimingChiSq; |
736 | locChargedTrackHypothesis->dNDF_Timing = 1; |
737 | } |
738 | |
739 | Particle_t DParticleID::IDTrack(float locCharge, float locMass){ |
740 | float locMassTolerance = 0.010; |
741 | if (locCharge > 0.0){ // Positive particles |
742 | if (fabs(locMass - ParticleMass(Proton)) < locMassTolerance) return Proton; |
743 | if (fabs(locMass - ParticleMass(PiPlus)) < locMassTolerance) return PiPlus; |
744 | if (fabs(locMass - ParticleMass(KPlus)) < locMassTolerance) return KPlus; |
745 | if (fabs(locMass - ParticleMass(Positron)) < locMassTolerance) return Positron; |
746 | if (fabs(locMass - ParticleMass(MuonPlus)) < locMassTolerance) return MuonPlus; |
747 | } else if (locCharge < 0.0){ // Negative particles |
748 | if (fabs(locMass - ParticleMass(PiMinus)) < locMassTolerance) return PiMinus; |
749 | if (fabs(locMass - ParticleMass(KMinus)) < locMassTolerance) return KMinus; |
750 | if (fabs(locMass - ParticleMass(MuonMinus)) < locMassTolerance) return MuonMinus; |
751 | if (fabs(locMass - ParticleMass(Electron)) < locMassTolerance) return Electron; |
752 | if (fabs(locMass - ParticleMass(AntiProton)) < locMassTolerance) return AntiProton; |
753 | } else { //Neutral Track |
754 | if (fabs(locMass - ParticleMass(Gamma)) < locMassTolerance) return Gamma; |
755 | if (fabs(locMass - ParticleMass(Neutron)) < locMassTolerance) return Neutron; |
756 | } |
757 | return Unknown; |
758 | } |
759 |