Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DTrackCandidate_factory.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DTrackCandidate_factory.cc
4 // Created: Mon Jul 18 15:23:04 EDT 2005
5 // Creator: davidl (on Darwin wire129.jlab.org 7.8.0 powerpc)
6 //
7 
8 /// Factory to match track candidates generated by the FDC- and CDC-specific
9 /// track finding codes. The code uses several algorithms in the following
10 /// order of precedence:
11 /// Method 1: Swims cdc candidates pointing in the forward direction
12 /// and tries to match them geometrically to fdc candidates.
13 /// Method 2: Projects the fdc candidates into the cdc region and tries
14 /// to match to the cdc hits in each cdc candidate that points
15 /// in the forward direction.
16 /// Method 3: Similar to method 2, except that it projects a cdc
17 /// candidate into the FDC region.
18 /// Method 4: Matches left-over fdc candidates to other left-over fdc
19 /// candidates.
20 /// Method 5: Matches cdc candidates that do not point toward the cdc
21 /// endplate that were not matched by previous methods to fdc
22 /// candidates.
23 /// Method 6: Tries to match stray unused cdc hits with fdc candidates
24 /// Method 7: Alternate method to match leftover fdc candidates that
25 /// have already been matched to other track candidates
26 /// Method 8: Attempts to "improve" a cdc candidate to be matched to an
27 /// FDC candidate with an assumption of the hit position in
28 /// outermost stereo straw
29 /// Methods 9-13: Various tricks to try to associate segments in the FDC
30 /// with other segments or tracks
31 /// If a match is found, the code attempts to improve the track parameters by
32 /// redoing the Riemann Circle fit with the additional hits. If an fdc
33 /// candidate is matched to a cdc candidate, or several previously unused hits
34 /// are added to the track, the code attempts to place the "start" position
35 /// parameters of the track at a radius just outside the start counter.
36 
37 #include <cmath>
38 using namespace std;
39 
42 #include "START_COUNTER/DSCHit.h"
43 #include "DANA/DApplication.h"
44 #include <JANA/JCalibration.h>
45 #include <TRACKING/DHoughFind.h>
46 
47 #include <TROOT.h>
48 #include <TH2F.h>
49 #include <TMath.h>
50 
51 #define CUT 10.
52 #define RADIUS_CUT 50.0
53 #define BEAM_VAR 1. // cm^2
54 #define EPS 0.001
55 
56 //------------------
57 // cdc_fdc_match
58 //------------------
59 inline bool cdc_fdc_match(double p_fdc,double p_cdc,double dist){
60  //double frac=fabs(1.-p_cdc/p_fdc);
61  //double frac2=fabs(1.-p_fdc/p_cdc);
62  double p=p_fdc;
63  if (p_cdc <p ) p=p_cdc;
64  if (dist<10. && dist <4.+1.75/p
65  //&& (frac<0.5 || frac2<0.5)
66  ) return true;
67  return false;
68 }
69 
70 //------------------
71 // SegmentSortByLayerincreasing
72 //------------------
73 inline bool SegmentSortByLayerincreasing(const DFDCSegment* const &segment1, const DFDCSegment* const &segment2) {
74  // Compare DFDCSegment->DFDCPseudo[0]->DFDCWire->layer
75  int layer1 = 100; // defaults just in case there is a segment with no hits
76  int layer2 = 100;
77 
78  if(segment1->hits.size()>0)layer1=segment1->hits[0]->wire->layer;
79  if(segment2->hits.size()>0)layer2=segment2->hits[0]->wire->layer;
80 
81  return layer1 < layer2;
82 }
83 
84 //------------------
85 // CDCHitSortByLayerincreasing
86 //------------------
87 inline bool CDCHitSortByLayerincreasing(const DCDCTrackHit* const &hit1, const DCDCTrackHit* const &hit2) {
88  // Used to sort CDC hits by layer (ring) with innermost layer hits first
89 
90  // if same ring, sort by wire number
91  if(hit1->wire->ring == hit2->wire->ring)
92  {
93  if(hit1->wire->straw == hit2->wire->straw)
94  return (hit1->dE > hit2->dE);
95  return hit1->wire->straw < hit2->wire->straw;
96  }
97 
98  return hit1->wire->ring < hit2->wire->ring;
99 }
100 
101 //------------------
102 // FDCHitSortByLayerincreasing
103 //------------------
104 inline bool FDCHitSortByLayerincreasing(const DFDCPseudo* const &hit1, const DFDCPseudo* const &hit2) {
105  // Used to sort FDC hits by layer with most upstream layer hits first
106  // if same layer, sort by wire number
107  if(hit1->wire->layer == hit2->wire->layer)
108  {
109  if(hit1->wire->wire == hit2->wire->wire)
110  return (hit1->dE > hit2->dE);
111  return (hit1->wire->wire < hit2->wire->wire);
112  }
113 
114  return hit1->wire->layer < hit2->wire->layer;
115 }
116 
117 //------------------
118 // init
119 //------------------
121 {
122  MAX_NUM_TRACK_CANDIDATES = 20;
123 
124  return NOERROR;
125 }
126 
127 //------------------
128 // brun
129 //------------------
130 jerror_t DTrackCandidate_factory::brun(JEventLoop* eventLoop,int32_t runnumber){
131  DApplication* dapp=dynamic_cast<DApplication*>(eventLoop->GetJApplication());
132  const DGeometry *dgeom = dapp->GetDGeometry(runnumber);
133  bfield = dapp->GetBfield(runnumber);
134  FactorForSenseOfRotation=(bfield->GetBz(0.,0.,65.)>0.)?-1.:1.;
135 
136  // Get start counter geometry;
137  dgeom->GetStartCounterGeom(sc_pos,sc_norm);
138 
139  dIsNoFieldFlag = (dynamic_cast<const DMagneticFieldMapNoField*>(bfield) != NULL);
140  if(dIsNoFieldFlag)
141  {
142  //Setting this flag makes it so that JANA does not delete the objects in _data. This factory will manage this memory.
143  //This is all of these pointers are just copied from the "StraightLine" factory, and should not be re-deleted.
144  SetFactoryFlag(NOT_OBJECT_OWNER);
145  }
146  else
147  ClearFactoryFlag(NOT_OBJECT_OWNER); //This factory will create it's own objects.
148 
149  // Get the position of the exit of the CDC endplate from DGeometry
150  double endplate_z,endplate_dz,endplate_rmin;
151  dgeom->GetCDCEndplate(endplate_z,endplate_dz,endplate_rmin,endplate_rmax);
152  cdc_endplate.SetZ(endplate_z+endplate_dz);
153 
154  dParticleID = NULL;
155  eventLoop->GetSingle(dParticleID);
156 
157  JCalibration *jcalib = dapp->GetJCalibration(runnumber);
158  map<string, double> targetparms;
159  if (jcalib->Get("TARGET/target_parms",targetparms)==false){
160  TARGET_Z = targetparms["TARGET_Z_POSITION"];
161  }
162  else{
163  dgeom->GetTargetZ(TARGET_Z);
164  }
165 
166  // Initialize the stepper
167  stepper=new DMagneticFieldStepper(bfield);
168  stepper->SetStepSize(1.0);
169 
170  DEBUG_HISTS=false;
171  gPARMS->SetDefaultParameter("TRKFIND:DEBUG_HISTS",DEBUG_HISTS);
172 
173  if(DEBUG_HISTS){
174  dapp->Lock();
175  /*
176  match_center_dist2=(TH2F*)gROOT->FindObject("match_center_dist2");
177  if (!match_center_dist2){
178  match_center_dist2=new TH2F("match_center_dist2","larger radius vs matching distance squared between two circle centers",100,0,100.,100,0,100);
179  match_center_dist2->SetYTitle("r_{c} [cm]");
180  match_center_dist2->SetXTitle("(#Deltad)^{2} [cm^{2}]");
181  }
182  */
183  match_dist=(TH2F*)gROOT->FindObject("match_dist");
184  if (!match_dist){
185  match_dist=new TH2F("match_dist","Matching distance",
186  120,0.,60.,500,0,25.);
187  match_dist->SetXTitle("r (cm)");
188  match_dist->SetYTitle("#Deltar (cm)");
189  }
190  match_dist_vs_p=(TH2F*)gROOT->FindObject("match_dist_vs_p");
191  if (!match_dist_vs_p) {
192  match_dist_vs_p=new TH2F("match_dist_vs_p","Matching distance vs p",
193  50,0.,7.,100,0,25.);
194  match_dist_vs_p->SetYTitle("#Deltar (cm)");
195  match_dist_vs_p->SetXTitle("p (GeV/c)");
196  }
197  dapp->Unlock();
198  }
199 
200  gPARMS->SetDefaultParameter("TRKFIND:MAX_NUM_TRACK_CANDIDATES", MAX_NUM_TRACK_CANDIDATES);
201 
202  // MIN_NUM_HITS=6;
203  //gPARMS->SetDefaultParameter("TRKFIND:MIN_NUM_HITS", MIN_NUM_HITS);
204 
205  DEBUG_LEVEL=0;
206  gPARMS->SetDefaultParameter("TRKFIND:DEBUG_LEVEL", DEBUG_LEVEL);
207 
208  return NOERROR;
209 }
210 
211 //------------------
212 // erun
213 //------------------
215 {
216  if (stepper) {
217  delete stepper;
218  stepper = nullptr;
219  }
220 
221  return NOERROR;
222 }
223 
224 //------------------
225 // erun
226 //------------------
228 {
229  if (stepper) {
230  delete stepper;
231  stepper = nullptr;
232  }
233 
234  return NOERROR;
235 }
236 
237 
238 
239 //------------------
240 // evnt
241 //------------------
242 jerror_t DTrackCandidate_factory::evnt(JEventLoop *loop, uint64_t eventnumber)
243 {
244  if(dIsNoFieldFlag)
245  {
246  //Clear previous objects: //JANA doesn't do it because NOT_OBJECT_OWNER was set
247  //It DID delete them though, in the "StraightLine" factory
248  _data.clear();
249 
250  vector<const DTrackCandidate*> locStraightLineCandidates;
251  loop->Get(locStraightLineCandidates, "StraightLine");
252  for(size_t loc_i = 0; loc_i < locStraightLineCandidates.size(); ++loc_i)
253  _data.push_back(const_cast<DTrackCandidate*>(locStraightLineCandidates[loc_i]));
254  return NOERROR;
255  }
256 
257  // Start counter hits
258  vector<const DSCHit *>schits;
259  loop->Get(schits);
260 
261 
262  // Clear private vectors
263  cdctrackcandidates.clear();
264  fdctrackcandidates.clear();
265  trackcandidates.clear();
266  mycdchits.clear();
267 
268  // Get the track candidates from the CDC and FDC candidate finders
269  loop->Get(cdctrackcandidates, "CDC");
270  loop->Get(fdctrackcandidates, "FDCCathodes");
271 
272  // List of cdc hits
273  loop->Get(mycdchits);
274 
275  // Vectors for keeping track of cdc matches and projections to the endplate
276  vector<unsigned int> cdc_forward_ids;
277  vector<unsigned int> cdc_backward_ids;
278  vector<DVector3> cdc_endplate_projections;
279 
280  // Vector to keep track of cdc hits used in candidates
281  vector<unsigned int>used_cdc_hits(mycdchits.size());
282 
283  // vector to keep track of the matching status of each fdc candidate
284  vector<int>forward_matches(fdctrackcandidates.size());
285 
286  // Normal vector for CDC endplate
287  DVector3 norm(0,0,1);
288 
289  // Keep track of CDC hits that have already been used in track candidates
290  for(unsigned int i=0; i<cdctrackcandidates.size(); i++){
291  const DTrackCandidate *srccan = cdctrackcandidates[i];
292  for (unsigned int n=0;n<srccan->used_cdc_indexes.size();n++){
293  used_cdc_hits[srccan->used_cdc_indexes[n]]=1;
294  }
295  }
296  unsigned int num_unmatched_cdcs=0;
297  for (unsigned int i=0;i<used_cdc_hits.size();i++){
298  if (used_cdc_hits[i]==0) num_unmatched_cdcs++;
299  }
300 
301  //Loop through the list of CDC candidates, flagging those that point toward
302  // the FDC.
303  for(unsigned int i=0; i<cdctrackcandidates.size(); i++){
304  const DTrackCandidate *srccan = cdctrackcandidates[i];
305  DVector3 mom=srccan->momentum();
306  DVector3 pos=srccan->position();
307 
308  // Propagate track to CDC endplate
309  bool isForward=false;
310  if (fdctrackcandidates.size()>0){
311  if (mom.Theta()<M_PI_2){
312  // First do a quick projection using a helical model to see if it is
313  // worth adding this cdc candidate to the list of forward-going tracks
314  // that could pass into the FDC...
315  ProjectHelixToZ(cdc_endplate.z(),srccan->charge(),mom,pos);
316 
317  if (pos.Perp()<60.){
318  // do an actual swim to the cdc endplate
319  mom=srccan->momentum();
320  pos=srccan->position();
321  stepper->SetCharge(srccan->charge());
322  stepper->SwimToPlane(pos,mom,cdc_endplate,norm,NULL);
323  if (pos.Perp()<60.){
324  cdc_endplate_projections.push_back(pos);
325  cdc_forward_ids.push_back(i);
326  isForward=true;
327  }
328  }
329  }
330  }
331  if (isForward==false){
332  cdc_backward_ids.push_back(i);
333  }
334  }
335 
336  // Variables for candidate number accounting
337  int num_forward_cdc_cands_remaining=cdc_forward_ids.size();
338  int num_fdc_cands_remaining=fdctrackcandidates.size();
339  vector<int>cdc_forward_matches(cdc_forward_ids.size());
340  vector<int>cdc_backward_matches(cdc_backward_ids.size());
341 
342  // Loop through the list of FDC candidates looking for matches between the
343  // CDC and the FDC in the transition region.
344  if (num_forward_cdc_cands_remaining>0){
345  for(unsigned int i=0; i<fdctrackcandidates.size(); i++){
346  // Break out if there are no forward-pointing cdc candidates that have
347  // not already been matched to fdc candidates.
348  if (num_forward_cdc_cands_remaining==0) break;
349 
350  // The current FDC candidate
351  const DTrackCandidate *fdccan = fdctrackcandidates[i];
352  vector<const DFDCSegment *>segments;
353  fdccan->GetT(segments);
354  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
355  if (segments[0]->package!=0) continue;
356 
357  // Flag for matching status
358  bool got_match=false;
359 
360  if (DEBUG_LEVEL>0) _DBG_ << "Attempting FDC/CDC matching method #1..." <<endl;
361 
362  // Check that the z-position at the doca to the beam line is within the
363  // active volume of the detector to prevent connecting low momentum
364  // curlers coming off the cdc endplate at a small angle with CDC
365  // candidates
366  if (CheckZPosition(fdccan)==false){
367  // mark to avoid trying to match to CDC with the alternate
368  // matching algorithms below
369  forward_matches[i]=-1;
370  continue;
371  }
372 
373  // First try the matching method that projects the cdc candidate to the
374  // cdc endplate where the fdc candidates are reported.
375  if (MatchMethod1(fdccan,cdc_forward_ids,cdc_endplate_projections,
376  cdc_forward_matches)){
377  if (DEBUG_LEVEL>0) _DBG_ << "... matched to FDC candidate #" << i <<endl;
378 
379  got_match=true;
380  }
381  else{
382  if (DEBUG_LEVEL>0) _DBG_ << "Attempting FDC/CDC matching method #2..." <<endl;
383  // loop over the forward-pointing cdc candidates
384  for (unsigned int j=0;j<cdc_forward_ids.size();j++){
385  if (cdc_forward_matches[j]) continue;
386  const DTrackCandidate *cdccan=cdctrackcandidates[cdc_forward_ids[j]];
387 
388  // Try to gather up stray CDC hits from candidates that were not
389  // matched with the previous algorithm by projecting the helical track
390  // from the fdc into the cdc region
391  if (MatchMethod2(fdccan,cdccan)){
392  if (DEBUG_LEVEL>0) _DBG_ << "... matched to FDC candidate #" << i <<endl;
393  // mark the cdc candidate as matched
394  cdc_forward_matches[j]=1;
395 
396  if (DEBUG_LEVEL>0)
397  _DBG_ << ".. matched to CDC candidate #" <<cdc_forward_ids[j] <<endl;
398  got_match=true;
399  break;
400  }
401  }
402  }
403 
404  if (got_match){
405  // Mark the FDC candidate as matched
406  forward_matches[i]=1;
407  num_fdc_cands_remaining--;
408 
409  // update number of unmatched forward-pointing cdc candidates
410  num_forward_cdc_cands_remaining--;
411  }
412  } // loop over fdc candidates
413  } // check for forward-pointing cdc candidates
414 
415  // If starting with the fdc candidates did not lead to a complete set of
416  // CDC-FDC matches, try looping over the remaining CDC candidates that point
417  // toward the FDC.
418  if (num_forward_cdc_cands_remaining>0){
419  for (unsigned int i=0;i<cdc_forward_ids.size();i++){
420  if (cdc_forward_matches[i]) continue;
421  if (num_forward_cdc_cands_remaining==0) break;
422 
423  if (DEBUG_LEVEL>0) _DBG_ << "Attempting FDC/CDC matching method #3..." <<endl;
424 
425  // This method projects the cdc track into the FDC region
426  const DTrackCandidate *cdccan=cdctrackcandidates[cdc_forward_ids[i]];
427  if (MatchMethod3(cdccan,forward_matches)){
428  num_fdc_cands_remaining--;
429  num_forward_cdc_cands_remaining--;
430 
431  //Mark the cdc track candidate as matched
432  cdc_forward_matches[i]=1;
433 
434  if (DEBUG_LEVEL>0) _DBG_ << "... matched to CDC candidate #" << i <<endl;
435  }
436  } // loop over forward-pointing cdc candidates
437  }
438 
439  // The following uses a trick to improve the circle fit and "fix" the
440  // direction of a cdc candidate for those candidates whose outermost hit
441  // is a stereo straw by assuming that the z position is at the end of this
442  // straw at the cdc endplate, thereby giving us an additional point in the
443  // xy plane that can be used in the circle fit. The code then attempts to
444  // match this "improved" cdc candidate with the remaining fdc candidates.
445  if (num_fdc_cands_remaining>0 && num_forward_cdc_cands_remaining>0){
446  for (unsigned int j=0;j<cdc_forward_ids.size();j++){
447  if (num_fdc_cands_remaining==0) break;
448  if (num_forward_cdc_cands_remaining==0) break;
449  if (cdc_forward_matches[j]==0){
450  const DTrackCandidate *cdccan = cdctrackcandidates[cdc_forward_ids[j]];
451 
452  if (MatchMethod8(cdccan,forward_matches)==true){
453  cdc_forward_matches[j]=1;
454  num_fdc_cands_remaining--;
455  num_forward_cdc_cands_remaining--;
456  }
457 
458  }
459  }
460  }
461 
462  // add to the main list of candidates those we did not successfully merge
463  if (num_forward_cdc_cands_remaining>0){
464  for (unsigned int j=0;j<cdc_forward_ids.size();j++){
465  if (cdc_forward_matches[j]==0){
466  DTrackCandidate *can = new DTrackCandidate;
467 
468  const DTrackCandidate *cdccan = cdctrackcandidates[cdc_forward_ids[j]];
469  vector<const DCDCTrackHit *>cdchits;
470  cdccan->GetT(cdchits);
471 
472  // circle parameters
473  can->rc=cdccan->rc;
474  can->xc=cdccan->xc;
475  can->yc=cdccan->yc;
476 
477  DVector3 mom=cdccan->momentum();
478  DVector3 pos=cdccan->position();
479 
480  can->setMomentum(mom);
481  can->setPosition(pos);
482  can->setPID(cdccan->PID());
483 
484  for (unsigned int n=0;n<cdchits.size();n++){
485  used_cdc_hits[cdccan->used_cdc_indexes[n]]=1;
486  can->AddAssociatedObject(cdchits[n]);
487  }
488  can->chisq=cdccan->chisq;
489  can->Ndof=cdccan->Ndof;
490  trackcandidates.push_back(can);
491  }
492  }
493  }
494 
495  for (unsigned int j=0;j<cdc_backward_ids.size();j++){
496  const DTrackCandidate *cdccan = cdctrackcandidates[cdc_backward_ids[j]];
497 
498  // Sometimes the cdc track candidate parameters for tracks that are actually
499  // going forward are so poor that they don't seem to point towards the cdc
500  // end plate, so the previous matching methods fail. Try one more time
501  // to match these to FDC segments by using Method 8...
502  if (num_fdc_cands_remaining>0
503  && MatchMethod8(cdccan,forward_matches)==true){
504  num_fdc_cands_remaining--;
505  cdc_backward_matches[j]=1;
506  }
507  else{
508  DVector3 mom=cdccan->momentum();
509  DVector3 pos=cdccan->position();
510 
511  // Check for candidates that appear to go backwards but are actually
512  // going forwards and try to match these to remaining fdc candidates
513  if (num_fdc_cands_remaining>0 && mom.Theta()>M_PI_2 && !sc_pos.empty()){
514  if (TryToFlipDirection(schits,mom,pos)){
515  if (DEBUG_LEVEL>0){
516  _DBG_<< "Flipped direction of track (backward to forward) to look for FDC match..." << endl;
517  }
518  DVector3 norm(0.,0.,1.);
519  double p_cdc=mom.Mag();
520  stepper->SetCharge(cdccan->charge());
521  stepper->SwimToPlane(pos,mom,cdc_endplate,norm,NULL);
522 
523  for (unsigned int i=0;i<fdctrackcandidates.size();i++){
524  if (num_fdc_cands_remaining==0) break;
525  if (forward_matches[i]==0){
526  const DTrackCandidate *fdccan=fdctrackcandidates[i];
527  if (MatchMethod2(fdccan,cdccan)){
528  if (DEBUG_LEVEL>0) {
529  _DBG_ << "... matched to FDC candidate #" << i <<endl;
530  }
531  forward_matches[i]=1;
532  cdc_backward_matches[j]=1;
533  num_fdc_cands_remaining--;
534  break;
535  }
536 
537  // Use MatchMethod1 if the previous method did not work
538  DVector3 fdcpos=fdccan->position();
539  DVector3 fdcmom=fdccan->momentum();
540  double p_fdc=fdcmom.Mag();
541  ProjectHelixToZ(cdc_endplate.z(),fdccan->charge(),fdcmom,fdcpos);
542  double diff=(pos-fdcpos).Mag();
543  if (cdc_fdc_match(p_fdc,p_cdc,diff)){
544  // Get the segment data
545  vector<const DFDCSegment *>segments;
546  fdccan->GetT(segments);
547 
548  // The following code snippet is intended to prevent matching a cdc
549  // track candidate to a low momentum particle curling from the cdc endplate
550  double theta=fdcmom.Theta();
551  if (segments.size()>1 && p_fdc<0.3 && theta< 5.*M_PI/180.){
552  continue;
553  }
554 
555  if (MakeCandidateFromMethod1(theta,segments,cdccan)){
556  forward_matches[i]=1;
557  num_fdc_cands_remaining--;
558  cdc_backward_matches[j]=1;
559  if (DEBUG_LEVEL>0)
560  _DBG_ << ".. matched to CDC candidate #" << cdc_backward_ids[j] <<endl;
561  break;
562  }
563  } // match criterion met?
564  } // fdc candidate not already matched?
565  } // loop over fdc candidates
566  }
567  } // do we have fdc candidates remaining?
568  }
569  } //loop over "backward" going cdc tracks
570 
571  // put the remaining "backward" tracks in the main list of candidates
572  for (unsigned int j=0;j<cdc_backward_ids.size();j++){
573  if (cdc_backward_matches[j]==0){
574  const DTrackCandidate *cdccan = cdctrackcandidates[cdc_backward_ids[j]];
575 
576  // Get the cdc hits
577  vector<const DCDCTrackHit *>cdchits;
578  cdccan->GetT(cdchits);
579  stable_sort(cdchits.begin(), cdchits.end(), CDCHitSortByLayerincreasing);
580 
581  DTrackCandidate *can = new DTrackCandidate;
582  can->setMomentum(cdccan->momentum());
583  can->setPosition(cdccan->position());
584  can->setPID(cdccan->PID());
585 
586  // circle parameters
587  can->rc=cdccan->rc;
588  can->xc=cdccan->xc;
589  can->yc=cdccan->yc;
590 
591  for (unsigned int n=0;n<cdchits.size();n++){
592  can->AddAssociatedObject(cdchits[n]);
593  }
594  can->chisq=cdccan->chisq;
595  can->Ndof=cdccan->Ndof;
596 
597  trackcandidates.push_back(can);
598  }
599  }
600 
601  // If there are more than one FDC candidates remaining, use the best track
602  // candidate knowledge we have so far to recheck for matches to other fdc
603  // candidates.
604  if (num_fdc_cands_remaining>1){
605  for (unsigned int j=0;j<fdctrackcandidates.size();j++){
606  if (num_fdc_cands_remaining<1) break;
607  if (forward_matches[j]<=0){
608  // Try to match to fdc candidates that have not already been matched
609  // to another track
610  if (MatchMethod4(fdctrackcandidates[j],forward_matches,num_fdc_cands_remaining)==true){
611  forward_matches[j]=1;
612  num_fdc_cands_remaining--;
613  }
614  }
615  }
616  }
617 
618  // Of the remaining fdc candidates, output those that have more than one
619  // segment associated with them.
620  if (num_fdc_cands_remaining>0){
621  for (unsigned int j=0;j<fdctrackcandidates.size();j++){
622  if (forward_matches[j]<=0){
623  const DTrackCandidate *fdccan = fdctrackcandidates[j];
624 
625  // Get the segment data
626  vector<const DFDCSegment *>segments;
627  fdccan->GetT(segments);
628 
629  if (segments.size()>1){
630  // Create new candidate for output
631  DTrackCandidate *can = new DTrackCandidate;
632  // circle parameters
633  can->rc=fdccan->rc;
634  can->xc=fdccan->xc;
635  can->yc=fdccan->yc;
636 
637  can->setMomentum(fdccan->momentum());
638  can->setPosition(fdccan->position());
639  can->setPID(fdccan->PID());
640  can->chisq=fdccan->chisq;
641  can->Ndof=fdccan->Ndof;
642  for (unsigned int m=0;m<segments.size();m++){
643  for (unsigned int n=0;n<segments[m]->hits.size();n++){
644  const DFDCPseudo *fdchit=segments[m]->hits[n];
645  can->AddAssociatedObject(fdchit);
646  }
647  }
648  trackcandidates.push_back(can);
649 
650  num_fdc_cands_remaining--;
651  forward_matches[j]=1;
652  }
653  }
654  }
655  }
656 
657  // Try to match remaining fdc candidates to track candidates that have
658  // track segments that have already been matched together
659  if (num_fdc_cands_remaining>0){
660  vector<int>candidate_updated(trackcandidates.size());
661  for (unsigned int i=0;i<trackcandidates.size();i++){
662  if (num_fdc_cands_remaining<=0) break;
663 
664  DTrackCandidate *can=trackcandidates[i];
665  if (MatchMethod7(can,forward_matches,num_fdc_cands_remaining)==false){
666  if (can->momentum().Mag()<0.5){
667  if (MatchMethod12(can,forward_matches,num_fdc_cands_remaining)){
668  candidate_updated[i]=1;
669  }
670  }
671  }
672  }
673  if (num_fdc_cands_remaining>0){
674  // if the candidate was updated, try again...
675  for (unsigned int i=0;i<trackcandidates.size();i++){
676  if (num_fdc_cands_remaining==0) break;
677  if (candidate_updated[i]==1){
678  DTrackCandidate *can=trackcandidates[i];
679  if (MatchMethod7(can,forward_matches,num_fdc_cands_remaining)==false){
680  if (can->momentum().Mag()<0.5){
681  MatchMethod12(can,forward_matches,num_fdc_cands_remaining);
682  }
683  }
684  }
685  }
686  }
687  }
688 
689  // We should be left with only single-segment fdc candidates. We try to
690  // connect them together using alternate fitting techniques, either by
691  // forcing the circle to originate from the target or at the other extreme
692  // not including the fake point at the origin.
693  if (num_fdc_cands_remaining){
694  bool matched_stray_segments=MatchStraySegments(forward_matches,
695  num_fdc_cands_remaining);
696  if (num_fdc_cands_remaining && matched_stray_segments){
697  for (unsigned int i=0;i<trackcandidates.size();i++){
698  if (num_fdc_cands_remaining==0) break;
699 
700  DTrackCandidate *can=trackcandidates[i];
701  if (MatchMethod7(can,forward_matches,num_fdc_cands_remaining)==false){
702  if (can->momentum().Mag()<0.5){
703  MatchMethod12(can,forward_matches,num_fdc_cands_remaining);
704  }
705  }
706  }
707  }
708  if (num_fdc_cands_remaining){
709  // Not much we can do here -- add to the final list of candidates
710  for (unsigned int j=0;j<forward_matches.size();j++){
711  if (num_fdc_cands_remaining==0) break;
712  if (forward_matches[j]<=0){
713  const DTrackCandidate *srccan=fdctrackcandidates[j];
714  // Get the segment data
715  vector<const DFDCSegment *>segments;
716  srccan->GetT(segments);
717  const DFDCSegment *segment=segments[0];
718 
719  DTrackCandidate *can = new DTrackCandidate;
720  // circle parameters
721  can->rc=srccan->rc;
722  can->xc=srccan->xc;
723  can->yc=srccan->yc;
724 
725  can->Ndof=srccan->Ndof;
726  can->chisq=srccan->chisq;
727  can->setPID(srccan->PID());
728  can->setMomentum(srccan->momentum());
729  can->setPosition(srccan->position());
730  for (unsigned int n=0;n<segment->hits.size();n++){
731  const DFDCPseudo *fdchit=segment->hits[n];
732  can->AddAssociatedObject(fdchit);
733  }
734 
735  trackcandidates.push_back(can);
736  }
737  }
738  }
739  }
740 
741  //There are frequently several hits in the CDC that are not associated with
742  // any track segment. In this case, try to attach these stray hits to a
743  // track in the FDC that has hits in the first package.
744  if (num_unmatched_cdcs>0){
745  if (DEBUG_LEVEL>0){
746  _DBG_ << "Trying to use stray CDC hits in match to FDC..." << endl;
747  }
748 
749  for (unsigned int i=0;i<trackcandidates.size();i++){
750  if (num_unmatched_cdcs>0){
751  DTrackCandidate *candidate=trackcandidates[i];
752  // Get the hits from the candidate
753  vector<const DCDCTrackHit *>usedcdchits;
754  candidate->GetT(usedcdchits);
755  if (usedcdchits.size()==0){
756  vector<const DFDCPseudo*>usedfdchits;
757  candidate->GetT(usedfdchits);
758  // Sort the hits
759  stable_sort(usedfdchits.begin(),usedfdchits.end(),FDCHitSortByLayerincreasing);
760  if ((usedfdchits[0]->wire->layer-1)/6==0){
761  MatchMethod6(candidate,usedfdchits,used_cdc_hits,num_unmatched_cdcs);
762  }
763  }
764  }
765  }
766  }
767 
768  // Only output the candidates that have at least a minimum number of hits
769  for (unsigned int i=0;i<trackcandidates.size();i++){
770  DTrackCandidate *candidate=trackcandidates[i];
771  // Get the hits from the candidate
772  vector<const DFDCPseudo*>myfdchits;
773  candidate->GetT(myfdchits);
774  vector<const DCDCTrackHit *>mycdchits;
775  candidate->GetT(mycdchits);
776 
777  if (mycdchits.size()>=3 || myfdchits.size()>=3){
778  _data.push_back(candidate);
779  }
780  else delete candidate;
781  }
782 
783  if((int(_data.size()) > MAX_NUM_TRACK_CANDIDATES) && (MAX_NUM_TRACK_CANDIDATES >= 0))
784  {
785  if (DEBUG_LEVEL>0) _DBG_ << "Number of candidates = " << _data.size()
786  << " > " << MAX_NUM_TRACK_CANDIDATES
787  << " --- skipping track fitting! " << endl;
788  for(size_t loc_i = 0; loc_i < _data.size(); ++loc_i)
789  delete _data[loc_i];
790  _data.clear();
791  }
792 
793 
794  // Set CDC ring & FDC plane hit patterns
795  for(size_t loc_i = 0; loc_i < _data.size(); ++loc_i)
796  {
797  vector<const DCDCTrackHit*> locCDCTrackHits;
798  _data[loc_i]->Get(locCDCTrackHits);
799 
800  vector<const DFDCPseudo*> locFDCPseudos;
801  _data[loc_i]->Get(locFDCPseudos);
802 
803  _data[loc_i]->dCDCRings = dParticleID->Get_CDCRingBitPattern(locCDCTrackHits);
804  _data[loc_i]->dFDCPlanes = dParticleID->Get_FDCPlaneBitPattern(locFDCPseudos);
805  }
806 
807  return NOERROR;
808 }
809 
810 
811 // Obtain position and momentum at the exit of a given package using the
812 // helical track model.
814  DVector3 &pos,
815  DVector3 &mom) const{
816  // Position of track segment at last hit plane of package
817  double x=segment->xc+segment->rc*cos(segment->Phi1);
818  double y=segment->yc+segment->rc*sin(segment->Phi1);
819  double z=segment->hits[0]->wire->origin.z();
820 
821  // Track parameters
822  //double kappa=segment->q/(2.*segment->rc);
823  double phi0=segment->phi0;
824  double tanl=segment->tanl;
825  double z0=segment->z_vertex;
826 
827  // Useful intermediate variables
828  double cosp=cos(phi0);
829  double sinp=sin(phi0);
830  double sperp=(z-z0)/tanl;
831  //double twoks=2.*kappa*sperp;
832  double twoks=FactorForSenseOfRotation*segment->q*sperp/segment->rc;
833  double sin2ks=sin(twoks);
834  double cos2ks=cos(twoks);
835 
836  // Get Bfield
837  double B=fabs(bfield->GetBz(x,y,z));
838 
839  // Momentum
840  double pt=0.003*B*segment->rc;
841  double px=pt*(cosp*cos2ks-sinp*sin2ks);
842  double py=pt*(sinp*cos2ks+cosp*sin2ks);
843  double pz=pt*tanl;
844 
845  pos.SetXYZ(x,y,z);
846  mom.SetXYZ(px,py,pz);
847 }
848 
849 // Get position and momentum at doca to beam line
851  double Bz,
852  DVector3 &pos,
853  DVector3 &mom) const{
854  // Find position at doca to beam line
855  double phi0=atan2(-fit.x0,fit.y0);
856  if (fit.h<0) phi0+=M_PI;
857  double sinphi0=sin(phi0);
858  double sign=(sinphi0>0)?1.:-1.;
859  if (fabs(sinphi0)<1e-8) sinphi0=sign*1e-8;
860  double cosphi0=cos(phi0);
861  double D=FactorForSenseOfRotation*fit.h*fit.r0-fit.x0/sinphi0;
862  double x=-D*sinphi0;
863  double y=D*cosphi0;
864  double dx=pos.x()-x;
865  double dy=pos.y()-y;
866  double ratio=sqrt(dx*dx+dy*dy)/(2.*fit.r0);
867  double phi_s=(ratio<1.)?2.*asin(ratio):M_PI;
868  double newz=pos.z()-phi_s*fit.tanl*fit.r0;
869  pos.SetXYZ(x,y,newz);
870 
871  // momentum at POCA to beam line
872  double pt=0.003*Bz*fit.r0;
873  mom.SetXYZ(pt*cosphi0,pt*sinphi0,pt*fit.tanl);
874 }
875 
876 // Get the position and momentum at a fixed radius from the beam line
878  double Bz,
879  const DVector3 &origin,
880  DVector3 &pos,
881  DVector3 &mom) const{
882  double r2=90.0;
883  double xc=fit.x0;
884  double yc=fit.y0;
885  double rc=fit.r0;
886  double tworc=2.*rc;
887  double rc2=rc*rc;
888  double xc2=xc*xc;
889  double yc2=yc*yc;
890  double xc2_plus_yc2=xc2+yc2;
891  double a=(r2-xc2_plus_yc2-rc2)/tworc;
892  double b=xc2_plus_yc2-a*a;
893  if (b<0){
894  // We did not find an intersection between the two circles, so return
895  // an error. The values of mom and pos are not changed.
896  return VALUE_OUT_OF_RANGE;
897  }
898 
899  double temp1=yc*sqrt(b);
900  double temp2=xc*a;
901  double cosphi_plus=(temp2+temp1)/xc2_plus_yc2;
902  double cosphi_minus=(temp2-temp1)/xc2_plus_yc2;
903 
904  // Direction tangent and transverse momentum
905  double tanl=fit.tanl;
906  double pt=0.003*Bz*rc;
907 
908  double phi_plus=acos(cosphi_plus);
909  double phi_minus=acos(cosphi_minus);
910  double x_plus=xc+rc*cosphi_plus;
911  double x_minus=xc+rc*cosphi_minus;
912  double y_plus=yc+rc*sin(phi_plus);
913  double y_minus=yc+rc*sin(phi_minus);
914 
915  // if the resulting radial position on the circle from the fit does not agree
916  // with the radius to which we are matching, we have the wrong sign for phi+
917  // or phi-
918  double r2_plus=x_plus*x_plus+y_plus*y_plus;
919  double r2_minus=x_minus*x_minus+y_minus*y_minus;
920  if (fabs(r2-r2_plus)>EPS){
921  phi_plus*=-1.;
922  y_plus=yc+rc*sin(phi_plus);
923  }
924  if (fabs(r2-r2_minus)>EPS){
925  phi_minus*=-1.;
926  y_minus=yc+rc*sin(phi_minus);
927  }
928 
929  // Choose phi- or phi+ depending on proximity to one of the cdc hits
930  double xwire=origin.x();
931  double ywire=origin.y();
932  double dx=x_minus-xwire;
933  double dy=y_minus-ywire;
934  double d2_minus=dx*dx+dy*dy;
935  dx=x_plus-xwire;
936  dy=y_plus-ywire;
937  double d2_plus=dx*dx+dy*dy;
938 
939  DVector3 pos0(pos); // save the input position, for use in finding z
940  if (d2_plus>d2_minus){
941  fit.h=-1.;
942  phi_minus=M_PI-phi_minus;
943  pos.SetXYZ(x_minus,y_minus,0.); // z will be filled later
944  mom.SetXYZ(pt*sin(phi_minus),pt*cos(phi_minus),pt*tanl);
945  }
946  else{
947  fit.h=1.;
948  phi_plus*=-1.;
949  pos.SetXYZ(x_plus,y_plus,0.); // z will be filled later
950  mom.SetXYZ(pt*sin(phi_plus),pt*cos(phi_plus),pt*tanl);
951  }
952  // Next find the z-position corresponding to the new (x,y) position
953  double ratio=(pos0-pos).Perp()/tworc;
954  double sperp=(ratio<1.)?tworc*asin(ratio):tworc*M_PI_2;
955  pos.SetZ(pos0.z()-sperp*tanl);
956 
957  return NOERROR;
958 }
959 
960 // Find the position along a helical path at the z-position z
961 void DTrackCandidate_factory::ProjectHelixToZ(const double z,const double q,
962  const DVector3 &mom,
963  DVector3 &pos){
964  double pt=mom.Perp();
965  double phi=mom.Phi();
966  double sinphi=sin(phi);
967  double cosphi=cos(phi);
968  double tanl=tan(M_PI_2-mom.Theta());
969  double x0=pos.X();
970  double y0=pos.Y();
971  double z0=pos.Z();
972  double B=fabs(bfield->GetBz(x0,y0,z0));
973  double twokappa=FactorForSenseOfRotation*0.003*B*q/pt;
974  double one_over_twokappa=1./twokappa;
975  double sperp=(z-z0)/tanl;
976  double twoks=twokappa*sperp;
977  double sin2ks=sin(twoks);
978  double one_minus_cos2ks=1.-cos(twoks);
979  double x=x0+(cosphi*sin2ks-sinphi*one_minus_cos2ks)*one_over_twokappa;
980  double y=y0+(sinphi*sin2ks+cosphi*one_minus_cos2ks)*one_over_twokappa;
981 
982  pos.SetXYZ(x,y,z);
983 }
984 
985 
986 // Routine to do a crude match between cdc wires and a helical approximation to
987 // the trajectory
989  double q,
990  const DVector3 &pos,
991  const DVector3 &mom){
992  double pt=mom.Perp();
993  double phi=mom.Phi();
994  double sinphi=sin(phi);
995  double cosphi=cos(phi);
996  double tanl=tan(M_PI_2-mom.Theta());
997  double x0=pos.X();
998  double y0=pos.Y();
999  double z0=pos.Z();
1000  // _DBG_ <<endl;
1001  double B=fabs(bfield->GetBz(x0,y0,z0));
1002  double twokappa=FactorForSenseOfRotation*0.003*B*q/pt;
1003  double one_over_twokappa=1./twokappa;
1004 
1005  double sperp=0;
1006  DVector3 origin=hit->wire->origin;
1007  double z0w=origin.z();
1008  DVector3 dir=(1./hit->wire->udir.z())*hit->wire->udir;
1009 
1010  DVector3 wirepos;
1011  double old_doca2=1e8;
1012  double doca2=old_doca2;
1013  double z=z0;
1014  double x=x0,y=y0;
1015  while (z>50. && z<180. && x<60. && y<60.){
1016  old_doca2=doca2;
1017  sperp-=1.;
1018  double twoks=twokappa*sperp;
1019  double sin2ks=sin(twoks);
1020  double one_minus_cos2ks=1.-cos(twoks);
1021  x=x0+(cosphi*sin2ks-sinphi*one_minus_cos2ks)*one_over_twokappa;
1022  y=y0+(sinphi*sin2ks+cosphi*one_minus_cos2ks)*one_over_twokappa;
1023  z=z0+sperp*tanl;
1024 
1025  wirepos=origin+(z-z0w)*dir;
1026  double dxw=x-wirepos.x();
1027  double dyw=y-wirepos.y();
1028 
1029  doca2=dxw*dxw+dyw*dyw;
1030  if (doca2>old_doca2){
1031  break;
1032  }
1033  }
1034 
1035  return old_doca2;
1036 }
1037 
1038 
1039 // Find the particle charge given the helical fit result and an fdc hit
1040 // on the track
1042  const DFDCPseudo *fdchit,
1043  const DVector3 &pos
1044  ){
1045  // Get circle parameters
1046  double rc=fit.r0;
1047  double xc=fit.x0;
1048  double yc=fit.y0;
1049  // Compute phi rotation from "vertex" to fdc hit
1050  double dphi=(fdchit->wire->origin.Z()-pos.z())/(rc*fit.tanl);
1051  double Phi1=atan2(pos.Y()-yc,pos.X()-xc);
1052 
1053  // Positive and negative changes in phi
1054  double phiplus=Phi1+dphi;
1055  double phiminus=Phi1-dphi;
1056  DVector2 plus(xc+rc*cos(phiplus),yc+rc*sin(phiplus));
1057  DVector2 minus(xc+rc*cos(phiminus),yc+rc*sin(phiminus));
1058 
1059  // Compute differences
1060  double d2plus=(plus-fdchit->xy).Mod2();
1061  double d2minus=(minus-fdchit->xy).Mod2();
1062 
1063  if (d2minus<d2plus)
1064  return (-1.0);
1065  else
1066  return (+1.0);
1067 }
1068 
1069 
1070 
1071 // Redo the circle fit using all of the cdc axial wires and fdc hits associated
1072 // with the track candidate. Also compute the average Bz.
1074  vector<const DFDCSegment *>segments,
1075  vector<const DCDCTrackHit *>cdchits,
1076  double &Bz){
1077  unsigned int num_hits=0;
1078  // Initialize Bz
1079  Bz=0.;
1080 
1081  // Add the cdc axial wires to the list of hits to use in the fit
1082  for (unsigned int k=0;k<cdchits.size();k++){
1083  if (cdchits[k]->is_stereo==false){
1084  double cov=0.213; //guess
1085  const DVector3 origin=cdchits[k]->wire->origin;
1086  double x=origin.x(),y=origin.y(),z=origin.z();
1087  fit.AddHitXYZ(x,y,z,cov,cov,0.,true);
1088  Bz+=bfield->GetBz(x,y,z);
1089  num_hits++;
1090  }
1091  }
1092  // Add the FDC hits and estimate Bz
1093  for (unsigned int k=0;k<segments.size();k++){
1094  for (unsigned int n=0;n<segments[k]->hits.size();n++){
1095  const DFDCPseudo *fdchit=segments[k]->hits[n];
1096  fit.AddHit(fdchit);
1097  //bfield->GetField(x,y,z,Bx,By,Bz);
1098  //Bz_avg-=Bz;
1099  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),fdchit->wire->origin.z());
1100  }
1101  num_hits+=segments[k]->hits.size();
1102  }
1103  Bz=fabs(Bz)/double(num_hits);
1104 
1105  // Fit the points to a circle
1106  if (fit.FitCircleRiemann(segments[0]->rc)==NOERROR){
1107  double p=0.003*Bz*fit.r0/cos(atan(fit.tanl));
1108 
1109  if (p>3.){ // momentum is suspiciously high for a track going through both
1110  // the FDC and the CDC... try alternate circle fit...
1111  fit.FitCircle();
1112  }
1113  return NOERROR;
1114  }
1115 
1116  return RESOURCE_UNAVAILABLE;
1117 }
1118 
1119 // Method to match FDC and CDC candidates that projects the CDC candidate to the
1120 // cdc endplate, where the FDC candidates are reported.
1122  vector<unsigned int> &cdc_forward_ids,
1123  vector<DVector3>&cdc_endplate_projections,
1124  vector<int>&cdc_forward_matches
1125  ){
1126  // Momentum and position vectors for the FDC candidate
1127  DVector3 mom=fdccan->momentum();
1128  DVector3 pos=fdccan->position();
1129  double p_fdc=mom.Mag();
1130  ProjectHelixToZ(cdc_endplate.z(),fdccan->charge(),mom,pos);
1131 
1132  // loop over the cdc candidates looking for the smallest distance
1133  // between the cdc and fdc projections to the end plate
1134  double diff_min=1000.; // candidate matching difference
1135  unsigned int jmin=0;
1136  for (unsigned int j=0;j<cdc_forward_ids.size();j++){
1137  if (cdc_forward_matches[j]) continue;
1138  double diff=(cdc_endplate_projections[j]-pos).Mag();
1139  if (diff<diff_min){
1140  diff_min=diff;
1141  jmin=j;
1142  }
1143  }
1144 
1145  if (DEBUG_HISTS){
1146  match_dist->Fill(pos.Perp(),diff_min);
1147  match_dist_vs_p->Fill(p_fdc,diff_min);
1148  }
1149 
1150  // Magnitude of the momentum of the potential cdc match
1151  double p_cdc=cdctrackcandidates[cdc_forward_ids[jmin]]->momentum().Mag();
1152  if (cdc_fdc_match(p_fdc,p_cdc,diff_min)){
1153  // Get the segment data
1154  vector<const DFDCSegment *>segments;
1155  fdccan->GetT(segments);
1156 
1157  // The following code snippet is intended to prevent matching a cdc
1158  // track candidate to a low momentum particle curling from the cdc endplate
1159  if (segments.size()>1){
1160  double theta=180./M_PI*mom.Theta();
1161  if (p_fdc<0.3 && theta<5.) return false;
1162  }
1163 
1164  unsigned int cdc_index=cdc_forward_ids[jmin];
1165  if (MakeCandidateFromMethod1(mom.Theta(),segments,
1166  cdctrackcandidates[cdc_index])){
1167 
1168  if (DEBUG_LEVEL>0)
1169  _DBG_ << ".. matched to CDC candidate #" << cdc_index <<endl;
1170 
1171  // mark the cdc candidate as matched
1172  cdc_forward_matches[jmin]=1;
1173 
1174  return true;
1175  }
1176  } // got a cdc-fdc match
1177 
1178  // no match
1179  return false;
1180 }
1181 
1182 // Create new candidate after using Match Method 1 to match cdc and fdc
1183 // candidates
1184 bool DTrackCandidate_factory::MakeCandidateFromMethod1(double theta,vector<const DFDCSegment *>&segments,const DTrackCandidate *cdccan){
1185  // JANA does not maintain the order that the segments were added
1186  // as associated objects. Therefore, we need to reorder them here
1187  // so segment[0] is the most upstream segment.
1188  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
1189 
1190  // Get the associated cdc hits
1191  vector<const DCDCTrackHit *>cdchits;
1192  cdccan->GetT(cdchits);
1193 
1194  // Sort CDC hits by layer
1195  stable_sort(cdchits.begin(), cdchits.end(), CDCHitSortByLayerincreasing);
1196 
1197  // Abort if the track would have to pass from one quadrant into another
1198  // quadrant (this is more likely two roughly back-to-back tracks rather than
1199  // a single track).
1200  const DVector2 fdc_hit_pos=segments[0]->hits[0]->xy;
1201  const DVector3 cdc_wire_origin=cdchits[0]->wire->origin;
1202  if (cdc_wire_origin.x()*fdc_hit_pos.X()<0.
1203  || cdc_wire_origin.y()*fdc_hit_pos.Y()<0.){
1204  if (DEBUG_LEVEL>0) _DBG_ << "Skipping match of potential back-to-back tracks." <<endl;
1205  return false;
1206  }
1207 
1208  // average Bz
1209  double Bz_avg=0.;
1210 
1211  // Redo circle fit with additional hits
1212  DHelicalFit fit;
1213  if (DoRefit(fit,segments,cdchits,Bz_avg)==NOERROR){
1214  // Determine the polar angle
1215  double theta_cdc=cdccan->momentum().Theta();
1216  if (segments.size()==1 && theta_cdc<M_PI_4){
1217  double numcdc=double(cdchits.size());
1218  double numfdc=segments[0]->hits.size();
1219  theta=(theta*numfdc+theta_cdc*numcdc)/(numfdc+numcdc);
1220  }
1221  fit.tanl=tan(M_PI_2-theta);
1222 
1223  // FDC hit
1224  const DFDCPseudo *fdchit=segments[0]->hits[0];
1225  double zhit=fdchit->wire->origin.z();
1226  DVector3 pos(fdchit->xy.X(),fdchit->xy.Y(),zhit);
1227  DVector3 mom;
1228  UpdatePositionAndMomentum(fit,Bz_avg,cdchits[0]->wire->origin,pos,mom);
1229 
1230  // Create new track candidate object
1231  DTrackCandidate *can = new DTrackCandidate;
1232  can->used_cdc_indexes=cdccan->used_cdc_indexes;
1233  // circle parameters
1234  can->rc=fit.r0;
1235  can->xc=fit.x0;
1236  can->yc=fit.y0;
1237 
1238  // Add cdc and fdc hits to the track as associated objects
1239  for (unsigned int m=0;m<segments.size();m++){
1240  for (unsigned int n=0;n<segments[m]->hits.size();n++){
1241  can->AddAssociatedObject(segments[m]->hits[n]);
1242  }
1243  }
1244  for (unsigned int n=0;n<cdchits.size();n++){
1245  can->AddAssociatedObject(cdchits[n]);
1246  }
1247 
1248  can->chisq=fit.chisq;
1249  can->Ndof=fit.ndof;
1250  Particle_t locPID = (FactorForSenseOfRotation*fit.h > 0.0) ? PiPlus : PiMinus;
1251  can->setPID(locPID);
1252  can->setMomentum(mom);
1253  can->setPosition(pos);
1254 
1255  trackcandidates.push_back(can);
1256 
1257  return true;
1258  }
1259  return false;
1260 }
1261 
1262 // Method to match CDC and FDC candidates that projects an FDC candidate into
1263 // the CDC region using a helical approximation to the trajectory. The code
1264 // computes a doca to each wire in the cdc candidate and counts matches based
1265 // on the probability that the cdc wire is on the track.
1267  const DTrackCandidate *cdccan
1268  ){
1269  // Get the cdc hits associated with this cdc candidate
1270  vector<const DCDCTrackHit *>cdchits;
1271  cdccan->GetT(cdchits);
1272  stable_sort(cdchits.begin(),cdchits.end(),CDCHitSortByLayerincreasing);
1273 
1274  // Variables to count the number of matching hits and the match fraction
1275  unsigned int num_match=0;
1276  unsigned int num_cdc=0;
1277 
1278  // Get the track parameters from the fdc candidate
1279  DVector3 pos=fdccan->position();
1280  DVector3 mom=fdccan->momentum();
1281  double q=fdccan->charge();
1282 
1283  // Check to see if the outer hit in the CDC does not exceed the radius of
1284  // the FDC position to try to avoid false matches...
1285  unsigned int outer_index=cdchits.size()-1;
1286  DVector3 origin=cdchits[outer_index]->wire->origin;
1287  DVector3 dir=(1./cdchits[outer_index]->wire->udir.z())*cdchits[outer_index]->wire->udir;
1288  DVector3 cdc_outer_wire_pos=origin+(167.-origin.z())*dir;
1289  if (cdc_outer_wire_pos.Perp()>pos.Perp()) {
1290  return false;
1291  }
1292  // Make sure that the rough position of the CDC track at the end plate
1293  // is not too far off from the position of the fdc track near the end plate
1294  if ((cdc_outer_wire_pos-pos).Mag()>5.){
1295  return false;
1296  }
1297 
1298  // loop over the cdc hits and count hits that agree with a projection of
1299  // the helix into the cdc
1300  for (unsigned int m=0;m<cdchits.size();m++){
1301  double variance=1.6;
1302  // Use a helical approximation to the track to match both axial and
1303  // stereo wires
1304  double dr2=DocaToHelix(cdchits[m],q,pos,mom);
1305  double prob=isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
1306 
1307  if (prob>0.01) num_match++;
1308  if (DEBUG_LEVEL>1) _DBG_ << "CDC s: " << cdchits[m]->wire->straw
1309  << " r: " << cdchits[m]->wire->ring
1310  << " prob: " << prob << endl;
1311 
1312  num_cdc++;
1313  }
1314 
1315  if (num_match>=3 && double(num_match)/double(num_cdc)>0.33){
1316  // Get the segment data
1317  vector<const DFDCSegment *>segments;
1318  fdccan->GetT(segments);
1319 
1320  // JANA does not maintain the order that the segments were added
1321  // as associated objects. Therefore, we need to reorder them here
1322  // so segment[0] is the most upstream segment.
1323  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
1324 
1325  // Abort if the track would have to pass from one quadrant into the opposite
1326  // quadrant (this is more likely two roughly back-to-back tracks rather than
1327  // a single track).
1328  const DVector2 fdc_hit_pos=segments[0]->hits[0]->xy;
1329  const DVector3 cdc_wire_origin=cdchits[0]->wire->origin;
1330  if (cdc_wire_origin.x()*fdc_hit_pos.X()<0.
1331  && cdc_wire_origin.y()*fdc_hit_pos.Y()<0.){
1332  if (DEBUG_LEVEL>0) _DBG_ << "Skipping match of potential back-to-back tracks." <<endl;
1333  return false;
1334  }
1335 
1336  // Put the fdc candidate in the combined list
1337  DTrackCandidate *can = new DTrackCandidate;
1338  can->setPID((q > 0.0) ? PiPlus : PiMinus);
1339 
1340  // copy the list of cdc indices over from the cdc candidate
1341  can->used_cdc_indexes=cdccan->used_cdc_indexes;
1342 
1343  // Add the fdc hits to track candidate as associated objects
1344  unsigned int num_fdc_hits=0;
1345  for (unsigned int m=0;m<segments.size();m++){
1346  for (unsigned int n=0;n<segments[m]->hits.size();n++){
1347  can->AddAssociatedObject(segments[m]->hits[n]);
1348  num_fdc_hits++;
1349  }
1350  }
1351  // Add the CDC hits to the track candidate
1352  for (unsigned int m=0;m<cdchits.size();m++){
1353  can->AddAssociatedObject(cdchits[m]);
1354  }
1355 
1356  // Average Bz
1357  double Bz_avg=0.;
1358 
1359  // Redo circle fit with additional hits
1360  DHelicalFit fit;
1361  //...first add the tangent to the dip angle to the fit class...
1362  double theta=fdccan->momentum().Theta();
1363  double theta_cdc=cdccan->momentum().Theta();
1364  if (segments.size()==1&& theta_cdc<M_PI_4){
1365  double numcdc=double(cdchits.size());
1366  double numfdc=segments[0]->hits.size();
1367  theta=(theta*numfdc+theta_cdc*numcdc)/(numfdc+numcdc);
1368  }
1369  fit.tanl=tan(M_PI_2-theta);
1370  if (DoRefit(fit,segments,cdchits,Bz_avg)==NOERROR){
1371  fit.FindSenseOfRotation();
1372  Particle_t locPID = ((FactorForSenseOfRotation*fit.h > 0.0) ? PiPlus : PiMinus);
1373  can->setPID(locPID);
1374 
1375  // FDC hit
1376  const DFDCPseudo *fdchit=segments[0]->hits[0];
1377  double zhit=fdchit->wire->origin.z();
1378  pos.SetXYZ(fdchit->xy.X(),fdchit->xy.Y(),zhit);
1379  UpdatePositionAndMomentum(fit,Bz_avg,cdchits[0]->wire->origin,pos,mom);
1380 
1381  // circle parameters
1382  can->rc=fit.r0;
1383  can->xc=fit.x0;
1384  can->yc=fit.y0;
1385 
1386  can->chisq=fit.chisq;
1387  can->Ndof=fit.ndof;
1388  can->setMomentum(mom);
1389  can->setPosition(pos);
1390  }
1391  else{
1392  //_DBG_ << endl;
1393  // circle parameters
1394  can->rc=fdccan->rc;
1395  can->xc=fdccan->xc;
1396  can->yc=fdccan->yc;
1397  can->Ndof=fdccan->Ndof;
1398  can->chisq=fdccan->chisq;
1399  can->setMomentum(fdccan->momentum());
1400  can->setPosition(fdccan->position());
1401  }
1402 
1403  trackcandidates.push_back(can);
1404 
1405  return true;
1406  }
1407 
1408  return false;
1409  }
1410 
1411  // Method to match CDC and FDC candidates that projects the CDC track into the
1412  // FDC region.
1414  vector<int> &forward_matches
1415  ){
1416  // Get hits already linked to this candidate from associated objects
1417  vector<const DCDCTrackHit *>cdchits;
1418  cdccan->GetT(cdchits);
1419  stable_sort(cdchits.begin(), cdchits.end(), CDCHitSortByLayerincreasing);
1420 
1421  // loop over fdc candidates
1422  for (unsigned int k=0;k<fdctrackcandidates.size();k++){
1423  if (forward_matches[k]==0){
1424  const DTrackCandidate *fdccan = fdctrackcandidates[k];
1425  // fdc and cdc candidate momenta
1426  double p_fdc=fdccan->momentum().Mag();
1427  double p_cdc=cdccan->momentum().Mag();
1428  if (p_fdc/p_cdc>0.5){
1429  // Get the segment data
1430  vector<const DFDCSegment *>segments;
1431  fdccan->GetT(segments);
1432  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
1433 
1434  // Only try to match candidate if this fdc candidate has hits in the
1435  // first package
1436  if (segments[0]->package>0) continue;
1437 
1438 
1439  // Abort if the track would have to pass from one quadrant into the opposite
1440  // quadrant (this is more likely two roughly back-to-back tracks rather than
1441  // a single track).
1442  const DVector2 fdc_hit_pos=segments[0]->hits[0]->xy;
1443  const DVector3 cdc_wire_origin=cdchits[0]->wire->origin;
1444  if (cdc_wire_origin.x()*fdc_hit_pos.X()<0.
1445  && cdc_wire_origin.y()*fdc_hit_pos.Y()<0.){
1446  if (DEBUG_LEVEL>0) _DBG_ << "Skipping match of potential back-to-back tracks." <<endl;
1447  continue;
1448  }
1449 
1450  // Momentum and position vectors for the CDC candidate
1451  DVector3 mom=cdccan->momentum();
1452  DVector3 pos=cdccan->position();
1453  double q=cdccan->charge();
1454 
1455  // Try to match unmatched fdc candidates
1456  int num_match=0;
1457  int num_hits=0;
1458  for (unsigned int m=0;m<segments.size();m++){
1459  for (unsigned int n=0;n<segments[m]->hits.size();n++){
1460  unsigned int ind=segments[m]->hits.size()-1-n;
1461  const DFDCPseudo *hit=segments[m]->hits[ind];
1462 
1463  if (pos.Perp()<48.5){
1464  ProjectHelixToZ(hit->wire->origin.z(),q,mom,pos);
1465 
1466  // difference
1467  DVector2 XY=hit->xy;
1468  double dx=XY.X()-pos.x();
1469  double dy=XY.Y()-pos.y();
1470  double dr2=dx*dx+dy*dy;
1471 
1472  double variance=1.0;
1473  double prob = isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
1474  if (prob>0.01) num_match++;
1475 
1476  num_hits++;
1477  }
1478  }
1479  if (num_match>=3
1480  || (num_match>0 && double(num_match)/double(num_hits)>0.33)){
1481  DTrackCandidate *can = new DTrackCandidate;
1482 
1483  can->setPID(cdccan->PID());
1484  can->used_cdc_indexes=cdccan->used_cdc_indexes;
1485 
1486  // mark the fdc track candidate as matched
1487  forward_matches[k]=1;
1488 
1489  // Add cdc hits to the candidate
1490  for (unsigned int m=0;m<cdchits.size();m++){
1491  can->AddAssociatedObject(cdchits[m]);
1492  }
1493 
1494  // Add fdc hits to the candidate
1495  for (unsigned int m=0;m<segments.size();m++){
1496  for (unsigned int n=0;n<segments[m]->hits.size();n++){
1497  can->AddAssociatedObject(segments[m]->hits[n]);
1498  }
1499  }
1500 
1501  // average Bz
1502  double Bz_avg=0.;
1503 
1504  // Redo helical fit with all available hits
1505  DHelicalFit fit;
1506  if (DoRefit(fit,segments,cdchits,Bz_avg)==NOERROR){
1507  // Determine the polar angle
1508  double theta=fdccan->momentum().Theta();
1509  double theta_cdc=cdccan->momentum().Theta();
1510  if (segments.size()==1 && theta_cdc<M_PI_4){
1511  double numcdc=double(cdchits.size());
1512  double numfdc=segments[0]->hits.size();
1513  theta=(theta*numfdc+theta_cdc*numcdc)/(numfdc+numcdc);
1514  }
1515  fit.tanl=tan(M_PI_2-theta);
1516 
1517  // Redo the line fit
1518  fit.FitLineRiemann();
1519 
1520  // Set the charge
1521  fit.FindSenseOfRotation();
1522  Particle_t locPID = ((FactorForSenseOfRotation*fit.h > 0.0) ? PiPlus : PiMinus);
1523  can->setPID(locPID);
1524  // FDC hit
1525  const DFDCPseudo *fdchit=segments[0]->hits[0];
1526  double zhit=fdchit->wire->origin.z();
1527  pos.SetXYZ(fdchit->xy.X(),fdchit->xy.Y(),zhit);
1528  UpdatePositionAndMomentum(fit,Bz_avg,cdchits[0]->wire->origin,
1529  pos,mom);
1530 
1531  // circle parameters
1532  can->rc=fit.r0;
1533  can->xc=fit.x0;
1534  can->yc=fit.y0;
1535 
1536  can->chisq=fit.chisq;
1537  can->Ndof=fit.ndof;
1538  can->setMomentum(mom);
1539  can->setPosition(pos);
1540  }
1541  else{
1542  //_DBG_ << endl;
1543  // circle parameters
1544  can->rc=cdccan->rc;
1545  can->xc=cdccan->xc;
1546  can->yc=cdccan->yc;
1547  can->Ndof=cdccan->Ndof;
1548  can->chisq=cdccan->chisq;
1549  can->setMomentum(cdccan->momentum());
1550  can->setPosition(cdccan->position());
1551  }
1552 
1553  trackcandidates.push_back(can);
1554 
1555  if (DEBUG_LEVEL>0) _DBG_ << ".. matched to FDC candidate #" << k <<endl;
1556 
1557  return true;
1558  } // got a match
1559  } // loop over segments
1560  } // check that we have not already matched to this fdc candidate
1561  } // momentum check
1562  } // loop over fdc candidates
1563 
1564  return false;
1565  }
1566 
1567 // This method tries to match unmatched fdc candidates
1569  vector<int> &forward_matches,
1570  int &num_fdc_cands_remaining){
1571  // Get segments already linked to this candidate from associated objects
1572  vector<const DFDCSegment *>src_segments;
1573  srccan->GetT(src_segments);
1574 
1575  if (src_segments.size()==1) return false;
1576  stable_sort(src_segments.begin(), src_segments.end(), SegmentSortByLayerincreasing);
1577 
1578  if (DEBUG_LEVEL>0) _DBG_ << "Attempting matching method #4..." <<endl;
1579 
1580  unsigned int pack1_last=src_segments[src_segments.size()-1]->package;
1581  unsigned int pack1_first=src_segments[0]->package;
1582 
1583  for (unsigned int k=0;k<fdctrackcandidates.size();k++){
1584  if (num_fdc_cands_remaining==0) break;
1585  if (forward_matches[k]==0){
1586  const DTrackCandidate *fdccan = fdctrackcandidates[k];
1587 
1588  // Get the segment data
1589  vector<const DFDCSegment *>segments;
1590  fdccan->GetT(segments);
1591  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
1592 
1593  const DFDCPseudo *firsthit=segments[0]->hits[0];
1594  unsigned int pack2_first=segments[0]->package;
1595  unsigned int pack2_last=segments[segments.size()-1]->package;
1596 
1597  // if (pack2_first>pack1_last || pack2_last<pack1_first){
1598  if (pack2_first-pack1_last==1 || pack1_first-pack2_last==1){
1599  // Momentum and position vectors for the input candidate
1600  DVector3 mom=srccan->momentum();
1601  DVector3 pos=srccan->position();
1602  double q=srccan->charge();
1603  DVector3 norm(0.,0.,1.);
1604 
1605  if (pack2_last<pack1_first){
1606  mom=(-1.0)*mom;
1607  }
1608 
1609  // Swim to the first hit in the candidate to which we wish to match
1610  // using the stepper
1611  stepper->SetCharge(q);
1612  stepper->SwimToPlane(pos,mom,firsthit->wire->origin,norm,NULL);
1613 
1614  double dx=pos.x()-firsthit->xy.X();
1615  double dy=pos.y()-firsthit->xy.Y();
1616  double d2=dx*dx+dy*dy;
1617  double variance=1.;
1618  double prob=TMath::Prob(d2/variance,1);
1619 
1620  unsigned int num_match=(prob>0.01)?1:0;
1621 
1622  // Try to match unmatched fdc candidates
1623  for (unsigned int i=1;i<segments[0]->hits.size();i++){
1624  const DFDCPseudo *hit=segments[0]->hits[i];
1625 
1626  if (pos.Perp()<48.5){
1627  ProjectHelixToZ(hit->wire->origin.z(),q,mom,pos);
1628 
1629  DVector2 XY=hit->xy;
1630  double dx=XY.X()-pos.x();
1631  double dy=XY.Y()-pos.y();
1632  double dr2=dx*dx+dy*dy;
1633 
1634  double variance=1.0;
1635  double prob = isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
1636  if (prob>0.01) num_match++;
1637  }
1638  }
1639  if (num_match>=3){
1640  forward_matches[k]=1;
1641 
1642  // Create new candidate for output
1643  DTrackCandidate *can = new DTrackCandidate;
1644 
1645  // average Bz
1646  double Bz_avg=0.;
1647  unsigned int num_hits=0;
1648 
1649  // Create a new DHelicalFit object for fitting combined data
1650  DHelicalFit fit;
1651  // Fake point at origin
1652  fit.AddHitXYZ(0.,0.,TARGET_Z,BEAM_VAR,BEAM_VAR,0.,true);
1653  // Add hits to the fit object and also to the track candidate
1654  // itself as associated objects
1655  for (unsigned int m=0;m<src_segments.size();m++){
1656  for (unsigned int n=0;n<src_segments[m]->hits.size();n++){
1657  const DFDCPseudo *fdchit=src_segments[m]->hits[n];
1658  fit.AddHit(fdchit);
1659  can->AddAssociatedObject(fdchit);
1660 
1661  //bfield->GetField(x,y,z,Bx,By,Bz);
1662  //Bz_avg-=Bz;
1663  Bz_avg+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),
1664  fdchit->wire->origin.z());
1665  }
1666  num_hits+=src_segments[m]->hits.size();
1667  }
1668  for (unsigned int m=0;m<segments.size();m++){
1669  for (unsigned int n=0;n<segments[m]->hits.size();n++){
1670  const DFDCPseudo *fdchit=segments[m]->hits[n];
1671  fit.AddHit(fdchit);
1672  can->AddAssociatedObject(fdchit);
1673 
1674  //bfield->GetField(x,y,z,Bx,By,Bz);
1675  //Bz_avg-=Bz;
1676  Bz_avg+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),
1677  fdchit->wire->origin.z());
1678  }
1679  num_hits+=segments[m]->hits.size();
1680  }
1681 
1682  // Fit the points to a circle
1683  if (fit.FitCircleRiemann(segments[0]->rc)==NOERROR){
1684  // Compute new transverse momentum
1685  Bz_avg=fabs(Bz_avg)/double(num_hits);
1686 
1687  // Guess for theta and z from input candidates
1688  double theta=fdccan->momentum().Theta();
1689  fit.tanl=tan(M_PI_2-theta);
1690  fit.z_vertex=srccan->position().Z();
1691 
1692  // Redo line fit
1693  fit.FitLineRiemann();
1694 
1695  double p=0.003*fit.r0*Bz_avg/cos(atan(fit.tanl));
1696  if (p>10.){ // Check for extremely stiff tracks, some of which
1697  // will have unphysical momenta... try alternate circle fit
1698  fit.FitCircle();
1699  }
1700  // Guess charge from fit
1701  fit.h=GetSenseOfRotation(fit,firsthit,srccan->position());
1702  Particle_t locPID = ((FactorForSenseOfRotation*fit.h > 0.0) ? PiPlus : PiMinus);
1703  can->setPID(locPID);
1704 
1705  // put z position just upstream of the first hit in z
1706  const DHFHit_t *myhit=fit.GetHits()[0];
1707  pos.SetXYZ(myhit->x,myhit->y,myhit->z);
1708  GetPositionAndMomentum(myhit->z-1.,fit,Bz_avg,pos,mom);
1709 
1710  // circle parameters
1711  can->rc=fit.r0;
1712  can->xc=fit.x0;
1713  can->yc=fit.y0;
1714 
1715  can->setPosition(pos);
1716  can->setMomentum(mom);
1717  can->chisq=fit.chisq;
1718  can->Ndof=fit.ndof;
1719  trackcandidates.push_back(can);
1720 
1721  num_fdc_cands_remaining--;
1722 
1723  if (DEBUG_LEVEL>0)
1724  _DBG_ << "Found a match using method #4" <<endl;
1725  return true;
1726  } // circle fit
1727  } // got a match?
1728  } // is the first package in the new fdc candidate downstream of the last?
1729  } // check that we have not already matched this fdc candidate
1730  } // loop over fdc track candidates
1731 
1732  return false;
1733 }
1734 
1735 // Matching method to try to deal with CDC candidates that do not point
1736 // directly at the the cdc endplate but could possibly be matched to FDC
1737 // candidates.
1739  vector<const DCDCTrackHit *>&cdchits,
1740  vector<int> &forward_matches
1741  ){
1742  // Loop over the fdc track candidates
1743  for (unsigned int k=0;k<fdctrackcandidates.size();k++){
1744  if (forward_matches[k]==0){
1745  const DTrackCandidate *fdccan = fdctrackcandidates[k];
1746 
1747  unsigned int num_match=0;
1748  unsigned int num_cdc=0;
1749 
1750  DVector3 pos=fdccan->position();
1751  DVector3 mom=fdccan->momentum();
1752  double q=fdccan->charge();
1753 
1754  for (unsigned int m=0;m<cdchits.size();m++){
1755  double variance=1.0;
1756  // Use a helical approximation to the track to match both axial and
1757  // stereo wires
1758  double dr2=DocaToHelix(cdchits[m],q,pos,mom);
1759  double prob=isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
1760 
1761  if (prob>0.01) num_match++;
1762  if (DEBUG_LEVEL>1) _DBG_ << "CDC s: " << cdchits[m]->wire->straw
1763  << " r: " << cdchits[m]->wire->ring
1764  << " prob: " << prob << endl;
1765 
1766  num_cdc++;
1767  }
1768 
1769  if (num_match>=3 && double(num_match)/double(num_cdc)>0.33){
1770  // Get the segment data
1771  vector<const DFDCSegment *>segments;
1772  fdccan->GetT(segments);
1773 
1774  // JANA does not maintain the order that the segments were added
1775  // as associated objects. Therefore, we need to reorder them here
1776  // so segment[0] is the most upstream segment.
1777  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
1778 
1779  // Abort if the track would have to pass from one quadrant into the opposite
1780  // quadrant (this is more likely two roughly back-to-back tracks rather than
1781  // a single track).
1782  const DVector2 fdc_hit_pos=segments[0]->hits[0]->xy;
1783  const DVector3 cdc_wire_origin=cdchits[0]->wire->origin;
1784  if (cdc_wire_origin.x()*fdc_hit_pos.X()<0.
1785  && cdc_wire_origin.y()*fdc_hit_pos.Y()<0.){
1786  if (DEBUG_LEVEL>0) _DBG_ << "Skipping match of potential back-to-back tracks." <<endl;
1787  continue;
1788  }
1789 
1790  // Mark this fdc candidate as having a match to a cdc candidate
1791  forward_matches[k]=1;
1792 
1793  if (DEBUG_LEVEL>0) _DBG_ << "... matched to FDC candidate #" << k <<endl;
1794 
1795  // Add fdc hits to the candidate
1796  for (unsigned int m=0;m<segments.size();m++){
1797  for (unsigned int n=0;n<segments[m]->hits.size();n++){
1798  can->AddAssociatedObject(segments[m]->hits[n]);
1799  }
1800  }
1801 
1802  // Average Bz
1803  double Bz_avg=0.;
1804 
1805  // Instantiate the helical fitter to do the refit
1806  DHelicalFit fit;
1807  if (DoRefit(fit,segments,cdchits,Bz_avg)==NOERROR){
1808  // circle parameters
1809  can->rc=fit.r0;
1810  can->xc=fit.x0;
1811  can->yc=fit.y0;
1812 
1813  // Determine the polar angle
1814  double theta=fdccan->momentum().Theta();
1815  fit.tanl=tan(M_PI_2-theta);
1816 
1817  Particle_t locPID = ((FactorForSenseOfRotation*fit.h > 0.0) ? PiPlus : PiMinus);
1818  can->setPID(locPID);
1819 
1820  // FDC hit
1821  const DFDCPseudo *fdchit=segments[0]->hits[0];
1822  double zhit=fdchit->wire->origin.z();
1823  pos.SetXYZ(fdchit->xy.X(),fdchit->xy.Y(),zhit);
1824  UpdatePositionAndMomentum(fit,Bz_avg,cdchits[0]->wire->origin,
1825  pos,mom);
1826 
1827  can->chisq=fit.chisq;
1828  can->Ndof=fit.ndof;
1829  can->setMomentum(mom);
1830  can->setPosition(pos);
1831  }
1832  return true;
1833  } // check for match
1834  } // check that the candidate has not already been matched
1835  } // loop over fdc candidates
1836 
1837  return false;
1838 }
1839 
1840 // Method to match FDC candidates with stray CDC hits unassociated with track
1841 // candidates
1843  vector<const DFDCPseudo*>&fdchits,
1844  vector<unsigned int>&used_cdc_hits,
1845  unsigned int &num_unmatched_cdcs
1846  ){
1847  // Input candidate parameters
1848  DVector3 pos=can->position();
1849  DVector3 mom=can->momentum();
1850  double q=can->charge();
1851 
1852  // Variables to keep track of cdc hits
1853  bool got_inner_index=false;
1854  unsigned int inner_index=0;
1855  int id_for_smallest_dr=-1;
1856  int old_ring=-1;
1857  double dr2_min=1e6;
1858 
1859  for (unsigned int k=0;k<used_cdc_hits.size();k++){
1860  // We only want to use one hit from a given ring to avoid confusing the
1861  // circle refit with curlers...
1862  if (mycdchits[k]->wire->ring!=old_ring){
1863  if (id_for_smallest_dr>=0){
1864  if (!used_cdc_hits[id_for_smallest_dr]){
1865  num_unmatched_cdcs--;
1866  used_cdc_hits[id_for_smallest_dr]=1;
1867 
1868  can->used_cdc_indexes.push_back(id_for_smallest_dr);
1869  can->AddAssociatedObject(mycdchits[id_for_smallest_dr]);
1870 
1871  if (got_inner_index==false){
1872  inner_index=id_for_smallest_dr;
1873  got_inner_index=true;
1874  }
1875  }
1876  }
1877  // Reset matching variables
1878  dr2_min=1e6;
1879  id_for_smallest_dr=-1;
1880  }
1881 
1882  if (!used_cdc_hits[k]){
1883  double variance=1.0;
1884  // Use a helical approximation to the track to match both axial and
1885  // stereo wires
1886  double dr2=DocaToHelix(mycdchits[k],q,pos,mom);
1887  double prob=isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
1888 
1889  if (prob>0.5){
1890  // Look for closest match
1891  if (dr2<dr2_min){
1892  dr2_min=dr2;
1893  id_for_smallest_dr=k;
1894  }
1895  }
1896  }
1897  old_ring=mycdchits[k]->wire->ring;
1898  }
1899  // Grab the last potential match
1900  if (id_for_smallest_dr>=0){
1901  if (!used_cdc_hits[id_for_smallest_dr]){
1902  num_unmatched_cdcs--;
1903  used_cdc_hits[id_for_smallest_dr]=1;
1904 
1905  can->used_cdc_indexes.push_back(id_for_smallest_dr);
1906  can->AddAssociatedObject(mycdchits[id_for_smallest_dr]);
1907  }
1908  }
1909 
1910  // We found some matched hits. Update the start position of the candidate.
1911  if (got_inner_index){
1912  const DFDCPseudo *firsthit=fdchits[0];
1913 
1914  // Compute the average Bz
1915  double Bz_avg=0.,denom=0.;
1916  for (unsigned int m=0;m<fdchits.size();m++){
1917  const DFDCPseudo *fdchit=fdchits[m];
1918  double x=fdchit->xy.X();
1919  double y=fdchit->xy.Y();
1920  double z=fdchit->wire->origin.z();
1921 
1922  Bz_avg+=bfield->GetBz(x,y,z);
1923  denom+=1.;
1924  }
1925  Bz_avg=fabs(Bz_avg)/denom;
1926 
1927  // Store the current track parameters in the DHelicalFit class
1928  DHelicalFit fit;
1929  fit.r0=mom.Perp()/(0.003*Bz_avg);
1930  fit.phi=mom.Phi();
1931  fit.h=q*FactorForSenseOfRotation;
1932  fit.x0=pos.x()-fit.h*fit.r0*sin(fit.phi);
1933  fit.y0=pos.y()+fit.h*fit.r0*cos(fit.phi);
1934  fit.tanl=tan(M_PI_2-mom.Theta());
1935  fit.z_vertex=0; // actualy we don't need this..
1936  // Use fdc hit for input to the following routines because the z-position is
1937  // well-defined...
1938  double zhit=firsthit->wire->origin.z();
1939  pos.SetXYZ(firsthit->xy.X(),firsthit->xy.Y(),zhit);
1940  UpdatePositionAndMomentum(fit,Bz_avg,mycdchits[inner_index]->wire->origin,
1941  pos,mom);
1942 
1943  // update the track parameters
1944  can->setMomentum(mom);
1945  can->setPosition(pos);
1946 
1947  if (DEBUG_LEVEL>0) _DBG_ << "... matched stray CDC hits ..." << endl;
1948  } // match at least one cdc hit
1949 }
1950 
1951 // This method tries to match unmatched fdc candidates to candidates that
1952 // already have fdc/cdc matches
1954  vector<int> &forward_matches,
1955  int &num_fdc_cands_remaining){
1956  if (DEBUG_LEVEL>0) _DBG_ << "Attempting matching method #7..." <<endl;
1957 
1958  // Get the hits associated with this candidate
1959  vector<const DFDCPseudo *>fdchits;
1960  srccan->GetT(fdchits);
1961  if (fdchits.size()==0) return false;
1962 
1963  stable_sort(fdchits.begin(),fdchits.end(),FDCHitSortByLayerincreasing);
1964  unsigned int pack1_last=(fdchits[fdchits.size()-1]->wire->layer-1)/6;
1965 
1966  for (unsigned int k=0;k<fdctrackcandidates.size();k++){
1967  if (num_fdc_cands_remaining==0) break;
1968  if (forward_matches[k]==0){
1969  const DTrackCandidate *fdccan = fdctrackcandidates[k];
1970 
1971  // Get the segment data
1972  vector<const DFDCSegment *>segments;
1973  fdccan->GetT(segments);
1974  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
1975 
1976  const DFDCPseudo *firsthit=segments[0]->hits[0];
1977  unsigned int pack2_first=segments[0]->package;
1978 
1979  if (pack2_first-pack1_last==1){ // match in adjacent packages
1980  // Momentum and position vectors for the input candidate
1981  DVector3 mom=srccan->momentum();
1982  DVector3 pos=srccan->position();
1983  double q=srccan->charge();
1984  DVector3 norm(0.,0.,1.);
1985 
1986  // Swim to the first hit in the candidate to which we wish to match
1987  // using the stepper
1988  stepper->SetCharge(q);
1989  stepper->SwimToPlane(pos,mom,firsthit->wire->origin,norm,NULL);
1990 
1991  double dx=pos.x()-firsthit->xy.X();
1992  double dy=pos.y()-firsthit->xy.Y();
1993  double d2=dx*dx+dy*dy;
1994  double variance=1.;
1995  double prob=TMath::Prob(d2/variance,1);
1996 
1997  unsigned int num_match=(prob>0.01)?1:0;
1998 
1999  // Try to match unmatched fdc candidates
2000  for (unsigned int i=1;i<segments[0]->hits.size();i++){
2001  const DFDCPseudo *hit=segments[0]->hits[i];
2002 
2003  if (pos.Perp()<48.5){
2004  ProjectHelixToZ(hit->wire->origin.z(),q,mom,pos);
2005 
2006  DVector2 XY=hit->xy;
2007  double dx=XY.X()-pos.x();
2008  double dy=XY.Y()-pos.y();
2009  double dr2=dx*dx+dy*dy;
2010 
2011  double variance=1.0;
2012  double prob = isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
2013  if (prob>0.01) num_match++;
2014  }
2015  }
2016  if (num_match>=3){
2017  forward_matches[k]=1;
2018  num_fdc_cands_remaining--;
2019 
2020  // average Bz
2021  double Bz=0.;
2022  unsigned int num_hits=0;
2023 
2024  // Create a new DHelicalFit object for fitting combined data
2025  DHelicalFit fit;
2026 
2027  // Get the cdc hits associated with this track candidate and add the
2028  // axial straws to the list of hits to use in the circle fit
2029  vector<const DCDCTrackHit *>cdchits;
2030  srccan->GetT(cdchits);
2031  stable_sort(cdchits.begin(), cdchits.end(), CDCHitSortByLayerincreasing);
2032  for (unsigned int i=0;i<cdchits.size();i++){
2033  if (cdchits[i]->is_stereo==false){
2034  double cov=0.213; //guess
2035  const DVector3 origin=cdchits[i]->wire->origin;
2036  double x=origin.x(),y=origin.y(),z=origin.z();
2037  fit.AddHitXYZ(x,y,z,cov,cov,0.,true);
2038  Bz+=bfield->GetBz(x,y,z);
2039  num_hits++;
2040  }
2041  }
2042  // Add the FDC hits from the existing track to this list
2043  for (unsigned int i=0;i<fdchits.size();i++){
2044  fit.AddHit(fdchits[i]);
2045  double zhit=fdchits[i]->wire->origin.z();
2046 
2047  Bz+=bfield->GetBz(fdchits[i]->xy.X(),fdchits[i]->xy.Y(),zhit);
2048  num_hits++;
2049 
2050  if (zhit<firsthit->wire->origin.z()){
2051  firsthit=fdchits[i];
2052  }
2053  }
2054  // Add the new set of FDC hits; also add them as associated objects
2055  // to the track
2056  for (unsigned int m=0;m<segments.size();m++){
2057  for (unsigned int n=0;n<segments[m]->hits.size();n++){
2058  const DFDCPseudo *fdchit=segments[m]->hits[n];
2059  fit.AddHit(fdchit);
2060  double zhit=fdchit->wire->origin.z();
2061 
2062  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),zhit);
2063  srccan->AddAssociatedObject(fdchit);
2064  }
2065  num_hits+=segments[m]->hits.size();
2066  }
2067  Bz=fabs(Bz)/double(num_hits);
2068 
2069  // Redo the circle fit with the extra hits
2070  if (fit.FitCircleRiemann(srccan->rc)==NOERROR){
2071  // Determine the polar angle
2072  double theta=srccan->momentum().Theta();
2073  fit.tanl=tan(M_PI_2-theta);
2074 
2075  double p=0.003*fit.r0*Bz/cos(atan(fit.tanl));
2076  if ((cdchits.size())>0?(p>3.):(p>10.)){
2077  // Suspiciously high momentum: try alternate circle fit...
2078  fit.FitCircle();
2079  }
2080 
2081  if (cdchits.size()>0){
2082  // FDC hit
2083  double zhit=firsthit->wire->origin.z();
2084  pos.SetXYZ(firsthit->xy.X(),firsthit->xy.Y(),zhit);
2085  UpdatePositionAndMomentum(fit,Bz,cdchits[0]->wire->origin,
2086  pos,mom);
2087  }
2088  else{
2089  // put z position just upstream of the first hit in z
2090  const DHFHit_t *myhit=fit.GetHits()[0];
2091  pos.SetXYZ(myhit->x,myhit->y,myhit->z);
2092  GetPositionAndMomentum(myhit->z-1.,fit,Bz,pos,mom);
2093  }
2094  srccan->rc=fit.r0;
2095  srccan->xc=fit.x0;
2096  srccan->yc=fit.y0;
2097 
2098  srccan->chisq=fit.chisq;
2099  srccan->Ndof=fit.ndof;
2100  srccan->setMomentum(mom);
2101  srccan->setPosition(pos);
2102  }
2103 
2104  if (DEBUG_LEVEL>0) _DBG_ << "Found a match using method #7" <<endl;
2105  return true;
2106  } // got a match?
2107  } // is the first package in the new fdc candidate downstream of the last?
2108  } // check that we have not already matched this fdc candidate
2109  } // loop over fdc track candidates
2110 
2111  return false;
2112 }
2113 
2114 
2115 // This method tries to improve the quality of the circle fit of a cdc
2116 // candidate by assuming that if the outermost hit is in a stereo straw,
2117 // if this track is going to match to an fdc candidate, the location of the
2118 // hit along the straw is likely to be near the end of the straw, thus
2119 // providing another useful point on the circle. After refitting the circle,
2120 // the code adjusts the dip angle and tries to match to the remaining fdc
2121 // candidates.
2123  vector<int> &forward_matches
2124  ){
2125  // Get the cdc hits associated with this track candidate
2126  vector<const DCDCTrackHit *>cdchits;
2127  cdccan->GetT(cdchits);
2128  stable_sort(cdchits.begin(), cdchits.end(), CDCHitSortByLayerincreasing);
2129 
2130  unsigned int last_index=cdchits.size()-1;
2131  if (cdchits[last_index]->is_stereo==true
2132  && cdchits[last_index]->wire->ring<13){
2133  DHelicalFit fit;
2134 
2135  // Assume the outermost stereo hit occurs near the end of the straw
2136  DVector3 origin=cdchits[last_index]->wire->origin;
2137  DVector3 dir=cdchits[last_index]->wire->udir;
2138  DVector3 wirepos=origin+(75./dir.z())*dir;
2139  double cov=0.2;
2140  double x=wirepos.x(),y=wirepos.y(),z=wirepos.z();
2141  fit.AddHitXYZ(x,y,z,cov,cov,0,true);
2142  double Bz=bfield->GetBz(x,y,z);
2143  int num_hits=1;
2144 
2145  // Add the cdc axial wires to the list of hits to use in the fit
2146  for (unsigned int k=0;k<cdchits.size();k++){
2147  if (cdchits[k]->is_stereo==false){
2148  cov=0.2; //guess
2149  origin=cdchits[k]->wire->origin;
2150  double x=origin.x(),y=origin.y(),z=origin.z();
2151  fit.AddHitXYZ(x,y,z,cov,cov,0.,true);
2152  Bz+=bfield->GetBz(x,y,z);
2153  num_hits++;
2154  }
2155  }
2156  Bz=fabs(Bz)/num_hits;
2157 
2158  // Fit the points to a circle assuming that the circle goes through the
2159  // origin.
2160  if (fit.FitCircle()!=NOERROR) return false;
2161 
2162  // Determine the tangent of the dip angle
2163  double tworc=2.*fit.r0;
2164  double ratio=wirepos.Perp()/tworc;
2165  double sperp=tworc*((ratio<1.)?asin(ratio):M_PI_2);
2166  fit.tanl=(wirepos.z()-TARGET_Z)/sperp;
2167 
2168  // Find sense of rotation (proportional to the charge)
2170  double q=fit.h*FactorForSenseOfRotation;
2171 
2172  // Provide an initial guess for the position and momentum that is just
2173  // outside the CDC tracking volume
2174  DVector3 pos=wirepos,mom;
2175  UpdatePositionAndMomentum(fit,Bz,cdchits[0]->wire->origin,pos,mom);
2176 
2177  // Set the charge for the stepper
2178  stepper->SetCharge(q);
2179  // Vector normal to the fdc planes
2180  DVector3 norm(0.,0.,1.);
2181 
2182  // Loop over the fdc candidates looking for a match
2183  for (unsigned int k=0;k<fdctrackcandidates.size();k++){
2184  if (forward_matches[k]==0){
2185  const DTrackCandidate *fdccan = fdctrackcandidates[k];
2186 
2187  // Get the segment data
2188  vector<const DFDCSegment *>segments;
2189  fdccan->GetT(segments);
2190  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
2191 
2192  // only do this for candidates with segments in the first package
2193  if (segments[0]->package>0) continue;
2194 
2195  const DFDCPseudo *firsthit=segments[0]->hits[0];
2196 
2197  // Make copies of the momentum and position vectors for input to
2198  // the swimmer
2199  DVector3 my_mom(mom);
2200  DVector3 my_pos(pos);
2201 
2202  // Swim to the first hit in the candidate to which we wish to match
2203  // using the stepper
2204  stepper->SwimToPlane(my_pos,my_mom,firsthit->wire->origin,norm,NULL);
2205 
2206  // Match based on proximity of projection to hit
2207  double dx=my_pos.x()-firsthit->xy.X();
2208  double dy=my_pos.y()-firsthit->xy.Y();
2209  double d2=dx*dx+dy*dy;
2210  double variance=1.;
2211  double prob=TMath::Prob(d2/variance,1);
2212 
2213  unsigned int num_match=(prob>0.01)?1:0;
2214 
2215  // Try to match further hits in most upstream segment
2216  for (unsigned int i=1;i<segments[0]->hits.size();i++){
2217  const DFDCPseudo *hit=segments[0]->hits[i];
2218 
2219  if (my_pos.Perp()<48.5){
2220  ProjectHelixToZ(hit->wire->origin.z(),q,my_mom,my_pos);
2221 
2222  DVector2 XY=hit->xy;
2223  double dx=XY.X()-my_pos.x();
2224  double dy=XY.Y()-my_pos.y();
2225  double dr2=dx*dx+dy*dy;
2226 
2227  double variance=1.0;
2228  double prob = isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
2229  if (prob>0.01) num_match++;
2230  }
2231  }
2232  if (num_match>=3){
2233  forward_matches[k]=1;
2234 
2235  // Keep track of magnetic field in FDC
2236  double Bz_fdc=0;
2237  unsigned int num_hits_fdc=0;
2238 
2239  // Drop the first cdc hit in the list, since it isn't an
2240  // axial straw so the actual x,y position of the wire
2241  // depends on z, which we don't really know yet.
2242  fit.PruneHit(0);
2243 
2244  // Add the fdc hits to the fit class
2245  for (unsigned int m=0;m<segments.size();m++){
2246  for (unsigned int n=0;n<segments[m]->hits.size();n++){
2247  const DFDCPseudo *fdchit=segments[m]->hits[n];
2248  fit.AddHit(fdchit);
2249 
2250  Bz_fdc+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),
2251  fdchit->wire->origin.z());
2252  }
2253  num_hits_fdc+=segments[m]->hits.size();
2254  }
2255 
2256  // Fake point at origin
2257  fit.AddHitXYZ(0.,0.,TARGET_Z,BEAM_VAR,BEAM_VAR,0.,true);
2258  // Fit the points to a circle
2259  if (fit.FitCircleRiemann(segments[0]->rc)==NOERROR){
2260  // Use the fdc track candidate to get tanl
2261  double theta=fdccan->momentum().Theta();
2262  double theta_cdc=cdccan->momentum().Theta();
2263  if (segments.size()==1 && theta_cdc<M_PI_4){
2264  double numcdc=double(cdchits.size());
2265  double numfdc=segments[0]->hits.size();
2266  theta=(theta*numfdc+theta_cdc*numcdc)/(numfdc+numcdc);
2267  }
2268  fit.tanl=tan(M_PI_2-theta);
2269 
2270  Bz=0.5*(Bz+fabs(Bz_fdc)/num_hits_fdc);
2271 
2272  double p=0.003*fit.r0*Bz/cos(atan(fit.tanl));
2273  if (p>10.){
2274  // momentum is suspiciously high for a track going through both
2275  // the FDC and the CDC... try alternate circle fit
2276  fit.FitCircle();
2277  }
2278  // FDC hit
2279  const DFDCPseudo *fdchit=segments[0]->hits[0];
2280  double zhit=fdchit->wire->origin.z();
2281  pos.SetXYZ(fdchit->xy.X(),fdchit->xy.Y(),zhit);
2282  UpdatePositionAndMomentum(fit,Bz,cdchits[0]->wire->origin,pos,mom);
2283 
2284  DTrackCandidate *can = new DTrackCandidate;
2285  // circle parameters
2286  can->rc=fit.r0;
2287  can->xc=fit.x0;
2288  can->yc=fit.y0;
2289 
2290  can->setPID((q > 0.0) ? PiPlus : PiMinus);
2291  can->setMomentum(my_mom);
2292  can->setPosition(my_pos);
2293  can->chisq=fit.chisq;
2294  can->Ndof=fit.ndof;
2295 
2296  // Add hits as associated objects
2297  for (unsigned int m=0;m<segments.size();m++){
2298  for (unsigned int n=0;n<segments[m]->hits.size();n++){
2299  const DFDCPseudo *fdchit=segments[m]->hits[n];
2300  can->AddAssociatedObject(fdchit);
2301  }
2302  }
2303  for (unsigned int n=0;n<cdchits.size();n++){
2304  can->AddAssociatedObject(cdchits[n]);
2305  }
2306 
2307  trackcandidates.push_back(can);
2308 
2309  if (DEBUG_LEVEL>0) _DBG_ << "Matched using Method #8" <<endl;
2310 
2311  return true;
2312  } // circle fit
2313  } // match criterion
2314  } // check that fdc candidate has not already been matched
2315  } // loop over fdc candidates
2316  } // Check that the outermost hit is a stereo hit
2317 
2318  return false;
2319 }
2320 
2321 
2322 // Method to try to match unmatched FDC segments by forcing the circle fits
2323 // to go through the origin.
2324 bool DTrackCandidate_factory::MatchMethod9(unsigned int src_index,
2325  const DTrackCandidate *srccan,
2326  const DFDCSegment *segment,
2327  vector<const DTrackCandidate*>&cands,
2328  vector<int> &forward_matches){
2329  if (DEBUG_LEVEL>0){
2330  _DBG_ << "Attempting Match method #9..." << endl;
2331  }
2332  double q=srccan->charge();
2333  int pack1=segment->package;
2334 
2335  // Get hits from segment and redo fit forcing the circle to go through (0,0)
2336  DHelicalFit fit1;
2337  for (unsigned int n=0;n<segment->hits.size();n++){
2338  const DFDCPseudo *hit=segment->hits[n];
2339  fit1.AddHit(hit);
2340  }
2341  if (fit1.FitCircle()!=NOERROR) return false;
2342 
2343  // Sense of rotation
2344  fit1.h=q*FactorForSenseOfRotation;
2345 
2346  // Use the fdc track candidate to get tanl
2347  double theta=srccan->momentum().Theta();
2348  fit1.tanl=tan(M_PI_2-theta);
2349 
2350  // Find the magnetic field at the first hit in the first segment
2351  double x=segment->hits[0]->xy.X();
2352  double y=segment->hits[0]->xy.Y();
2353  double z=segment->hits[0]->wire->origin.z();
2354  double Bz=fabs(bfield->GetBz(x,y,z));
2355 
2356  // Get position and momentum for the first segment
2357  DVector3 mypos,mymom;
2358  GetPositionAndMomentum(z,fit1,Bz,mypos,mymom);
2359 
2360  // Loop over the rest of the fdc track candidates, skipping those that have
2361  // already been used
2362  for (unsigned int k=src_index+1;k<forward_matches.size();k++){
2363  if (forward_matches[k]==0){
2364  const DTrackCandidate *can2=cands[k];
2365  // Get the segment data
2366  vector<const DFDCSegment *>segments2;
2367  can2->GetT(segments2);
2368 
2369  int pack2=segments2[0]->package;
2370  if (abs(pack1-pack2)>0){
2371  // Get hits from the second segment and redo fit forcing circle
2372  // to go through (0,0)
2373  DHelicalFit fit2;
2374  for (unsigned int n=0;n<segments2[0]->hits.size();n++){
2375  const DFDCPseudo *hit=segments2[0]->hits[n];
2376  fit2.AddHit(hit);
2377  }
2378  if (fit2.FitCircle()!=NOERROR) continue;
2379 
2380  // Match using centers of circles
2381  double dx=fit1.x0-fit2.x0;
2382  double dy=fit1.y0-fit2.y0;
2383  double circle_center_diff2=dx*dx+dy*dy;
2384  double got_match=false;
2385  if (circle_center_diff2<9.0) got_match=true;
2386  // try another matching method here if got_match==false
2387  else{
2388  // Sense of rotation
2389  double q2=can2->charge();
2390  fit2.h=q2*FactorForSenseOfRotation;
2391 
2392  // Use the fdc track candidate to get tanl
2393  theta=can2->momentum().Theta();
2394  fit2.tanl=tan(M_PI_2-theta);
2395 
2396  // Try to match segments by swimming through the field
2397  got_match=MatchMethod11(q,mypos,mymom,fit2,segment,segments2[0]);
2398  // _DBG_ << endl;
2399  }
2400  if (got_match){
2401  forward_matches[k]=1;
2402  forward_matches[src_index]=1;
2403 
2404  // Create a new DTrackCandidate for output
2405  DTrackCandidate *can = new DTrackCandidate;
2406 
2407  // variables for finding <Bz>
2408  double Bz=0;
2409  int num_hits=0;
2410 
2411  // Add hits from first segment as associated objects
2412  for (unsigned int n=0;n<segment->hits.size();n++){
2413  const DFDCPseudo *fdchit=segment->hits[n];
2414  can->AddAssociatedObject(fdchit);
2415 
2416  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),
2417  fdchit->wire->origin.z());
2418  num_hits++;
2419  }
2420 
2421  // Add the hits from the second segment to the first fit object
2422  // and refit the circle. Also add them as associated objects
2423  // to the new candidate.
2424  for (unsigned int n=0;n<segments2[0]->hits.size();n++){
2425  const DFDCPseudo *hit=segments2[0]->hits[n];
2426  fit1.AddHit(hit);
2427  can->AddAssociatedObject(hit);
2428 
2429  Bz+=bfield->GetBz(hit->xy.X(),hit->xy.Y(),
2430  hit->wire->origin.z());
2431  num_hits++;
2432  }
2433  Bz=fabs(Bz)/double(num_hits);
2434 
2435  // Initialize variables needed for output
2436  DVector3 mom=srccan->momentum();
2437  DVector3 pos=srccan->position();
2438 
2439  can->Ndof=srccan->Ndof;
2440  can->chisq=srccan->chisq;
2441 
2442  if (fit1.FitCircleRiemann(fit1.r0)==NOERROR){
2443  can->Ndof=fit1.ndof;
2444  can->chisq=fit1.chisq;
2445 
2446  // Redo line fit
2447  fit1.FitLineRiemann();
2448 
2449  double p=0.003*fit1.r0*Bz/cos(atan(fit1.tanl));
2450  if (p>10.){
2451  // Try an alternate circle fit
2452  fit1.FitCircle();
2453  }
2454 
2455  // Guess charge from fit
2456  fit1.h=GetSenseOfRotation(fit1,segments2[0]->hits[0],
2457  srccan->position());
2458  q=FactorForSenseOfRotation*fit1.h;
2459 
2460  // put z position just upstream of the first hit in z
2461  const DHFHit_t *myhit=fit1.GetHits()[0];
2462  pos.SetXYZ(myhit->x,myhit->y,myhit->z);
2463  GetPositionAndMomentum(myhit->z-1.,fit1,Bz,pos,mom);
2464  }
2465  // circle parameters
2466  can->rc=fit1.r0;
2467  can->xc=fit1.x0;
2468  can->yc=fit1.y0;
2469 
2470  can->setPID((q > 0.0) ? PiPlus : PiMinus);
2471  can->setPosition(pos);
2472  can->setMomentum(mom);
2473 
2474  trackcandidates.push_back(can);
2475 
2476  if (DEBUG_LEVEL>0){
2477  _DBG_ << "Match method #9 succeeded..." << endl;
2478  }
2479 
2480  return true;
2481  } // circle center match
2482  } // different packages?
2483  } // already matched?
2484  } // loop over tracks
2485 
2486  return false;
2487 }
2488 
2489 // Method to try to match unmatched FDC segments by assuming that the tracks
2490 // are sufficiently stiff we are better served by something closer to a
2491 // "straight-line" approximation
2492 bool DTrackCandidate_factory::MatchMethod10(unsigned int src_index,
2493  const DTrackCandidate *srccan,
2494  const DFDCSegment *segment,
2495  vector<const DTrackCandidate*>&cands,
2496  vector<int> &forward_matches){
2497  if (DEBUG_LEVEL>0){
2498  _DBG_ << "Attempting Match method #10..." << endl;
2499  }
2500  double q=srccan->charge();
2501  int pack1=segment->package;
2502 
2503  // Get hits from segment and redo fit
2504  DHelicalFit fit1;
2505  for (unsigned int n=0;n<segment->hits.size();n++){
2506  const DFDCPseudo *hit=segment->hits[n];
2507  fit1.AddHit(hit);
2508  }
2509  fit1.FitCircleStraightTrack();
2510 
2511  // Sense of rotation
2512  fit1.h=q*FactorForSenseOfRotation;
2513 
2514  // Use the fdc track candidate to get tanl
2515  double theta=srccan->momentum().Theta();
2516  fit1.tanl=tan(M_PI_2-theta);
2517 
2518  // Find the magnetic field at the first hit in the first segment
2519  double x=segment->hits[0]->xy.X();
2520  double y=segment->hits[0]->xy.Y();
2521  double z=segment->hits[0]->wire->origin.z();
2522  double Bz=fabs(bfield->GetBz(x,y,z));
2523 
2524  // Get position and momentum for the first segment
2525  DVector3 mypos,mymom;
2526  GetPositionAndMomentum(z,fit1,Bz,mypos,mymom);
2527 
2528  // Loop over the rest of the fdc track candidates, skipping those that have
2529  // already been used
2530  for (unsigned int k=src_index+1;k<forward_matches.size();k++){
2531  if (forward_matches[k]==0){
2532  const DTrackCandidate *can2=cands[k];
2533  // Get the segment data
2534  vector<const DFDCSegment *>segments2;
2535  can2->GetT(segments2);
2536 
2537  int pack2=segments2[0]->package;
2538  if (abs(pack1-pack2)>0){
2539  // Get hits from the second segment and redo fit
2540  DHelicalFit fit2;
2541  for (unsigned int n=0;n<segments2[0]->hits.size();n++){
2542  const DFDCPseudo *hit=segments2[0]->hits[n];
2543  fit2.AddHit(hit);
2544  }
2545  fit2.FitCircleStraightTrack();
2546 
2547  // Sense of rotation
2548  double q2=can2->charge();
2549  fit2.h=q2*FactorForSenseOfRotation;
2550 
2551  // Use the fdc track candidate to get tanl
2552  theta=can2->momentum().Theta();
2553  fit2.tanl=tan(M_PI_2-theta);
2554 
2555  // Try to match segments by swimming through the field
2556  if (MatchMethod11(q,mypos,mymom,fit2,segment,segments2[0])){
2557  forward_matches[k]=1;
2558  forward_matches[src_index]=1;
2559 
2560  // Create a new DTrackCandidate for output
2561  DTrackCandidate *can = new DTrackCandidate;
2562 
2563  // variables for finding <Bz>
2564  double Bz=0;
2565  int num_hits=0;
2566 
2567  // Add hits from first segment as associated objects
2568  for (unsigned int n=0;n<segment->hits.size();n++){
2569  const DFDCPseudo *fdchit=segment->hits[n];
2570  can->AddAssociatedObject(fdchit);
2571 
2572  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),
2573  fdchit->wire->origin.z());
2574  num_hits++;
2575  }
2576 
2577  // Add the hits from the second segment to the first fit object
2578  // and refit the circle. Also add them as associated objects
2579  // to the new candidate.
2580  for (unsigned int n=0;n<segments2[0]->hits.size();n++){
2581  const DFDCPseudo *hit=segments2[0]->hits[n];
2582  fit1.AddHit(hit);
2583  can->AddAssociatedObject(hit);
2584 
2585  Bz+=bfield->GetBz(hit->xy.X(),hit->xy.Y(),
2586  hit->wire->origin.z());
2587  num_hits++;
2588  }
2589  Bz=fabs(Bz)/double(num_hits);
2590 
2591  // Initialize variables needed for output
2592  DVector3 mom=srccan->momentum();
2593  DVector3 pos=srccan->position();
2594  double q=srccan->charge();
2595  can->Ndof=srccan->Ndof;
2596  can->chisq=srccan->chisq;
2597 
2598  if (fit1.FitCircleRiemann(fit1.r0)==NOERROR){
2599  can->Ndof=fit1.ndof;
2600  can->chisq=fit1.chisq;
2601 
2602  // Redo line fit
2603  fit1.FitLineRiemann();
2604 
2605  double p=0.003*fit1.r0*Bz/cos(atan(fit1.tanl));
2606  if (p>10.){
2607  // unphysical momentum, try alternate circle fit...
2608  fit1.FitCircle();
2609  }
2610 
2611  // Guess charge from fit
2612  fit1.h=GetSenseOfRotation(fit1,segments2[0]->hits[0],
2613  srccan->position());
2614  q=FactorForSenseOfRotation*fit1.h;
2615 
2616  // put z position just upstream of the first hit in z
2617  const DHFHit_t *myhit=fit1.GetHits()[0];
2618  pos.SetXYZ(myhit->x,myhit->y,myhit->z);
2619  GetPositionAndMomentum(myhit->z-1.,fit1,Bz,pos,mom);
2620  }
2621  // circle parameters
2622  can->rc=fit1.r0;
2623  can->xc=fit1.x0;
2624  can->yc=fit1.y0;
2625 
2626  can->setPID((q > 0.0) ? PiPlus : PiMinus);
2627  can->setPosition(pos);
2628  can->setMomentum(mom);
2629 
2630  trackcandidates.push_back(can);
2631 
2632  if (DEBUG_LEVEL>0){
2633  _DBG_ << "Match method #10 succeeded..." << endl;
2634  }
2635  return true;
2636  } // minimum number of matching hits
2637  } // different packages?
2638  } // already matched?
2639  } // loop over tracks
2640 
2641  return false;
2642 }
2643 
2644 // Swims from one FDC segment to another segment looking for a match. If this
2645 // fails, swims from the second second to the first in the opposite direction.
2647  DVector3 &mymom,
2648  DHelicalFit &fit2,
2649  const DFDCSegment *segment1,
2650  const DFDCSegment *segment2
2651  ){
2652  if (DEBUG_LEVEL>0){
2653  _DBG_ << "Attempting Match method #11..." << endl;
2654  }
2655 
2656  // Package numbers
2657  int pack1=segment1->package;
2658  int pack2=segment2->package;
2659 
2660  // Set direction of propagation for traversing from segment1 to segment2
2661  if ((pack2<pack1 && mymom.z()>0.) || (pack1>pack2 && mymom.z()<0.)) mymom=(-1.)*mymom;
2662 
2663  // Find the magnetic field at the first hit of the second segment
2664  double x=segment2->hits[0]->xy.X();
2665  double y=segment2->hits[0]->xy.Y();
2666  double z=segment2->hits[0]->wire->origin.z();
2667 
2668  double Bz=fabs(bfield->GetBz(x,y,z));
2669 
2670  // Make local copies of input momentum and position
2671  DVector3 mymom1(mymom);
2672  DVector3 mypos1(mypos);
2673 
2674  // Get position and momentum for the second segment
2675  DVector3 mypos2,mymom2;
2676  GetPositionAndMomentum(z,fit2,Bz,mypos2,mymom2);
2677 
2678  if (pack2>pack1) mymom2=(-1.)*mymom2;
2679 
2680  // Swim from the first segment to the second segment using the stepper
2681  const DFDCPseudo *secondhit=segment2->hits[0];
2682  DVector3 norm(0.,0.,1.);
2683  stepper->SetCharge(q);
2684  stepper->SwimToPlane(mypos1,mymom1,secondhit->wire->origin,norm,NULL);
2685 
2686  // _DBG_<< endl;
2687  double variance=1.;
2688  if (mypos1.Perp()<48.5){
2689  // Look for match at first hit
2690  double dx=mypos1.x()-secondhit->xy.X();
2691  double dy=mypos1.y()-secondhit->xy.Y();
2692  double d2=dx*dx+dy*dy;
2693  double prob=TMath::Prob(d2/variance,1);
2694 
2695  unsigned int num_match=(prob>0.01)?1:0;
2696 
2697  // Try to match more hits
2698  for (unsigned int i=1;i<segment2->hits.size();i++){
2699  const DFDCPseudo *hit=segment2->hits[i];
2700 
2701  if (mypos1.Perp()<48.5){
2702  ProjectHelixToZ(hit->wire->origin.z(),q,mymom1,mypos1);
2703 
2704  DVector2 XY=hit->xy;
2705  double dx=XY.X()-mypos1.x();
2706  double dy=XY.Y()-mypos1.y();
2707  double dr2=dx*dx+dy*dy;
2708 
2709  double variance=1.0;
2710  double prob = isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
2711  if (prob>0.01) num_match++;
2712  }
2713  }
2714  if (num_match>=3){
2715  if (DEBUG_LEVEL>0){
2716  _DBG_ << "Method 11: found match!" << endl;
2717  }
2718  return true;
2719  }
2720  }
2721 
2722  // Try swimming in opposite direction
2723  secondhit=segment1->hits[0];
2724 
2725  double q2=fit2.h*FactorForSenseOfRotation;
2726  stepper->SetCharge(q2);
2727  stepper->SwimToPlane(mypos2,mymom2,secondhit->wire->origin,norm,NULL);
2728  // _DBG_ << mypos2.x() << " " << mypos2.y() << endl;
2729  if (mypos2.Perp()<48.5){
2730  // Look for match at first hit
2731  double dx=mypos2.x()-secondhit->xy.X();
2732  double dy=mypos2.y()-secondhit->xy.Y();
2733  double d2=dx*dx+dy*dy;
2734 
2735  double prob=TMath::Prob(d2/variance,1);
2736 
2737  unsigned int num_match=(prob>0.01)?1:0;
2738 
2739  // Try to match more hits
2740  for (unsigned int i=1;i<segment1->hits.size();i++){
2741  const DFDCPseudo *hit=segment1->hits[i];
2742 
2743  if (mypos2.Perp()<48.5){
2744  ProjectHelixToZ(hit->wire->origin.z(),q2,mymom2,mypos2);
2745 
2746  DVector2 XY=hit->xy;
2747  double dx=XY.X()-mypos2.x();
2748  double dy=XY.Y()-mypos2.y();
2749  double dr2=dx*dx+dy*dy;
2750 
2751  double variance=1.0;
2752  double prob = isfinite(dr2) ? TMath::Prob(dr2/variance,1):0.0;
2753  if (prob>0.01) num_match++;
2754  }
2755  }
2756  if (num_match>=3){
2757  if (DEBUG_LEVEL>0){
2758  _DBG_ << "Method 11: found match!" << endl;
2759  }
2760  return true;
2761  }
2762  }
2763 
2764  return false;
2765 }
2766 
2767 
2768 // Match low momentum track candidates using circle centers and radii of
2769 // curvature
2771  vector<int> &forward_matches,
2772  int &num_fdc_cands_remaining){
2773  if (DEBUG_LEVEL>0){
2774  _DBG_ << "Attempting matching method #12..." <<endl;
2775  }
2776  for (unsigned int i=0;i<fdctrackcandidates.size();i++){
2777  if (num_fdc_cands_remaining==0) return false;
2778  if (forward_matches[i]) continue;
2779 
2780  const DTrackCandidate *fdccan = fdctrackcandidates[i];
2781  if (fdccan->momentum().Mag()>0.5) continue;
2782 
2783  // Find how close the circle centers are to each other
2784  double dx=can->xc-fdccan->xc;
2785  double dy=can->yc-fdccan->yc;
2786  double dr2=dx*dx+dy*dy;
2787  // Require circle centers, radii and angles to agree at a reasonable level
2788  if (dr2<4.0 && fabs((can->rc-fdccan->rc)/can->rc)<0.5
2789  && fabs(can->momentum().Theta()-fdccan->momentum().Theta())<0.35 // 20 degrees
2790  ){
2791  // Get the segments belonging to the fdc candidate
2792  vector<const DFDCSegment *>segments;
2793  fdccan->GetT(segments);
2794  stable_sort(segments.begin(), segments.end(), SegmentSortByLayerincreasing);
2795 
2796  // Get the hits from the input candidate
2797  vector<const DFDCPseudo*>myfdchits;
2798  can->GetT(myfdchits);
2799  if (myfdchits.size()>0){
2800  stable_sort(myfdchits.begin(),myfdchits.end(),FDCHitSortByLayerincreasing);
2801  unsigned int last_package
2802  =(myfdchits[myfdchits.size()-1]->wire->layer-1)/6;
2803  // look for something downstream...
2804  if (segments[0]->package-last_package==1){
2805  vector<const DCDCTrackHit *>cdchits;
2806  can->GetT(cdchits);
2807  stable_sort(cdchits.begin(), cdchits.end(), CDCHitSortByLayerincreasing);
2808  // Variables for computing average Bz
2809  double Bz=0;
2810  unsigned int num_hits=0;
2811 
2812  // Instantiate the helical fitter to do the refit
2813  DHelicalFit fit;
2814  // Add CDC axial hits
2815  for (unsigned int k=0;k<cdchits.size();k++){
2816  if (cdchits[k]->is_stereo==false){
2817  double cov=0.213; //guess
2818  const DVector3 origin=cdchits[k]->wire->origin;
2819  double x=origin.x(),y=origin.y(),z=origin.z();
2820  fit.AddHitXYZ(x,y,z,cov,cov,0.,true);
2821  }
2822  }
2823  // Add the FDC hits and estimate Bz
2824  for (unsigned int k=0;k<segments.size();k++){
2825  for (unsigned int n=0;n<segments[k]->hits.size();n++){
2826  const DFDCPseudo *fdchit=segments[k]->hits[n];
2827  fit.AddHit(fdchit);
2828  //bfield->GetField(x,y,z,Bx,By,Bz);
2829  //Bz_avg-=Bz;
2830  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),fdchit->wire->origin.z());
2831  }
2832  num_hits+=segments[k]->hits.size();
2833  }
2834  for (unsigned int k=0;k<myfdchits.size();k++){
2835  const DFDCPseudo *fdchit=myfdchits[k];
2836  fit.AddHit(fdchit);
2837  //bfield->GetField(x,y,z,Bx,By,Bz);
2838  //Bz_avg-=Bz;
2839  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),fdchit->wire->origin.z());
2840  }
2841  num_hits+=myfdchits.size();
2842  Bz=fabs(Bz)/double(num_hits);
2843 
2844  // Do the circle fit with all of the matched FDC hits
2845  if (fit.FitCircleRiemann(segments[0]->rc)==NOERROR){
2846  // Determine the polar angle
2847  double theta=fdccan->momentum().Theta();
2848  double theta_cdc=can->momentum().Theta();
2849  if (segments.size()==1 && theta_cdc<M_PI_4){
2850  double numcdc=double(cdchits.size());
2851  double numfdc=segments[0]->hits.size();
2852  theta=(theta*numfdc+theta_cdc*numcdc)/(numfdc+numcdc);
2853  }
2854  fit.tanl=tan(M_PI_2-theta);
2855  // Redo the line fit
2856  fit.FitLineRiemann();
2857 
2858  DVector3 myorigin;
2859  if (myfdchits.size()) myorigin.SetXYZ(myfdchits[0]->xy.X(),
2860  myfdchits[0]->xy.Y(),
2861  myfdchits[0]->wire->origin.z());
2862  if (cdchits.size()) myorigin=cdchits[0]->wire->origin;
2863  DVector3 pos=fdccan->position(),mom;
2864  UpdatePositionAndMomentum(fit,Bz,myorigin,pos,mom);
2865 
2866  // circle parameters
2867  can->rc=fit.r0;
2868  can->xc=fit.x0;
2869  can->yc=fit.y0;
2870 
2871  // Add additional fdc hits to the track as associated objects
2872  for (unsigned int m=0;m<segments.size();m++){
2873  for (unsigned int n=0;n<segments[m]->hits.size();n++){
2874  can->AddAssociatedObject(segments[m]->hits[n]);
2875  }
2876  }
2877  can->chisq=fit.chisq;
2878  can->Ndof=fit.ndof;
2879  Particle_t locPID = (FactorForSenseOfRotation*fit.h > 0.0) ? PiPlus : PiMinus;
2880  can->setPID(locPID);
2881  can->setMomentum(mom);
2882  can->setPosition(pos);
2883 
2884  forward_matches[i]=1;
2885  num_fdc_cands_remaining--;
2886 
2887  if (DEBUG_LEVEL>0){
2888  _DBG_ << "... Found match!" << endl;
2889  }
2890  return true;
2891  } // circle fit
2892  } // look for packages downstream of those attached to candidate
2893  } // if we have fdc hits in the existing track candidate
2894  else{
2895  // Get the cdc hits belonging to the track
2896  vector<const DCDCTrackHit *>cdchits;
2897  can->GetT(cdchits);
2898  stable_sort(cdchits.begin(), cdchits.end(), CDCHitSortByLayerincreasing);
2899 
2900  // Variables for computing average Bz
2901  double Bz=0;
2902  unsigned int num_hits=0;
2903 
2904  // Instantiate the helical fitter to do the refit
2905  DHelicalFit fit;
2906  // Add CDC axial hits
2907  for (unsigned int k=0;k<cdchits.size();k++){
2908  if (cdchits[k]->is_stereo==false){
2909  double cov=0.213; //guess
2910  const DVector3 origin=cdchits[k]->wire->origin;
2911  double x=origin.x(),y=origin.y(),z=origin.z();
2912  fit.AddHitXYZ(x,y,z,cov,cov,0.,true);
2913  }
2914  }
2915  // Add the FDC hits and estimate Bz
2916  for (unsigned int k=0;k<segments.size();k++){
2917  for (unsigned int n=0;n<segments[k]->hits.size();n++){
2918  const DFDCPseudo *fdchit=segments[k]->hits[n];
2919  fit.AddHit(fdchit);
2920  //bfield->GetField(x,y,z,Bx,By,Bz);
2921  //Bz_avg-=Bz;
2922  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),fdchit->wire->origin.z());
2923  }
2924  num_hits+=segments[k]->hits.size();
2925  }
2926  Bz=fabs(Bz)/double(num_hits);
2927 
2928  // Do the circle fit with all of the matched FDC hits
2929  if (fit.FitCircleRiemann(segments[0]->rc)==NOERROR){
2930  // Determine the polar angle
2931  double theta=fdccan->momentum().Theta();
2932  double theta_cdc=can->momentum().Theta();
2933  if (segments.size()==1 && theta_cdc<M_PI_4){
2934  double numcdc=double(cdchits.size());
2935  double numfdc=segments[0]->hits.size();
2936  theta=(theta*numfdc+theta_cdc*numcdc)/(numfdc+numcdc);
2937  }
2938  // recompute position and momentum
2939  fit.tanl=tan(M_PI_2-theta);
2940  DVector3 myorigin=cdchits[0]->wire->origin;
2941  DVector3 pos=fdccan->position(),mom;
2942  UpdatePositionAndMomentum(fit,Bz,cdchits[0]->wire->origin,pos,mom);
2943 
2944  // circle parameters
2945  can->rc=fit.r0;
2946  can->xc=fit.x0;
2947  can->yc=fit.y0;
2948 
2949  // Add additional fdc hits to the track as associated objects
2950  for (unsigned int m=0;m<segments.size();m++){
2951  for (unsigned int n=0;n<segments[m]->hits.size();n++){
2952  can->AddAssociatedObject(segments[m]->hits[n]);
2953  }
2954  }
2955 
2956  can->setPosition(pos);
2957  can->chisq=fit.chisq;
2958  can->Ndof=fit.ndof;
2959  Particle_t locPID = (FactorForSenseOfRotation*fit.h > 0.0) ? PiPlus : PiMinus;
2960  can->setPID(locPID);
2961  can->setMomentum(mom);
2962 
2963  forward_matches[i]=1;
2964  num_fdc_cands_remaining--;
2965 
2966  if (DEBUG_LEVEL>0){
2967  _DBG_ << "... Found match!" << endl;
2968  }
2969  return true;
2970  } // circle fit worked
2971  }
2972  } // matching criteria
2973  } // loop over existing track candidates
2974 
2975  return false;
2976 }
2977 
2978 // Attempts to match two single-segment track candidates by only using the
2979 // hit information to fit circles (i.e., not requiring the tracks to originate
2980 // from the target region.) The idea is to recover some tracks arising from
2981 // secondary interactions or decays beyond the target.
2982 bool DTrackCandidate_factory::MatchMethod13(unsigned int src_index,
2983  const DTrackCandidate *srccan,
2984  const DFDCSegment *segment,
2985  vector<const DTrackCandidate*>&cands,
2986  vector<int> &forward_matches){
2987  if (DEBUG_LEVEL>0){
2988  _DBG_ << "Attempting Match method #13..." << endl;
2989  }
2990  double q=srccan->charge();
2991  int pack1=segment->package;
2992 
2993  // Get hits from segment and redo fit
2994  DHelicalFit fit1;
2995  for (unsigned int n=0;n<segment->hits.size();n++){
2996  const DFDCPseudo *hit=segment->hits[n];
2997  fit1.AddHit(hit);
2998  }
2999 
3000  if (fit1.FitCircleRiemann(srccan->rc)!=NOERROR) return false;
3001 
3002  // Guess for theta and z from input candidates
3003  double theta=srccan->momentum().Theta();
3004  fit1.tanl=tan(M_PI_2-theta);
3005  fit1.z_vertex=srccan->position().Z();
3006 
3007  // Redo line fit
3008  if (fit1.FitLineRiemann()!=NOERROR) return false;
3009 
3010  // Find the magnetic field at the first hit in the first segment
3011  double x=segment->hits[0]->xy.X();
3012  double y=segment->hits[0]->xy.Y();
3013  double z=segment->hits[0]->wire->origin.z();
3014  double Bz=fabs(bfield->GetBz(x,y,z));
3015 
3016  // Get position and momentum for the first segment
3017  DVector3 mypos,mymom;
3018  GetPositionAndMomentum(z,fit1,Bz,mypos,mymom);
3019 
3020  // Loop over the rest of the fdc track candidates, skipping those that have
3021  // already been used
3022  for (unsigned int k=src_index+1;k<forward_matches.size();k++){
3023  if (forward_matches[k]==0){
3024  const DTrackCandidate *can2=fdctrackcandidates[k];
3025  // Get the segment data
3026  vector<const DFDCSegment *>segments2;
3027  can2->GetT(segments2);
3028 
3029  int pack2=segments2[0]->package;
3030  if (abs(pack1-pack2)>0){
3031  // Get hits from the second segment and redo fit
3032  DHelicalFit fit2;
3033  for (unsigned int n=0;n<segments2[0]->hits.size();n++){
3034  const DFDCPseudo *hit=segments2[0]->hits[n];
3035  fit2.AddHit(hit);
3036  }
3037 
3038  if (fit2.FitCircleRiemann(segments2[0]->rc)!=NOERROR) continue;
3039 
3040  // Guess for theta and z from input candidates
3041  theta=can2->momentum().Theta();
3042  fit2.tanl=tan(M_PI_2-theta);
3043  fit2.z_vertex=srccan->position().Z();
3044 
3045  // Redo line fit
3046  if (fit2.FitLineRiemann()!=NOERROR) continue;
3047 
3048  // Try to match segments by swimming through the field
3049  if (MatchMethod11(q,mypos,mymom,fit2,segment,segments2[0])){
3050  forward_matches[k]=1;
3051  forward_matches[src_index]=1;
3052 
3053  // Create a new DTrackCandidate for output
3054  DTrackCandidate *can = new DTrackCandidate;
3055 
3056  // variables for finding <Bz>
3057  double Bz=0;
3058  int num_hits=0;
3059 
3060  // Add hits from first segment as associated objects
3061  for (unsigned int n=0;n<segment->hits.size();n++){
3062  const DFDCPseudo *fdchit=segment->hits[n];
3063  can->AddAssociatedObject(fdchit);
3064 
3065  Bz+=bfield->GetBz(fdchit->xy.X(),fdchit->xy.Y(),
3066  fdchit->wire->origin.z());
3067  num_hits++;
3068  }
3069 
3070  // Add the hits from the second segment to the first fit object
3071  // and refit the circle. Also add them as associated objects
3072  // to the new candidate.
3073  for (unsigned int n=0;n<segments2[0]->hits.size();n++){
3074  const DFDCPseudo *hit=segments2[0]->hits[n];
3075  fit1.AddHit(hit);
3076  can->AddAssociatedObject(hit);
3077 
3078  Bz+=bfield->GetBz(hit->xy.X(),hit->xy.Y(),
3079  hit->wire->origin.z());
3080  num_hits++;
3081  }
3082  Bz=fabs(Bz)/double(num_hits);
3083 
3084  // Initialize variables needed for output
3085  DVector3 mom=srccan->momentum();
3086  DVector3 pos=srccan->position();
3087  double q=srccan->charge();
3088  can->Ndof=srccan->Ndof;
3089  can->chisq=srccan->chisq;
3090 
3091  if (fit1.FitCircleRiemann(fit1.r0)==NOERROR){
3092  can->Ndof=fit1.ndof;
3093  can->chisq=fit1.chisq;
3094 
3095  // Redo line fit
3096  fit1.FitLineRiemann();
3097 
3098  // Guess charge from fit
3099  fit1.h=GetSenseOfRotation(fit1,segments2[0]->hits[0],
3100  srccan->position());
3101  q=FactorForSenseOfRotation*fit1.h;
3102 
3103  // put z position just upstream of the first hit in z
3104  const DHFHit_t *myhit=fit1.GetHits()[0];
3105  pos.SetXYZ(myhit->x,myhit->y,myhit->z);
3106  GetPositionAndMomentum(myhit->z-1.,fit1,Bz,pos,mom);
3107  }
3108  // circle parameters
3109  can->rc=fit1.r0;
3110  can->xc=fit1.x0;
3111  can->yc=fit1.y0;
3112 
3113  can->setPID((q > 0.0) ? PiPlus : PiMinus);
3114  can->setPosition(pos);
3115  can->setMomentum(mom);
3116 
3117  trackcandidates.push_back(can);
3118 
3119  if (DEBUG_LEVEL>0){
3120  _DBG_ << "Match method #13 succeeded..." << endl;
3121  }
3122  return true;
3123  } // minimum number of matching hits
3124  } // different packages?
3125  } // already matched?
3126  } // loop over tracks
3127 
3128  return false;
3129 }
3130 
3131 // Routine to return momentum and position given the helical parameters and the
3132 // z-component of the magnetic field
3133 void
3135  double Bz,DVector3 &pos,
3136  DVector3 &mom) const{
3137  double xc=fit.x0;
3138  double yc=fit.y0;
3139  double rc=fit.r0;
3140  // Position
3141  double phi1=atan2(pos.y()-yc,pos.x()-xc);
3142  double q_over_rc_tanl=FactorForSenseOfRotation*fit.h/(rc*fit.tanl);
3143  double dphi_s=(pos.z()-z)*q_over_rc_tanl;
3144  double dphi1=phi1-dphi_s;// was -
3145  double x=xc+rc*cos(dphi1);
3146  double y=yc+rc*sin(dphi1);
3147  pos.SetXYZ(x,y,z);
3148 
3149  dphi1*=-1.;
3150  if (fit.h<0) dphi1+=M_PI;
3151 
3152  // Momentum
3153  double pt=0.003*fabs(Bz)*rc;
3154  double px=pt*sin(dphi1);
3155  double py=pt*cos(dphi1);
3156  double pz=pt*fit.tanl;
3157  mom.SetXYZ(px,py,pz);
3158 }
3159 
3160 // Use information from the start counter to try to correct the momentum and
3161 // position for tracks seem to be pointing backwards but are probably pointing
3162 // forwards. In these cases the circle projection intersects with a start
3163 // counter paddle but the z-position at the radius r just outside the start
3164 // counter barrel region is downstream of the nose, which does not make
3165 // sense for a particle that is actually heading upstream...
3166 bool DTrackCandidate_factory::TryToFlipDirection(vector<const DSCHit *>&schits,
3167  DVector3 &mom,DVector3 &pos) const{
3168  if (schits.size()==0) return false;
3169  if (DEBUG_LEVEL>0){
3170  _DBG_ << "Attempting to flip direction of track..." << endl;
3171  }
3172 
3173  double zsc=sc_pos[0][1].z();
3174  if (pos.z()>zsc){
3175  unsigned int best_sc_sector_id=0;
3176  double dphi_min=1000.;
3177  double cand_phi=pos.Phi();
3178  for (unsigned int k=0;k<schits.size();k++){
3179  unsigned int sector_id=schits[k]->sector-1;
3180  double dphi=cand_phi-sc_pos[sector_id][0].Phi();
3181  if (dphi<-M_PI) dphi+=2.*M_PI;
3182  if (dphi>M_PI) dphi-=2.*M_PI;
3183 
3184  if (fabs(dphi)<dphi_min){
3185  best_sc_sector_id=sector_id;
3186  dphi_min=fabs(dphi);
3187  }
3188  }
3189  if (dphi_min<0.105){
3190  // simplest approach: just change the direction -z -> +z
3191  mom.SetMagThetaPhi(mom.Mag(),M_PI-mom.Theta(),mom.Phi());
3192  pos=sc_pos[best_sc_sector_id][1];
3193  // _DBG_ << " Event " << eventnumber << endl;
3194  if (DEBUG_LEVEL>0){
3195  _DBG_ << "Changing direction of CDC candidate..." << endl;
3196  }
3197  return true;
3198  }
3199  }
3200 
3201 
3202  return false;
3203 }
3204 
3205 // Last ditch attempt to match stray segments in the FDC to other track stubs
3206 // after all other matching techniques have been tried...
3207 bool DTrackCandidate_factory::MatchStraySegments(vector<int> &forward_matches,
3208  int &num_fdc_cands_remaining){
3209  if (DEBUG_LEVEL>0){
3210  _DBG_ << "Attempting to match stray FDC segments..." << endl;
3211  }
3212 
3213  bool got_new_match=false;
3214  for (unsigned int j=0;j<forward_matches.size();j++){
3215  if (num_fdc_cands_remaining==0) break;
3216  if (forward_matches[j]==0){
3217  const DTrackCandidate *srccan=fdctrackcandidates[j];
3218 
3219  // Get the segment data
3220  vector<const DFDCSegment *>segments;
3221  srccan->GetT(segments);
3222  const DFDCSegment *segment=segments[0];
3223 
3224  // redo circle fits for segments, forcing the circles to go through (0,0)
3225  if (MatchMethod9(j,srccan,segment,fdctrackcandidates,forward_matches)){
3226  if (DEBUG_LEVEL>0) _DBG_ << "Matched FDC segments using method #9" << endl;
3227  num_fdc_cands_remaining-=2;
3228  got_new_match=true;
3229  }
3230  // Redo circle fit assuming track is almost straight
3231  else if (MatchMethod10(j,srccan,segment,fdctrackcandidates,
3232  forward_matches)){
3233  if (DEBUG_LEVEL>0) _DBG_ << "Matched FDC segments using method #10" << endl;
3234  num_fdc_cands_remaining-=2;
3235  got_new_match=true;
3236  }
3237  // Redo circle fits without any assumption that the tracks originate
3238  // from the target
3239  else if (MatchMethod13(j,srccan,segment,fdctrackcandidates,
3240  forward_matches)){
3241  if (DEBUG_LEVEL>0) _DBG_ << "Matched FDC segments using method #13" << endl;
3242  num_fdc_cands_remaining-=2;
3243  got_new_match=true;
3244  }
3245  } // not already matched
3246  }
3247  return got_new_match;
3248 }
3249 
3250 // Routine for updating the position and radius given an input position pos.
3251 // If the circle from the track intersects the circle with a radius just outside
3252 // the start counter, returns the position and momentum at the place where the
3253 // two circles intersect. If the two circles do not intersect, returns the
3254 // position at the doca to the beam line. If the z position is far upstream
3255 // of the active volume for either case, places the position at z=0.
3257  double Bz,
3258  const DVector3 &origin,
3259  DVector3 &pos,
3260  DVector3 &mom) const{
3261  // Get position at fixed radius with respect to the beam line
3262  if (GetPositionAndMomentum(fit,Bz,origin,pos,mom)!=NOERROR){
3263  // Get position and momentum at doca to beam line
3264  GetPositionAndMomentum(fit,Bz,pos,mom);
3265  }
3266  // if the z-position is far away from the active volume of the detector,
3267  // place position at fixed z=0.
3268  if (pos.z()<0){
3269  GetPositionAndMomentum(0.,fit,Bz,pos,mom);
3270  }
3271 }
3272 
3273 // Returns false if the z position at the doca to the beam line is less than 0
3275  const{
3276  double phi0=atan2(-fdccan->xc,fdccan->yc);
3277  double q=fdccan->charge();
3278  if (FactorForSenseOfRotation*q<0) phi0+=M_PI;
3279  double sinphi0=sin(phi0);
3280  double sign=(sinphi0>0)?1.:-1.;
3281  if (fabs(sinphi0)<1e-8) sinphi0=sign*1e-8;
3282  double D=q*fdccan->rc-fdccan->xc/sinphi0;
3283  double x=-D*sinphi0;
3284  double y=D*cos(phi0);
3285  DVector3 pos=fdccan->position();
3286  double dx=pos.x()-x;
3287  double dy=pos.y()-y;
3288  double ratio=sqrt(dx*dx+dy*dy)/(2.*fdccan->rc);
3289  double phi_s=(ratio<1.)?2.*asin(ratio):M_PI;
3290  double newz=pos.z()-phi_s*tan(M_PI_2-fdccan->momentum().Theta())*fdccan->rc;
3291 
3292  return (newz>0);
3293 }
3294 
3295 
void setMomentum(const DVector3 &aMomentum)
DVector2 xy
rough x,y coordinates in lab coordinate system
Definition: DFDCPseudo.h:100
#define BEAM_VAR
DApplication * dapp
#define EPS
double rc
Definition: DFDCSegment.h:59
bool SegmentSortByLayerincreasing(const DFDCSegment *const &segment1, const DFDCSegment *const &segment2)
double z_vertex
Definition: DFDCSegment.h:65
const DCDCWire * wire
Definition: DCDCTrackHit.h:37
TVector2 DVector2
Definition: DVector2.h:9
TVector3 DVector3
Definition: DVector3.h:14
virtual jerror_t brun(JEventLoop *eventLoop, int32_t runnumber)
double Bz_avg
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
float z_vertex
Definition: DHelicalFit.h:158
double phi0
Definition: DFDCSegment.h:65
#define y
DMagneticFieldMap * GetBfield(unsigned int run_number=1)
bool MatchMethod8(const DTrackCandidate *cdccan, vector< int > &forward_matches)
const DVector3 & position(void) const
const DFDCWire * wire
DFDCWire for this wire.
Definition: DFDCPseudo.h:92
void UpdatePositionAndMomentum(DHelicalFit &fit, double Bz, const DVector3 &origin, DVector3 &pos, DVector3 &mom) const
bool cdc_fdc_match(double p_fdc, double p_cdc, double dist)
bool MatchMethod3(const DTrackCandidate *cdccan, vector< int > &forward_matches)
jerror_t FitCircleRiemann(float rc=0.)
Definition: DHelicalFit.cc:505
class DFDCPseudo: definition for a reconstructed point in the FDC
Definition: DFDCPseudo.h:74
void MatchMethod6(DTrackCandidate *can, vector< const DFDCPseudo * > &fdchits, vector< unsigned int > &used_cdc_hits, unsigned int &num_unmatched_cdcs)
virtual jerror_t evnt(JEventLoop *loop, uint64_t eventnumber)
Invoked via JEventProcessor virtual method.
bool MakeCandidateFromMethod1(double theta, vector< const DFDCSegment * > &segments, const DTrackCandidate *cdccan)
bool MatchMethod2(const DTrackCandidate *fdccan, const DTrackCandidate *cdccan)
DMagneticFieldStepper class.
double xc
Definition: DFDCSegment.h:59
bool TryToFlipDirection(vector< const DSCHit * > &scihits, DVector3 &mom, DVector3 &pos) const
jerror_t AddHitXYZ(float x, float y, float z)
Definition: DHelicalFit.cc:200
int layer
1-24
Definition: DFDCWire.h:16
unsigned int package
Definition: DFDCSegment.h:73
jerror_t AddHit(float r, float phi, float z)
Definition: DHelicalFit.cc:190
TEllipse * e
vector< int > used_cdc_indexes
bool MatchMethod7(DTrackCandidate *srccan, vector< int > &forward_matches, int &num_fdc_cands_remaining)
vector< const DFDCPseudo * > hits
Definition: DFDCSegment.h:76
bool MatchMethod10(unsigned int src_index, const DTrackCandidate *srccan, const DFDCSegment *segment, vector< const DTrackCandidate * > &cands, vector< int > &forward_matches)
jerror_t GuessChargeFromCircleFit(void)
Definition: DHelicalFit.cc:887
double Phi1
Definition: DFDCSegment.h:63
bool MatchMethod13(unsigned int src_index, const DTrackCandidate *srccan, const DFDCSegment *segment, vector< const DTrackCandidate * > &cands, vector< int > &forward_matches)
int straw
Definition: DCDCWire.h:81
bool MatchStraySegments(vector< int > &forward_matches, int &num_fdc_cands_remaining)
double dE
energy deposition, from integral
Definition: DFDCPseudo.h:96
DGeometry * GetDGeometry(unsigned int run_number)
#define _DBG_
Definition: HDEVIO.h:12
double DocaToHelix(const DCDCTrackHit *hit, double q, const DVector3 &pos, const DVector3 &mom)
jerror_t DoRefit(DHelicalFit &fit, vector< const DFDCSegment * >segments, vector< const DCDCTrackHit * >cdchits, double &Bz)
void ProjectHelixToZ(const double z, const double q, const DVector3 &mom, DVector3 &pos)
jerror_t FitCircle(void)
Definition: DHelicalFit.cc:385
bool MatchMethod12(DTrackCandidate *srccan, vector< int > &forward_matches, int &num_fdc_cands_remaining)
const vector< DHFHit_t * > GetHits() const
Definition: DHelicalFit.h:132
bool MatchMethod1(const DTrackCandidate *fdccan, vector< unsigned int > &cdc_forward_ids, vector< DVector3 > &cdc_endplate_projections, vector< int > &cdc_forward_matches)
bool CDCHitSortByLayerincreasing(const DCDCTrackHit *const &hit1, const DCDCTrackHit *const &hit2)
bool MatchMethod5(DTrackCandidate *can, vector< const DCDCTrackHit * > &cdchits, vector< int > &forward_matches)
double charge(void) const
TH1D * py[NCHANNELS]
&lt;A href=&quot;index.html#legend&quot;&gt; &lt;IMG src=&quot;CORE.png&quot; width=&quot;100&quot;&gt; &lt;/A&gt;
void setPID(Particle_t locPID)
jerror_t FitLineRiemann(void)
Definition: DHelicalFit.cc:660
double sqrt(double)
double tanl
Definition: DFDCSegment.h:67
double sin(double)
float chisq
Chi-squared for the track (not chisq/dof!)
bool MatchMethod9(unsigned int src_index, const DTrackCandidate *srccan, const DFDCSegment *segment, vector< const DTrackCandidate * > &cands, vector< int > &forward_matches)
bool CheckZPosition(const DTrackCandidate *fdccan) const
void FindSenseOfRotation(void)
jerror_t FitCircleStraightTrack()
Definition: DHelicalFit.cc:762
const DVector3 & momentum(void) const
double GetSenseOfRotation(DHelicalFit &fit, const DFDCPseudo *fdchit, const DVector3 &pos)
int wire
1-N
Definition: DFDCWire.h:17
int ring
Definition: DCDCWire.h:80
bool FDCHitSortByLayerincreasing(const DFDCPseudo *const &hit1, const DFDCPseudo *const &hit2)
jerror_t PruneHit(int idx)
Definition: DHelicalFit.cc:330
void GetPositionAndMomentum(const DFDCSegment *segment, DVector3 &pos, DVector3 &mom) const
double q
Definition: DFDCSegment.h:69
float x
Definition: DHelicalFit.h:84
int Ndof
Number of degrees of freedom in the fit.
bool GetCDCEndplate(double &z, double &dz, double &rmin, double &rmax) const
Definition: DGeometry.cc:1497
void setPosition(const DVector3 &aPosition)
bool MatchMethod11(double q, DVector3 &mypos, DVector3 &mymom, DHelicalFit &fit2, const DFDCSegment *segment1, const DFDCSegment *segment2)
TDirectory * dir
Definition: bcal_hist_eff.C:31
bool MatchMethod4(const DTrackCandidate *srccan, vector< int > &forward_matches, int &num_fdc_cands_remaining)
class DFDCSegment: definition for a track segment in the FDC
Definition: DFDCSegment.h:31
bool GetTargetZ(double &z_target) const
z-location of center of target
Definition: DGeometry.cc:1933
float z
point in lab coordinates
Definition: DHelicalFit.h:84
float y
Definition: DHelicalFit.h:84
Particle_t PID(void) const
bool GetStartCounterGeom(vector< vector< DVector3 > > &pos, vector< vector< DVector3 > > &norm) const
Definition: DGeometry.cc:1983
double yc
Definition: DFDCSegment.h:59
Particle_t
Definition: particleType.h:12