Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DEventProcessor_trkres_tree.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DEventProcessor_trkres_tree.cc
4 // Created: Tue Apr 7 14:54:33 EDT 2009
5 // Creator: davidl (on Darwin harriet.jlab.org 9.6.0 i386)
6 //
7 
9 
10 #include <iostream>
11 #include <iomanip>
12 #include <cmath>
13 #include <utility>
14 #include <vector>
15 using namespace std;
16 
17 #include <TROOT.h>
18 
19 #include <JANA/JApplication.h>
20 #include <JANA/JEventLoop.h>
21 
22 #include <DANA/DApplication.h>
23 #include <TRACKING/DMCThrown.h>
25 #include <CDC/DCDCTrackHit.h>
26 #include <FDC/DFDCPseudo.h>
28 
29 
30 // Routine used to create our DEventProcessor
31 extern "C"{
32 void InitPlugin(JApplication *app){
33  InitJANAPlugin(app);
34  app->AddProcessor(new DEventProcessor_trkres_tree());
35 }
36 } // "C"
37 
38 
39 //------------------
40 // DEventProcessor_track_hists
41 //------------------
43 {
44  trkres_ptr = &trkres;
45 
46  pthread_mutex_init(&mutex, NULL);
47 }
48 
49 //------------------
50 // ~DEventProcessor_track_hists
51 //------------------
53 {
54 
55 }
56 
57 //------------------
58 // init
59 //------------------
61 {
62  // Create TRACKING directory
63  TDirectory *dir = (TDirectory*)gROOT->FindObject("TRACKING");
64  if(!dir)dir = new TDirectoryFile("TRACKING","TRACKING");
65  dir->cd();
66 
67  ttrkres = new TTree("track","Track Res.");
68  ttrkres->Branch("E","trackres",&trkres_ptr);
69 
70  dir->cd("../");
71 
72  return NOERROR;
73 }
74 
75 //------------------
76 // brun
77 //------------------
78 jerror_t DEventProcessor_trkres_tree::brun(JEventLoop *loop, int32_t runnumber)
79 {
80  // These are copied from DTrackFitterALT1.cc
81  double locSIGMA_CDC = 0.0150;
82  double locSIGMA_FDC_ANODE = 0.0200;
83  double locSIGMA_FDC_CATHODE = 0.0200;
84 
85  gPARMS->SetDefaultParameter("TRKFIT:SIGMA_CDC", locSIGMA_CDC);
86  gPARMS->SetDefaultParameter("TRKFIT:SIGMA_FDC_ANODE", locSIGMA_FDC_ANODE);
87  gPARMS->SetDefaultParameter("TRKFIT:SIGMA_FDC_CATHODE", locSIGMA_FDC_CATHODE);
88 
89  DApplication *dapp = dynamic_cast<DApplication*>(loop->GetJApplication());
90 
91  pthread_mutex_lock(&mutex);
92 
93  bfield = dapp->GetBfield(runnumber);
94 
95  SIGMA_CDC = locSIGMA_CDC;
96  SIGMA_FDC_ANODE = locSIGMA_FDC_ANODE;
97  SIGMA_FDC_CATHODE = locSIGMA_FDC_CATHODE;
98 
99  pthread_mutex_unlock(&mutex);
100 
101  return NOERROR;
102 }
103 
104 //------------------
105 // evnt
106 //------------------
107 jerror_t DEventProcessor_trkres_tree::evnt(JEventLoop *loop, uint64_t eventnumber)
108 {
109  vector<const DMCTrajectoryPoint*> trajpoints;
110  vector<const DCDCTrackHit*> cdchits;
111  vector<const DFDCPseudo*> fdchits;
112  const DMCThrown *mcthrown;
113 
114  loop->Get(trajpoints);
115  loop->Get(cdchits);
116  loop->Get(fdchits);
117  loop->GetSingle(mcthrown);
118 
119  // Assume all hits belong to this one thrown track
120  // (this should only be used on data procuded with
121  // NOSECONDARIES set to 1 !!)
122  vector<meas_t> meas; // container to hold measurements
123 
124  // Loop over CDC hits, adding them to list
125  for(unsigned int i=0; i<cdchits.size(); i++){
126  const DCoordinateSystem *wire = cdchits[i]->wire;
127 
128  meas_t m;
129  m.err = SIGMA_CDC;
130  m.errc = 0.0;
131 
132  // Find trajectory point closest to this wire
133  m.traj = FindTrajectoryPoint(wire, m.radlen, m.s, trajpoints);
134  double Bx, By, Bz;
135  bfield->GetField(m.traj->x, m.traj->y, m.traj->z, Bx, By, Bz);
136  m.B = sqrt(Bx*Bx + By*By + Bz*Bz);
137 
138  meas.push_back(m);
139  }
140 
141  // Loop over FDC hits, adding them to list
142  for(unsigned int i=0; i<fdchits.size(); i++){
143  const DCoordinateSystem *wire = fdchits[i]->wire;
144 
145  meas_t m;
146  m.err = SIGMA_FDC_ANODE;
147  m.errc = 0.0;
148 
149  // Find trajectory point closest to this wire
150  m.traj = FindTrajectoryPoint(wire, m.radlen, m.s, trajpoints);
151  double Bx, By, Bz;
152  bfield->GetField(m.traj->x, m.traj->y, m.traj->z, Bx, By, Bz);
153  m.B = sqrt(Bx*Bx + By*By + Bz*Bz);
154 
155  meas.push_back(m);
156  }
157 
158  if(meas.size()<5)return NOERROR;
159 
160  double deltak, pt_res;
161  GetPtRes(meas, deltak, pt_res);
162 
163  double theta_res;
164  GetThetaRes(meas, theta_res);
165 
166  double pt = sqrt(pow((double)meas[0].traj->px,2.0) + pow((double)meas[0].traj->py,2.0));
167  double p = sqrt(pow((double)meas[0].traj->pz,2.0) + pow(pt,2.0));
168  double theta = asin(pt/p);
169  if(theta<0.0)theta+=2.0*M_PI;
170 
171  DVector3 dthrown = mcthrown->momentum();
172 
173  // Although we are only filling objects local to this plugin, TTree::Fill() periodically writes to file: Global ROOT lock
174  japp->RootWriteLock(); //ACQUIRE ROOT LOCK
175 
176  trkres.event = eventnumber;
177  trkres.recon.SetXYZ(meas[0].traj->px, meas[0].traj->py, meas[0].traj->pz);
178  trkres.thrown.SetXYZ(dthrown.X(), dthrown.Y(), dthrown.Z());
179  trkres.deltak = deltak;
180  trkres.pt_res = pt_res;
181  trkres.p_res = (pt_res*pt + fabs(pt/tan(theta)*theta_res))/sin(theta)/p;
182  trkres.theta_res = theta_res;
183  trkres.phi_res = 0;
184 
185  ttrkres->Fill();
186 
187  japp->RootUnLock(); //RELEASE ROOT LOCK
188 
189  return NOERROR;
190 }
191 
192 //------------------
193 // FindTrajectoryPoint
194 //------------------
195 const DMCTrajectoryPoint* DEventProcessor_trkres_tree::FindTrajectoryPoint(const DCoordinateSystem *wire, double &radlen, double &s, vector<const DMCTrajectoryPoint*> trajpoints)
196 {
197  // Loop over all points, keeping track of the one closest to the wire
198  const DMCTrajectoryPoint* best=NULL;
199  double min_dist = 1.0E6;
200  s = 0.0;
201  radlen = 0.0;
202  double best_radlen=0.0;
203  double best_s=0.0;
204  for(unsigned int i=0; i<trajpoints.size(); i++){
205  const DMCTrajectoryPoint* traj = trajpoints[i];
206  DVector3 d(traj->x-wire->origin.X(), traj->y-wire->origin.Y(), traj->z-wire->origin.Z());
207  double d_dot_udir = d.Dot(wire->udir);
208  double dist = sqrt(d.Mag2() - d_dot_udir*d_dot_udir);
209  double dist_past_end = fabs(d_dot_udir) - wire->L/2.0;
210  if(dist_past_end>0.0) dist = sqrt(dist*dist + dist_past_end*dist_past_end);
211 
212  s += traj->step;
213  radlen += (double)traj->step/(double)traj->radlen;
214 
215  if(dist<min_dist){
216  min_dist = dist;
217  best = traj;
218  best_s = s;
219  best_radlen = radlen;
220  }
221  }
222 
223  // Copy integrated steps and radiation lengths for this step into references
224  s = best_s;
225  radlen = best_radlen;
226 
227  return best;
228 }
229 
230 //------------------
231 // GetPtRes
232 //------------------
233 void DEventProcessor_trkres_tree::GetPtRes(vector<meas_t> &meas, double &deltak, double &pt_res)
234 {
235  // Calculate using second method (eq. 28.47 PDG July 2008, pg. 309)
236  double Vs1 = 0.0;
237  double Vs2 = 0.0;
238  double Vs3 = 0.0;
239  double Vs4 = 0.0;
240  double w = 0.0;
241  double Bavg = 0.0;
242  for(unsigned int i=0; i<meas.size(); i++){
243  double s = meas[i].s - meas[0].s;
244  double e = meas[i].err;
245 
246  w += 1.0/(e*e);
247  Vs1 += s/(e*e);
248  Vs2 += s*s/(e*e);
249  Vs3 += s*s*s/(e*e);
250  Vs4 += s*s*s*s/(e*e);
251  Bavg += meas[i].B;
252  }
253  double Vss = (Vs2 - Vs1*Vs1)/w;
254  double Vs2s2 = (Vs4 - Vs2*Vs2)/w;
255  double Vss2 = (Vs3 - Vs2*Vs1)/w;
256 
257  double deltak_res = sqrt(4.0/w*Vss/(Vss*Vs2s2 - Vss2*Vss2));
258 
259  // Resolution due to multiple scattering
260  double radlen = meas[meas.size()-1].radlen; // we want total integrated from vertex
261  double L = meas[meas.size()-1].s - meas[0].s; // pathlength through detector
262  double pt = sqrt(pow((double)meas[0].traj->px,2.0) + pow((double)meas[0].traj->py,2.0));
263  double p = sqrt(pow((double)meas[0].traj->pz,2.0) + pow(pt,2.0));
264  double beta = p/sqrt(p*p + pow(0.13957,2.0)); // assume pion (could get this from meas[0].traj->part)
265  double lambda = M_PI/2.0 - asin(pt/p);
266  double deltak_ms = 0.016*sqrt(radlen)/(L*p*beta*pow(cos(lambda), 2.0));
267 
268  deltak = sqrt(deltak_res*deltak_res + deltak_ms*deltak_ms);
269 
270  // Use the average B-field to estimate the curvature based on the
271  // momentum at the first trajectory point.
272  Bavg/=(double)meas.size();
273  double k = 0.003*Bavg/pt;
274 
275  pt_res = deltak/k;
276 }
277 
278 //------------------
279 // GetThetaRes
280 //------------------
281 void DEventProcessor_trkres_tree::GetThetaRes(vector<meas_t> &meas, double &theta_res)
282 {
283  // Error due to position resolution.
284  // This is based on the method outlined in Mark Ito's GlueX note 1015-v2, page 7.
285 
286  // This essentially is eq. 12 from Mark's paper, but in a different form. This
287  // form I got off of Wikipedia and it includes individual errors. The wikipedia
288  // one also divides by N-2 rather than N. (I believe this may be due to the 2
289  // parameters of the linear fit).
290  double s_avg = 0.0;
291  double err2_avg = 0.0;
292  for(unsigned int i=0; i<meas.size(); i++){
293  double s = meas[i].s - meas[0].s;
294  double e = meas[i].err;
295 
296  s_avg += s;
297  err2_avg += e*e;
298  }
299  s_avg/=(double)meas.size();
300  err2_avg/=(double)(meas.size()-2);
301 
302  double sum=0.0;
303  for(unsigned int i=0; i<meas.size(); i++){
304  double s = meas[i].s - meas[0].s;
305 
306  sum += pow(s - s_avg, 2.0);
307  }
308 
309  // The difference from Mark's note and here is that in the note he had a factor
310  // of 1/sec^2(theta) arising from the derivative of arctan(theta). However, in
311  // that example, the error bars are always in the y-direction which is not always
312  // perpendicular to the "track". This leads to a zero contribution to the error
313  // at pi/2 in his formula. Here, we take the result at theta=0 since that is where
314  // the error direction is perpendicular to the track direction as it always is
315  // in the case of real, helical tracks. Note that I'm tempted to take an arctan
316  // of the dtheta_res here, but I think the derivative method is probably correct.
317  // In the limit of the error being small compared to the track length, the small
318  // angle approximation is valid so it doesn't really matter.
319  double dtheta_res = sqrt(err2_avg/sum);
320 
321  // Error due to multiple scattering
322  double radlen = meas[meas.size()-1].radlen; // we want total integrated from vertex
323  double pt = sqrt(pow((double)meas[0].traj->px,2.0) + pow((double)meas[0].traj->py,2.0));
324  double p = sqrt(pow((double)meas[0].traj->pz,2.0) + pow(pt,2.0));
325  double beta = p/sqrt(p*p + pow(0.13957,2.0)); // assume pion (could get this from meas[0].traj->part)
326  double dtheta_ms = 0.0136*sqrt(radlen)/(beta*p)*(1.0+0.038*log(radlen))/sqrt(3.0);
327 
328  theta_res = sqrt(dtheta_res*dtheta_res + dtheta_ms*dtheta_ms);
329 }
330 
331 //------------------
332 // erun
333 //------------------
335 {
336 
337  return NOERROR;
338 }
339 
340 //------------------
341 // fini
342 //------------------
344 {
345 
346  return NOERROR;
347 }
348 
DApplication * dapp
TVector3 DVector3
Definition: DVector3.h:14
jerror_t evnt(JEventLoop *eventLoop, uint64_t eventnumber)
Called every event.
void GetPtRes(vector< meas_t > &meas, double &deltak, double &pt_res)
jerror_t fini(void)
Called after last event of last event source has been processed.
DMagneticFieldMap * GetBfield(unsigned int run_number=1)
jerror_t erun(void)
Called everytime run number changes, provided brun has been called.
JApplication * japp
TEllipse * e
jerror_t init(void)
Called once at program start.
InitPlugin_t InitPlugin
const DMCTrajectoryPoint * FindTrajectoryPoint(const DCoordinateSystem *wire, double &radlen, double &s, vector< const DMCTrajectoryPoint * > trajpoints)
void GetThetaRes(vector< meas_t > &meas, double &theta_res)
double sqrt(double)
double sin(double)
const DVector3 & momentum(void) const
jerror_t brun(JEventLoop *eventLoop, int32_t runnumber)
Called everytime a new run number is detected.
TDirectory * dir
Definition: bcal_hist_eff.C:31